blob: 8a1628e81f3c8826e3a1cb97b35e28f40aac8c41 [file] [log] [blame]
Eric Andersendf82f612001-06-28 07:46:40 +00001/* vi: set sw=4 ts=4: */
2/*
3 * ash shell port for busybox
4 *
Denys Vlasenko73067272010-01-12 22:11:24 +01005 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
8 * Original BSD copyright notice is retained at the end of this file.
9 *
Eric Andersendf82f612001-06-28 07:46:40 +000010 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000011 * The Regents of the University of California. All rights reserved.
Eric Andersencb57d552001-06-28 07:25:16 +000012 *
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
Eric Andersen81fe1232003-07-29 06:38:40 +000014 * was re-ported from NetBSD and debianized.
15 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +020016 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Eric Andersencb57d552001-06-28 07:25:16 +000017 */
18
Eric Andersenc470f442003-07-28 09:56:35 +000019/*
Denis Vlasenko653d8e72009-03-19 21:59:35 +000020 * The following should be set to reflect the type of system you have:
Eric Andersenc470f442003-07-28 09:56:35 +000021 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
22 * define SYSV if you are running under System V.
23 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
24 * define DEBUG=2 to compile in and turn on debugging.
25 *
Denys Vlasenkof451b2c2012-06-09 02:06:57 +020026 * When debugging is on (DEBUG is 1 and "set -o debug" was executed),
27 * debugging info will be written to ./trace and a quit signal
28 * will generate a core dump.
Eric Andersenc470f442003-07-28 09:56:35 +000029 */
Denis Vlasenkof1733952009-03-19 23:21:55 +000030#define DEBUG 0
Denis Vlasenko653d8e72009-03-19 21:59:35 +000031/* Tweak debug output verbosity here */
32#define DEBUG_TIME 0
33#define DEBUG_PID 1
34#define DEBUG_SIG 1
35
Eric Andersenc470f442003-07-28 09:56:35 +000036#define PROFILE 0
Denis Vlasenko0e6f6612008-02-15 15:02:15 +000037
Denis Vlasenko0e6f6612008-02-15 15:02:15 +000038#define JOBS ENABLE_ASH_JOB_CONTROL
Eric Andersenc470f442003-07-28 09:56:35 +000039
Denis Vlasenkob012b102007-02-19 22:43:01 +000040#include <paths.h>
41#include <setjmp.h>
42#include <fnmatch.h>
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020043#include <sys/times.h>
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020044#include <sys/utsname.h> /* for setting $HOSTNAME */
Denys Vlasenko73067272010-01-12 22:11:24 +010045
Denys Vlasenko20704f02011-03-23 17:59:27 +010046#include "busybox.h" /* for applet_names */
47#include "unicode.h"
48
Denys Vlasenko73067272010-01-12 22:11:24 +010049#include "shell_common.h"
Denys Vlasenko26777aa2010-11-22 23:49:10 +010050#if ENABLE_SH_MATH_SUPPORT
51# include "math.h"
52#endif
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020053#if ENABLE_ASH_RANDOM_SUPPORT
54# include "random.h"
Denys Vlasenko36df0482009-10-19 16:07:28 +020055#else
56# define CLEAR_RANDOM_T(rnd) ((void)0)
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020057#endif
Denis Vlasenko61befda2008-11-25 01:36:03 +000058
Denys Vlasenko1fcbff22010-06-26 02:40:08 +020059#include "NUM_APPLETS.h"
Denys Vlasenko14974842010-03-23 01:08:26 +010060#if NUM_APPLETS == 1
Denis Vlasenko61befda2008-11-25 01:36:03 +000061/* STANDALONE does not make sense, and won't compile */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020062# undef CONFIG_FEATURE_SH_STANDALONE
63# undef ENABLE_FEATURE_SH_STANDALONE
64# undef IF_FEATURE_SH_STANDALONE
Denys Vlasenko14974842010-03-23 01:08:26 +010065# undef IF_NOT_FEATURE_SH_STANDALONE
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020066# define ENABLE_FEATURE_SH_STANDALONE 0
67# define IF_FEATURE_SH_STANDALONE(...)
68# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
Eric Andersencb57d552001-06-28 07:25:16 +000069#endif
70
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000071#ifndef PIPE_BUF
Denis Vlasenko653d8e72009-03-19 21:59:35 +000072# define PIPE_BUF 4096 /* amount of buffering in a pipe */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000073#endif
74
Denys Vlasenko153fcaa2010-02-21 05:17:41 +010075#if !BB_MMU
Denis Vlasenko653d8e72009-03-19 21:59:35 +000076# error "Do not even bother, ash will not run on NOMMU machine"
Denis Vlasenkob012b102007-02-19 22:43:01 +000077#endif
78
Denys Vlasenko771f1992010-07-16 14:31:34 +020079//config:config ASH
80//config: bool "ash"
81//config: default y
82//config: depends on !NOMMU
83//config: help
84//config: Tha 'ash' shell adds about 60k in the default configuration and is
85//config: the most complete and most pedantically correct shell included with
86//config: busybox. This shell is actually a derivative of the Debian 'dash'
87//config: shell (by Herbert Xu), which was created by porting the 'ash' shell
88//config: (written by Kenneth Almquist) from NetBSD.
89//config:
90//config:config ASH_BASH_COMPAT
91//config: bool "bash-compatible extensions"
92//config: default y
93//config: depends on ASH
94//config: help
95//config: Enable bash-compatible extensions.
96//config:
Denys Vlasenko046341e2011-02-04 17:53:59 +010097//config:config ASH_IDLE_TIMEOUT
98//config: bool "Idle timeout variable"
99//config: default n
100//config: depends on ASH
101//config: help
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100102//config: Enables bash-like auto-logout after $TMOUT seconds of idle time.
Denys Vlasenko046341e2011-02-04 17:53:59 +0100103//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200104//config:config ASH_JOB_CONTROL
105//config: bool "Job control"
106//config: default y
107//config: depends on ASH
108//config: help
109//config: Enable job control in the ash shell.
110//config:
111//config:config ASH_ALIAS
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100112//config: bool "Alias support"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200113//config: default y
114//config: depends on ASH
115//config: help
116//config: Enable alias support in the ash shell.
117//config:
118//config:config ASH_GETOPTS
119//config: bool "Builtin getopt to parse positional parameters"
120//config: default y
121//config: depends on ASH
122//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100123//config: Enable support for getopts builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200124//config:
125//config:config ASH_BUILTIN_ECHO
126//config: bool "Builtin version of 'echo'"
127//config: default y
128//config: depends on ASH
129//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100130//config: Enable support for echo builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200131//config:
132//config:config ASH_BUILTIN_PRINTF
133//config: bool "Builtin version of 'printf'"
134//config: default y
135//config: depends on ASH
136//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100137//config: Enable support for printf builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200138//config:
139//config:config ASH_BUILTIN_TEST
140//config: bool "Builtin version of 'test'"
141//config: default y
142//config: depends on ASH
143//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100144//config: Enable support for test builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200145//config:
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200146//config:config ASH_HELP
147//config: bool "help builtin"
148//config: default y
149//config: depends on ASH
150//config: help
151//config: Enable help builtin in ash.
152//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200153//config:config ASH_CMDCMD
154//config: bool "'command' command to override shell builtins"
155//config: default y
156//config: depends on ASH
157//config: help
158//config: Enable support for the ash 'command' builtin, which allows
159//config: you to run the specified command with the specified arguments,
160//config: even when there is an ash builtin command with the same name.
161//config:
162//config:config ASH_MAIL
163//config: bool "Check for new mail on interactive shells"
164//config: default n
165//config: depends on ASH
166//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100167//config: Enable "check for new mail" function in the ash shell.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200168//config:
169//config:config ASH_OPTIMIZE_FOR_SIZE
170//config: bool "Optimize for size instead of speed"
171//config: default y
172//config: depends on ASH
173//config: help
174//config: Compile ash for reduced size at the price of speed.
175//config:
176//config:config ASH_RANDOM_SUPPORT
177//config: bool "Pseudorandom generator and $RANDOM variable"
178//config: default y
179//config: depends on ASH
180//config: help
181//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
182//config: Each read of "$RANDOM" will generate a new pseudorandom value.
183//config: You can reset the generator by using a specified start value.
184//config: After "unset RANDOM" the generator will switch off and this
185//config: variable will no longer have special treatment.
186//config:
187//config:config ASH_EXPAND_PRMT
188//config: bool "Expand prompt string"
189//config: default y
190//config: depends on ASH
191//config: help
192//config: "PS#" may contain volatile content, such as backquote commands.
193//config: This option recreates the prompt string from the environment
194//config: variable each time it is displayed.
Denys Vlasenko51ca7762010-07-16 17:16:40 +0200195//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200196
Denys Vlasenko20704f02011-03-23 17:59:27 +0100197//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
198//applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, sh))
199//applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, bash))
200
201//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
202//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
203
Denis Vlasenkob012b102007-02-19 22:43:01 +0000204
Denis Vlasenko01631112007-12-16 17:20:38 +0000205/* ============ Hash table sizes. Configurable. */
206
207#define VTABSIZE 39
208#define ATABSIZE 39
209#define CMDTABLESIZE 31 /* should be prime */
210
211
Denis Vlasenkob012b102007-02-19 22:43:01 +0000212/* ============ Shell options */
213
214static const char *const optletters_optnames[] = {
215 "e" "errexit",
216 "f" "noglob",
217 "I" "ignoreeof",
218 "i" "interactive",
219 "m" "monitor",
220 "n" "noexec",
221 "s" "stdin",
222 "x" "xtrace",
223 "v" "verbose",
224 "C" "noclobber",
225 "a" "allexport",
226 "b" "notify",
227 "u" "nounset",
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100228 "\0" "vi"
Michael Abbott359da5e2009-12-04 23:03:29 +0100229#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100230 ,"\0" "pipefail"
Michael Abbott359da5e2009-12-04 23:03:29 +0100231#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000232#if DEBUG
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000233 ,"\0" "nolog"
234 ,"\0" "debug"
Denis Vlasenkob012b102007-02-19 22:43:01 +0000235#endif
236};
237
Denys Vlasenko285ad152009-12-04 23:02:27 +0100238#define optletters(n) optletters_optnames[n][0]
239#define optnames(n) (optletters_optnames[n] + 1)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000240
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000241enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
Denis Vlasenkob012b102007-02-19 22:43:01 +0000242
Eric Andersenc470f442003-07-28 09:56:35 +0000243
Denis Vlasenkob012b102007-02-19 22:43:01 +0000244/* ============ Misc data */
Eric Andersenc470f442003-07-28 09:56:35 +0000245
Denys Vlasenkoea8b2522010-06-02 12:57:26 +0200246#define msg_illnum "Illegal number: %s"
Denis Vlasenkoaa744452007-02-23 01:04:22 +0000247
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +0000248/*
Eric Andersenc470f442003-07-28 09:56:35 +0000249 * We enclose jmp_buf in a structure so that we can declare pointers to
250 * jump locations. The global variable handler contains the location to
Denis Vlasenkof1733952009-03-19 23:21:55 +0000251 * jump to when an exception occurs, and the global variable exception_type
Eric Andersenaff114c2004-04-14 17:51:38 +0000252 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000253 * exception handlers, the user should save the value of handler on entry
254 * to an inner scope, set handler to point to a jmploc structure for the
255 * inner scope, and restore handler on exit from the scope.
256 */
Eric Andersenc470f442003-07-28 09:56:35 +0000257struct jmploc {
258 jmp_buf loc;
259};
Denis Vlasenko01631112007-12-16 17:20:38 +0000260
261struct globals_misc {
262 /* pid of main shell */
263 int rootpid;
264 /* shell level: 0 for the main shell, 1 for its children, and so on */
265 int shlvl;
266#define rootshell (!shlvl)
267 char *minusc; /* argument to -c option */
268
269 char *curdir; // = nullstr; /* current working directory */
270 char *physdir; // = nullstr; /* physical working directory */
271
272 char *arg0; /* value of $0 */
273
274 struct jmploc *exception_handler;
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000275
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200276 volatile int suppress_int; /* counter */
277 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000278 /* last pending signal */
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200279 volatile /*sig_atomic_t*/ smallint pending_sig;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000280 smallint exception_type; /* kind of exception (0..5) */
Denis Vlasenko01631112007-12-16 17:20:38 +0000281 /* exceptions */
Eric Andersenc470f442003-07-28 09:56:35 +0000282#define EXINT 0 /* SIGINT received */
283#define EXERROR 1 /* a generic error */
284#define EXSHELLPROC 2 /* execute a shell procedure */
285#define EXEXEC 3 /* command execution failed */
286#define EXEXIT 4 /* exit the shell */
287#define EXSIG 5 /* trapped signal in wait(1) */
Eric Andersen2870d962001-07-02 17:27:21 +0000288
Denis Vlasenko01631112007-12-16 17:20:38 +0000289 smallint isloginsh;
Denis Vlasenkob07a4962008-06-22 13:16:23 +0000290 char nullstr[1]; /* zero length string */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000291
292 char optlist[NOPTS];
293#define eflag optlist[0]
294#define fflag optlist[1]
295#define Iflag optlist[2]
296#define iflag optlist[3]
297#define mflag optlist[4]
298#define nflag optlist[5]
299#define sflag optlist[6]
300#define xflag optlist[7]
301#define vflag optlist[8]
302#define Cflag optlist[9]
303#define aflag optlist[10]
304#define bflag optlist[11]
305#define uflag optlist[12]
306#define viflag optlist[13]
Michael Abbott359da5e2009-12-04 23:03:29 +0100307#if ENABLE_ASH_BASH_COMPAT
308# define pipefail optlist[14]
309#else
310# define pipefail 0
311#endif
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000312#if DEBUG
Michael Abbott359da5e2009-12-04 23:03:29 +0100313# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT]
314# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT]
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000315#endif
316
317 /* trap handler commands */
Denis Vlasenko01631112007-12-16 17:20:38 +0000318 /*
319 * Sigmode records the current value of the signal handlers for the various
320 * modes. A value of zero means that the current handler is not known.
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000321 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
Denis Vlasenko01631112007-12-16 17:20:38 +0000322 */
323 char sigmode[NSIG - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000324#define S_DFL 1 /* default signal handling (SIG_DFL) */
325#define S_CATCH 2 /* signal is caught */
326#define S_IGN 3 /* signal is ignored (SIG_IGN) */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000327#define S_HARD_IGN 4 /* signal is ignored permenantly */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000328
Denis Vlasenko01631112007-12-16 17:20:38 +0000329 /* indicates specified signal received */
Denis Vlasenko4b875702009-03-19 13:30:04 +0000330 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
Denys Vlasenko238bf182010-05-18 15:49:07 +0200331 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000332 char *trap[NSIG];
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200333 char **trap_ptr; /* used only by "trap hack" */
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000334
335 /* Rarely referenced stuff */
336#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200337 random_t random_gen;
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000338#endif
339 pid_t backgndpid; /* pid of last background process */
340 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
Denis Vlasenko01631112007-12-16 17:20:38 +0000341};
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000342extern struct globals_misc *const ash_ptr_to_globals_misc;
343#define G_misc (*ash_ptr_to_globals_misc)
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000344#define rootpid (G_misc.rootpid )
345#define shlvl (G_misc.shlvl )
346#define minusc (G_misc.minusc )
347#define curdir (G_misc.curdir )
348#define physdir (G_misc.physdir )
349#define arg0 (G_misc.arg0 )
Denis Vlasenko01631112007-12-16 17:20:38 +0000350#define exception_handler (G_misc.exception_handler)
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000351#define exception_type (G_misc.exception_type )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200352#define suppress_int (G_misc.suppress_int )
353#define pending_int (G_misc.pending_int )
354#define pending_sig (G_misc.pending_sig )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000355#define isloginsh (G_misc.isloginsh )
356#define nullstr (G_misc.nullstr )
357#define optlist (G_misc.optlist )
358#define sigmode (G_misc.sigmode )
359#define gotsig (G_misc.gotsig )
Denys Vlasenko238bf182010-05-18 15:49:07 +0200360#define may_have_traps (G_misc.may_have_traps )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000361#define trap (G_misc.trap )
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200362#define trap_ptr (G_misc.trap_ptr )
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200363#define random_gen (G_misc.random_gen )
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000364#define backgndpid (G_misc.backgndpid )
365#define job_warning (G_misc.job_warning)
Denis Vlasenko01631112007-12-16 17:20:38 +0000366#define INIT_G_misc() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000367 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
368 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +0000369 curdir = nullstr; \
370 physdir = nullstr; \
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200371 trap_ptr = trap; \
Denis Vlasenko01631112007-12-16 17:20:38 +0000372} while (0)
373
374
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000375/* ============ DEBUG */
376#if DEBUG
377static void trace_printf(const char *fmt, ...);
378static void trace_vprintf(const char *fmt, va_list va);
379# define TRACE(param) trace_printf param
380# define TRACEV(param) trace_vprintf param
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000381# define close(fd) do { \
382 int dfd = (fd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000383 if (close(dfd) < 0) \
Denys Vlasenko883cea42009-07-11 15:31:59 +0200384 bb_error_msg("bug on %d: closing %d(0x%x)", \
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000385 __LINE__, dfd, dfd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000386} while (0)
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000387#else
388# define TRACE(param)
389# define TRACEV(param)
390#endif
391
392
Denis Vlasenko559691a2008-10-05 18:39:31 +0000393/* ============ Utility functions */
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000394#define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
395
Denys Vlasenko1961aea2013-02-26 00:36:53 +0100396#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
397#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
398
Denis Vlasenko559691a2008-10-05 18:39:31 +0000399static int isdigit_str9(const char *str)
400{
401 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
402 while (--maxlen && isdigit(*str))
403 str++;
404 return (*str == '\0');
405}
Denis Vlasenko01631112007-12-16 17:20:38 +0000406
Denys Vlasenko8837c5d2010-06-02 12:56:18 +0200407static const char *var_end(const char *var)
408{
409 while (*var)
410 if (*var++ == '=')
411 break;
412 return var;
413}
414
Denis Vlasenko559691a2008-10-05 18:39:31 +0000415
416/* ============ Interrupts / exceptions */
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100417
418static void exitshell(void) NORETURN;
419
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000420/*
Eric Andersen2870d962001-07-02 17:27:21 +0000421 * These macros allow the user to suspend the handling of interrupt signals
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000422 * over a period of time. This is similar to SIGHOLD or to sigblock, but
Eric Andersen2870d962001-07-02 17:27:21 +0000423 * much more efficient and portable. (But hacking the kernel is so much
424 * more fun than worrying about efficiency and portability. :-))
425 */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000426#define INT_OFF do { \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200427 suppress_int++; \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000428 xbarrier(); \
429} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000430
431/*
432 * Called to raise an exception. Since C doesn't include exceptions, we
433 * just do a longjmp to the exception handler. The type of exception is
Denis Vlasenko4b875702009-03-19 13:30:04 +0000434 * stored in the global variable "exception_type".
Denis Vlasenkob012b102007-02-19 22:43:01 +0000435 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000436static void raise_exception(int) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000437static void
438raise_exception(int e)
439{
440#if DEBUG
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000441 if (exception_handler == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000442 abort();
443#endif
444 INT_OFF;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000445 exception_type = e;
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000446 longjmp(exception_handler->loc, 1);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000447}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000448#if DEBUG
449#define raise_exception(e) do { \
450 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
451 raise_exception(e); \
452} while (0)
453#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000454
455/*
456 * Called from trap.c when a SIGINT is received. (If the user specifies
457 * that SIGINT is to be trapped or ignored using the trap builtin, then
458 * this routine is not called.) Suppressint is nonzero when interrupts
459 * are held using the INT_OFF macro. (The test for iflag is just
460 * defensive programming.)
461 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000462static void raise_interrupt(void) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000463static void
464raise_interrupt(void)
465{
Denis Vlasenko4b875702009-03-19 13:30:04 +0000466 int ex_type;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000467
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200468 pending_int = 0;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000469 /* Signal is not automatically unmasked after it is raised,
470 * do it ourself - unmask all signals */
Denis Vlasenko3f165fa2008-03-17 08:29:08 +0000471 sigprocmask_allsigs(SIG_UNBLOCK);
Denys Vlasenko238bf182010-05-18 15:49:07 +0200472 /* pending_sig = 0; - now done in signal_handler() */
Denis Vlasenko7c139b42007-03-21 20:17:27 +0000473
Denis Vlasenko4b875702009-03-19 13:30:04 +0000474 ex_type = EXSIG;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000475 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
476 if (!(rootshell && iflag)) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000477 /* Kill ourself with SIGINT */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000478 signal(SIGINT, SIG_DFL);
479 raise(SIGINT);
480 }
Denis Vlasenko4b875702009-03-19 13:30:04 +0000481 ex_type = EXINT;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000482 }
Denis Vlasenko4b875702009-03-19 13:30:04 +0000483 raise_exception(ex_type);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000484 /* NOTREACHED */
485}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000486#if DEBUG
487#define raise_interrupt() do { \
488 TRACE(("raising interrupt on line %d\n", __LINE__)); \
489 raise_interrupt(); \
490} while (0)
491#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000492
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000493static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000494int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000495{
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +0000496 xbarrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200497 if (--suppress_int == 0 && pending_int) {
Denis Vlasenkob012b102007-02-19 22:43:01 +0000498 raise_interrupt();
499 }
500}
501#define INT_ON int_on()
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000502static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000503force_int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000504{
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +0000505 xbarrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200506 suppress_int = 0;
507 if (pending_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000508 raise_interrupt();
509}
510#define FORCE_INT_ON force_int_on()
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000511
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200512#define SAVE_INT(v) ((v) = suppress_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000513
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000514#define RESTORE_INT(v) do { \
515 xbarrier(); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200516 suppress_int = (v); \
517 if (suppress_int == 0 && pending_int) \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000518 raise_interrupt(); \
519} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000520
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000521
Denis Vlasenkobc54cff2007-02-23 01:05:52 +0000522/* ============ Stdout/stderr output */
Eric Andersenc470f442003-07-28 09:56:35 +0000523
Eric Andersenc470f442003-07-28 09:56:35 +0000524static void
Denis Vlasenkob012b102007-02-19 22:43:01 +0000525outstr(const char *p, FILE *file)
Denis Vlasenkoe5570da2007-02-19 22:41:55 +0000526{
Denis Vlasenkob012b102007-02-19 22:43:01 +0000527 INT_OFF;
528 fputs(p, file);
529 INT_ON;
530}
531
532static void
533flush_stdout_stderr(void)
534{
535 INT_OFF;
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100536 fflush_all();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000537 INT_ON;
538}
539
Denys Vlasenko9c541002015-10-07 15:44:36 +0200540/* Was called outcslow(c,FILE*), but c was always '\n' */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000541static void
Denys Vlasenko9c541002015-10-07 15:44:36 +0200542newline_and_flush(FILE *dest)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000543{
544 INT_OFF;
Denys Vlasenko9c541002015-10-07 15:44:36 +0200545 putc('\n', dest);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000546 fflush(dest);
547 INT_ON;
548}
549
550static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
551static int
552out1fmt(const char *fmt, ...)
553{
554 va_list ap;
555 int r;
556
557 INT_OFF;
558 va_start(ap, fmt);
559 r = vprintf(fmt, ap);
560 va_end(ap);
561 INT_ON;
562 return r;
563}
564
565static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
566static int
567fmtstr(char *outbuf, size_t length, const char *fmt, ...)
568{
569 va_list ap;
570 int ret;
571
572 va_start(ap, fmt);
573 INT_OFF;
574 ret = vsnprintf(outbuf, length, fmt, ap);
575 va_end(ap);
576 INT_ON;
577 return ret;
578}
579
580static void
581out1str(const char *p)
582{
583 outstr(p, stdout);
584}
585
586static void
587out2str(const char *p)
588{
589 outstr(p, stderr);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100590 flush_stdout_stderr();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000591}
592
593
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000594/* ============ Parser structures */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +0000595
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000596/* control characters in argument strings */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100597#define CTL_FIRST CTLESC
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200598#define CTLESC ((unsigned char)'\201') /* escape next character */
599#define CTLVAR ((unsigned char)'\202') /* variable defn */
600#define CTLENDVAR ((unsigned char)'\203')
601#define CTLBACKQ ((unsigned char)'\204')
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200602#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
603#define CTLENDARI ((unsigned char)'\207')
604#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100605#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000606
607/* variable substitution byte (follows CTLVAR) */
608#define VSTYPE 0x0f /* type of variable substitution */
609#define VSNUL 0x10 /* colon--treat the empty string as unset */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000610
611/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000612#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
613#define VSMINUS 0x2 /* ${var-text} */
614#define VSPLUS 0x3 /* ${var+text} */
615#define VSQUESTION 0x4 /* ${var?message} */
616#define VSASSIGN 0x5 /* ${var=text} */
617#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
618#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
619#define VSTRIMLEFT 0x8 /* ${var#pattern} */
620#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
621#define VSLENGTH 0xa /* ${#var} */
622#if ENABLE_ASH_BASH_COMPAT
623#define VSSUBSTR 0xc /* ${var:position:length} */
624#define VSREPLACE 0xd /* ${var/pattern/replacement} */
625#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
626#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000627
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000628static const char dolatstr[] ALIGN1 = {
Ron Yorston549deab2015-05-18 09:57:51 +0200629 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000630};
Ron Yorston549deab2015-05-18 09:57:51 +0200631#define DOLATSTRLEN 6
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000632
Denis Vlasenko559691a2008-10-05 18:39:31 +0000633#define NCMD 0
634#define NPIPE 1
635#define NREDIR 2
636#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000637#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000638#define NAND 5
639#define NOR 6
640#define NSEMI 7
641#define NIF 8
642#define NWHILE 9
643#define NUNTIL 10
644#define NFOR 11
645#define NCASE 12
646#define NCLIST 13
647#define NDEFUN 14
648#define NARG 15
649#define NTO 16
650#if ENABLE_ASH_BASH_COMPAT
651#define NTO2 17
652#endif
653#define NCLOBBER 18
654#define NFROM 19
655#define NFROMTO 20
656#define NAPPEND 21
657#define NTOFD 22
658#define NFROMFD 23
659#define NHERE 24
660#define NXHERE 25
661#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000662#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000663
664union node;
665
666struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000667 smallint type; /* Nxxxx */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000668 union node *assign;
669 union node *args;
670 union node *redirect;
671};
672
673struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000674 smallint type;
675 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000676 struct nodelist *cmdlist;
677};
678
679struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000680 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000681 union node *n;
682 union node *redirect;
683};
684
685struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000686 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000687 union node *ch1;
688 union node *ch2;
689};
690
691struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000692 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000693 union node *test;
694 union node *ifpart;
695 union node *elsepart;
696};
697
698struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000699 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000700 union node *args;
701 union node *body;
702 char *var;
703};
704
705struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000706 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000707 union node *expr;
708 union node *cases;
709};
710
711struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000712 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000713 union node *next;
714 union node *pattern;
715 union node *body;
716};
717
718struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000719 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000720 union node *next;
721 char *text;
722 struct nodelist *backquote;
723};
724
Denis Vlasenko559691a2008-10-05 18:39:31 +0000725/* nfile and ndup layout must match!
726 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
727 * that it is actually NTO2 (>&file), and change its type.
728 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000729struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000730 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000731 union node *next;
732 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000733 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000734 union node *fname;
735 char *expfname;
736};
737
738struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000739 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000740 union node *next;
741 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000742 int dupfd;
743 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000744 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000745};
746
747struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000748 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000749 union node *next;
750 int fd;
751 union node *doc;
752};
753
754struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000755 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000756 union node *com;
757};
758
759union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000760 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000761 struct ncmd ncmd;
762 struct npipe npipe;
763 struct nredir nredir;
764 struct nbinary nbinary;
765 struct nif nif;
766 struct nfor nfor;
767 struct ncase ncase;
768 struct nclist nclist;
769 struct narg narg;
770 struct nfile nfile;
771 struct ndup ndup;
772 struct nhere nhere;
773 struct nnot nnot;
774};
775
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200776/*
777 * NODE_EOF is returned by parsecmd when it encounters an end of file.
778 * It must be distinct from NULL.
779 */
780#define NODE_EOF ((union node *) -1L)
781
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000782struct nodelist {
783 struct nodelist *next;
784 union node *n;
785};
786
787struct funcnode {
788 int count;
789 union node n;
790};
791
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000792/*
793 * Free a parse tree.
794 */
795static void
796freefunc(struct funcnode *f)
797{
798 if (f && --f->count < 0)
799 free(f);
800}
801
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000802
803/* ============ Debugging output */
804
805#if DEBUG
806
807static FILE *tracefile;
808
809static void
810trace_printf(const char *fmt, ...)
811{
812 va_list va;
813
814 if (debug != 1)
815 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000816 if (DEBUG_TIME)
817 fprintf(tracefile, "%u ", (int) time(NULL));
818 if (DEBUG_PID)
819 fprintf(tracefile, "[%u] ", (int) getpid());
820 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200821 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000822 va_start(va, fmt);
823 vfprintf(tracefile, fmt, va);
824 va_end(va);
825}
826
827static void
828trace_vprintf(const char *fmt, va_list va)
829{
830 if (debug != 1)
831 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000832 if (DEBUG_TIME)
833 fprintf(tracefile, "%u ", (int) time(NULL));
834 if (DEBUG_PID)
835 fprintf(tracefile, "[%u] ", (int) getpid());
836 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200837 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000838 vfprintf(tracefile, fmt, va);
839}
840
841static void
842trace_puts(const char *s)
843{
844 if (debug != 1)
845 return;
846 fputs(s, tracefile);
847}
848
849static void
850trace_puts_quoted(char *s)
851{
852 char *p;
853 char c;
854
855 if (debug != 1)
856 return;
857 putc('"', tracefile);
858 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100859 switch ((unsigned char)*p) {
860 case '\n': c = 'n'; goto backslash;
861 case '\t': c = 't'; goto backslash;
862 case '\r': c = 'r'; goto backslash;
863 case '\"': c = '\"'; goto backslash;
864 case '\\': c = '\\'; goto backslash;
865 case CTLESC: c = 'e'; goto backslash;
866 case CTLVAR: c = 'v'; goto backslash;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100867 case CTLBACKQ: c = 'q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000868 backslash:
869 putc('\\', tracefile);
870 putc(c, tracefile);
871 break;
872 default:
873 if (*p >= ' ' && *p <= '~')
874 putc(*p, tracefile);
875 else {
876 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +0100877 putc((*p >> 6) & 03, tracefile);
878 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000879 putc(*p & 07, tracefile);
880 }
881 break;
882 }
883 }
884 putc('"', tracefile);
885}
886
887static void
888trace_puts_args(char **ap)
889{
890 if (debug != 1)
891 return;
892 if (!*ap)
893 return;
894 while (1) {
895 trace_puts_quoted(*ap);
896 if (!*++ap) {
897 putc('\n', tracefile);
898 break;
899 }
900 putc(' ', tracefile);
901 }
902}
903
904static void
905opentrace(void)
906{
907 char s[100];
908#ifdef O_APPEND
909 int flags;
910#endif
911
912 if (debug != 1) {
913 if (tracefile)
914 fflush(tracefile);
915 /* leave open because libedit might be using it */
916 return;
917 }
918 strcpy(s, "./trace");
919 if (tracefile) {
920 if (!freopen(s, "a", tracefile)) {
921 fprintf(stderr, "Can't re-open %s\n", s);
922 debug = 0;
923 return;
924 }
925 } else {
926 tracefile = fopen(s, "a");
927 if (tracefile == NULL) {
928 fprintf(stderr, "Can't open %s\n", s);
929 debug = 0;
930 return;
931 }
932 }
933#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000934 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000935 if (flags >= 0)
936 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
937#endif
938 setlinebuf(tracefile);
939 fputs("\nTracing started.\n", tracefile);
940}
941
942static void
943indent(int amount, char *pfx, FILE *fp)
944{
945 int i;
946
947 for (i = 0; i < amount; i++) {
948 if (pfx && i == amount - 1)
949 fputs(pfx, fp);
950 putc('\t', fp);
951 }
952}
953
954/* little circular references here... */
955static void shtree(union node *n, int ind, char *pfx, FILE *fp);
956
957static void
958sharg(union node *arg, FILE *fp)
959{
960 char *p;
961 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100962 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000963
964 if (arg->type != NARG) {
965 out1fmt("<node type %d>\n", arg->type);
966 abort();
967 }
968 bqlist = arg->narg.backquote;
969 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100970 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000971 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -0700972 p++;
973 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000974 break;
975 case CTLVAR:
976 putc('$', fp);
977 putc('{', fp);
978 subtype = *++p;
979 if (subtype == VSLENGTH)
980 putc('#', fp);
981
Dan Fandrich77d48722010-09-07 23:38:28 -0700982 while (*p != '=') {
983 putc(*p, fp);
984 p++;
985 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000986
987 if (subtype & VSNUL)
988 putc(':', fp);
989
990 switch (subtype & VSTYPE) {
991 case VSNORMAL:
992 putc('}', fp);
993 break;
994 case VSMINUS:
995 putc('-', fp);
996 break;
997 case VSPLUS:
998 putc('+', fp);
999 break;
1000 case VSQUESTION:
1001 putc('?', fp);
1002 break;
1003 case VSASSIGN:
1004 putc('=', fp);
1005 break;
1006 case VSTRIMLEFT:
1007 putc('#', fp);
1008 break;
1009 case VSTRIMLEFTMAX:
1010 putc('#', fp);
1011 putc('#', fp);
1012 break;
1013 case VSTRIMRIGHT:
1014 putc('%', fp);
1015 break;
1016 case VSTRIMRIGHTMAX:
1017 putc('%', fp);
1018 putc('%', fp);
1019 break;
1020 case VSLENGTH:
1021 break;
1022 default:
1023 out1fmt("<subtype %d>", subtype);
1024 }
1025 break;
1026 case CTLENDVAR:
1027 putc('}', fp);
1028 break;
1029 case CTLBACKQ:
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001030 putc('$', fp);
1031 putc('(', fp);
1032 shtree(bqlist->n, -1, NULL, fp);
1033 putc(')', fp);
1034 break;
1035 default:
1036 putc(*p, fp);
1037 break;
1038 }
1039 }
1040}
1041
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001042static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001043shcmd(union node *cmd, FILE *fp)
1044{
1045 union node *np;
1046 int first;
1047 const char *s;
1048 int dftfd;
1049
1050 first = 1;
1051 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001052 if (!first)
1053 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001054 sharg(np, fp);
1055 first = 0;
1056 }
1057 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001058 if (!first)
1059 putc(' ', fp);
1060 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001061 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001062 case NTO: s = ">>"+1; dftfd = 1; break;
1063 case NCLOBBER: s = ">|"; dftfd = 1; break;
1064 case NAPPEND: s = ">>"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001065#if ENABLE_ASH_BASH_COMPAT
1066 case NTO2:
1067#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001068 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001069 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001070 case NFROMFD: s = "<&"; break;
1071 case NFROMTO: s = "<>"; break;
1072 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001073 }
1074 if (np->nfile.fd != dftfd)
1075 fprintf(fp, "%d", np->nfile.fd);
1076 fputs(s, fp);
1077 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1078 fprintf(fp, "%d", np->ndup.dupfd);
1079 } else {
1080 sharg(np->nfile.fname, fp);
1081 }
1082 first = 0;
1083 }
1084}
1085
1086static void
1087shtree(union node *n, int ind, char *pfx, FILE *fp)
1088{
1089 struct nodelist *lp;
1090 const char *s;
1091
1092 if (n == NULL)
1093 return;
1094
1095 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001096
1097 if (n == NODE_EOF) {
1098 fputs("<EOF>", fp);
1099 return;
1100 }
1101
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001102 switch (n->type) {
1103 case NSEMI:
1104 s = "; ";
1105 goto binop;
1106 case NAND:
1107 s = " && ";
1108 goto binop;
1109 case NOR:
1110 s = " || ";
1111 binop:
1112 shtree(n->nbinary.ch1, ind, NULL, fp);
1113 /* if (ind < 0) */
1114 fputs(s, fp);
1115 shtree(n->nbinary.ch2, ind, NULL, fp);
1116 break;
1117 case NCMD:
1118 shcmd(n, fp);
1119 if (ind >= 0)
1120 putc('\n', fp);
1121 break;
1122 case NPIPE:
1123 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001124 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001125 if (lp->next)
1126 fputs(" | ", fp);
1127 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001128 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001129 fputs(" &", fp);
1130 if (ind >= 0)
1131 putc('\n', fp);
1132 break;
1133 default:
1134 fprintf(fp, "<node type %d>", n->type);
1135 if (ind >= 0)
1136 putc('\n', fp);
1137 break;
1138 }
1139}
1140
1141static void
1142showtree(union node *n)
1143{
1144 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001145 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001146}
1147
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001148#endif /* DEBUG */
1149
1150
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001151/* ============ Parser data */
1152
1153/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001154 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1155 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001156struct strlist {
1157 struct strlist *next;
1158 char *text;
1159};
1160
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001161struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001162
Denis Vlasenkob012b102007-02-19 22:43:01 +00001163struct strpush {
1164 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001165 char *prev_string;
1166 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001167#if ENABLE_ASH_ALIAS
1168 struct alias *ap; /* if push was associated with an alias */
1169#endif
1170 char *string; /* remember the string since it may change */
1171};
1172
1173struct parsefile {
1174 struct parsefile *prev; /* preceding file on stack */
1175 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001176 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001177 int left_in_line; /* number of chars left in this line */
1178 int left_in_buffer; /* number of chars left in this buffer past the line */
1179 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001180 char *buf; /* input buffer */
1181 struct strpush *strpush; /* for pushing strings at this level */
1182 struct strpush basestrpush; /* so pushing one is fast */
1183};
1184
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001185static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001186static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001187static int startlinno; /* line # where last token started */
1188static char *commandname; /* currently executing command */
1189static struct strlist *cmdenviron; /* environment for builtin command */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001190static uint8_t exitstatus; /* exit status of last command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001191
1192
1193/* ============ Message printing */
1194
1195static void
1196ash_vmsg(const char *msg, va_list ap)
1197{
1198 fprintf(stderr, "%s: ", arg0);
1199 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001200 if (strcmp(arg0, commandname))
1201 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001202 if (!iflag || g_parsefile->pf_fd > 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001203 fprintf(stderr, "line %d: ", startlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001204 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001205 vfprintf(stderr, msg, ap);
Denys Vlasenko9c541002015-10-07 15:44:36 +02001206 newline_and_flush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001207}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001208
1209/*
1210 * Exverror is called to raise the error exception. If the second argument
1211 * is not NULL then error prints an error message using printf style
1212 * formatting. It then raises the error exception.
1213 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001214static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001215static void
1216ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001217{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001218#if DEBUG
1219 if (msg) {
1220 TRACE(("ash_vmsg_and_raise(%d, \"", cond));
1221 TRACEV((msg, ap));
1222 TRACE(("\") pid=%d\n", getpid()));
1223 } else
1224 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
1225 if (msg)
1226#endif
1227 ash_vmsg(msg, ap);
1228
1229 flush_stdout_stderr();
1230 raise_exception(cond);
1231 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001232}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001233
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001234static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001235static void
1236ash_msg_and_raise_error(const char *msg, ...)
1237{
1238 va_list ap;
1239
1240 va_start(ap, msg);
1241 ash_vmsg_and_raise(EXERROR, msg, ap);
1242 /* NOTREACHED */
1243 va_end(ap);
1244}
1245
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001246static void raise_error_syntax(const char *) NORETURN;
1247static void
1248raise_error_syntax(const char *msg)
1249{
1250 ash_msg_and_raise_error("syntax error: %s", msg);
1251 /* NOTREACHED */
1252}
1253
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001254static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001255static void
1256ash_msg_and_raise(int cond, const char *msg, ...)
1257{
1258 va_list ap;
1259
1260 va_start(ap, msg);
1261 ash_vmsg_and_raise(cond, msg, ap);
1262 /* NOTREACHED */
1263 va_end(ap);
1264}
1265
1266/*
1267 * error/warning routines for external builtins
1268 */
1269static void
1270ash_msg(const char *fmt, ...)
1271{
1272 va_list ap;
1273
1274 va_start(ap, fmt);
1275 ash_vmsg(fmt, ap);
1276 va_end(ap);
1277}
1278
1279/*
1280 * Return a string describing an error. The returned string may be a
1281 * pointer to a static buffer that will be overwritten on the next call.
1282 * Action describes the operation that got the error.
1283 */
1284static const char *
1285errmsg(int e, const char *em)
1286{
1287 if (e == ENOENT || e == ENOTDIR) {
1288 return em;
1289 }
1290 return strerror(e);
1291}
1292
1293
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001294/* ============ Memory allocation */
1295
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001296#if 0
1297/* I consider these wrappers nearly useless:
1298 * ok, they return you to nearest exception handler, but
1299 * how much memory do you leak in the process, making
1300 * memory starvation worse?
1301 */
1302static void *
1303ckrealloc(void * p, size_t nbytes)
1304{
1305 p = realloc(p, nbytes);
1306 if (!p)
1307 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1308 return p;
1309}
1310
1311static void *
1312ckmalloc(size_t nbytes)
1313{
1314 return ckrealloc(NULL, nbytes);
1315}
1316
1317static void *
1318ckzalloc(size_t nbytes)
1319{
1320 return memset(ckmalloc(nbytes), 0, nbytes);
1321}
1322
1323static char *
1324ckstrdup(const char *s)
1325{
1326 char *p = strdup(s);
1327 if (!p)
1328 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1329 return p;
1330}
1331#else
1332/* Using bbox equivalents. They exit if out of memory */
1333# define ckrealloc xrealloc
1334# define ckmalloc xmalloc
1335# define ckzalloc xzalloc
1336# define ckstrdup xstrdup
1337#endif
1338
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001339/*
1340 * It appears that grabstackstr() will barf with such alignments
1341 * because stalloc() will return a string allocated in a new stackblock.
1342 */
1343#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1344enum {
1345 /* Most machines require the value returned from malloc to be aligned
1346 * in some way. The following macro will get this right
1347 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001348 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001349 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001350 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001351};
1352
1353struct stack_block {
1354 struct stack_block *prev;
1355 char space[MINSIZE];
1356};
1357
1358struct stackmark {
1359 struct stack_block *stackp;
1360 char *stacknxt;
1361 size_t stacknleft;
1362 struct stackmark *marknext;
1363};
1364
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001365
Denis Vlasenko01631112007-12-16 17:20:38 +00001366struct globals_memstack {
1367 struct stack_block *g_stackp; // = &stackbase;
1368 struct stackmark *markp;
1369 char *g_stacknxt; // = stackbase.space;
1370 char *sstrend; // = stackbase.space + MINSIZE;
1371 size_t g_stacknleft; // = MINSIZE;
1372 int herefd; // = -1;
1373 struct stack_block stackbase;
1374};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001375extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1376#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001377#define g_stackp (G_memstack.g_stackp )
1378#define markp (G_memstack.markp )
1379#define g_stacknxt (G_memstack.g_stacknxt )
1380#define sstrend (G_memstack.sstrend )
1381#define g_stacknleft (G_memstack.g_stacknleft)
1382#define herefd (G_memstack.herefd )
1383#define stackbase (G_memstack.stackbase )
1384#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001385 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1386 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001387 g_stackp = &stackbase; \
1388 g_stacknxt = stackbase.space; \
1389 g_stacknleft = MINSIZE; \
1390 sstrend = stackbase.space + MINSIZE; \
1391 herefd = -1; \
1392} while (0)
1393
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001394
Denis Vlasenko01631112007-12-16 17:20:38 +00001395#define stackblock() ((void *)g_stacknxt)
1396#define stackblocksize() g_stacknleft
1397
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001398/*
1399 * Parse trees for commands are allocated in lifo order, so we use a stack
1400 * to make this more efficient, and also to avoid all sorts of exception
1401 * handling code to handle interrupts in the middle of a parse.
1402 *
1403 * The size 504 was chosen because the Ultrix malloc handles that size
1404 * well.
1405 */
1406static void *
1407stalloc(size_t nbytes)
1408{
1409 char *p;
1410 size_t aligned;
1411
1412 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001413 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001414 size_t len;
1415 size_t blocksize;
1416 struct stack_block *sp;
1417
1418 blocksize = aligned;
1419 if (blocksize < MINSIZE)
1420 blocksize = MINSIZE;
1421 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1422 if (len < blocksize)
1423 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1424 INT_OFF;
1425 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001426 sp->prev = g_stackp;
1427 g_stacknxt = sp->space;
1428 g_stacknleft = blocksize;
1429 sstrend = g_stacknxt + blocksize;
1430 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001431 INT_ON;
1432 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001433 p = g_stacknxt;
1434 g_stacknxt += aligned;
1435 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001436 return p;
1437}
1438
Denis Vlasenko597906c2008-02-20 16:38:54 +00001439static void *
1440stzalloc(size_t nbytes)
1441{
1442 return memset(stalloc(nbytes), 0, nbytes);
1443}
1444
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001445static void
1446stunalloc(void *p)
1447{
1448#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001449 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001450 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001451 abort();
1452 }
1453#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001454 g_stacknleft += g_stacknxt - (char *)p;
1455 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001456}
1457
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001458/*
1459 * Like strdup but works with the ash stack.
1460 */
1461static char *
1462ststrdup(const char *p)
1463{
1464 size_t len = strlen(p) + 1;
1465 return memcpy(stalloc(len), p, len);
1466}
1467
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001468static void
1469setstackmark(struct stackmark *mark)
1470{
Denis Vlasenko01631112007-12-16 17:20:38 +00001471 mark->stackp = g_stackp;
1472 mark->stacknxt = g_stacknxt;
1473 mark->stacknleft = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001474 mark->marknext = markp;
1475 markp = mark;
1476}
1477
1478static void
1479popstackmark(struct stackmark *mark)
1480{
1481 struct stack_block *sp;
1482
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001483 if (!mark->stackp)
1484 return;
1485
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001486 INT_OFF;
1487 markp = mark->marknext;
Denis Vlasenko01631112007-12-16 17:20:38 +00001488 while (g_stackp != mark->stackp) {
1489 sp = g_stackp;
1490 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001491 free(sp);
1492 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001493 g_stacknxt = mark->stacknxt;
1494 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001495 sstrend = mark->stacknxt + mark->stacknleft;
1496 INT_ON;
1497}
1498
1499/*
1500 * When the parser reads in a string, it wants to stick the string on the
1501 * stack and only adjust the stack pointer when it knows how big the
1502 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1503 * of space on top of the stack and stackblocklen returns the length of
1504 * this block. Growstackblock will grow this space by at least one byte,
1505 * possibly moving it (like realloc). Grabstackblock actually allocates the
1506 * part of the block that has been used.
1507 */
1508static void
1509growstackblock(void)
1510{
1511 size_t newlen;
1512
Denis Vlasenko01631112007-12-16 17:20:38 +00001513 newlen = g_stacknleft * 2;
1514 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001515 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1516 if (newlen < 128)
1517 newlen += 128;
1518
Denis Vlasenko01631112007-12-16 17:20:38 +00001519 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001520 struct stack_block *oldstackp;
1521 struct stackmark *xmark;
1522 struct stack_block *sp;
1523 struct stack_block *prevstackp;
1524 size_t grosslen;
1525
1526 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001527 oldstackp = g_stackp;
1528 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001529 prevstackp = sp->prev;
1530 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1531 sp = ckrealloc(sp, grosslen);
1532 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001533 g_stackp = sp;
1534 g_stacknxt = sp->space;
1535 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001536 sstrend = sp->space + newlen;
1537
1538 /*
1539 * Stack marks pointing to the start of the old block
1540 * must be relocated to point to the new block
1541 */
1542 xmark = markp;
1543 while (xmark != NULL && xmark->stackp == oldstackp) {
Denis Vlasenko01631112007-12-16 17:20:38 +00001544 xmark->stackp = g_stackp;
1545 xmark->stacknxt = g_stacknxt;
1546 xmark->stacknleft = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001547 xmark = xmark->marknext;
1548 }
1549 INT_ON;
1550 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001551 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001552 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001553 char *p = stalloc(newlen);
1554
1555 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001556 g_stacknxt = memcpy(p, oldspace, oldlen);
1557 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001558 }
1559}
1560
1561static void
1562grabstackblock(size_t len)
1563{
1564 len = SHELL_ALIGN(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001565 g_stacknxt += len;
1566 g_stacknleft -= len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001567}
1568
1569/*
1570 * The following routines are somewhat easier to use than the above.
1571 * The user declares a variable of type STACKSTR, which may be declared
1572 * to be a register. The macro STARTSTACKSTR initializes things. Then
1573 * the user uses the macro STPUTC to add characters to the string. In
1574 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1575 * grown as necessary. When the user is done, she can just leave the
1576 * string there and refer to it using stackblock(). Or she can allocate
1577 * the space for it using grabstackstr(). If it is necessary to allow
1578 * someone else to use the stack temporarily and then continue to grow
1579 * the string, the user should use grabstack to allocate the space, and
1580 * then call ungrabstr(p) to return to the previous mode of operation.
1581 *
1582 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1583 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1584 * is space for at least one character.
1585 */
1586static void *
1587growstackstr(void)
1588{
1589 size_t len = stackblocksize();
1590 if (herefd >= 0 && len >= 1024) {
1591 full_write(herefd, stackblock(), len);
1592 return stackblock();
1593 }
1594 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001595 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001596}
1597
1598/*
1599 * Called from CHECKSTRSPACE.
1600 */
1601static char *
1602makestrspace(size_t newlen, char *p)
1603{
Denis Vlasenko01631112007-12-16 17:20:38 +00001604 size_t len = p - g_stacknxt;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001605 size_t size = stackblocksize();
1606
1607 for (;;) {
1608 size_t nleft;
1609
1610 size = stackblocksize();
1611 nleft = size - len;
1612 if (nleft >= newlen)
1613 break;
1614 growstackblock();
1615 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001616 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001617}
1618
1619static char *
1620stack_nputstr(const char *s, size_t n, char *p)
1621{
1622 p = makestrspace(n, p);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001623 p = (char *)memcpy(p, s, n) + n;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001624 return p;
1625}
1626
1627static char *
1628stack_putstr(const char *s, char *p)
1629{
1630 return stack_nputstr(s, strlen(s), p);
1631}
1632
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001633static char *
1634_STPUTC(int c, char *p)
1635{
1636 if (p == sstrend)
1637 p = growstackstr();
1638 *p++ = c;
1639 return p;
1640}
1641
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001642#define STARTSTACKSTR(p) ((p) = stackblock())
1643#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001644#define CHECKSTRSPACE(n, p) do { \
1645 char *q = (p); \
1646 size_t l = (n); \
1647 size_t m = sstrend - q; \
1648 if (l > m) \
1649 (p) = makestrspace(l, q); \
1650} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001651#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001652#define STACKSTRNUL(p) do { \
1653 if ((p) == sstrend) \
1654 (p) = growstackstr(); \
1655 *(p) = '\0'; \
1656} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001657#define STUNPUTC(p) (--(p))
1658#define STTOPC(p) ((p)[-1])
1659#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001660
1661#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001662#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001663#define stackstrend() ((void *)sstrend)
1664
1665
1666/* ============ String helpers */
1667
1668/*
1669 * prefix -- see if pfx is a prefix of string.
1670 */
1671static char *
1672prefix(const char *string, const char *pfx)
1673{
1674 while (*pfx) {
1675 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001676 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001677 }
1678 return (char *) string;
1679}
1680
1681/*
1682 * Check for a valid number. This should be elsewhere.
1683 */
1684static int
1685is_number(const char *p)
1686{
1687 do {
1688 if (!isdigit(*p))
1689 return 0;
1690 } while (*++p != '\0');
1691 return 1;
1692}
1693
1694/*
1695 * Convert a string of digits to an integer, printing an error message on
1696 * failure.
1697 */
1698static int
1699number(const char *s)
1700{
1701 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001702 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001703 return atoi(s);
1704}
1705
1706/*
1707 * Produce a possibly single quoted string suitable as input to the shell.
1708 * The return string is allocated on the stack.
1709 */
1710static char *
1711single_quote(const char *s)
1712{
1713 char *p;
1714
1715 STARTSTACKSTR(p);
1716
1717 do {
1718 char *q;
1719 size_t len;
1720
1721 len = strchrnul(s, '\'') - s;
1722
1723 q = p = makestrspace(len + 3, p);
1724
1725 *q++ = '\'';
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001726 q = (char *)memcpy(q, s, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001727 *q++ = '\'';
1728 s += len;
1729
1730 STADJUST(q - p, p);
1731
Denys Vlasenkocd716832009-11-28 22:14:02 +01001732 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001733 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001734 len = 0;
1735 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001736
1737 q = p = makestrspace(len + 3, p);
1738
1739 *q++ = '"';
Denys Vlasenkocd716832009-11-28 22:14:02 +01001740 q = (char *)memcpy(q, s - len, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001741 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001742
1743 STADJUST(q - p, p);
1744 } while (*s);
1745
Denys Vlasenkocd716832009-11-28 22:14:02 +01001746 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001747
1748 return stackblock();
1749}
1750
1751
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001752/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001753
1754static char **argptr; /* argument list for builtin commands */
1755static char *optionarg; /* set by nextopt (like getopt) */
1756static char *optptr; /* used by nextopt */
1757
1758/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001759 * XXX - should get rid of. Have all builtins use getopt(3).
1760 * The library getopt must have the BSD extension static variable
1761 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001762 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001763 * Standard option processing (a la getopt) for builtin routines.
1764 * The only argument that is passed to nextopt is the option string;
1765 * the other arguments are unnecessary. It returns the character,
1766 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001767 */
1768static int
1769nextopt(const char *optstring)
1770{
1771 char *p;
1772 const char *q;
1773 char c;
1774
1775 p = optptr;
1776 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001777 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001778 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001779 if (p == NULL)
1780 return '\0';
1781 if (*p != '-')
1782 return '\0';
1783 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001784 return '\0';
1785 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001786 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001787 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001788 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001789 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001790 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001791 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001792 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001793 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001794 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001795 if (*++q == ':')
1796 q++;
1797 }
1798 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001799 if (*p == '\0') {
1800 p = *argptr++;
1801 if (p == NULL)
1802 ash_msg_and_raise_error("no arg for -%c option", c);
1803 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001804 optionarg = p;
1805 p = NULL;
1806 }
1807 optptr = p;
1808 return c;
1809}
1810
1811
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001812/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001813
Denis Vlasenko01631112007-12-16 17:20:38 +00001814/*
1815 * The parsefile structure pointed to by the global variable parsefile
1816 * contains information about the current file being read.
1817 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001818struct shparam {
1819 int nparam; /* # of positional parameters (without $0) */
1820#if ENABLE_ASH_GETOPTS
1821 int optind; /* next parameter to be processed by getopts */
1822 int optoff; /* used by getopts */
1823#endif
1824 unsigned char malloced; /* if parameter list dynamically allocated */
1825 char **p; /* parameter list */
1826};
1827
1828/*
1829 * Free the list of positional parameters.
1830 */
1831static void
1832freeparam(volatile struct shparam *param)
1833{
Denis Vlasenko01631112007-12-16 17:20:38 +00001834 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001835 char **ap, **ap1;
1836 ap = ap1 = param->p;
1837 while (*ap)
1838 free(*ap++);
1839 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001840 }
1841}
1842
1843#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001844static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001845#endif
1846
1847struct var {
1848 struct var *next; /* next entry in hash list */
1849 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001850 const char *var_text; /* name=value */
1851 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001852 /* the variable gets set/unset */
1853};
1854
1855struct localvar {
1856 struct localvar *next; /* next local variable in list */
1857 struct var *vp; /* the variable that was made local */
1858 int flags; /* saved flags */
1859 const char *text; /* saved text */
1860};
1861
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001862/* flags */
1863#define VEXPORT 0x01 /* variable is exported */
1864#define VREADONLY 0x02 /* variable cannot be modified */
1865#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1866#define VTEXTFIXED 0x08 /* text is statically allocated */
1867#define VSTACK 0x10 /* text is allocated on the stack */
1868#define VUNSET 0x20 /* the variable is not set */
1869#define VNOFUNC 0x40 /* don't call the callback function */
1870#define VNOSET 0x80 /* do not set variable - just readonly test */
1871#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001872#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001873# define VDYNAMIC 0x200 /* dynamic variable */
1874#else
1875# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001876#endif
1877
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001878
Denis Vlasenko01631112007-12-16 17:20:38 +00001879/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001880#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001881static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001882change_lc_all(const char *value)
1883{
1884 if (value && *value != '\0')
1885 setlocale(LC_ALL, value);
1886}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001887static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001888change_lc_ctype(const char *value)
1889{
1890 if (value && *value != '\0')
1891 setlocale(LC_CTYPE, value);
1892}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001893#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001894#if ENABLE_ASH_MAIL
1895static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01001896static void changemail(const char *var_value) FAST_FUNC;
1897#else
1898# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001899#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001900static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001901#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001902static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001903#endif
1904
Denis Vlasenko01631112007-12-16 17:20:38 +00001905static const struct {
1906 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001907 const char *var_text;
1908 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00001909} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02001910 /*
1911 * Note: VEXPORT would not work correctly here for NOFORK applets:
1912 * some environment strings may be constant.
1913 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001914 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001915#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001916 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
1917 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001918#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001919 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1920 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1921 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1922 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001923#if ENABLE_ASH_GETOPTS
Denis Vlasenko01631112007-12-16 17:20:38 +00001924 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001925#endif
1926#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001927 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001928#endif
1929#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001930 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
1931 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001932#endif
1933#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001934 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001935#endif
1936};
1937
Denis Vlasenko0b769642008-07-24 07:54:57 +00001938struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00001939
1940struct globals_var {
1941 struct shparam shellparam; /* $@ current positional parameters */
1942 struct redirtab *redirlist;
1943 int g_nullredirs;
1944 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1945 struct var *vartab[VTABSIZE];
1946 struct var varinit[ARRAY_SIZE(varinit_data)];
1947};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001948extern struct globals_var *const ash_ptr_to_globals_var;
1949#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00001950#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00001951//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00001952#define g_nullredirs (G_var.g_nullredirs )
1953#define preverrout_fd (G_var.preverrout_fd)
1954#define vartab (G_var.vartab )
1955#define varinit (G_var.varinit )
1956#define INIT_G_var() do { \
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00001957 unsigned i; \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001958 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1959 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001960 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001961 varinit[i].flags = varinit_data[i].flags; \
1962 varinit[i].var_text = varinit_data[i].var_text; \
1963 varinit[i].var_func = varinit_data[i].var_func; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001964 } \
1965} while (0)
1966
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001967#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001968#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001969# define vmail (&vifs)[1]
1970# define vmpath (&vmail)[1]
1971# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001972#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001973# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001974#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001975#define vps1 (&vpath)[1]
1976#define vps2 (&vps1)[1]
1977#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001978#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001979# define voptind (&vps4)[1]
1980# if ENABLE_ASH_RANDOM_SUPPORT
1981# define vrandom (&voptind)[1]
1982# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001983#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001984# if ENABLE_ASH_RANDOM_SUPPORT
1985# define vrandom (&vps4)[1]
1986# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001987#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001988
1989/*
1990 * The following macros access the values of the above variables.
1991 * They have to skip over the name. They return the null string
1992 * for unset variables.
1993 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001994#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001995#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001996#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001997# define mailval() (vmail.var_text + 5)
1998# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001999# define mpathset() ((vmpath.flags & VUNSET) == 0)
2000#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002001#define pathval() (vpath.var_text + 5)
2002#define ps1val() (vps1.var_text + 4)
2003#define ps2val() (vps2.var_text + 4)
2004#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002005#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002006# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002007#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002008
Denis Vlasenko01631112007-12-16 17:20:38 +00002009#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002010static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002011getoptsreset(const char *value)
2012{
2013 shellparam.optind = number(value);
2014 shellparam.optoff = -1;
2015}
2016#endif
2017
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002018/*
2019 * Compares two strings up to the first = or '\0'. The first
2020 * string must be terminated by '='; the second may be terminated by
2021 * either '=' or '\0'.
2022 */
2023static int
2024varcmp(const char *p, const char *q)
2025{
2026 int c, d;
2027
2028 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002029 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002030 goto out;
2031 p++;
2032 q++;
2033 }
2034 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002035 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002036 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002037 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002038 out:
2039 return c - d;
2040}
2041
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002042/*
2043 * Find the appropriate entry in the hash table from the name.
2044 */
2045static struct var **
2046hashvar(const char *p)
2047{
2048 unsigned hashval;
2049
2050 hashval = ((unsigned char) *p) << 4;
2051 while (*p && *p != '=')
2052 hashval += (unsigned char) *p++;
2053 return &vartab[hashval % VTABSIZE];
2054}
2055
2056static int
2057vpcmp(const void *a, const void *b)
2058{
2059 return varcmp(*(const char **)a, *(const char **)b);
2060}
2061
2062/*
2063 * This routine initializes the builtin variables.
2064 */
2065static void
2066initvar(void)
2067{
2068 struct var *vp;
2069 struct var *end;
2070 struct var **vpp;
2071
2072 /*
2073 * PS1 depends on uid
2074 */
2075#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002076 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002077#else
2078 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002079 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002080#endif
2081 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002082 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002083 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002084 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002085 vp->next = *vpp;
2086 *vpp = vp;
2087 } while (++vp < end);
2088}
2089
2090static struct var **
2091findvar(struct var **vpp, const char *name)
2092{
2093 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002094 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002095 break;
2096 }
2097 }
2098 return vpp;
2099}
2100
2101/*
2102 * Find the value of a variable. Returns NULL if not set.
2103 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002104static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002105lookupvar(const char *name)
2106{
2107 struct var *v;
2108
2109 v = *findvar(hashvar(name), name);
2110 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002111#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002112 /*
2113 * Dynamic variables are implemented roughly the same way they are
2114 * in bash. Namely, they're "special" so long as they aren't unset.
2115 * As soon as they're unset, they're no longer dynamic, and dynamic
2116 * lookup will no longer happen at that point. -- PFM.
2117 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002118 if (v->flags & VDYNAMIC)
2119 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002120#endif
2121 if (!(v->flags & VUNSET))
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002122 return var_end(v->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002123 }
2124 return NULL;
2125}
2126
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002127static void reinit_unicode_for_ash(void)
2128{
2129 /* Unicode support should be activated even if LANG is set
2130 * _during_ shell execution, not only if it was set when
2131 * shell was started. Therefore, re-check LANG every time:
2132 */
2133 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2134 || ENABLE_UNICODE_USING_LOCALE
2135 ) {
2136 const char *s = lookupvar("LC_ALL");
2137 if (!s) s = lookupvar("LC_CTYPE");
2138 if (!s) s = lookupvar("LANG");
2139 reinit_unicode(s);
2140 }
2141}
2142
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002143/*
2144 * Search the environment of a builtin command.
2145 */
Mike Frysinger98c52642009-04-02 10:02:37 +00002146static const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002147bltinlookup(const char *name)
2148{
2149 struct strlist *sp;
2150
2151 for (sp = cmdenviron; sp; sp = sp->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002152 if (varcmp(sp->text, name) == 0)
2153 return var_end(sp->text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002154 }
2155 return lookupvar(name);
2156}
2157
2158/*
2159 * Same as setvar except that the variable and value are passed in
2160 * the first argument as name=value. Since the first argument will
2161 * be actually stored in the table, it should not be a string that
2162 * will go away.
2163 * Called with interrupts off.
2164 */
2165static void
2166setvareq(char *s, int flags)
2167{
2168 struct var *vp, **vpp;
2169
2170 vpp = hashvar(s);
2171 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2172 vp = *findvar(vpp, s);
2173 if (vp) {
2174 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2175 const char *n;
2176
2177 if (flags & VNOSAVE)
2178 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002179 n = vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002180 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2181 }
2182
2183 if (flags & VNOSET)
2184 return;
2185
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002186 if (vp->var_func && !(flags & VNOFUNC))
2187 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002188
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002189 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2190 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002191
2192 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2193 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002194 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002195 if (flags & VNOSET)
2196 return;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002197 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002198 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002199 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002200 *vpp = vp;
2201 }
2202 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2203 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002204 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002205 vp->flags = flags;
2206}
2207
2208/*
2209 * Set the value of a variable. The flags argument is ored with the
2210 * flags of the variable. If val is NULL, the variable is unset.
2211 */
2212static void
2213setvar(const char *name, const char *val, int flags)
2214{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002215 const char *q;
2216 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002217 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002218 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002219 size_t vallen;
2220
2221 q = endofname(name);
2222 p = strchrnul(q, '=');
2223 namelen = p - name;
2224 if (!namelen || p != q)
2225 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2226 vallen = 0;
2227 if (val == NULL) {
2228 flags |= VUNSET;
2229 } else {
2230 vallen = strlen(val);
2231 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002232
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002233 INT_OFF;
2234 nameeq = ckmalloc(namelen + vallen + 2);
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002235 p = memcpy(nameeq, name, namelen) + namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002236 if (val) {
2237 *p++ = '=';
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002238 p = memcpy(p, val, vallen) + vallen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002239 }
2240 *p = '\0';
2241 setvareq(nameeq, flags | VNOSAVE);
2242 INT_ON;
2243}
2244
Denys Vlasenko03dad222010-01-12 23:29:57 +01002245static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002246setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002247{
2248 setvar(name, val, 0);
2249}
2250
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002251#if ENABLE_ASH_GETOPTS
2252/*
2253 * Safe version of setvar, returns 1 on success 0 on failure.
2254 */
2255static int
2256setvarsafe(const char *name, const char *val, int flags)
2257{
2258 int err;
2259 volatile int saveint;
2260 struct jmploc *volatile savehandler = exception_handler;
2261 struct jmploc jmploc;
2262
2263 SAVE_INT(saveint);
2264 if (setjmp(jmploc.loc))
2265 err = 1;
2266 else {
2267 exception_handler = &jmploc;
2268 setvar(name, val, flags);
2269 err = 0;
2270 }
2271 exception_handler = savehandler;
2272 RESTORE_INT(saveint);
2273 return err;
2274}
2275#endif
2276
2277/*
2278 * Unset the specified variable.
2279 */
2280static int
2281unsetvar(const char *s)
2282{
2283 struct var **vpp;
2284 struct var *vp;
2285 int retval;
2286
2287 vpp = findvar(hashvar(s), s);
2288 vp = *vpp;
2289 retval = 2;
2290 if (vp) {
2291 int flags = vp->flags;
2292
2293 retval = 1;
2294 if (flags & VREADONLY)
2295 goto out;
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002296#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002297 vp->flags &= ~VDYNAMIC;
2298#endif
2299 if (flags & VUNSET)
2300 goto ok;
2301 if ((flags & VSTRFIXED) == 0) {
2302 INT_OFF;
2303 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002304 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002305 *vpp = vp->next;
2306 free(vp);
2307 INT_ON;
2308 } else {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002309 setvar0(s, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002310 vp->flags &= ~VEXPORT;
2311 }
2312 ok:
2313 retval = 0;
2314 }
2315 out:
2316 return retval;
2317}
2318
2319/*
2320 * Process a linked list of variable assignments.
2321 */
2322static void
2323listsetvar(struct strlist *list_set_var, int flags)
2324{
2325 struct strlist *lp = list_set_var;
2326
2327 if (!lp)
2328 return;
2329 INT_OFF;
2330 do {
2331 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002332 lp = lp->next;
2333 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002334 INT_ON;
2335}
2336
2337/*
2338 * Generate a list of variables satisfying the given conditions.
2339 */
2340static char **
2341listvars(int on, int off, char ***end)
2342{
2343 struct var **vpp;
2344 struct var *vp;
2345 char **ep;
2346 int mask;
2347
2348 STARTSTACKSTR(ep);
2349 vpp = vartab;
2350 mask = on | off;
2351 do {
2352 for (vp = *vpp; vp; vp = vp->next) {
2353 if ((vp->flags & mask) == on) {
2354 if (ep == stackstrend())
2355 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002356 *ep++ = (char*)vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002357 }
2358 }
2359 } while (++vpp < vartab + VTABSIZE);
2360 if (ep == stackstrend())
2361 ep = growstackstr();
2362 if (end)
2363 *end = ep;
2364 *ep++ = NULL;
2365 return grabstackstr(ep);
2366}
2367
2368
2369/* ============ Path search helper
2370 *
2371 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002372 * of the path before the first call; path_advance will update
2373 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002374 * the possible path expansions in sequence. If an option (indicated by
2375 * a percent sign) appears in the path entry then the global variable
2376 * pathopt will be set to point to it; otherwise pathopt will be set to
2377 * NULL.
2378 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002379static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002380
2381static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002382path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002383{
2384 const char *p;
2385 char *q;
2386 const char *start;
2387 size_t len;
2388
2389 if (*path == NULL)
2390 return NULL;
2391 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002392 for (p = start; *p && *p != ':' && *p != '%'; p++)
2393 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002394 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2395 while (stackblocksize() < len)
2396 growstackblock();
2397 q = stackblock();
2398 if (p != start) {
2399 memcpy(q, start, p - start);
2400 q += p - start;
2401 *q++ = '/';
2402 }
2403 strcpy(q, name);
2404 pathopt = NULL;
2405 if (*p == '%') {
2406 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002407 while (*p && *p != ':')
2408 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002409 }
2410 if (*p == ':')
2411 *path = p + 1;
2412 else
2413 *path = NULL;
2414 return stalloc(len);
2415}
2416
2417
2418/* ============ Prompt */
2419
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002420static smallint doprompt; /* if set, prompt the user */
2421static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002422
2423#if ENABLE_FEATURE_EDITING
2424static line_input_t *line_input_state;
2425static const char *cmdedit_prompt;
2426static void
2427putprompt(const char *s)
2428{
2429 if (ENABLE_ASH_EXPAND_PRMT) {
2430 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002431 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002432 return;
2433 }
2434 cmdedit_prompt = s;
2435}
2436#else
2437static void
2438putprompt(const char *s)
2439{
2440 out2str(s);
2441}
2442#endif
2443
2444#if ENABLE_ASH_EXPAND_PRMT
2445/* expandstr() needs parsing machinery, so it is far away ahead... */
2446static const char *expandstr(const char *ps);
2447#else
2448#define expandstr(s) s
2449#endif
2450
2451static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002452setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002453{
2454 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002455 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2456
2457 if (!do_set)
2458 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002459
2460 needprompt = 0;
2461
2462 switch (whichprompt) {
2463 case 1:
2464 prompt = ps1val();
2465 break;
2466 case 2:
2467 prompt = ps2val();
2468 break;
2469 default: /* 0 */
2470 prompt = nullstr;
2471 }
2472#if ENABLE_ASH_EXPAND_PRMT
2473 setstackmark(&smark);
2474 stalloc(stackblocksize());
2475#endif
2476 putprompt(expandstr(prompt));
2477#if ENABLE_ASH_EXPAND_PRMT
2478 popstackmark(&smark);
2479#endif
2480}
2481
2482
2483/* ============ The cd and pwd commands */
2484
2485#define CD_PHYSICAL 1
2486#define CD_PRINT 2
2487
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002488static int
2489cdopt(void)
2490{
2491 int flags = 0;
2492 int i, j;
2493
2494 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002495 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002496 if (i != j) {
2497 flags ^= CD_PHYSICAL;
2498 j = i;
2499 }
2500 }
2501
2502 return flags;
2503}
2504
2505/*
2506 * Update curdir (the name of the current directory) in response to a
2507 * cd command.
2508 */
2509static const char *
2510updatepwd(const char *dir)
2511{
2512 char *new;
2513 char *p;
2514 char *cdcomppath;
2515 const char *lim;
2516
2517 cdcomppath = ststrdup(dir);
2518 STARTSTACKSTR(new);
2519 if (*dir != '/') {
2520 if (curdir == nullstr)
2521 return 0;
2522 new = stack_putstr(curdir, new);
2523 }
2524 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002525 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002526 if (*dir != '/') {
2527 if (new[-1] != '/')
2528 USTPUTC('/', new);
2529 if (new > lim && *lim == '/')
2530 lim++;
2531 } else {
2532 USTPUTC('/', new);
2533 cdcomppath++;
2534 if (dir[1] == '/' && dir[2] != '/') {
2535 USTPUTC('/', new);
2536 cdcomppath++;
2537 lim++;
2538 }
2539 }
2540 p = strtok(cdcomppath, "/");
2541 while (p) {
2542 switch (*p) {
2543 case '.':
2544 if (p[1] == '.' && p[2] == '\0') {
2545 while (new > lim) {
2546 STUNPUTC(new);
2547 if (new[-1] == '/')
2548 break;
2549 }
2550 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002551 }
2552 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002553 break;
2554 /* fall through */
2555 default:
2556 new = stack_putstr(p, new);
2557 USTPUTC('/', new);
2558 }
2559 p = strtok(0, "/");
2560 }
2561 if (new > lim)
2562 STUNPUTC(new);
2563 *new = 0;
2564 return stackblock();
2565}
2566
2567/*
2568 * Find out what the current directory is. If we already know the current
2569 * directory, this routine returns immediately.
2570 */
2571static char *
2572getpwd(void)
2573{
Denis Vlasenko01631112007-12-16 17:20:38 +00002574 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002575 return dir ? dir : nullstr;
2576}
2577
2578static void
2579setpwd(const char *val, int setold)
2580{
2581 char *oldcur, *dir;
2582
2583 oldcur = dir = curdir;
2584
2585 if (setold) {
2586 setvar("OLDPWD", oldcur, VEXPORT);
2587 }
2588 INT_OFF;
2589 if (physdir != nullstr) {
2590 if (physdir != oldcur)
2591 free(physdir);
2592 physdir = nullstr;
2593 }
2594 if (oldcur == val || !val) {
2595 char *s = getpwd();
2596 physdir = s;
2597 if (!val)
2598 dir = s;
2599 } else
2600 dir = ckstrdup(val);
2601 if (oldcur != dir && oldcur != nullstr) {
2602 free(oldcur);
2603 }
2604 curdir = dir;
2605 INT_ON;
2606 setvar("PWD", dir, VEXPORT);
2607}
2608
2609static void hashcd(void);
2610
2611/*
2612 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2613 * know that the current directory has changed.
2614 */
2615static int
2616docd(const char *dest, int flags)
2617{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002618 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002619 int err;
2620
2621 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2622
2623 INT_OFF;
2624 if (!(flags & CD_PHYSICAL)) {
2625 dir = updatepwd(dest);
2626 if (dir)
2627 dest = dir;
2628 }
2629 err = chdir(dest);
2630 if (err)
2631 goto out;
2632 setpwd(dir, 1);
2633 hashcd();
2634 out:
2635 INT_ON;
2636 return err;
2637}
2638
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002639static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002640cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002641{
2642 const char *dest;
2643 const char *path;
2644 const char *p;
2645 char c;
2646 struct stat statb;
2647 int flags;
2648
2649 flags = cdopt();
2650 dest = *argptr;
2651 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002652 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002653 else if (LONE_DASH(dest)) {
2654 dest = bltinlookup("OLDPWD");
2655 flags |= CD_PRINT;
2656 }
2657 if (!dest)
2658 dest = nullstr;
2659 if (*dest == '/')
2660 goto step7;
2661 if (*dest == '.') {
2662 c = dest[1];
2663 dotdot:
2664 switch (c) {
2665 case '\0':
2666 case '/':
2667 goto step6;
2668 case '.':
2669 c = dest[2];
2670 if (c != '.')
2671 goto dotdot;
2672 }
2673 }
2674 if (!*dest)
2675 dest = ".";
2676 path = bltinlookup("CDPATH");
2677 if (!path) {
2678 step6:
2679 step7:
2680 p = dest;
2681 goto docd;
2682 }
2683 do {
2684 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002685 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002686 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2687 if (c && c != ':')
2688 flags |= CD_PRINT;
2689 docd:
2690 if (!docd(p, flags))
2691 goto out;
2692 break;
2693 }
2694 } while (path);
2695 ash_msg_and_raise_error("can't cd to %s", dest);
2696 /* NOTREACHED */
2697 out:
2698 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002699 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002700 return 0;
2701}
2702
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002703static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002704pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002705{
2706 int flags;
2707 const char *dir = curdir;
2708
2709 flags = cdopt();
2710 if (flags) {
2711 if (physdir == nullstr)
2712 setpwd(dir, 0);
2713 dir = physdir;
2714 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002715 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002716 return 0;
2717}
2718
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002719
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002720/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002721
Denis Vlasenko834dee72008-10-07 09:18:30 +00002722
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002723#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002724
Eric Andersenc470f442003-07-28 09:56:35 +00002725/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002726#define CWORD 0 /* character is nothing special */
2727#define CNL 1 /* newline character */
2728#define CBACK 2 /* a backslash character */
2729#define CSQUOTE 3 /* single quote */
2730#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002731#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002732#define CBQUOTE 6 /* backwards single quote */
2733#define CVAR 7 /* a dollar sign */
2734#define CENDVAR 8 /* a '}' character */
2735#define CLP 9 /* a left paren in arithmetic */
2736#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002737#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002738#define CCTL 12 /* like CWORD, except it must be escaped */
2739#define CSPCL 13 /* these terminate a word */
2740#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002741
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002742#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002743#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002744# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002745#endif
2746
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002747#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002748
Mike Frysinger98c52642009-04-02 10:02:37 +00002749#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002750# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002751#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002752# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002753#endif
Denys Vlasenko068d3862009-11-29 01:41:11 +01002754static const uint16_t S_I_T[] = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002755#if ENABLE_ASH_ALIAS
2756 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2757#endif
2758 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2759 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2760 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2761 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2762 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2763 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2764 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2765 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2766 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2767 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2768 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002769#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002770 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2771 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2772 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2773#endif
2774#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002775};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002776/* Constants below must match table above */
2777enum {
2778#if ENABLE_ASH_ALIAS
2779 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2780#endif
2781 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2782 CNL_CNL_CNL_CNL , /* 2 */
2783 CWORD_CCTL_CCTL_CWORD , /* 3 */
2784 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2785 CVAR_CVAR_CWORD_CVAR , /* 5 */
2786 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2787 CSPCL_CWORD_CWORD_CLP , /* 7 */
2788 CSPCL_CWORD_CWORD_CRP , /* 8 */
2789 CBACK_CBACK_CCTL_CBACK , /* 9 */
2790 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2791 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2792 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2793 CWORD_CWORD_CWORD_CWORD , /* 13 */
2794 CCTL_CCTL_CCTL_CCTL , /* 14 */
2795};
Eric Andersen2870d962001-07-02 17:27:21 +00002796
Denys Vlasenkocd716832009-11-28 22:14:02 +01002797/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2798 * caller must ensure proper cast on it if c is *char_ptr!
2799 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002800/* Values for syntax param */
2801#define BASESYNTAX 0 /* not in quotes */
2802#define DQSYNTAX 1 /* in double quotes */
2803#define SQSYNTAX 2 /* in single quotes */
2804#define ARISYNTAX 3 /* in arithmetic */
2805#define PSSYNTAX 4 /* prompt. never passed to SIT() */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002806
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002807#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002808
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002809static int
2810SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002811{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00002812 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
Denys Vlasenkocd716832009-11-28 22:14:02 +01002813# if ENABLE_ASH_ALIAS
2814 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002815 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
2816 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
2817 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2818 11, 3 /* "}~" */
2819 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002820# else
2821 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002822 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
2823 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
2824 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2825 10, 2 /* "}~" */
2826 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002827# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002828 const char *s;
2829 int indx;
2830
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002831 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002832 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002833# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002834 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002835 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002836 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002837# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002838 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002839 /* Cast is purely for paranoia here,
2840 * just in case someone passed signed char to us */
2841 if ((unsigned char)c >= CTL_FIRST
2842 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002843 ) {
2844 return CCTL;
2845 }
2846 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002847 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002848 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002849 indx = syntax_index_table[s - spec_symbls];
2850 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002851 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002852}
2853
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002854#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002855
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002856static const uint8_t syntax_index_table[] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002857 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002858 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2859 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2860 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2861 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2862 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2867 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2868 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2869 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2872 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2877 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2889 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2890 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2891 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2892 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2893 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2894 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2895 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2896 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2897 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2898 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2899 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2900 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2901 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2902 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2903 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2904 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
2905 /* 47 "/" */ CWORD_CCTL_CCTL_CWORD,
2906 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2907 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2908 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2909 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2910 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2911 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2912 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2913 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2914 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2915 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2916 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2917 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2918 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2919 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2920 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2921 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2922 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2923 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2924 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2925 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2926 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2927 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2928 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2929 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2950 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2951 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2952 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2955 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
2983 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2984 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
2985 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
2986 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2987 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2988 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2989 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2990 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2991 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2992 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2993 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2994 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2995 /* 137 */ CWORD_CWORD_CWORD_CWORD,
2996 /* 138 */ CWORD_CWORD_CWORD_CWORD,
2997 /* 139 */ CWORD_CWORD_CWORD_CWORD,
2998 /* 140 */ CWORD_CWORD_CWORD_CWORD,
2999 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3000 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3001 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3002 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3003 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3004 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3005 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3006 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3007 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3008 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3009 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3010 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3011 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3012 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3013 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3014 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3015 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3016 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3017 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3018 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3019 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3020 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3021 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3029 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3042 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3047 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3112 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3113 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003114 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003115# if ENABLE_ASH_ALIAS
3116 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3117# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003118};
3119
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003120# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003121
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003122#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003123
Eric Andersen2870d962001-07-02 17:27:21 +00003124
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003125/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003126
Denis Vlasenko131ae172007-02-18 13:00:19 +00003127#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003128
3129#define ALIASINUSE 1
3130#define ALIASDEAD 2
3131
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003132struct alias {
3133 struct alias *next;
3134 char *name;
3135 char *val;
3136 int flag;
3137};
3138
Denis Vlasenko01631112007-12-16 17:20:38 +00003139
3140static struct alias **atab; // [ATABSIZE];
3141#define INIT_G_alias() do { \
3142 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3143} while (0)
3144
Eric Andersen2870d962001-07-02 17:27:21 +00003145
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003146static struct alias **
3147__lookupalias(const char *name) {
3148 unsigned int hashval;
3149 struct alias **app;
3150 const char *p;
3151 unsigned int ch;
3152
3153 p = name;
3154
3155 ch = (unsigned char)*p;
3156 hashval = ch << 4;
3157 while (ch) {
3158 hashval += ch;
3159 ch = (unsigned char)*++p;
3160 }
3161 app = &atab[hashval % ATABSIZE];
3162
3163 for (; *app; app = &(*app)->next) {
3164 if (strcmp(name, (*app)->name) == 0) {
3165 break;
3166 }
3167 }
3168
3169 return app;
3170}
3171
3172static struct alias *
3173lookupalias(const char *name, int check)
3174{
3175 struct alias *ap = *__lookupalias(name);
3176
3177 if (check && ap && (ap->flag & ALIASINUSE))
3178 return NULL;
3179 return ap;
3180}
3181
3182static struct alias *
3183freealias(struct alias *ap)
3184{
3185 struct alias *next;
3186
3187 if (ap->flag & ALIASINUSE) {
3188 ap->flag |= ALIASDEAD;
3189 return ap;
3190 }
3191
3192 next = ap->next;
3193 free(ap->name);
3194 free(ap->val);
3195 free(ap);
3196 return next;
3197}
Eric Andersencb57d552001-06-28 07:25:16 +00003198
Eric Andersenc470f442003-07-28 09:56:35 +00003199static void
3200setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003201{
3202 struct alias *ap, **app;
3203
3204 app = __lookupalias(name);
3205 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003206 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003207 if (ap) {
3208 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003209 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003210 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003211 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003212 ap->flag &= ~ALIASDEAD;
3213 } else {
3214 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003215 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003216 ap->name = ckstrdup(name);
3217 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003218 /*ap->flag = 0; - ckzalloc did it */
3219 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003220 *app = ap;
3221 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003222 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003223}
3224
Eric Andersenc470f442003-07-28 09:56:35 +00003225static int
3226unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003227{
Eric Andersencb57d552001-06-28 07:25:16 +00003228 struct alias **app;
3229
3230 app = __lookupalias(name);
3231
3232 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003233 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003234 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003235 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003236 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003237 }
3238
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003239 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003240}
3241
Eric Andersenc470f442003-07-28 09:56:35 +00003242static void
3243rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003244{
Eric Andersencb57d552001-06-28 07:25:16 +00003245 struct alias *ap, **app;
3246 int i;
3247
Denis Vlasenkob012b102007-02-19 22:43:01 +00003248 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003249 for (i = 0; i < ATABSIZE; i++) {
3250 app = &atab[i];
3251 for (ap = *app; ap; ap = *app) {
3252 *app = freealias(*app);
3253 if (ap == *app) {
3254 app = &ap->next;
3255 }
3256 }
3257 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003258 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003259}
3260
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003261static void
3262printalias(const struct alias *ap)
3263{
3264 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3265}
3266
Eric Andersencb57d552001-06-28 07:25:16 +00003267/*
3268 * TODO - sort output
3269 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003270static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003271aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003272{
3273 char *n, *v;
3274 int ret = 0;
3275 struct alias *ap;
3276
Denis Vlasenko68404f12008-03-17 09:00:54 +00003277 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003278 int i;
3279
Denis Vlasenko68404f12008-03-17 09:00:54 +00003280 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003281 for (ap = atab[i]; ap; ap = ap->next) {
3282 printalias(ap);
3283 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003284 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003285 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003286 }
3287 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003288 v = strchr(n+1, '=');
3289 if (v == NULL) { /* n+1: funny ksh stuff */
3290 ap = *__lookupalias(n);
3291 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003292 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003293 ret = 1;
3294 } else
3295 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003296 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003297 *v++ = '\0';
3298 setalias(n, v);
3299 }
3300 }
3301
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003302 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003303}
3304
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003305static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003306unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003307{
3308 int i;
3309
3310 while ((i = nextopt("a")) != '\0') {
3311 if (i == 'a') {
3312 rmaliases();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003313 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003314 }
3315 }
3316 for (i = 0; *argptr; argptr++) {
3317 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003318 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003319 i = 1;
3320 }
3321 }
3322
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003323 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003324}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003325
Denis Vlasenko131ae172007-02-18 13:00:19 +00003326#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003327
Eric Andersenc470f442003-07-28 09:56:35 +00003328
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003329/* ============ jobs.c */
3330
3331/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003332#define FORK_FG 0
3333#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003334#define FORK_NOJOB 2
3335
3336/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003337#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3338#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3339#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003340#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003341
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003342/*
3343 * A job structure contains information about a job. A job is either a
3344 * single process or a set of processes contained in a pipeline. In the
3345 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3346 * array of pids.
3347 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003348struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003349 pid_t ps_pid; /* process id */
3350 int ps_status; /* last process status from wait() */
3351 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003352};
3353
3354struct job {
3355 struct procstat ps0; /* status of process */
3356 struct procstat *ps; /* status or processes when more than one */
3357#if JOBS
3358 int stopstatus; /* status of a stopped job */
3359#endif
3360 uint32_t
3361 nprocs: 16, /* number of processes */
3362 state: 8,
3363#define JOBRUNNING 0 /* at least one proc running */
3364#define JOBSTOPPED 1 /* all procs are stopped */
3365#define JOBDONE 2 /* all procs are completed */
3366#if JOBS
3367 sigint: 1, /* job was killed by SIGINT */
3368 jobctl: 1, /* job running under job control */
3369#endif
3370 waited: 1, /* true if this entry has been waited for */
3371 used: 1, /* true if this entry is in used */
3372 changed: 1; /* true if status has changed */
3373 struct job *prev_job; /* previous job */
3374};
3375
Denis Vlasenko68404f12008-03-17 09:00:54 +00003376static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003377static int forkshell(struct job *, union node *, int);
3378static int waitforjob(struct job *);
3379
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003380#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003381enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003382#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003383#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003384static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003385static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003386#endif
3387
3388/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003389 * Ignore a signal.
3390 */
3391static void
3392ignoresig(int signo)
3393{
3394 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3395 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3396 /* No, need to do it */
3397 signal(signo, SIG_IGN);
3398 }
3399 sigmode[signo - 1] = S_HARD_IGN;
3400}
3401
3402/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003403 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003404 */
3405static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003406signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003407{
3408 gotsig[signo - 1] = 1;
3409
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003410 if (signo == SIGINT && !trap[SIGINT]) {
3411 if (!suppress_int) {
3412 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003413 raise_interrupt(); /* does not return */
3414 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003415 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003416 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003417 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003418 }
3419}
3420
3421/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003422 * Set the signal handler for the specified signal. The routine figures
3423 * out what it should be set to.
3424 */
3425static void
3426setsignal(int signo)
3427{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003428 char *t;
3429 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003430 struct sigaction act;
3431
3432 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003433 new_act = S_DFL;
3434 if (t != NULL) { /* trap for this sig is set */
3435 new_act = S_CATCH;
3436 if (t[0] == '\0') /* trap is "": ignore this sig */
3437 new_act = S_IGN;
3438 }
3439
3440 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003441 switch (signo) {
3442 case SIGINT:
3443 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003444 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003445 break;
3446 case SIGQUIT:
3447#if DEBUG
3448 if (debug)
3449 break;
3450#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003451 /* man bash:
3452 * "In all cases, bash ignores SIGQUIT. Non-builtin
3453 * commands run by bash have signal handlers
3454 * set to the values inherited by the shell
3455 * from its parent". */
3456 new_act = S_IGN;
3457 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003458 case SIGTERM:
3459 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003460 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003461 break;
3462#if JOBS
3463 case SIGTSTP:
3464 case SIGTTOU:
3465 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003466 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003467 break;
3468#endif
3469 }
3470 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003471//TODO: if !rootshell, we reset SIGQUIT to DFL,
3472//whereas we have to restore it to what shell got on entry
3473//from the parent. See comment above
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003474
3475 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003476 cur_act = *t;
3477 if (cur_act == 0) {
3478 /* current setting is not yet known */
3479 if (sigaction(signo, NULL, &act)) {
3480 /* pretend it worked; maybe we should give a warning,
3481 * but other shells don't. We don't alter sigmode,
3482 * so we retry every time.
3483 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003484 return;
3485 }
3486 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003487 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003488 if (mflag
3489 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3490 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003491 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003492 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003493 }
3494 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003495 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003496 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003497
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003498 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003499 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003500 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003501 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003502 break;
3503 case S_IGN:
3504 act.sa_handler = SIG_IGN;
3505 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003506 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003507
3508 /* flags and mask matter only if !DFL and !IGN, but we do it
3509 * for all cases for more deterministic behavior:
3510 */
3511 act.sa_flags = 0;
3512 sigfillset(&act.sa_mask);
3513
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003514 sigaction_set(signo, &act);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003515
3516 *t = new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003517}
3518
3519/* mode flags for set_curjob */
3520#define CUR_DELETE 2
3521#define CUR_RUNNING 1
3522#define CUR_STOPPED 0
3523
3524/* mode flags for dowait */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003525#define DOWAIT_NONBLOCK WNOHANG
3526#define DOWAIT_BLOCK 0
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003527
3528#if JOBS
3529/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003530static int initialpgrp; //references:2
3531static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003532#endif
3533/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003534static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003535/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003536static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003537/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003538static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003539/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003540static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003541
3542static void
3543set_curjob(struct job *jp, unsigned mode)
3544{
3545 struct job *jp1;
3546 struct job **jpp, **curp;
3547
3548 /* first remove from list */
3549 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003550 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003551 jp1 = *jpp;
3552 if (jp1 == jp)
3553 break;
3554 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003555 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003556 *jpp = jp1->prev_job;
3557
3558 /* Then re-insert in correct position */
3559 jpp = curp;
3560 switch (mode) {
3561 default:
3562#if DEBUG
3563 abort();
3564#endif
3565 case CUR_DELETE:
3566 /* job being deleted */
3567 break;
3568 case CUR_RUNNING:
3569 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003570 * put after all stopped jobs.
3571 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003572 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003573 jp1 = *jpp;
3574#if JOBS
3575 if (!jp1 || jp1->state != JOBSTOPPED)
3576#endif
3577 break;
3578 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003579 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003580 /* FALLTHROUGH */
3581#if JOBS
3582 case CUR_STOPPED:
3583#endif
3584 /* newly stopped job - becomes curjob */
3585 jp->prev_job = *jpp;
3586 *jpp = jp;
3587 break;
3588 }
3589}
3590
3591#if JOBS || DEBUG
3592static int
3593jobno(const struct job *jp)
3594{
3595 return jp - jobtab + 1;
3596}
3597#endif
3598
3599/*
3600 * Convert a job name to a job structure.
3601 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003602#if !JOBS
3603#define getjob(name, getctl) getjob(name)
3604#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003605static struct job *
3606getjob(const char *name, int getctl)
3607{
3608 struct job *jp;
3609 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003610 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003611 unsigned num;
3612 int c;
3613 const char *p;
3614 char *(*match)(const char *, const char *);
3615
3616 jp = curjob;
3617 p = name;
3618 if (!p)
3619 goto currentjob;
3620
3621 if (*p != '%')
3622 goto err;
3623
3624 c = *++p;
3625 if (!c)
3626 goto currentjob;
3627
3628 if (!p[1]) {
3629 if (c == '+' || c == '%') {
3630 currentjob:
3631 err_msg = "No current job";
3632 goto check;
3633 }
3634 if (c == '-') {
3635 if (jp)
3636 jp = jp->prev_job;
3637 err_msg = "No previous job";
3638 check:
3639 if (!jp)
3640 goto err;
3641 goto gotit;
3642 }
3643 }
3644
3645 if (is_number(p)) {
3646 num = atoi(p);
Denys Vlasenko07f7ea72014-09-08 17:21:52 +02003647 if (num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003648 jp = jobtab + num - 1;
3649 if (jp->used)
3650 goto gotit;
3651 goto err;
3652 }
3653 }
3654
3655 match = prefix;
3656 if (*p == '?') {
3657 match = strstr;
3658 p++;
3659 }
3660
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003661 found = NULL;
3662 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003663 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003664 if (found)
3665 goto err;
3666 found = jp;
3667 err_msg = "%s: ambiguous";
3668 }
3669 jp = jp->prev_job;
3670 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003671 if (!found)
3672 goto err;
3673 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003674
3675 gotit:
3676#if JOBS
3677 err_msg = "job %s not created under job control";
3678 if (getctl && jp->jobctl == 0)
3679 goto err;
3680#endif
3681 return jp;
3682 err:
3683 ash_msg_and_raise_error(err_msg, name);
3684}
3685
3686/*
3687 * Mark a job structure as unused.
3688 */
3689static void
3690freejob(struct job *jp)
3691{
3692 struct procstat *ps;
3693 int i;
3694
3695 INT_OFF;
3696 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003697 if (ps->ps_cmd != nullstr)
3698 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003699 }
3700 if (jp->ps != &jp->ps0)
3701 free(jp->ps);
3702 jp->used = 0;
3703 set_curjob(jp, CUR_DELETE);
3704 INT_ON;
3705}
3706
3707#if JOBS
3708static void
3709xtcsetpgrp(int fd, pid_t pgrp)
3710{
3711 if (tcsetpgrp(fd, pgrp))
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003712 ash_msg_and_raise_error("can't set tty process group (%m)");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003713}
3714
3715/*
3716 * Turn job control on and off.
3717 *
3718 * Note: This code assumes that the third arg to ioctl is a character
3719 * pointer, which is true on Berkeley systems but not System V. Since
3720 * System V doesn't have job control yet, this isn't a problem now.
3721 *
3722 * Called with interrupts off.
3723 */
3724static void
3725setjobctl(int on)
3726{
3727 int fd;
3728 int pgrp;
3729
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003730 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003731 return;
3732 if (on) {
3733 int ofd;
3734 ofd = fd = open(_PATH_TTY, O_RDWR);
3735 if (fd < 0) {
3736 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3737 * That sometimes helps to acquire controlling tty.
3738 * Obviously, a workaround for bugs when someone
3739 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003740 fd = 2;
3741 while (!isatty(fd))
3742 if (--fd < 0)
3743 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003744 }
3745 fd = fcntl(fd, F_DUPFD, 10);
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003746 if (ofd >= 0)
3747 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003748 if (fd < 0)
3749 goto out;
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003750 /* fd is a tty at this point */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003751 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003752 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003753 pgrp = tcgetpgrp(fd);
3754 if (pgrp < 0) {
3755 out:
3756 ash_msg("can't access tty; job control turned off");
3757 mflag = on = 0;
3758 goto close;
3759 }
3760 if (pgrp == getpgrp())
3761 break;
3762 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003763 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003764 initialpgrp = pgrp;
3765
3766 setsignal(SIGTSTP);
3767 setsignal(SIGTTOU);
3768 setsignal(SIGTTIN);
3769 pgrp = rootpid;
3770 setpgid(0, pgrp);
3771 xtcsetpgrp(fd, pgrp);
3772 } else {
3773 /* turning job control off */
3774 fd = ttyfd;
3775 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003776 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003777 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003778 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003779 setpgid(0, pgrp);
3780 setsignal(SIGTSTP);
3781 setsignal(SIGTTOU);
3782 setsignal(SIGTTIN);
3783 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003784 if (fd >= 0)
3785 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003786 fd = -1;
3787 }
3788 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003789 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003790}
3791
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003792static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003793killcmd(int argc, char **argv)
3794{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003795 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003796 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003797 do {
3798 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003799 /*
3800 * "kill %N" - job kill
3801 * Converting to pgrp / pid kill
3802 */
3803 struct job *jp;
3804 char *dst;
3805 int j, n;
3806
3807 jp = getjob(argv[i], 0);
3808 /*
3809 * In jobs started under job control, we signal
3810 * entire process group by kill -PGRP_ID.
3811 * This happens, f.e., in interactive shell.
3812 *
3813 * Otherwise, we signal each child via
3814 * kill PID1 PID2 PID3.
3815 * Testcases:
3816 * sh -c 'sleep 1|sleep 1 & kill %1'
3817 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3818 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3819 */
3820 n = jp->nprocs; /* can't be 0 (I hope) */
3821 if (jp->jobctl)
3822 n = 1;
3823 dst = alloca(n * sizeof(int)*4);
3824 argv[i] = dst;
3825 for (j = 0; j < n; j++) {
3826 struct procstat *ps = &jp->ps[j];
3827 /* Skip non-running and not-stopped members
3828 * (i.e. dead members) of the job
3829 */
3830 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3831 continue;
3832 /*
3833 * kill_main has matching code to expect
3834 * leading space. Needed to not confuse
3835 * negative pids with "kill -SIGNAL_NO" syntax
3836 */
3837 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3838 }
3839 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003840 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003841 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003842 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003843 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003844}
3845
3846static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01003847showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003848{
Denys Vlasenko285ad152009-12-04 23:02:27 +01003849 struct procstat *ps;
3850 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003851
Denys Vlasenko285ad152009-12-04 23:02:27 +01003852 psend = jp->ps + jp->nprocs;
3853 for (ps = jp->ps + 1; ps < psend; ps++)
3854 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003855 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003856 flush_stdout_stderr();
3857}
3858
3859
3860static int
3861restartjob(struct job *jp, int mode)
3862{
3863 struct procstat *ps;
3864 int i;
3865 int status;
3866 pid_t pgid;
3867
3868 INT_OFF;
3869 if (jp->state == JOBDONE)
3870 goto out;
3871 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003872 pgid = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003873 if (mode == FORK_FG)
3874 xtcsetpgrp(ttyfd, pgid);
3875 killpg(pgid, SIGCONT);
3876 ps = jp->ps;
3877 i = jp->nprocs;
3878 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003879 if (WIFSTOPPED(ps->ps_status)) {
3880 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003881 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003882 ps++;
3883 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003884 out:
3885 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3886 INT_ON;
3887 return status;
3888}
3889
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003890static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003891fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003892{
3893 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003894 int mode;
3895 int retval;
3896
3897 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3898 nextopt(nullstr);
3899 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003900 do {
3901 jp = getjob(*argv, 1);
3902 if (mode == FORK_BG) {
3903 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01003904 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003905 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003906 out1str(jp->ps[0].ps_cmd);
3907 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003908 retval = restartjob(jp, mode);
3909 } while (*argv && *++argv);
3910 return retval;
3911}
3912#endif
3913
3914static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02003915sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003916{
3917 int col;
3918 int st;
3919
3920 col = 0;
3921 if (!WIFEXITED(status)) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003922 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003923 st = WSTOPSIG(status);
3924 else
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003925 st = WTERMSIG(status);
3926 if (sigonly) {
3927 if (st == SIGINT || st == SIGPIPE)
3928 goto out;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003929 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003930 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003931 }
3932 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01003933//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003934 col = fmtstr(s, 32, strsignal(st));
3935 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02003936 strcpy(s + col, " (core dumped)");
3937 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003938 }
3939 } else if (!sigonly) {
3940 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003941 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003942 }
3943 out:
3944 return col;
3945}
3946
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003947static int
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003948dowait(int wait_flags, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003949{
3950 int pid;
3951 int status;
3952 struct job *jp;
3953 struct job *thisjob;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003954
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00003955 TRACE(("dowait(0x%x) called\n", wait_flags));
3956
3957 /* Do a wait system call. If job control is compiled in, we accept
3958 * stopped processes. wait_flags may have WNOHANG, preventing blocking.
3959 * NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003960 if (doing_jobctl)
3961 wait_flags |= WUNTRACED;
3962 pid = waitpid(-1, &status, wait_flags);
Denis Vlasenkob21f3792009-03-19 23:09:58 +00003963 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
3964 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003965 if (pid <= 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003966 return pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003967
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003968 INT_OFF;
3969 thisjob = NULL;
3970 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003971 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003972 struct procstat *ps;
3973 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003974 if (jp->state == JOBDONE)
3975 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003976 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003977 ps = jp->ps;
3978 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003979 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003980 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003981 TRACE(("Job %d: changing status of proc %d "
3982 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01003983 jobno(jp), pid, ps->ps_status, status));
3984 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003985 thisjob = jp;
3986 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003987 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003988 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003989#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003990 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003991 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003992 if (WIFSTOPPED(ps->ps_status)) {
3993 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003994 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003995 }
3996#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01003997 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003998 if (!thisjob)
3999 continue;
4000
4001 /* Found the job where one of its processes changed its state.
4002 * Is there at least one live and running process in this job? */
4003 if (jobstate != JOBRUNNING) {
4004 /* No. All live processes in the job are stopped
4005 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4006 */
4007 thisjob->changed = 1;
4008 if (thisjob->state != jobstate) {
4009 TRACE(("Job %d: changing state from %d to %d\n",
4010 jobno(thisjob), thisjob->state, jobstate));
4011 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004012#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004013 if (jobstate == JOBSTOPPED)
4014 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004015#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004016 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004017 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004018 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004019 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004020 /* The process wasn't found in job list */
4021 if (JOBS && !WIFSTOPPED(status))
4022 jobless--;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004023 out:
4024 INT_ON;
4025
4026 if (thisjob && thisjob == job) {
4027 char s[48 + 1];
4028 int len;
4029
Denys Vlasenko9c541002015-10-07 15:44:36 +02004030 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004031 if (len) {
4032 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004033 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004034 out2str(s);
4035 }
4036 }
4037 return pid;
4038}
4039
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004040static int
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004041blocking_wait_with_raise_on_sig(void)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004042{
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004043 pid_t pid = dowait(DOWAIT_BLOCK, NULL);
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004044 if (pid <= 0 && pending_sig)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004045 raise_exception(EXSIG);
4046 return pid;
4047}
4048
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004049#if JOBS
4050static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004051showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004052{
4053 struct procstat *ps;
4054 struct procstat *psend;
4055 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004056 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004057 char s[16 + 16 + 48];
4058 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004059
4060 ps = jp->ps;
4061
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004062 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004063 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004064 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004065 return;
4066 }
4067
4068 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004069 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004070
4071 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004072 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004073 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004074 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004075
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004076 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004077 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004078
4079 psend = ps + jp->nprocs;
4080
4081 if (jp->state == JOBRUNNING) {
4082 strcpy(s + col, "Running");
4083 col += sizeof("Running") - 1;
4084 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004085 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004086 if (jp->state == JOBSTOPPED)
4087 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004088 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004089 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004090 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004091
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004092 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4093 * or prints several "PID | <cmdN>" lines,
4094 * depending on SHOW_PIDS bit.
4095 * We do not print status of individual processes
4096 * between PID and <cmdN>. bash does it, but not very well:
4097 * first line shows overall job status, not process status,
4098 * making it impossible to know 1st process status.
4099 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004100 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004101 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004102 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004103 s[0] = '\0';
4104 col = 33;
4105 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004106 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004107 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004108 fprintf(out, "%s%*c%s%s",
4109 s,
4110 33 - col >= 0 ? 33 - col : 0, ' ',
4111 ps == jp->ps ? "" : "| ",
4112 ps->ps_cmd
4113 );
4114 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004115 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004116
4117 jp->changed = 0;
4118
4119 if (jp->state == JOBDONE) {
4120 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4121 freejob(jp);
4122 }
4123}
4124
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004125/*
4126 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4127 * statuses have changed since the last call to showjobs.
4128 */
4129static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004130showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004131{
4132 struct job *jp;
4133
Denys Vlasenko883cea42009-07-11 15:31:59 +02004134 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004135
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004136 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004137 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004138 continue;
4139
4140 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004141 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004142 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004143 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004144 }
4145}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004146
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004147static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004148jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004149{
4150 int mode, m;
4151
4152 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004153 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004154 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004155 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004156 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004157 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004158 }
4159
4160 argv = argptr;
4161 if (*argv) {
4162 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004163 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004164 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004165 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004166 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004167 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004168
4169 return 0;
4170}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004171#endif /* JOBS */
4172
Michael Abbott359da5e2009-12-04 23:03:29 +01004173/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004174static int
4175getstatus(struct job *job)
4176{
4177 int status;
4178 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004179 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004180
Michael Abbott359da5e2009-12-04 23:03:29 +01004181 /* Fetch last member's status */
4182 ps = job->ps + job->nprocs - 1;
4183 status = ps->ps_status;
4184 if (pipefail) {
4185 /* "set -o pipefail" mode: use last _nonzero_ status */
4186 while (status == 0 && --ps >= job->ps)
4187 status = ps->ps_status;
4188 }
4189
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004190 retval = WEXITSTATUS(status);
4191 if (!WIFEXITED(status)) {
4192#if JOBS
4193 retval = WSTOPSIG(status);
4194 if (!WIFSTOPPED(status))
4195#endif
4196 {
4197 /* XXX: limits number of signals */
4198 retval = WTERMSIG(status);
4199#if JOBS
4200 if (retval == SIGINT)
4201 job->sigint = 1;
4202#endif
4203 }
4204 retval += 128;
4205 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004206 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004207 jobno(job), job->nprocs, status, retval));
4208 return retval;
4209}
4210
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004211static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004212waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004213{
4214 struct job *job;
4215 int retval;
4216 struct job *jp;
4217
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004218 if (pending_sig)
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004219 raise_exception(EXSIG);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004220
4221 nextopt(nullstr);
4222 retval = 0;
4223
4224 argv = argptr;
4225 if (!*argv) {
4226 /* wait for all jobs */
4227 for (;;) {
4228 jp = curjob;
4229 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004230 if (!jp) /* no running procs */
4231 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004232 if (jp->state == JOBRUNNING)
4233 break;
4234 jp->waited = 1;
4235 jp = jp->prev_job;
4236 }
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004237 blocking_wait_with_raise_on_sig();
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004238 /* man bash:
4239 * "When bash is waiting for an asynchronous command via
4240 * the wait builtin, the reception of a signal for which a trap
4241 * has been set will cause the wait builtin to return immediately
4242 * with an exit status greater than 128, immediately after which
4243 * the trap is executed."
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004244 *
4245 * blocking_wait_with_raise_on_sig raises signal handlers
4246 * if it gets no pid (pid < 0). However,
4247 * if child sends us a signal *and immediately exits*,
4248 * blocking_wait_with_raise_on_sig gets pid > 0
4249 * and does not handle pending_sig. Check this case: */
4250 if (pending_sig)
4251 raise_exception(EXSIG);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004252 }
4253 }
4254
4255 retval = 127;
4256 do {
4257 if (**argv != '%') {
4258 pid_t pid = number(*argv);
4259 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004260 while (1) {
4261 if (!job)
4262 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004263 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004264 break;
4265 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004266 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004267 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004268 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004269 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004270 /* loop until process terminated or stopped */
4271 while (job->state == JOBRUNNING)
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004272 blocking_wait_with_raise_on_sig();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004273 job->waited = 1;
4274 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004275 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004276 } while (*++argv);
4277
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004278 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004279 return retval;
4280}
4281
4282static struct job *
4283growjobtab(void)
4284{
4285 size_t len;
4286 ptrdiff_t offset;
4287 struct job *jp, *jq;
4288
4289 len = njobs * sizeof(*jp);
4290 jq = jobtab;
4291 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4292
4293 offset = (char *)jp - (char *)jq;
4294 if (offset) {
4295 /* Relocate pointers */
4296 size_t l = len;
4297
4298 jq = (struct job *)((char *)jq + l);
4299 while (l) {
4300 l -= sizeof(*jp);
4301 jq--;
4302#define joff(p) ((struct job *)((char *)(p) + l))
4303#define jmove(p) (p) = (void *)((char *)(p) + offset)
4304 if (joff(jp)->ps == &jq->ps0)
4305 jmove(joff(jp)->ps);
4306 if (joff(jp)->prev_job)
4307 jmove(joff(jp)->prev_job);
4308 }
4309 if (curjob)
4310 jmove(curjob);
4311#undef joff
4312#undef jmove
4313 }
4314
4315 njobs += 4;
4316 jobtab = jp;
4317 jp = (struct job *)((char *)jp + len);
4318 jq = jp + 3;
4319 do {
4320 jq->used = 0;
4321 } while (--jq >= jp);
4322 return jp;
4323}
4324
4325/*
4326 * Return a new job structure.
4327 * Called with interrupts off.
4328 */
4329static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004330makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004331{
4332 int i;
4333 struct job *jp;
4334
4335 for (i = njobs, jp = jobtab; ; jp++) {
4336 if (--i < 0) {
4337 jp = growjobtab();
4338 break;
4339 }
4340 if (jp->used == 0)
4341 break;
4342 if (jp->state != JOBDONE || !jp->waited)
4343 continue;
4344#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004345 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004346 continue;
4347#endif
4348 freejob(jp);
4349 break;
4350 }
4351 memset(jp, 0, sizeof(*jp));
4352#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004353 /* jp->jobctl is a bitfield.
4354 * "jp->jobctl |= jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004355 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004356 jp->jobctl = 1;
4357#endif
4358 jp->prev_job = curjob;
4359 curjob = jp;
4360 jp->used = 1;
4361 jp->ps = &jp->ps0;
4362 if (nprocs > 1) {
4363 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4364 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004365 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004366 jobno(jp)));
4367 return jp;
4368}
4369
4370#if JOBS
4371/*
4372 * Return a string identifying a command (to be printed by the
4373 * jobs command).
4374 */
4375static char *cmdnextc;
4376
4377static void
4378cmdputs(const char *s)
4379{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004380 static const char vstype[VSTYPE + 1][3] = {
4381 "", "}", "-", "+", "?", "=",
4382 "%", "%%", "#", "##"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00004383 IF_ASH_BASH_COMPAT(, ":", "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004384 };
4385
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004386 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004387 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004388 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004389 unsigned char c;
4390 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004391 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004392
Denys Vlasenko46a14772009-12-10 21:27:13 +01004393 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004394 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4395 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004396 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004397 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004398 switch (c) {
4399 case CTLESC:
4400 c = *p++;
4401 break;
4402 case CTLVAR:
4403 subtype = *p++;
4404 if ((subtype & VSTYPE) == VSLENGTH)
4405 str = "${#";
4406 else
4407 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004408 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004409 case CTLENDVAR:
4410 str = "\"}" + !(quoted & 1);
4411 quoted >>= 1;
4412 subtype = 0;
4413 goto dostr;
4414 case CTLBACKQ:
4415 str = "$(...)";
4416 goto dostr;
Mike Frysinger98c52642009-04-02 10:02:37 +00004417#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004418 case CTLARI:
4419 str = "$((";
4420 goto dostr;
4421 case CTLENDARI:
4422 str = "))";
4423 goto dostr;
4424#endif
4425 case CTLQUOTEMARK:
4426 quoted ^= 1;
4427 c = '"';
4428 break;
4429 case '=':
4430 if (subtype == 0)
4431 break;
4432 if ((subtype & VSTYPE) != VSNORMAL)
4433 quoted <<= 1;
4434 str = vstype[subtype & VSTYPE];
4435 if (subtype & VSNUL)
4436 c = ':';
4437 else
4438 goto checkstr;
4439 break;
4440 case '\'':
4441 case '\\':
4442 case '"':
4443 case '$':
4444 /* These can only happen inside quotes */
4445 cc[0] = c;
4446 str = cc;
4447 c = '\\';
4448 break;
4449 default:
4450 break;
4451 }
4452 USTPUTC(c, nextc);
4453 checkstr:
4454 if (!str)
4455 continue;
4456 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004457 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004458 USTPUTC(c, nextc);
4459 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004460 } /* while *p++ not NUL */
4461
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004462 if (quoted & 1) {
4463 USTPUTC('"', nextc);
4464 }
4465 *nextc = 0;
4466 cmdnextc = nextc;
4467}
4468
4469/* cmdtxt() and cmdlist() call each other */
4470static void cmdtxt(union node *n);
4471
4472static void
4473cmdlist(union node *np, int sep)
4474{
4475 for (; np; np = np->narg.next) {
4476 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004477 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004478 cmdtxt(np);
4479 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004480 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004481 }
4482}
4483
4484static void
4485cmdtxt(union node *n)
4486{
4487 union node *np;
4488 struct nodelist *lp;
4489 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004490
4491 if (!n)
4492 return;
4493 switch (n->type) {
4494 default:
4495#if DEBUG
4496 abort();
4497#endif
4498 case NPIPE:
4499 lp = n->npipe.cmdlist;
4500 for (;;) {
4501 cmdtxt(lp->n);
4502 lp = lp->next;
4503 if (!lp)
4504 break;
4505 cmdputs(" | ");
4506 }
4507 break;
4508 case NSEMI:
4509 p = "; ";
4510 goto binop;
4511 case NAND:
4512 p = " && ";
4513 goto binop;
4514 case NOR:
4515 p = " || ";
4516 binop:
4517 cmdtxt(n->nbinary.ch1);
4518 cmdputs(p);
4519 n = n->nbinary.ch2;
4520 goto donode;
4521 case NREDIR:
4522 case NBACKGND:
4523 n = n->nredir.n;
4524 goto donode;
4525 case NNOT:
4526 cmdputs("!");
4527 n = n->nnot.com;
4528 donode:
4529 cmdtxt(n);
4530 break;
4531 case NIF:
4532 cmdputs("if ");
4533 cmdtxt(n->nif.test);
4534 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004535 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004536 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004537 cmdputs("; else ");
4538 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004539 } else {
4540 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004541 }
4542 p = "; fi";
4543 goto dotail;
4544 case NSUBSHELL:
4545 cmdputs("(");
4546 n = n->nredir.n;
4547 p = ")";
4548 goto dotail;
4549 case NWHILE:
4550 p = "while ";
4551 goto until;
4552 case NUNTIL:
4553 p = "until ";
4554 until:
4555 cmdputs(p);
4556 cmdtxt(n->nbinary.ch1);
4557 n = n->nbinary.ch2;
4558 p = "; done";
4559 dodo:
4560 cmdputs("; do ");
4561 dotail:
4562 cmdtxt(n);
4563 goto dotail2;
4564 case NFOR:
4565 cmdputs("for ");
4566 cmdputs(n->nfor.var);
4567 cmdputs(" in ");
4568 cmdlist(n->nfor.args, 1);
4569 n = n->nfor.body;
4570 p = "; done";
4571 goto dodo;
4572 case NDEFUN:
4573 cmdputs(n->narg.text);
4574 p = "() { ... }";
4575 goto dotail2;
4576 case NCMD:
4577 cmdlist(n->ncmd.args, 1);
4578 cmdlist(n->ncmd.redirect, 0);
4579 break;
4580 case NARG:
4581 p = n->narg.text;
4582 dotail2:
4583 cmdputs(p);
4584 break;
4585 case NHERE:
4586 case NXHERE:
4587 p = "<<...";
4588 goto dotail2;
4589 case NCASE:
4590 cmdputs("case ");
4591 cmdputs(n->ncase.expr->narg.text);
4592 cmdputs(" in ");
4593 for (np = n->ncase.cases; np; np = np->nclist.next) {
4594 cmdtxt(np->nclist.pattern);
4595 cmdputs(") ");
4596 cmdtxt(np->nclist.body);
4597 cmdputs(";; ");
4598 }
4599 p = "esac";
4600 goto dotail2;
4601 case NTO:
4602 p = ">";
4603 goto redir;
4604 case NCLOBBER:
4605 p = ">|";
4606 goto redir;
4607 case NAPPEND:
4608 p = ">>";
4609 goto redir;
Denis Vlasenko559691a2008-10-05 18:39:31 +00004610#if ENABLE_ASH_BASH_COMPAT
4611 case NTO2:
4612#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004613 case NTOFD:
4614 p = ">&";
4615 goto redir;
4616 case NFROM:
4617 p = "<";
4618 goto redir;
4619 case NFROMFD:
4620 p = "<&";
4621 goto redir;
4622 case NFROMTO:
4623 p = "<>";
4624 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004625 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004626 cmdputs(p);
4627 if (n->type == NTOFD || n->type == NFROMFD) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004628 cmdputs(utoa(n->ndup.dupfd));
4629 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004630 }
4631 n = n->nfile.fname;
4632 goto donode;
4633 }
4634}
4635
4636static char *
4637commandtext(union node *n)
4638{
4639 char *name;
4640
4641 STARTSTACKSTR(cmdnextc);
4642 cmdtxt(n);
4643 name = stackblock();
4644 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4645 name, cmdnextc, cmdnextc));
4646 return ckstrdup(name);
4647}
4648#endif /* JOBS */
4649
4650/*
4651 * Fork off a subshell. If we are doing job control, give the subshell its
4652 * own process group. Jp is a job structure that the job is to be added to.
4653 * N is the command that will be evaluated by the child. Both jp and n may
4654 * be NULL. The mode parameter can be one of the following:
4655 * FORK_FG - Fork off a foreground process.
4656 * FORK_BG - Fork off a background process.
4657 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4658 * process group even if job control is on.
4659 *
4660 * When job control is turned off, background processes have their standard
4661 * input redirected to /dev/null (except for the second and later processes
4662 * in a pipeline).
4663 *
4664 * Called with interrupts off.
4665 */
4666/*
4667 * Clear traps on a fork.
4668 */
4669static void
4670clear_traps(void)
4671{
4672 char **tp;
4673
4674 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004675 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004676 INT_OFF;
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004677 if (trap_ptr == trap)
4678 free(*tp);
4679 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004680 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004681 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004682 setsignal(tp - trap);
4683 INT_ON;
4684 }
4685 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004686 may_have_traps = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004687}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004688
4689/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004690static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004691
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004692/* Called after fork(), in child */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004693static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004694forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004695{
4696 int oldlvl;
4697
4698 TRACE(("Child shell %d\n", getpid()));
4699 oldlvl = shlvl;
4700 shlvl++;
4701
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004702 /* man bash: "Non-builtin commands run by bash have signal handlers
4703 * set to the values inherited by the shell from its parent".
4704 * Do we do it correctly? */
4705
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004706 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004707
4708 if (mode == FORK_NOJOB /* is it `xxx` ? */
4709 && n && n->type == NCMD /* is it single cmd? */
4710 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004711 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004712 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4713 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4714 ) {
4715 TRACE(("Trap hack\n"));
4716 /* Awful hack for `trap` or $(trap).
4717 *
4718 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4719 * contains an example where "trap" is executed in a subshell:
4720 *
4721 * save_traps=$(trap)
4722 * ...
4723 * eval "$save_traps"
4724 *
4725 * Standard does not say that "trap" in subshell shall print
4726 * parent shell's traps. It only says that its output
4727 * must have suitable form, but then, in the above example
4728 * (which is not supposed to be normative), it implies that.
4729 *
4730 * bash (and probably other shell) does implement it
4731 * (traps are reset to defaults, but "trap" still shows them),
4732 * but as a result, "trap" logic is hopelessly messed up:
4733 *
4734 * # trap
4735 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4736 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4737 * # true | trap <--- trap is in subshell - no output (ditto)
4738 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4739 * trap -- 'echo Ho' SIGWINCH
4740 * # echo `(trap)` <--- in subshell in subshell - output
4741 * trap -- 'echo Ho' SIGWINCH
4742 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4743 * trap -- 'echo Ho' SIGWINCH
4744 *
4745 * The rules when to forget and when to not forget traps
4746 * get really complex and nonsensical.
4747 *
4748 * Our solution: ONLY bare $(trap) or `trap` is special.
4749 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004750 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02004751 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004752 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004753 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004754 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004755#if JOBS
4756 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004757 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004758 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004759 pid_t pgrp;
4760
4761 if (jp->nprocs == 0)
4762 pgrp = getpid();
4763 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004764 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004765 /* this can fail because we are doing it in the parent also */
4766 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004767 if (mode == FORK_FG)
4768 xtcsetpgrp(ttyfd, pgrp);
4769 setsignal(SIGTSTP);
4770 setsignal(SIGTTOU);
4771 } else
4772#endif
4773 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004774 /* man bash: "When job control is not in effect,
4775 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004776 ignoresig(SIGINT);
4777 ignoresig(SIGQUIT);
4778 if (jp->nprocs == 0) {
4779 close(0);
4780 if (open(bb_dev_null, O_RDONLY) != 0)
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00004781 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004782 }
4783 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004784 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004785 if (iflag) { /* why if iflag only? */
4786 setsignal(SIGINT);
4787 setsignal(SIGTERM);
4788 }
4789 /* man bash:
4790 * "In all cases, bash ignores SIGQUIT. Non-builtin
4791 * commands run by bash have signal handlers
4792 * set to the values inherited by the shell
4793 * from its parent".
4794 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004795 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004796 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004797#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02004798 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01004799 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004800 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004801 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02004802 /* "jobs": we do not want to clear job list for it,
4803 * instead we remove only _its_ own_ job from job list.
4804 * This makes "jobs .... | cat" more useful.
4805 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004806 freejob(curjob);
4807 return;
4808 }
4809#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004810 for (jp = curjob; jp; jp = jp->prev_job)
4811 freejob(jp);
4812 jobless = 0;
4813}
4814
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004815/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00004816#if !JOBS
4817#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4818#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004819static void
4820forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4821{
4822 TRACE(("In parent shell: child = %d\n", pid));
4823 if (!jp) {
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004824 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4825 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004826 jobless++;
4827 return;
4828 }
4829#if JOBS
4830 if (mode != FORK_NOJOB && jp->jobctl) {
4831 int pgrp;
4832
4833 if (jp->nprocs == 0)
4834 pgrp = pid;
4835 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004836 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004837 /* This can fail because we are doing it in the child also */
4838 setpgid(pid, pgrp);
4839 }
4840#endif
4841 if (mode == FORK_BG) {
4842 backgndpid = pid; /* set $! */
4843 set_curjob(jp, CUR_RUNNING);
4844 }
4845 if (jp) {
4846 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01004847 ps->ps_pid = pid;
4848 ps->ps_status = -1;
4849 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004850#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004851 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004852 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004853#endif
4854 }
4855}
4856
4857static int
4858forkshell(struct job *jp, union node *n, int mode)
4859{
4860 int pid;
4861
4862 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4863 pid = fork();
4864 if (pid < 0) {
4865 TRACE(("Fork failed, errno=%d", errno));
4866 if (jp)
4867 freejob(jp);
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +00004868 ash_msg_and_raise_error("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004869 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02004870 if (pid == 0) {
4871 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004872 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004873 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004874 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004875 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004876 return pid;
4877}
4878
4879/*
4880 * Wait for job to finish.
4881 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004882 * Under job control we have the problem that while a child process
4883 * is running interrupts generated by the user are sent to the child
4884 * but not to the shell. This means that an infinite loop started by
4885 * an interactive user may be hard to kill. With job control turned off,
4886 * an interactive user may place an interactive program inside a loop.
4887 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004888 * these interrupts to also abort the loop. The approach we take here
4889 * is to have the shell ignore interrupt signals while waiting for a
4890 * foreground process to terminate, and then send itself an interrupt
4891 * signal if the child process was terminated by an interrupt signal.
4892 * Unfortunately, some programs want to do a bit of cleanup and then
4893 * exit on interrupt; unless these processes terminate themselves by
4894 * sending a signal to themselves (instead of calling exit) they will
4895 * confuse this approach.
4896 *
4897 * Called with interrupts off.
4898 */
4899static int
4900waitforjob(struct job *jp)
4901{
4902 int st;
4903
4904 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004905
4906 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004907 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004908 /* In non-interactive shells, we _can_ get
4909 * a keyboard signal here and be EINTRed,
4910 * but we just loop back, waiting for command to complete.
4911 *
4912 * man bash:
4913 * "If bash is waiting for a command to complete and receives
4914 * a signal for which a trap has been set, the trap
4915 * will not be executed until the command completes."
4916 *
4917 * Reality is that even if trap is not set, bash
4918 * will not act on the signal until command completes.
4919 * Try this. sleep5intoff.c:
4920 * #include <signal.h>
4921 * #include <unistd.h>
4922 * int main() {
4923 * sigset_t set;
4924 * sigemptyset(&set);
4925 * sigaddset(&set, SIGINT);
4926 * sigaddset(&set, SIGQUIT);
4927 * sigprocmask(SIG_BLOCK, &set, NULL);
4928 * sleep(5);
4929 * return 0;
4930 * }
4931 * $ bash -c './sleep5intoff; echo hi'
4932 * ^C^C^C^C <--- pressing ^C once a second
4933 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004934 * $ bash -c './sleep5intoff; echo hi'
4935 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
4936 * $ _
4937 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004938 dowait(DOWAIT_BLOCK, jp);
4939 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004940 INT_ON;
4941
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004942 st = getstatus(jp);
4943#if JOBS
4944 if (jp->jobctl) {
4945 xtcsetpgrp(ttyfd, rootpid);
4946 /*
4947 * This is truly gross.
4948 * If we're doing job control, then we did a TIOCSPGRP which
4949 * caused us (the shell) to no longer be in the controlling
4950 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4951 * intuit from the subprocess exit status whether a SIGINT
4952 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4953 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004954 if (jp->sigint) /* TODO: do the same with all signals */
4955 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004956 }
4957 if (jp->state == JOBDONE)
4958#endif
4959 freejob(jp);
4960 return st;
4961}
4962
4963/*
4964 * return 1 if there are stopped jobs, otherwise 0
4965 */
4966static int
4967stoppedjobs(void)
4968{
4969 struct job *jp;
4970 int retval;
4971
4972 retval = 0;
4973 if (job_warning)
4974 goto out;
4975 jp = curjob;
4976 if (jp && jp->state == JOBSTOPPED) {
4977 out2str("You have stopped jobs.\n");
4978 job_warning = 2;
4979 retval++;
4980 }
4981 out:
4982 return retval;
4983}
4984
4985
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00004986/* ============ redir.c
4987 *
4988 * Code for dealing with input/output redirection.
4989 */
4990
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01004991#undef EMPTY
4992#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00004993#define EMPTY -2 /* marks an unused slot in redirtab */
Denis Vlasenko7d75a962007-11-22 08:16:57 +00004994#define CLOSED -3 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00004995
4996/*
4997 * Open a file in noclobber mode.
4998 * The code was copied from bash.
4999 */
5000static int
5001noclobberopen(const char *fname)
5002{
5003 int r, fd;
5004 struct stat finfo, finfo2;
5005
5006 /*
5007 * If the file exists and is a regular file, return an error
5008 * immediately.
5009 */
5010 r = stat(fname, &finfo);
5011 if (r == 0 && S_ISREG(finfo.st_mode)) {
5012 errno = EEXIST;
5013 return -1;
5014 }
5015
5016 /*
5017 * If the file was not present (r != 0), make sure we open it
5018 * exclusively so that if it is created before we open it, our open
5019 * will fail. Make sure that we do not truncate an existing file.
5020 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5021 * file was not a regular file, we leave O_EXCL off.
5022 */
5023 if (r != 0)
5024 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5025 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5026
5027 /* If the open failed, return the file descriptor right away. */
5028 if (fd < 0)
5029 return fd;
5030
5031 /*
5032 * OK, the open succeeded, but the file may have been changed from a
5033 * non-regular file to a regular file between the stat and the open.
5034 * We are assuming that the O_EXCL open handles the case where FILENAME
5035 * did not exist and is symlinked to an existing file between the stat
5036 * and open.
5037 */
5038
5039 /*
5040 * If we can open it and fstat the file descriptor, and neither check
5041 * revealed that it was a regular file, and the file has not been
5042 * replaced, return the file descriptor.
5043 */
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005044 if (fstat(fd, &finfo2) == 0
5045 && !S_ISREG(finfo2.st_mode)
5046 && finfo.st_dev == finfo2.st_dev
5047 && finfo.st_ino == finfo2.st_ino
5048 ) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005049 return fd;
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005050 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005051
5052 /* The file has been replaced. badness. */
5053 close(fd);
5054 errno = EEXIST;
5055 return -1;
5056}
5057
5058/*
5059 * Handle here documents. Normally we fork off a process to write the
5060 * data to a pipe. If the document is short, we can stuff the data in
5061 * the pipe without forking.
5062 */
5063/* openhere needs this forward reference */
5064static void expandhere(union node *arg, int fd);
5065static int
5066openhere(union node *redir)
5067{
5068 int pip[2];
5069 size_t len = 0;
5070
5071 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005072 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005073 if (redir->type == NHERE) {
5074 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005075 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005076 full_write(pip[1], redir->nhere.doc->narg.text, len);
5077 goto out;
5078 }
5079 }
5080 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005081 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005082 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005083 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5084 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5085 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5086 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005087 signal(SIGPIPE, SIG_DFL);
5088 if (redir->type == NHERE)
5089 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005090 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005091 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005092 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005093 }
5094 out:
5095 close(pip[1]);
5096 return pip[0];
5097}
5098
5099static int
5100openredirect(union node *redir)
5101{
5102 char *fname;
5103 int f;
5104
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02005105 fname = redir->nfile.expfname;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005106 switch (redir->nfile.type) {
5107 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005108 f = open(fname, O_RDONLY);
5109 if (f < 0)
5110 goto eopen;
5111 break;
5112 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005113 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005114 if (f < 0)
5115 goto ecreate;
5116 break;
5117 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00005118#if ENABLE_ASH_BASH_COMPAT
5119 case NTO2:
5120#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005121 /* Take care of noclobber mode. */
5122 if (Cflag) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005123 f = noclobberopen(fname);
5124 if (f < 0)
5125 goto ecreate;
5126 break;
5127 }
5128 /* FALLTHROUGH */
5129 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005130 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5131 if (f < 0)
5132 goto ecreate;
5133 break;
5134 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005135 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5136 if (f < 0)
5137 goto ecreate;
5138 break;
5139 default:
5140#if DEBUG
5141 abort();
5142#endif
5143 /* Fall through to eliminate warning. */
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005144/* Our single caller does this itself */
Denis Vlasenko0b769642008-07-24 07:54:57 +00005145// case NTOFD:
5146// case NFROMFD:
5147// f = -1;
5148// break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005149 case NHERE:
5150 case NXHERE:
5151 f = openhere(redir);
5152 break;
5153 }
5154
5155 return f;
5156 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005157 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005158 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005159 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005160}
5161
5162/*
5163 * Copy a file descriptor to be >= to. Returns -1
5164 * if the source file descriptor is closed, EMPTY if there are no unused
5165 * file descriptors left.
5166 */
Denis Vlasenko5a867312008-07-24 19:46:38 +00005167/* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
5168 * old code was doing close(to) prior to copyfd() to achieve the same */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005169enum {
5170 COPYFD_EXACT = (int)~(INT_MAX),
5171 COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1),
5172};
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005173static int
5174copyfd(int from, int to)
5175{
5176 int newfd;
5177
Denis Vlasenko5a867312008-07-24 19:46:38 +00005178 if (to & COPYFD_EXACT) {
5179 to &= ~COPYFD_EXACT;
5180 /*if (from != to)*/
5181 newfd = dup2(from, to);
5182 } else {
5183 newfd = fcntl(from, F_DUPFD, to);
5184 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005185 if (newfd < 0) {
5186 if (errno == EMFILE)
5187 return EMPTY;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005188 /* Happens when source fd is not open: try "echo >&99" */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005189 ash_msg_and_raise_error("%d: %m", from);
5190 }
5191 return newfd;
5192}
5193
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005194/* Struct def and variable are moved down to the first usage site */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005195struct two_fd_t {
5196 int orig, copy;
5197};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005198struct redirtab {
5199 struct redirtab *next;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005200 int nullredirs;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005201 int pair_count;
Denys Vlasenko606291b2009-09-23 23:15:43 +02005202 struct two_fd_t two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005203};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005204#define redirlist (G_var.redirlist)
Denis Vlasenko0b769642008-07-24 07:54:57 +00005205
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005206static int need_to_remember(struct redirtab *rp, int fd)
5207{
5208 int i;
5209
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005210 if (!rp) /* remembering was not requested */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005211 return 0;
5212
5213 for (i = 0; i < rp->pair_count; i++) {
5214 if (rp->two_fd[i].orig == fd) {
5215 /* already remembered */
5216 return 0;
5217 }
5218 }
5219 return 1;
5220}
5221
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005222/* "hidden" fd is a fd used to read scripts, or a copy of such */
5223static int is_hidden_fd(struct redirtab *rp, int fd)
5224{
5225 int i;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005226 struct parsefile *pf;
5227
5228 if (fd == -1)
5229 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005230 /* Check open scripts' fds */
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005231 pf = g_parsefile;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005232 while (pf) {
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005233 /* We skip pf_fd == 0 case because of the following case:
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005234 * $ ash # running ash interactively
5235 * $ . ./script.sh
5236 * and in script.sh: "exec 9>&0".
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005237 * Even though top-level pf_fd _is_ 0,
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005238 * it's still ok to use it: "read" builtin uses it,
5239 * why should we cripple "exec" builtin?
5240 */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005241 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005242 return 1;
5243 }
5244 pf = pf->prev;
5245 }
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005246
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005247 if (!rp)
5248 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005249 /* Check saved fds of redirects */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005250 fd |= COPYFD_RESTORE;
5251 for (i = 0; i < rp->pair_count; i++) {
5252 if (rp->two_fd[i].copy == fd) {
5253 return 1;
5254 }
5255 }
5256 return 0;
5257}
5258
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005259/*
5260 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5261 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005262 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005263 */
5264/* flags passed to redirect */
5265#define REDIR_PUSH 01 /* save previous values of file descriptors */
5266#define REDIR_SAVEFD2 03 /* set preverrout */
5267static void
5268redirect(union node *redir, int flags)
5269{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005270 struct redirtab *sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005271 int sv_pos;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005272 int i;
5273 int fd;
5274 int newfd;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005275 int copied_fd2 = -1;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005276
Denis Vlasenko01631112007-12-16 17:20:38 +00005277 g_nullredirs++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005278 if (!redir) {
5279 return;
5280 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005281
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005282 sv = NULL;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005283 sv_pos = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005284 INT_OFF;
5285 if (flags & REDIR_PUSH) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005286 union node *tmp = redir;
5287 do {
5288 sv_pos++;
Denis Vlasenko559691a2008-10-05 18:39:31 +00005289#if ENABLE_ASH_BASH_COMPAT
Chris Metcalfc3c1fb62010-01-08 13:18:06 +01005290 if (tmp->nfile.type == NTO2)
Denis Vlasenko559691a2008-10-05 18:39:31 +00005291 sv_pos++;
5292#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005293 tmp = tmp->nfile.next;
5294 } while (tmp);
5295 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005296 sv->next = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005297 sv->pair_count = sv_pos;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005298 redirlist = sv;
Denis Vlasenko01631112007-12-16 17:20:38 +00005299 sv->nullredirs = g_nullredirs - 1;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005300 g_nullredirs = 0;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005301 while (sv_pos > 0) {
5302 sv_pos--;
5303 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5304 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005305 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005306
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005307 do {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005308 int right_fd = -1;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005309 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005310 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005311 right_fd = redir->ndup.dupfd;
5312 //bb_error_msg("doing %d > %d", fd, right_fd);
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005313 /* redirect from/to same file descriptor? */
5314 if (right_fd == fd)
5315 continue;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005316 /* "echo >&10" and 10 is a fd opened to a sh script? */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005317 if (is_hidden_fd(sv, right_fd)) {
5318 errno = EBADF; /* as if it is closed */
5319 ash_msg_and_raise_error("%d: %m", right_fd);
5320 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005321 newfd = -1;
5322 } else {
5323 newfd = openredirect(redir); /* always >= 0 */
5324 if (fd == newfd) {
5325 /* Descriptor wasn't open before redirect.
5326 * Mark it for close in the future */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005327 if (need_to_remember(sv, fd)) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005328 goto remember_to_close;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005329 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005330 continue;
5331 }
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005332 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005333#if ENABLE_ASH_BASH_COMPAT
5334 redirect_more:
5335#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005336 if (need_to_remember(sv, fd)) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005337 /* Copy old descriptor */
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005338 /* Careful to not accidentally "save"
5339 * to the same fd as right side fd in N>&M */
5340 int minfd = right_fd < 10 ? 10 : right_fd + 1;
5341 i = fcntl(fd, F_DUPFD, minfd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005342/* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5343 * are closed in popredir() in the child, preventing them from leaking
5344 * into child. (popredir() also cleans up the mess in case of failures)
5345 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005346 if (i == -1) {
5347 i = errno;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005348 if (i != EBADF) {
5349 /* Strange error (e.g. "too many files" EMFILE?) */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005350 if (newfd >= 0)
5351 close(newfd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005352 errno = i;
5353 ash_msg_and_raise_error("%d: %m", fd);
5354 /* NOTREACHED */
5355 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005356 /* EBADF: it is not open - good, remember to close it */
5357 remember_to_close:
5358 i = CLOSED;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005359 } else { /* fd is open, save its copy */
5360 /* "exec fd>&-" should not close fds
5361 * which point to script file(s).
5362 * Force them to be restored afterwards */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005363 if (is_hidden_fd(sv, fd))
5364 i |= COPYFD_RESTORE;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005365 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005366 if (fd == 2)
5367 copied_fd2 = i;
5368 sv->two_fd[sv_pos].orig = fd;
5369 sv->two_fd[sv_pos].copy = i;
5370 sv_pos++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005371 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005372 if (newfd < 0) {
5373 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005374 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005375 /* Don't want to trigger debugging */
5376 if (fd != -1)
5377 close(fd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005378 } else {
5379 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005380 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005381 } else if (fd != newfd) { /* move newfd to fd */
5382 copyfd(newfd, fd | COPYFD_EXACT);
Denis Vlasenko559691a2008-10-05 18:39:31 +00005383#if ENABLE_ASH_BASH_COMPAT
5384 if (!(redir->nfile.type == NTO2 && fd == 2))
5385#endif
5386 close(newfd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005387 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005388#if ENABLE_ASH_BASH_COMPAT
5389 if (redir->nfile.type == NTO2 && fd == 1) {
5390 /* We already redirected it to fd 1, now copy it to 2 */
5391 newfd = 1;
5392 fd = 2;
5393 goto redirect_more;
5394 }
5395#endif
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005396 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005397
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005398 INT_ON;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005399 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5400 preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005401}
5402
5403/*
5404 * Undo the effects of the last redirection.
5405 */
5406static void
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005407popredir(int drop, int restore)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005408{
5409 struct redirtab *rp;
5410 int i;
5411
Denis Vlasenko01631112007-12-16 17:20:38 +00005412 if (--g_nullredirs >= 0)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005413 return;
5414 INT_OFF;
5415 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005416 for (i = 0; i < rp->pair_count; i++) {
5417 int fd = rp->two_fd[i].orig;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005418 int copy = rp->two_fd[i].copy;
5419 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005420 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005421 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005422 continue;
5423 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005424 if (copy != EMPTY) {
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005425 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
Denis Vlasenko22f74142008-07-24 22:34:43 +00005426 copy &= ~COPYFD_RESTORE;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005427 /*close(fd);*/
Denis Vlasenko22f74142008-07-24 22:34:43 +00005428 copyfd(copy, fd | COPYFD_EXACT);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005429 }
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005430 close(copy & ~COPYFD_RESTORE);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005431 }
5432 }
5433 redirlist = rp->next;
Denis Vlasenko01631112007-12-16 17:20:38 +00005434 g_nullredirs = rp->nullredirs;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005435 free(rp);
5436 INT_ON;
5437}
5438
5439/*
5440 * Undo all redirections. Called on error or interrupt.
5441 */
5442
5443/*
5444 * Discard all saved file descriptors.
5445 */
5446static void
5447clearredir(int drop)
5448{
5449 for (;;) {
Denis Vlasenko01631112007-12-16 17:20:38 +00005450 g_nullredirs = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005451 if (!redirlist)
5452 break;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005453 popredir(drop, /*restore:*/ 0);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005454 }
5455}
5456
5457static int
5458redirectsafe(union node *redir, int flags)
5459{
5460 int err;
5461 volatile int saveint;
5462 struct jmploc *volatile savehandler = exception_handler;
5463 struct jmploc jmploc;
5464
5465 SAVE_INT(saveint);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005466 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5467 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005468 if (!err) {
5469 exception_handler = &jmploc;
5470 redirect(redir, flags);
5471 }
5472 exception_handler = savehandler;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00005473 if (err && exception_type != EXERROR)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005474 longjmp(exception_handler->loc, 1);
5475 RESTORE_INT(saveint);
5476 return err;
5477}
5478
5479
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005480/* ============ Routines to expand arguments to commands
5481 *
5482 * We have to deal with backquotes, shell variables, and file metacharacters.
5483 */
5484
Mike Frysinger98c52642009-04-02 10:02:37 +00005485#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005486static arith_t
5487ash_arith(const char *s)
5488{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005489 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005490 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005491
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005492 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005493 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005494 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005495
5496 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005497 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005498 if (math_state.errmsg)
5499 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005500 INT_ON;
5501
5502 return result;
5503}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005504#endif
5505
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005506/*
5507 * expandarg flags
5508 */
5509#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5510#define EXP_TILDE 0x2 /* do normal tilde expansion */
5511#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5512#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5513#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Ron Yorston549deab2015-05-18 09:57:51 +02005514#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005515#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5516#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005517#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005518/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005519 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005520 */
5521#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5522#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005523#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5524#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Ron Yorston417622c2015-05-18 09:59:14 +02005525#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005526
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005527/* Add CTLESC when necessary. */
Ron Yorston549deab2015-05-18 09:57:51 +02005528#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005529/* Do not skip NUL characters. */
5530#define QUOTES_KEEPNUL EXP_TILDE
5531
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005532/*
5533 * Structure specifying which parts of the string should be searched
5534 * for IFS characters.
5535 */
5536struct ifsregion {
5537 struct ifsregion *next; /* next region in list */
5538 int begoff; /* offset of start of region */
5539 int endoff; /* offset of end of region */
5540 int nulonly; /* search for nul bytes only */
5541};
5542
5543struct arglist {
5544 struct strlist *list;
5545 struct strlist **lastp;
5546};
5547
5548/* output of current string */
5549static char *expdest;
5550/* list of back quote expressions */
5551static struct nodelist *argbackq;
5552/* first struct in list of ifs regions */
5553static struct ifsregion ifsfirst;
5554/* last struct in list */
5555static struct ifsregion *ifslastp;
5556/* holds expanded arg list */
5557static struct arglist exparg;
5558
5559/*
5560 * Our own itoa().
5561 */
Denys Vlasenko26777aa2010-11-22 23:49:10 +01005562#if !ENABLE_SH_MATH_SUPPORT
5563/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5564typedef long arith_t;
5565# define ARITH_FMT "%ld"
5566#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005567static int
5568cvtnum(arith_t num)
5569{
5570 int len;
5571
Denys Vlasenko9c541002015-10-07 15:44:36 +02005572 expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest);
5573 len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005574 STADJUST(len, expdest);
5575 return len;
5576}
5577
5578static size_t
5579esclen(const char *start, const char *p)
5580{
5581 size_t esc = 0;
5582
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005583 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005584 esc++;
5585 }
5586 return esc;
5587}
5588
5589/*
5590 * Remove any CTLESC characters from a string.
5591 */
5592static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005593rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005594{
Ron Yorston417622c2015-05-18 09:59:14 +02005595 static const char qchars[] ALIGN1 = {
5596 IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005597
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005598 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005599 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005600 unsigned protect_against_glob;
5601 unsigned globbing;
Ron Yorston417622c2015-05-18 09:59:14 +02005602 IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005603
Ron Yorston417622c2015-05-18 09:59:14 +02005604 p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005605 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005606 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005607
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005608 q = p;
5609 r = str;
5610 if (flag & RMESCAPE_ALLOC) {
5611 size_t len = p - str;
5612 size_t fulllen = len + strlen(p) + 1;
5613
5614 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005615 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005616 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005617 /* p and str may be invalidated by makestrspace */
5618 str = (char *)stackblock() + strloc;
5619 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005620 } else if (flag & RMESCAPE_HEAP) {
5621 r = ckmalloc(fulllen);
5622 } else {
5623 r = stalloc(fulllen);
5624 }
5625 q = r;
5626 if (len > 0) {
Denis Vlasenko29eb3592008-05-18 14:06:08 +00005627 q = (char *)memcpy(q, str, len) + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005628 }
5629 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005630
Ron Yorston549deab2015-05-18 09:57:51 +02005631 inquotes = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005632 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005633 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005634 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005635 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005636// Note: both inquotes and protect_against_glob only affect whether
5637// CTLESC,<ch> gets converted to <ch> or to \<ch>
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005638 inquotes = ~inquotes;
5639 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005640 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005641 continue;
5642 }
Ron Yorston549deab2015-05-18 09:57:51 +02005643 if ((unsigned char)*p == CTLESC) {
5644 p++;
5645 if (protect_against_glob) {
5646 *q++ = '\\';
5647 }
5648 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005649 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005650 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005651 goto copy;
5652 }
Ron Yorston417622c2015-05-18 09:59:14 +02005653#if ENABLE_ASH_BASH_COMPAT
5654 else if (*p == '/' && slash) {
5655 /* stop handling globbing and mark location of slash */
5656 globbing = slash = 0;
5657 *p = CTLESC;
5658 }
5659#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005660 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005661 copy:
5662 *q++ = *p++;
5663 }
5664 *q = '\0';
5665 if (flag & RMESCAPE_GROW) {
5666 expdest = r;
5667 STADJUST(q - r + 1, expdest);
5668 }
5669 return r;
5670}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005671#define pmatch(a, b) !fnmatch((a), (b), 0)
5672
5673/*
5674 * Prepare a pattern for a expmeta (internal glob(3)) call.
5675 *
5676 * Returns an stalloced string.
5677 */
5678static char *
Ron Yorston549deab2015-05-18 09:57:51 +02005679preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005680{
Ron Yorston549deab2015-05-18 09:57:51 +02005681 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005682}
5683
5684/*
5685 * Put a string on the stack.
5686 */
5687static void
5688memtodest(const char *p, size_t len, int syntax, int quotes)
5689{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005690 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005691
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005692 if (!len)
5693 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005694
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005695 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
5696
5697 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005698 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005699 if (c) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005700 int n = SIT(c, syntax);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005701 if ((quotes & QUOTES_ESC) &&
Ron Yorston549deab2015-05-18 09:57:51 +02005702 ((n == CCTL) ||
5703 (((quotes & EXP_FULL) || syntax != BASESYNTAX) &&
5704 n == CBACK)))
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005705 USTPUTC(CTLESC, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005706 } else if (!(quotes & QUOTES_KEEPNUL))
5707 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005708 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005709 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005710
5711 expdest = q;
5712}
5713
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005714static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005715strtodest(const char *p, int syntax, int quotes)
5716{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005717 size_t len = strlen(p);
5718 memtodest(p, len, syntax, quotes);
5719 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005720}
5721
5722/*
5723 * Record the fact that we have to scan this region of the
5724 * string for IFS characters.
5725 */
5726static void
5727recordregion(int start, int end, int nulonly)
5728{
5729 struct ifsregion *ifsp;
5730
5731 if (ifslastp == NULL) {
5732 ifsp = &ifsfirst;
5733 } else {
5734 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00005735 ifsp = ckzalloc(sizeof(*ifsp));
5736 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005737 ifslastp->next = ifsp;
5738 INT_ON;
5739 }
5740 ifslastp = ifsp;
5741 ifslastp->begoff = start;
5742 ifslastp->endoff = end;
5743 ifslastp->nulonly = nulonly;
5744}
5745
5746static void
5747removerecordregions(int endoff)
5748{
5749 if (ifslastp == NULL)
5750 return;
5751
5752 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005753 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005754 struct ifsregion *ifsp;
5755 INT_OFF;
5756 ifsp = ifsfirst.next->next;
5757 free(ifsfirst.next);
5758 ifsfirst.next = ifsp;
5759 INT_ON;
5760 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005761 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005762 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005763 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005764 ifslastp = &ifsfirst;
5765 ifsfirst.endoff = endoff;
5766 }
5767 return;
5768 }
5769
5770 ifslastp = &ifsfirst;
5771 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005772 ifslastp = ifslastp->next;
5773 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005774 struct ifsregion *ifsp;
5775 INT_OFF;
5776 ifsp = ifslastp->next->next;
5777 free(ifslastp->next);
5778 ifslastp->next = ifsp;
5779 INT_ON;
5780 }
5781 if (ifslastp->endoff > endoff)
5782 ifslastp->endoff = endoff;
5783}
5784
5785static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005786exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005787{
Denys Vlasenkocd716832009-11-28 22:14:02 +01005788 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005789 char *name;
5790 struct passwd *pw;
5791 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005792 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005793
5794 name = p + 1;
5795
5796 while ((c = *++p) != '\0') {
5797 switch (c) {
5798 case CTLESC:
5799 return startp;
5800 case CTLQUOTEMARK:
5801 return startp;
5802 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005803 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005804 goto done;
5805 break;
5806 case '/':
5807 case CTLENDVAR:
5808 goto done;
5809 }
5810 }
5811 done:
5812 *p = '\0';
5813 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02005814 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005815 } else {
5816 pw = getpwnam(name);
5817 if (pw == NULL)
5818 goto lose;
5819 home = pw->pw_dir;
5820 }
5821 if (!home || !*home)
5822 goto lose;
5823 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005824 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005825 return p;
5826 lose:
5827 *p = c;
5828 return startp;
5829}
5830
5831/*
5832 * Execute a command inside back quotes. If it's a builtin command, we
5833 * want to save its output in a block obtained from malloc. Otherwise
5834 * we fork off a subprocess and get the output of the command via a pipe.
5835 * Should be called with interrupts off.
5836 */
5837struct backcmd { /* result of evalbackcmd */
5838 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005839 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005840 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005841 struct job *jp; /* job structure for command */
5842};
5843
5844/* These forward decls are needed to use "eval" code for backticks handling: */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005845static uint8_t back_exitstatus; /* exit status of backquoted command */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005846#define EV_EXIT 01 /* exit after evaluating tree */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02005847static void evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005848
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02005849static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005850evalbackcmd(union node *n, struct backcmd *result)
5851{
5852 int saveherefd;
5853
5854 result->fd = -1;
5855 result->buf = NULL;
5856 result->nleft = 0;
5857 result->jp = NULL;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00005858 if (n == NULL)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005859 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005860
5861 saveherefd = herefd;
5862 herefd = -1;
5863
5864 {
5865 int pip[2];
5866 struct job *jp;
5867
5868 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005869 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko68404f12008-03-17 09:00:54 +00005870 jp = makejob(/*n,*/ 1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005871 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5872 FORCE_INT_ON;
5873 close(pip[0]);
5874 if (pip[1] != 1) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005875 /*close(1);*/
5876 copyfd(pip[1], 1 | COPYFD_EXACT);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005877 close(pip[1]);
5878 }
5879 eflag = 0;
5880 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5881 /* NOTREACHED */
5882 }
5883 close(pip[1]);
5884 result->fd = pip[0];
5885 result->jp = jp;
5886 }
5887 herefd = saveherefd;
5888 out:
5889 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5890 result->fd, result->buf, result->nleft, result->jp));
5891}
5892
5893/*
5894 * Expand stuff in backwards quotes.
5895 */
5896static void
Ron Yorston549deab2015-05-18 09:57:51 +02005897expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005898{
5899 struct backcmd in;
5900 int i;
5901 char buf[128];
5902 char *p;
5903 char *dest;
5904 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02005905 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005906 struct stackmark smark;
5907
5908 INT_OFF;
5909 setstackmark(&smark);
5910 dest = expdest;
5911 startloc = dest - (char *)stackblock();
5912 grabstackstr(dest);
5913 evalbackcmd(cmd, &in);
5914 popstackmark(&smark);
5915
5916 p = in.buf;
5917 i = in.nleft;
5918 if (i == 0)
5919 goto read;
5920 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02005921 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005922 read:
5923 if (in.fd < 0)
5924 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01005925 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005926 TRACE(("expbackq: read returns %d\n", i));
5927 if (i <= 0)
5928 break;
5929 p = buf;
5930 }
5931
Denis Vlasenko60818682007-09-28 22:07:23 +00005932 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005933 if (in.fd >= 0) {
5934 close(in.fd);
5935 back_exitstatus = waitforjob(in.jp);
5936 }
5937 INT_ON;
5938
5939 /* Eat all trailing newlines */
5940 dest = expdest;
5941 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5942 STUNPUTC(dest);
5943 expdest = dest;
5944
Ron Yorston549deab2015-05-18 09:57:51 +02005945 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005946 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005947 TRACE(("evalbackq: size:%d:'%.*s'\n",
5948 (int)((dest - (char *)stackblock()) - startloc),
5949 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005950 stackblock() + startloc));
5951}
5952
Mike Frysinger98c52642009-04-02 10:02:37 +00005953#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005954/*
5955 * Expand arithmetic expression. Backup to start of expression,
5956 * evaluate, place result in (backed up) result, adjust string position.
5957 */
5958static void
Ron Yorston549deab2015-05-18 09:57:51 +02005959expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005960{
5961 char *p, *start;
5962 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005963 int len;
5964
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00005965 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005966
5967 /*
5968 * This routine is slightly over-complicated for
5969 * efficiency. Next we scan backwards looking for the
5970 * start of arithmetic.
5971 */
5972 start = stackblock();
5973 p = expdest - 1;
5974 *p = '\0';
5975 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01005976 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005977 int esc;
5978
Denys Vlasenkocd716832009-11-28 22:14:02 +01005979 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005980 p--;
5981#if DEBUG
5982 if (p < start) {
5983 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5984 }
5985#endif
5986 }
5987
5988 esc = esclen(start, p);
5989 if (!(esc % 2)) {
5990 break;
5991 }
5992
5993 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01005994 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005995
5996 begoff = p - start;
5997
5998 removerecordregions(begoff);
5999
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006000 expdest = p;
6001
Ron Yorston549deab2015-05-18 09:57:51 +02006002 if (flag & QUOTES_ESC)
6003 rmescapes(p + 1, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006004
Ron Yorston549deab2015-05-18 09:57:51 +02006005 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006006
Ron Yorston549deab2015-05-18 09:57:51 +02006007 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006008 recordregion(begoff, begoff + len, 0);
6009}
6010#endif
6011
6012/* argstr needs it */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006013static char *evalvar(char *p, int flags, struct strlist *var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006014
6015/*
6016 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6017 * characters to allow for further processing. Otherwise treat
6018 * $@ like $* since no splitting will be performed.
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006019 *
6020 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
6021 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
6022 * for correct expansion of "B=$A" word.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006023 */
6024static void
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006025argstr(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006026{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006027 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006028 '=',
6029 ':',
6030 CTLQUOTEMARK,
6031 CTLENDVAR,
6032 CTLESC,
6033 CTLVAR,
6034 CTLBACKQ,
Mike Frysinger98c52642009-04-02 10:02:37 +00006035#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006036 CTLENDARI,
6037#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006038 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006039 };
6040 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006041 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006042 int inquotes;
6043 size_t length;
6044 int startloc;
6045
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006046 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006047 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006048 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006049 reject++;
6050 }
6051 inquotes = 0;
6052 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006053 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006054 char *q;
6055
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006056 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006057 tilde:
6058 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006059 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006060 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006061 }
6062 start:
6063 startloc = expdest - (char *)stackblock();
6064 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006065 unsigned char c;
6066
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006067 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006068 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006069 if (c) {
6070 if (!(c & 0x80)
Denys Vlasenko958581a2010-09-12 15:04:27 +02006071 IF_SH_MATH_SUPPORT(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006072 ) {
6073 /* c == '=' || c == ':' || c == CTLENDARI */
6074 length++;
6075 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006076 }
6077 if (length > 0) {
6078 int newloc;
6079 expdest = stack_nputstr(p, length, expdest);
6080 newloc = expdest - (char *)stackblock();
6081 if (breakall && !inquotes && newloc > startloc) {
6082 recordregion(startloc, newloc, 0);
6083 }
6084 startloc = newloc;
6085 }
6086 p += length + 1;
6087 length = 0;
6088
6089 switch (c) {
6090 case '\0':
6091 goto breakloop;
6092 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006093 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006094 p--;
6095 continue;
6096 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006097 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006098 reject++;
6099 /* fall through */
6100 case ':':
6101 /*
6102 * sort of a hack - expand tildes in variable
6103 * assignments (after the first '=' and after ':'s).
6104 */
6105 if (*--p == '~') {
6106 goto tilde;
6107 }
6108 continue;
6109 }
6110
6111 switch (c) {
6112 case CTLENDVAR: /* ??? */
6113 goto breakloop;
6114 case CTLQUOTEMARK:
Ron Yorston549deab2015-05-18 09:57:51 +02006115 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006116 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006117 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6118 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006119 goto start;
6120 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006121 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006122 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006123 p--;
6124 length++;
6125 startloc++;
6126 }
6127 break;
6128 case CTLESC:
6129 startloc++;
6130 length++;
Ron Yorston549deab2015-05-18 09:57:51 +02006131
6132 /*
6133 * Quoted parameter expansion pattern: remove quote
6134 * unless inside inner quotes or we have a literal
6135 * backslash.
6136 */
6137 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6138 EXP_QPAT && *p != '\\')
6139 break;
6140
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006141 goto addquote;
6142 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006143 TRACE(("argstr: evalvar('%s')\n", p));
Ron Yorston549deab2015-05-18 09:57:51 +02006144 p = evalvar(p, flags | inquotes, var_str_list);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006145 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006146 goto start;
6147 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006148 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006149 argbackq = argbackq->next;
6150 goto start;
Mike Frysinger98c52642009-04-02 10:02:37 +00006151#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006152 case CTLENDARI:
6153 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006154 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006155 goto start;
6156#endif
6157 }
6158 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006159 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006160}
6161
6162static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006163scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6164 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006165{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006166 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006167 char c;
6168
6169 loc = startp;
6170 loc2 = rmesc;
6171 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006172 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006173 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006174
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006175 c = *loc2;
6176 if (zero) {
6177 *loc2 = '\0';
6178 s = rmesc;
6179 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006180 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006181
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006182 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006183 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006184 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006185 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006186 loc++;
6187 loc++;
6188 loc2++;
6189 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006190 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006191}
6192
6193static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006194scanright(char *startp, char *rmesc, char *rmescend,
6195 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006196{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006197#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6198 int try2optimize = match_at_start;
6199#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006200 int esc = 0;
6201 char *loc;
6202 char *loc2;
6203
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006204 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6205 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6206 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6207 * Logic:
6208 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6209 * and on each iteration they go back two/one char until they reach the beginning.
6210 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6211 */
6212 /* TODO: document in what other circumstances we are called. */
6213
6214 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006215 int match;
6216 char c = *loc2;
6217 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006218 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006219 *loc2 = '\0';
6220 s = rmesc;
6221 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006222 match = pmatch(pattern, s);
6223 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006224 *loc2 = c;
6225 if (match)
6226 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006227#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6228 if (try2optimize) {
6229 /* Maybe we can optimize this:
6230 * if pattern ends with unescaped *, we can avoid checking
6231 * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6232 * it wont match truncated "raw_value_of_" strings too.
6233 */
6234 unsigned plen = strlen(pattern);
6235 /* Does it end with "*"? */
6236 if (plen != 0 && pattern[--plen] == '*') {
6237 /* "xxxx*" is not escaped */
6238 /* "xxx\*" is escaped */
6239 /* "xx\\*" is not escaped */
6240 /* "x\\\*" is escaped */
6241 int slashes = 0;
6242 while (plen != 0 && pattern[--plen] == '\\')
6243 slashes++;
6244 if (!(slashes & 1))
6245 break; /* ends with unescaped "*" */
6246 }
6247 try2optimize = 0;
6248 }
6249#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006250 loc--;
6251 if (quotes) {
6252 if (--esc < 0) {
6253 esc = esclen(startp, loc);
6254 }
6255 if (esc % 2) {
6256 esc--;
6257 loc--;
6258 }
6259 }
6260 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006261 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006262}
6263
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006264static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006265static void
6266varunset(const char *end, const char *var, const char *umsg, int varflags)
6267{
6268 const char *msg;
6269 const char *tail;
6270
6271 tail = nullstr;
6272 msg = "parameter not set";
6273 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006274 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006275 if (varflags & VSNUL)
6276 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006277 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006278 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006279 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006280 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006281 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006282}
6283
6284static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006285subevalvar(char *p, char *varname, int strloc, int subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006286 int startloc, int varflags, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006287{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006288 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006289 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006290 char *startp;
6291 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006292 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006293 char *str;
Ron Yorston417622c2015-05-18 09:59:14 +02006294 IF_ASH_BASH_COMPAT(char *repl = NULL;)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006295 IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006296 int saveherefd = herefd;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006297 int amount, resetloc;
6298 IF_ASH_BASH_COMPAT(int workloc;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006299 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006300 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006301
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006302 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6303 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006304
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006305 herefd = -1;
Ron Yorstoneb6b48b2015-05-18 09:51:35 +02006306 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
Ron Yorston549deab2015-05-18 09:57:51 +02006307 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6308 var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006309 STPUTC('\0', expdest);
6310 herefd = saveherefd;
6311 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006312 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006313
6314 switch (subtype) {
6315 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006316 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006317 amount = startp - expdest;
6318 STADJUST(amount, expdest);
6319 return startp;
6320
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006321 case VSQUESTION:
6322 varunset(p, varname, startp, varflags);
6323 /* NOTREACHED */
6324
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006325#if ENABLE_ASH_BASH_COMPAT
6326 case VSSUBSTR:
6327 loc = str = stackblock() + strloc;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006328 /* Read POS in ${var:POS:LEN} */
6329 pos = atoi(loc); /* number(loc) errors out on "1:4" */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006330 len = str - startp - 1;
6331
6332 /* *loc != '\0', guaranteed by parser */
6333 if (quotes) {
6334 char *ptr;
6335
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006336 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006337 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006338 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006339 len--;
6340 ptr++;
6341 }
6342 }
6343 }
6344 orig_len = len;
6345
6346 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006347 /* ${var::LEN} */
6348 len = number(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006349 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006350 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006351 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006352 while (*loc && *loc != ':') {
6353 /* TODO?
6354 * bash complains on: var=qwe; echo ${var:1a:123}
6355 if (!isdigit(*loc))
6356 ash_msg_and_raise_error(msg_illnum, str);
6357 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006358 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006359 }
6360 if (*loc++ == ':') {
6361 len = number(loc);
6362 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006363 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006364 if (pos < 0) {
6365 /* ${VAR:$((-n)):l} starts n chars from the end */
6366 pos = orig_len + pos;
6367 }
6368 if ((unsigned)pos >= orig_len) {
6369 /* apart from obvious ${VAR:999999:l},
6370 * covers ${VAR:$((-9999999)):l} - result is ""
6371 * (bash-compat)
6372 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006373 pos = 0;
6374 len = 0;
6375 }
6376 if (len > (orig_len - pos))
6377 len = orig_len - pos;
6378
6379 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006380 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006381 str++;
6382 }
6383 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006384 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006385 *loc++ = *str++;
6386 *loc++ = *str++;
6387 }
6388 *loc = '\0';
6389 amount = loc - expdest;
6390 STADJUST(amount, expdest);
6391 return loc;
6392#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006393 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006394
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006395 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006396
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006397 /* We'll comeback here if we grow the stack while handling
6398 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6399 * stack will need rebasing, and we'll need to remove our work
6400 * areas each time
6401 */
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006402 IF_ASH_BASH_COMPAT(restart:)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006403
6404 amount = expdest - ((char *)stackblock() + resetloc);
6405 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006406 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006407
6408 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006409 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006410 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006411 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006412 if (rmesc != startp) {
6413 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006414 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006415 }
6416 }
6417 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006418 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02006419 /*
6420 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6421 * The result is a_\_z_c (not a\_\_z_c)!
6422 *
6423 * The search pattern and replace string treat backslashes differently!
6424 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6425 * and string. It's only used on the first call.
6426 */
6427 preglob(str, IF_ASH_BASH_COMPAT(
6428 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
6429 RMESCAPE_SLASH :) 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006430
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006431#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006432 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006433 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006434 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006435
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006436 if (!repl) {
Ron Yorston417622c2015-05-18 09:59:14 +02006437 if ((repl=strchr(str, CTLESC)))
6438 *repl++ = '\0';
6439 else
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006440 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006441 }
Ron Yorston417622c2015-05-18 09:59:14 +02006442 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006443
6444 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006445 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006446 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006447
6448 len = 0;
6449 idx = startp;
6450 end = str - 1;
6451 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006452 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006453 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006454 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006455 if (!loc) {
6456 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006457 char *restart_detect = stackblock();
6458 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006459 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006460 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006461 idx++;
6462 len++;
6463 STPUTC(*idx, expdest);
6464 }
6465 if (stackblock() != restart_detect)
6466 goto restart;
6467 idx++;
6468 len++;
6469 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006470 /* continue; - prone to quadratic behavior, smarter code: */
6471 if (idx >= end)
6472 break;
6473 if (str[0] == '*') {
6474 /* Pattern is "*foo". If "*foo" does not match "long_string",
6475 * it would never match "ong_string" etc, no point in trying.
6476 */
6477 goto skip_matching;
6478 }
6479 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006480 }
6481
6482 if (subtype == VSREPLACEALL) {
6483 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006484 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006485 idx++;
6486 idx++;
6487 rmesc++;
6488 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006489 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006490 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006491 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006492
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006493 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006494 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006495 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006496 if (quotes && *loc == '\\') {
6497 STPUTC(CTLESC, expdest);
6498 len++;
6499 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006500 STPUTC(*loc, expdest);
6501 if (stackblock() != restart_detect)
6502 goto restart;
6503 len++;
6504 }
6505
6506 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006507 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006508 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006509 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006510 STPUTC(*idx, expdest);
6511 if (stackblock() != restart_detect)
6512 goto restart;
6513 len++;
6514 idx++;
6515 }
6516 break;
6517 }
6518 }
6519
6520 /* We've put the replaced text into a buffer at workloc, now
6521 * move it to the right place and adjust the stack.
6522 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006523 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006524 startp = (char *)stackblock() + startloc;
6525 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006526 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006527 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006528 STADJUST(-amount, expdest);
6529 return startp;
6530 }
6531#endif /* ENABLE_ASH_BASH_COMPAT */
6532
6533 subtype -= VSTRIMRIGHT;
6534#if DEBUG
6535 if (subtype < 0 || subtype > 7)
6536 abort();
6537#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006538 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006539 zero = subtype >> 1;
6540 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6541 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6542
6543 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6544 if (loc) {
6545 if (zero) {
6546 memmove(startp, loc, str - loc);
6547 loc = startp + (str - loc) - 1;
6548 }
6549 *loc = '\0';
6550 amount = loc - expdest;
6551 STADJUST(amount, expdest);
6552 }
6553 return loc;
6554}
6555
6556/*
6557 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006558 * name parameter (examples):
6559 * ash -c 'echo $1' name:'1='
6560 * ash -c 'echo $qwe' name:'qwe='
6561 * ash -c 'echo $$' name:'$='
6562 * ash -c 'echo ${$}' name:'$='
6563 * ash -c 'echo ${$##q}' name:'$=q'
6564 * ash -c 'echo ${#$}' name:'$='
6565 * note: examples with bad shell syntax:
6566 * ash -c 'echo ${#$1}' name:'$=1'
6567 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006568 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02006569static NOINLINE ssize_t
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006570varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006571{
Mike Frysinger98c52642009-04-02 10:02:37 +00006572 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006573 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006574 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006575 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006576 int sep;
Ron Yorston549deab2015-05-18 09:57:51 +02006577 int quoted = flags & EXP_QUOTED;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006578 int subtype = varflags & VSTYPE;
6579 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6580 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006581 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006582
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006583 sep = quoted ? ((flags & EXP_FULL) << CHAR_BIT) : 0;
6584
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006585 switch (*name) {
6586 case '$':
6587 num = rootpid;
6588 goto numvar;
6589 case '?':
6590 num = exitstatus;
6591 goto numvar;
6592 case '#':
6593 num = shellparam.nparam;
6594 goto numvar;
6595 case '!':
6596 num = backgndpid;
6597 if (num == 0)
6598 return -1;
6599 numvar:
6600 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006601 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006602 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00006603 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006604 for (i = NOPTS - 1; i >= 0; i--) {
6605 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00006606 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006607 len++;
6608 }
6609 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006610 check_1char_name:
6611#if 0
6612 /* handles cases similar to ${#$1} */
6613 if (name[2] != '\0')
6614 raise_error_syntax("bad substitution");
6615#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006616 break;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006617 case '@': {
6618 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006619 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006620
6621 if (quoted && (flags & EXP_FULL)) {
6622 /* note: this is not meant as PEOF value */
6623 sep = 1 << CHAR_BIT;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006624 goto param;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006625 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006626 /* fall through */
6627 case '*':
Denys Vlasenkocd716832009-11-28 22:14:02 +01006628 sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006629 param:
6630 ap = shellparam.p;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006631 sepc = sep;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006632 if (!ap)
6633 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006634 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006635 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006636
6637 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006638 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006639 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006640 }
6641 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006642 break;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006643 } /* case '@' and '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006644 case '0':
6645 case '1':
6646 case '2':
6647 case '3':
6648 case '4':
6649 case '5':
6650 case '6':
6651 case '7':
6652 case '8':
6653 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02006654 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006655 if (num < 0 || num > shellparam.nparam)
6656 return -1;
6657 p = num ? shellparam.p[num - 1] : arg0;
6658 goto value;
6659 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006660 /* NB: name has form "VAR=..." */
6661
6662 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6663 * which should be considered before we check variables. */
6664 if (var_str_list) {
6665 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6666 p = NULL;
6667 do {
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00006668 char *str, *eq;
6669 str = var_str_list->text;
6670 eq = strchr(str, '=');
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006671 if (!eq) /* stop at first non-assignment */
6672 break;
6673 eq++;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00006674 if (name_len == (unsigned)(eq - str)
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006675 && strncmp(str, name, name_len) == 0
6676 ) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006677 p = eq;
6678 /* goto value; - WRONG! */
6679 /* think "A=1 A=2 B=$A" */
6680 }
6681 var_str_list = var_str_list->next;
6682 } while (var_str_list);
6683 if (p)
6684 goto value;
6685 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006686 p = lookupvar(name);
6687 value:
6688 if (!p)
6689 return -1;
6690
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006691 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006692#if ENABLE_UNICODE_SUPPORT
6693 if (subtype == VSLENGTH && len > 0) {
6694 reinit_unicode_for_ash();
6695 if (unicode_status == UNICODE_ON) {
6696 len = unicode_strlen(p);
6697 }
6698 }
6699#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006700 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006701 }
6702
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006703 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006704 STADJUST(-len, expdest);
6705 return len;
6706}
6707
6708/*
6709 * Expand a variable, and return a pointer to the next character in the
6710 * input string.
6711 */
6712static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006713evalvar(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006714{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006715 char varflags;
6716 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02006717 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006718 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006719 char *var;
6720 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006721 int startloc;
6722 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006723
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006724 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006725 subtype = varflags & VSTYPE;
Ron Yorston549deab2015-05-18 09:57:51 +02006726 quoted = flags & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006727 var = p;
6728 easy = (!quoted || (*var == '@' && shellparam.nparam));
6729 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02006730 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006731
6732 again:
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006733 varlen = varvalue(var, varflags, flags, var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006734 if (varflags & VSNUL)
6735 varlen--;
6736
6737 if (subtype == VSPLUS) {
6738 varlen = -1 - varlen;
6739 goto vsplus;
6740 }
6741
6742 if (subtype == VSMINUS) {
6743 vsplus:
6744 if (varlen < 0) {
6745 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006746 p,
Ron Yorston549deab2015-05-18 09:57:51 +02006747 flags | EXP_TILDE | EXP_WORD,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006748 var_str_list
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006749 );
6750 goto end;
6751 }
6752 if (easy)
6753 goto record;
6754 goto end;
6755 }
6756
6757 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6758 if (varlen < 0) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006759 if (subevalvar(p, var, /* strloc: */ 0,
6760 subtype, startloc, varflags,
Ron Yorston549deab2015-05-18 09:57:51 +02006761 /* quotes: */ flags & ~QUOTES_ESC,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006762 var_str_list)
6763 ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006764 varflags &= ~VSNUL;
6765 /*
6766 * Remove any recorded regions beyond
6767 * start of variable
6768 */
6769 removerecordregions(startloc);
6770 goto again;
6771 }
6772 goto end;
6773 }
6774 if (easy)
6775 goto record;
6776 goto end;
6777 }
6778
6779 if (varlen < 0 && uflag)
6780 varunset(p, var, 0, 0);
6781
6782 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006783 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006784 goto record;
6785 }
6786
6787 if (subtype == VSNORMAL) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006788 if (easy)
6789 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006790 goto end;
6791 }
6792
6793#if DEBUG
6794 switch (subtype) {
6795 case VSTRIMLEFT:
6796 case VSTRIMLEFTMAX:
6797 case VSTRIMRIGHT:
6798 case VSTRIMRIGHTMAX:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006799#if ENABLE_ASH_BASH_COMPAT
6800 case VSSUBSTR:
6801 case VSREPLACE:
6802 case VSREPLACEALL:
6803#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006804 break;
6805 default:
6806 abort();
6807 }
6808#endif
6809
6810 if (varlen >= 0) {
6811 /*
6812 * Terminate the string and start recording the pattern
6813 * right after it
6814 */
6815 STPUTC('\0', expdest);
6816 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006817 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006818 startloc, varflags, flags, var_str_list)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006819 int amount = expdest - (
6820 (char *)stackblock() + patloc - 1
6821 );
6822 STADJUST(-amount, expdest);
6823 }
6824 /* Remove any recorded regions beyond start of variable */
6825 removerecordregions(startloc);
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006826 record:
6827 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006828 }
6829
6830 end:
6831 if (subtype != VSNORMAL) { /* skip to end of alternative */
6832 int nesting = 1;
6833 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006834 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006835 if (c == CTLESC)
6836 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02006837 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006838 if (varlen >= 0)
6839 argbackq = argbackq->next;
6840 } else if (c == CTLVAR) {
6841 if ((*p++ & VSTYPE) != VSNORMAL)
6842 nesting++;
6843 } else if (c == CTLENDVAR) {
6844 if (--nesting == 0)
6845 break;
6846 }
6847 }
6848 }
6849 return p;
6850}
6851
6852/*
6853 * Break the argument string into pieces based upon IFS and add the
6854 * strings to the argument list. The regions of the string to be
6855 * searched for IFS characters have been stored by recordregion.
6856 */
6857static void
6858ifsbreakup(char *string, struct arglist *arglist)
6859{
6860 struct ifsregion *ifsp;
6861 struct strlist *sp;
6862 char *start;
6863 char *p;
6864 char *q;
6865 const char *ifs, *realifs;
6866 int ifsspc;
6867 int nulonly;
6868
6869 start = string;
6870 if (ifslastp != NULL) {
6871 ifsspc = 0;
6872 nulonly = 0;
6873 realifs = ifsset() ? ifsval() : defifs;
6874 ifsp = &ifsfirst;
6875 do {
6876 p = string + ifsp->begoff;
6877 nulonly = ifsp->nulonly;
6878 ifs = nulonly ? nullstr : realifs;
6879 ifsspc = 0;
6880 while (p < string + ifsp->endoff) {
6881 q = p;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006882 if ((unsigned char)*p == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006883 p++;
6884 if (!strchr(ifs, *p)) {
6885 p++;
6886 continue;
6887 }
6888 if (!nulonly)
6889 ifsspc = (strchr(defifs, *p) != NULL);
6890 /* Ignore IFS whitespace at start */
6891 if (q == start && ifsspc) {
6892 p++;
6893 start = p;
6894 continue;
6895 }
6896 *q = '\0';
Denis Vlasenko597906c2008-02-20 16:38:54 +00006897 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006898 sp->text = start;
6899 *arglist->lastp = sp;
6900 arglist->lastp = &sp->next;
6901 p++;
6902 if (!nulonly) {
6903 for (;;) {
6904 if (p >= string + ifsp->endoff) {
6905 break;
6906 }
6907 q = p;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006908 if ((unsigned char)*p == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006909 p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00006910 if (strchr(ifs, *p) == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006911 p = q;
6912 break;
Denis Vlasenko597906c2008-02-20 16:38:54 +00006913 }
6914 if (strchr(defifs, *p) == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006915 if (ifsspc) {
6916 p++;
6917 ifsspc = 0;
6918 } else {
6919 p = q;
6920 break;
6921 }
6922 } else
6923 p++;
6924 }
6925 }
6926 start = p;
6927 } /* while */
6928 ifsp = ifsp->next;
6929 } while (ifsp != NULL);
6930 if (nulonly)
6931 goto add;
6932 }
6933
6934 if (!*start)
6935 return;
6936
6937 add:
Denis Vlasenko597906c2008-02-20 16:38:54 +00006938 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006939 sp->text = start;
6940 *arglist->lastp = sp;
6941 arglist->lastp = &sp->next;
6942}
6943
6944static void
6945ifsfree(void)
6946{
6947 struct ifsregion *p;
6948
6949 INT_OFF;
6950 p = ifsfirst.next;
6951 do {
6952 struct ifsregion *ifsp;
6953 ifsp = p->next;
6954 free(p);
6955 p = ifsp;
6956 } while (p);
6957 ifslastp = NULL;
6958 ifsfirst.next = NULL;
6959 INT_ON;
6960}
6961
6962/*
6963 * Add a file name to the list.
6964 */
6965static void
6966addfname(const char *name)
6967{
6968 struct strlist *sp;
6969
Denis Vlasenko597906c2008-02-20 16:38:54 +00006970 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006971 sp->text = ststrdup(name);
6972 *exparg.lastp = sp;
6973 exparg.lastp = &sp->next;
6974}
6975
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006976/*
6977 * Do metacharacter (i.e. *, ?, [...]) expansion.
6978 */
6979static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006980expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006981{
6982 char *p;
6983 const char *cp;
6984 char *start;
6985 char *endname;
6986 int metaflag;
6987 struct stat statb;
6988 DIR *dirp;
6989 struct dirent *dp;
6990 int atend;
6991 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01006992 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006993
6994 metaflag = 0;
6995 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01006996 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006997 if (*p == '*' || *p == '?')
6998 metaflag = 1;
6999 else if (*p == '[') {
7000 char *q = p + 1;
7001 if (*q == '!')
7002 q++;
7003 for (;;) {
7004 if (*q == '\\')
7005 q++;
7006 if (*q == '/' || *q == '\0')
7007 break;
7008 if (*++q == ']') {
7009 metaflag = 1;
7010 break;
7011 }
7012 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007013 } else {
7014 if (*p == '\\')
7015 esc++;
7016 if (p[esc] == '/') {
7017 if (metaflag)
7018 break;
7019 start = p + esc + 1;
7020 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007021 }
7022 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007023 if (metaflag == 0) { /* we've reached the end of the file name */
7024 if (enddir != expdir)
7025 metaflag++;
7026 p = name;
7027 do {
7028 if (*p == '\\')
7029 p++;
7030 *enddir++ = *p;
7031 } while (*p++);
7032 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7033 addfname(expdir);
7034 return;
7035 }
7036 endname = p;
7037 if (name < start) {
7038 p = name;
7039 do {
7040 if (*p == '\\')
7041 p++;
7042 *enddir++ = *p++;
7043 } while (p < start);
7044 }
7045 if (enddir == expdir) {
7046 cp = ".";
7047 } else if (enddir == expdir + 1 && *expdir == '/') {
7048 cp = "/";
7049 } else {
7050 cp = expdir;
7051 enddir[-1] = '\0';
7052 }
7053 dirp = opendir(cp);
7054 if (dirp == NULL)
7055 return;
7056 if (enddir != expdir)
7057 enddir[-1] = '/';
7058 if (*endname == 0) {
7059 atend = 1;
7060 } else {
7061 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007062 *endname = '\0';
7063 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007064 }
7065 matchdot = 0;
7066 p = start;
7067 if (*p == '\\')
7068 p++;
7069 if (*p == '.')
7070 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007071 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007072 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007073 continue;
7074 if (pmatch(start, dp->d_name)) {
7075 if (atend) {
7076 strcpy(enddir, dp->d_name);
7077 addfname(expdir);
7078 } else {
7079 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7080 continue;
7081 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007082 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007083 }
7084 }
7085 }
7086 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007087 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007088 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007089}
7090
7091static struct strlist *
7092msort(struct strlist *list, int len)
7093{
7094 struct strlist *p, *q = NULL;
7095 struct strlist **lpp;
7096 int half;
7097 int n;
7098
7099 if (len <= 1)
7100 return list;
7101 half = len >> 1;
7102 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007103 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007104 q = p;
7105 p = p->next;
7106 }
7107 q->next = NULL; /* terminate first half of list */
7108 q = msort(list, half); /* sort first half of list */
7109 p = msort(p, len - half); /* sort second half */
7110 lpp = &list;
7111 for (;;) {
7112#if ENABLE_LOCALE_SUPPORT
7113 if (strcoll(p->text, q->text) < 0)
7114#else
7115 if (strcmp(p->text, q->text) < 0)
7116#endif
7117 {
7118 *lpp = p;
7119 lpp = &p->next;
7120 p = *lpp;
7121 if (p == NULL) {
7122 *lpp = q;
7123 break;
7124 }
7125 } else {
7126 *lpp = q;
7127 lpp = &q->next;
7128 q = *lpp;
7129 if (q == NULL) {
7130 *lpp = p;
7131 break;
7132 }
7133 }
7134 }
7135 return list;
7136}
7137
7138/*
7139 * Sort the results of file name expansion. It calculates the number of
7140 * strings to sort and then calls msort (short for merge sort) to do the
7141 * work.
7142 */
7143static struct strlist *
7144expsort(struct strlist *str)
7145{
7146 int len;
7147 struct strlist *sp;
7148
7149 len = 0;
7150 for (sp = str; sp; sp = sp->next)
7151 len++;
7152 return msort(str, len);
7153}
7154
7155static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007156expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007157{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00007158 static const char metachars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007159 '*', '?', '[', 0
7160 };
7161 /* TODO - EXP_REDIR */
7162
7163 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007164 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007165 struct strlist **savelastp;
7166 struct strlist *sp;
7167 char *p;
7168
7169 if (fflag)
7170 goto nometa;
7171 if (!strpbrk(str->text, metachars))
7172 goto nometa;
7173 savelastp = exparg.lastp;
7174
7175 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007176 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007177 {
7178 int i = strlen(str->text);
7179 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
7180 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007181 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007182 free(expdir);
7183 if (p != str->text)
7184 free(p);
7185 INT_ON;
7186 if (exparg.lastp == savelastp) {
7187 /*
7188 * no matches
7189 */
7190 nometa:
7191 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007192 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007193 exparg.lastp = &str->next;
7194 } else {
7195 *exparg.lastp = NULL;
7196 *savelastp = sp = expsort(*savelastp);
7197 while (sp->next != NULL)
7198 sp = sp->next;
7199 exparg.lastp = &sp->next;
7200 }
7201 str = str->next;
7202 }
7203}
7204
7205/*
7206 * Perform variable substitution and command substitution on an argument,
7207 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7208 * perform splitting and file name expansion. When arglist is NULL, perform
7209 * here document expansion.
7210 */
7211static void
7212expandarg(union node *arg, struct arglist *arglist, int flag)
7213{
7214 struct strlist *sp;
7215 char *p;
7216
7217 argbackq = arg->narg.backquote;
7218 STARTSTACKSTR(expdest);
7219 ifsfirst.next = NULL;
7220 ifslastp = NULL;
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007221 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007222 argstr(arg->narg.text, flag,
7223 /* var_str_list: */ arglist ? arglist->list : NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007224 p = _STPUTC('\0', expdest);
7225 expdest = p - 1;
7226 if (arglist == NULL) {
7227 return; /* here document expanded */
7228 }
7229 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007230 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007231 exparg.lastp = &exparg.list;
7232 /*
7233 * TODO - EXP_REDIR
7234 */
7235 if (flag & EXP_FULL) {
7236 ifsbreakup(p, &exparg);
7237 *exparg.lastp = NULL;
7238 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007239 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007240 } else {
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007241 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007242 rmescapes(p, 0);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007243 TRACE(("expandarg: rmescapes:'%s'\n", p));
7244 }
Denis Vlasenko597906c2008-02-20 16:38:54 +00007245 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007246 sp->text = p;
7247 *exparg.lastp = sp;
7248 exparg.lastp = &sp->next;
7249 }
7250 if (ifsfirst.next)
7251 ifsfree();
7252 *exparg.lastp = NULL;
7253 if (exparg.list) {
7254 *arglist->lastp = exparg.list;
7255 arglist->lastp = exparg.lastp;
7256 }
7257}
7258
7259/*
7260 * Expand shell variables and backquotes inside a here document.
7261 */
7262static void
7263expandhere(union node *arg, int fd)
7264{
7265 herefd = fd;
Ron Yorston549deab2015-05-18 09:57:51 +02007266 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007267 full_write(fd, stackblock(), expdest - (char *)stackblock());
7268}
7269
7270/*
7271 * Returns true if the pattern matches the string.
7272 */
7273static int
7274patmatch(char *pattern, const char *string)
7275{
Ron Yorston549deab2015-05-18 09:57:51 +02007276 return pmatch(preglob(pattern, 0), string);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007277}
7278
7279/*
7280 * See if a pattern matches in a case statement.
7281 */
7282static int
7283casematch(union node *pattern, char *val)
7284{
7285 struct stackmark smark;
7286 int result;
7287
7288 setstackmark(&smark);
7289 argbackq = pattern->narg.backquote;
7290 STARTSTACKSTR(expdest);
7291 ifslastp = NULL;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007292 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7293 /* var_str_list: */ NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007294 STACKSTRNUL(expdest);
7295 result = patmatch(stackblock(), val);
7296 popstackmark(&smark);
7297 return result;
7298}
7299
7300
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007301/* ============ find_command */
7302
7303struct builtincmd {
7304 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007305 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007306 /* unsigned flags; */
7307};
7308#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007309/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007310 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007311#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007312#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007313
7314struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007315 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007316 union param {
7317 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007318 /* index >= 0 for commands without path (slashes) */
7319 /* (TODO: what exactly does the value mean? PATH position?) */
7320 /* index == -1 for commands with slashes */
7321 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007322 const struct builtincmd *cmd;
7323 struct funcnode *func;
7324 } u;
7325};
7326/* values of cmdtype */
7327#define CMDUNKNOWN -1 /* no entry in table for command */
7328#define CMDNORMAL 0 /* command is an executable program */
7329#define CMDFUNCTION 1 /* command is a shell function */
7330#define CMDBUILTIN 2 /* command is a shell builtin */
7331
7332/* action to find_command() */
7333#define DO_ERR 0x01 /* prints errors */
7334#define DO_ABS 0x02 /* checks absolute paths */
7335#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7336#define DO_ALTPATH 0x08 /* using alternate path */
7337#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7338
7339static void find_command(char *, struct cmdentry *, int, const char *);
7340
7341
7342/* ============ Hashing commands */
7343
7344/*
7345 * When commands are first encountered, they are entered in a hash table.
7346 * This ensures that a full path search will not have to be done for them
7347 * on each invocation.
7348 *
7349 * We should investigate converting to a linear search, even though that
7350 * would make the command name "hash" a misnomer.
7351 */
7352
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007353struct tblentry {
7354 struct tblentry *next; /* next entry in hash chain */
7355 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007356 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007357 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007358 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007359};
7360
Denis Vlasenko01631112007-12-16 17:20:38 +00007361static struct tblentry **cmdtable;
7362#define INIT_G_cmdtable() do { \
7363 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7364} while (0)
7365
7366static int builtinloc = -1; /* index in path of %builtin, or -1 */
7367
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007368
7369static void
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007370tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007371{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007372#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007373 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007374 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007375 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007376 while (*envp)
7377 putenv(*envp++);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007378 run_applet_no_and_exit(applet_no, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007379 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007380 /* re-exec ourselves with the new arguments */
7381 execve(bb_busybox_exec_path, argv, envp);
7382 /* If they called chroot or otherwise made the binary no longer
7383 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007384 }
7385#endif
7386
7387 repeat:
7388#ifdef SYSV
7389 do {
7390 execve(cmd, argv, envp);
7391 } while (errno == EINTR);
7392#else
7393 execve(cmd, argv, envp);
7394#endif
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007395 if (cmd == (char*) bb_busybox_exec_path) {
7396 /* We already visited ENOEXEC branch below, don't do it again */
7397//TODO: try execve(initial_argv0_of_shell, argv, envp) before giving up?
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007398 free(argv);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007399 return;
7400 }
7401 if (errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007402 /* Run "cmd" as a shell script:
7403 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7404 * "If the execve() function fails with ENOEXEC, the shell
7405 * shall execute a command equivalent to having a shell invoked
7406 * with the command name as its first operand,
7407 * with any remaining arguments passed to the new shell"
7408 *
7409 * That is, do not use $SHELL, user's shell, or /bin/sh;
7410 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007411 *
7412 * Note that bash reads ~80 chars of the file, and if it sees
7413 * a zero byte before it sees newline, it doesn't try to
7414 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007415 * message and exit code 126. For one, this prevents attempts
7416 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007417 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007418 char **ap;
7419 char **new;
7420
7421 for (ap = argv; *ap; ap++)
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007422 continue;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007423 new = ckmalloc((ap - argv + 2) * sizeof(new[0]));
7424 new[0] = (char*) "ash";
7425 new[1] = cmd;
7426 ap = new + 2;
7427 while ((*ap++ = *++argv) != NULL)
Denis Vlasenko597906c2008-02-20 16:38:54 +00007428 continue;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007429 cmd = (char*) bb_busybox_exec_path;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007430 argv = new;
7431 goto repeat;
7432 }
7433}
7434
7435/*
7436 * Exec a program. Never returns. If you change this routine, you may
7437 * have to change the find_command routine as well.
7438 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007439static void shellexec(char **, const char *, int) NORETURN;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007440static void
7441shellexec(char **argv, const char *path, int idx)
7442{
7443 char *cmdname;
7444 int e;
7445 char **envp;
7446 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007447 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007448
Denis Vlasenko34c73c42008-08-16 11:48:02 +00007449 clearredir(/*drop:*/ 1);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007450 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007451 if (strchr(argv[0], '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007452#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007453 || (applet_no = find_applet_by_name(argv[0])) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007454#endif
7455 ) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007456 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007457 if (applet_no >= 0) {
7458 /* We tried execing ourself, but it didn't work.
7459 * Maybe /proc/self/exe doesn't exist?
7460 * Try $PATH search.
7461 */
7462 goto try_PATH;
7463 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007464 e = errno;
7465 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007466 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007467 e = ENOENT;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007468 while ((cmdname = path_advance(&path, argv[0])) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007469 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007470 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007471 if (errno != ENOENT && errno != ENOTDIR)
7472 e = errno;
7473 }
7474 stunalloc(cmdname);
7475 }
7476 }
7477
7478 /* Map to POSIX errors */
7479 switch (e) {
7480 case EACCES:
7481 exerrno = 126;
7482 break;
7483 case ENOENT:
7484 exerrno = 127;
7485 break;
7486 default:
7487 exerrno = 2;
7488 break;
7489 }
7490 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007491 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7492 argv[0], e, suppress_int));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007493 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
7494 /* NOTREACHED */
7495}
7496
7497static void
7498printentry(struct tblentry *cmdp)
7499{
7500 int idx;
7501 const char *path;
7502 char *name;
7503
7504 idx = cmdp->param.index;
7505 path = pathval();
7506 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007507 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007508 stunalloc(name);
7509 } while (--idx >= 0);
7510 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7511}
7512
7513/*
7514 * Clear out command entries. The argument specifies the first entry in
7515 * PATH which has changed.
7516 */
7517static void
7518clearcmdentry(int firstchange)
7519{
7520 struct tblentry **tblp;
7521 struct tblentry **pp;
7522 struct tblentry *cmdp;
7523
7524 INT_OFF;
7525 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7526 pp = tblp;
7527 while ((cmdp = *pp) != NULL) {
7528 if ((cmdp->cmdtype == CMDNORMAL &&
7529 cmdp->param.index >= firstchange)
7530 || (cmdp->cmdtype == CMDBUILTIN &&
7531 builtinloc >= firstchange)
7532 ) {
7533 *pp = cmdp->next;
7534 free(cmdp);
7535 } else {
7536 pp = &cmdp->next;
7537 }
7538 }
7539 }
7540 INT_ON;
7541}
7542
7543/*
7544 * Locate a command in the command hash table. If "add" is nonzero,
7545 * add the command to the table if it is not already present. The
7546 * variable "lastcmdentry" is set to point to the address of the link
7547 * pointing to the entry, so that delete_cmd_entry can delete the
7548 * entry.
7549 *
7550 * Interrupts must be off if called with add != 0.
7551 */
7552static struct tblentry **lastcmdentry;
7553
7554static struct tblentry *
7555cmdlookup(const char *name, int add)
7556{
7557 unsigned int hashval;
7558 const char *p;
7559 struct tblentry *cmdp;
7560 struct tblentry **pp;
7561
7562 p = name;
7563 hashval = (unsigned char)*p << 4;
7564 while (*p)
7565 hashval += (unsigned char)*p++;
7566 hashval &= 0x7FFF;
7567 pp = &cmdtable[hashval % CMDTABLESIZE];
7568 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7569 if (strcmp(cmdp->cmdname, name) == 0)
7570 break;
7571 pp = &cmdp->next;
7572 }
7573 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007574 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7575 + strlen(name)
7576 /* + 1 - already done because
7577 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007578 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007579 cmdp->cmdtype = CMDUNKNOWN;
7580 strcpy(cmdp->cmdname, name);
7581 }
7582 lastcmdentry = pp;
7583 return cmdp;
7584}
7585
7586/*
7587 * Delete the command entry returned on the last lookup.
7588 */
7589static void
7590delete_cmd_entry(void)
7591{
7592 struct tblentry *cmdp;
7593
7594 INT_OFF;
7595 cmdp = *lastcmdentry;
7596 *lastcmdentry = cmdp->next;
7597 if (cmdp->cmdtype == CMDFUNCTION)
7598 freefunc(cmdp->param.func);
7599 free(cmdp);
7600 INT_ON;
7601}
7602
7603/*
7604 * Add a new command entry, replacing any existing command entry for
7605 * the same name - except special builtins.
7606 */
7607static void
7608addcmdentry(char *name, struct cmdentry *entry)
7609{
7610 struct tblentry *cmdp;
7611
7612 cmdp = cmdlookup(name, 1);
7613 if (cmdp->cmdtype == CMDFUNCTION) {
7614 freefunc(cmdp->param.func);
7615 }
7616 cmdp->cmdtype = entry->cmdtype;
7617 cmdp->param = entry->u;
7618 cmdp->rehash = 0;
7619}
7620
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007621static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007622hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007623{
7624 struct tblentry **pp;
7625 struct tblentry *cmdp;
7626 int c;
7627 struct cmdentry entry;
7628 char *name;
7629
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007630 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007631 clearcmdentry(0);
7632 return 0;
7633 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007634
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007635 if (*argptr == NULL) {
7636 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7637 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7638 if (cmdp->cmdtype == CMDNORMAL)
7639 printentry(cmdp);
7640 }
7641 }
7642 return 0;
7643 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007644
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007645 c = 0;
7646 while ((name = *argptr) != NULL) {
7647 cmdp = cmdlookup(name, 0);
7648 if (cmdp != NULL
7649 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007650 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7651 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007652 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007653 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007654 find_command(name, &entry, DO_ERR, pathval());
7655 if (entry.cmdtype == CMDUNKNOWN)
7656 c = 1;
7657 argptr++;
7658 }
7659 return c;
7660}
7661
7662/*
7663 * Called when a cd is done. Marks all commands so the next time they
7664 * are executed they will be rehashed.
7665 */
7666static void
7667hashcd(void)
7668{
7669 struct tblentry **pp;
7670 struct tblentry *cmdp;
7671
7672 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7673 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007674 if (cmdp->cmdtype == CMDNORMAL
7675 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02007676 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007677 && builtinloc > 0)
7678 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007679 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007680 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007681 }
7682 }
7683}
7684
7685/*
7686 * Fix command hash table when PATH changed.
7687 * Called before PATH is changed. The argument is the new value of PATH;
7688 * pathval() still returns the old value at this point.
7689 * Called with interrupts off.
7690 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007691static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007692changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007693{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007694 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007695 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007696 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007697 int idx_bltin;
7698
7699 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007700 firstchange = 9999; /* assume no change */
7701 idx = 0;
7702 idx_bltin = -1;
7703 for (;;) {
7704 if (*old != *new) {
7705 firstchange = idx;
7706 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007707 || (*old == ':' && *new == '\0')
7708 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007709 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007710 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007711 old = new; /* ignore subsequent differences */
7712 }
7713 if (*new == '\0')
7714 break;
7715 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7716 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007717 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007718 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007719 new++;
7720 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007721 }
7722 if (builtinloc < 0 && idx_bltin >= 0)
7723 builtinloc = idx_bltin; /* zap builtins */
7724 if (builtinloc >= 0 && idx_bltin < 0)
7725 firstchange = 0;
7726 clearcmdentry(firstchange);
7727 builtinloc = idx_bltin;
7728}
7729
7730#define TEOF 0
7731#define TNL 1
7732#define TREDIR 2
7733#define TWORD 3
7734#define TSEMI 4
7735#define TBACKGND 5
7736#define TAND 6
7737#define TOR 7
7738#define TPIPE 8
7739#define TLP 9
7740#define TRP 10
7741#define TENDCASE 11
7742#define TENDBQUOTE 12
7743#define TNOT 13
7744#define TCASE 14
7745#define TDO 15
7746#define TDONE 16
7747#define TELIF 17
7748#define TELSE 18
7749#define TESAC 19
7750#define TFI 20
7751#define TFOR 21
7752#define TIF 22
7753#define TIN 23
7754#define TTHEN 24
7755#define TUNTIL 25
7756#define TWHILE 26
7757#define TBEGIN 27
7758#define TEND 28
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007759typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007760
7761/* first char is indicating which tokens mark the end of a list */
7762static const char *const tokname_array[] = {
7763 "\1end of file",
7764 "\0newline",
7765 "\0redirection",
7766 "\0word",
7767 "\0;",
7768 "\0&",
7769 "\0&&",
7770 "\0||",
7771 "\0|",
7772 "\0(",
7773 "\1)",
7774 "\1;;",
7775 "\1`",
7776#define KWDOFFSET 13
7777 /* the following are keywords */
7778 "\0!",
7779 "\0case",
7780 "\1do",
7781 "\1done",
7782 "\1elif",
7783 "\1else",
7784 "\1esac",
7785 "\1fi",
7786 "\0for",
7787 "\0if",
7788 "\0in",
7789 "\1then",
7790 "\0until",
7791 "\0while",
7792 "\0{",
7793 "\1}",
7794};
7795
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007796/* Wrapper around strcmp for qsort/bsearch/... */
7797static int
7798pstrcmp(const void *a, const void *b)
7799{
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00007800 return strcmp((char*) a, (*(char**) b) + 1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007801}
7802
7803static const char *const *
7804findkwd(const char *s)
7805{
7806 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00007807 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7808 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007809}
7810
7811/*
7812 * Locate and print what a word is...
7813 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007814static int
7815describe_command(char *command, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007816{
7817 struct cmdentry entry;
7818 struct tblentry *cmdp;
7819#if ENABLE_ASH_ALIAS
7820 const struct alias *ap;
7821#endif
7822 const char *path = pathval();
7823
7824 if (describe_command_verbose) {
7825 out1str(command);
7826 }
7827
7828 /* First look at the keywords */
7829 if (findkwd(command)) {
7830 out1str(describe_command_verbose ? " is a shell keyword" : command);
7831 goto out;
7832 }
7833
7834#if ENABLE_ASH_ALIAS
7835 /* Then look at the aliases */
7836 ap = lookupalias(command, 0);
7837 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00007838 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007839 out1str("alias ");
7840 printalias(ap);
7841 return 0;
7842 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00007843 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007844 goto out;
7845 }
7846#endif
7847 /* Then check if it is a tracked alias */
7848 cmdp = cmdlookup(command, 0);
7849 if (cmdp != NULL) {
7850 entry.cmdtype = cmdp->cmdtype;
7851 entry.u = cmdp->param;
7852 } else {
7853 /* Finally use brute force */
7854 find_command(command, &entry, DO_ABS, path);
7855 }
7856
7857 switch (entry.cmdtype) {
7858 case CMDNORMAL: {
7859 int j = entry.u.index;
7860 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007861 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007862 p = command;
7863 } else {
7864 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007865 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007866 stunalloc(p);
7867 } while (--j >= 0);
7868 }
7869 if (describe_command_verbose) {
7870 out1fmt(" is%s %s",
7871 (cmdp ? " a tracked alias for" : nullstr), p
7872 );
7873 } else {
7874 out1str(p);
7875 }
7876 break;
7877 }
7878
7879 case CMDFUNCTION:
7880 if (describe_command_verbose) {
7881 out1str(" is a shell function");
7882 } else {
7883 out1str(command);
7884 }
7885 break;
7886
7887 case CMDBUILTIN:
7888 if (describe_command_verbose) {
7889 out1fmt(" is a %sshell builtin",
7890 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7891 "special " : nullstr
7892 );
7893 } else {
7894 out1str(command);
7895 }
7896 break;
7897
7898 default:
7899 if (describe_command_verbose) {
7900 out1str(": not found\n");
7901 }
7902 return 127;
7903 }
7904 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01007905 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007906 return 0;
7907}
7908
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007909static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007910typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007911{
Denis Vlasenko46846e22007-05-20 13:08:31 +00007912 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007913 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00007914 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007915
Denis Vlasenko46846e22007-05-20 13:08:31 +00007916 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00007917 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00007918 i++;
7919 verbose = 0;
7920 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00007921 while (argv[i]) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00007922 err |= describe_command(argv[i++], verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007923 }
7924 return err;
7925}
7926
7927#if ENABLE_ASH_CMDCMD
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007928static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007929commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007930{
7931 int c;
7932 enum {
7933 VERIFY_BRIEF = 1,
7934 VERIFY_VERBOSE = 2,
7935 } verify = 0;
7936
7937 while ((c = nextopt("pvV")) != '\0')
7938 if (c == 'V')
7939 verify |= VERIFY_VERBOSE;
7940 else if (c == 'v')
7941 verify |= VERIFY_BRIEF;
7942#if DEBUG
7943 else if (c != 'p')
7944 abort();
7945#endif
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00007946 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
7947 if (verify && (*argptr != NULL)) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007948 return describe_command(*argptr, verify - VERIFY_BRIEF);
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00007949 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007950
7951 return 0;
7952}
7953#endif
7954
7955
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007956/* ============ eval.c */
Eric Andersencb57d552001-06-28 07:25:16 +00007957
Denis Vlasenko340299a2008-11-21 10:36:36 +00007958static int funcblocksize; /* size of structures in function */
7959static int funcstringsize; /* size of strings in node */
7960static void *funcblock; /* block to allocate function from */
7961static char *funcstring; /* block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007962
Eric Andersencb57d552001-06-28 07:25:16 +00007963/* flags in argument to evaltree */
Denis Vlasenko340299a2008-11-21 10:36:36 +00007964#define EV_EXIT 01 /* exit after evaluating tree */
7965#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Eric Andersenc470f442003-07-28 09:56:35 +00007966#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00007967
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02007968static const uint8_t nodesize[N_NUMBER] = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00007969 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
7970 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
7971 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
7972 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
7973 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
7974 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
7975 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
7976 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
7977 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
7978 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
7979 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
7980 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
7981 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
7982 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
7983 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
7984 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
7985 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00007986#if ENABLE_ASH_BASH_COMPAT
Denis Vlasenko340299a2008-11-21 10:36:36 +00007987 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00007988#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00007989 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
7990 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
7991 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
7992 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
7993 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
7994 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
7995 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
7996 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
7997 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007998};
7999
8000static void calcsize(union node *n);
8001
8002static void
8003sizenodelist(struct nodelist *lp)
8004{
8005 while (lp) {
8006 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8007 calcsize(lp->n);
8008 lp = lp->next;
8009 }
8010}
8011
8012static void
8013calcsize(union node *n)
8014{
8015 if (n == NULL)
8016 return;
8017 funcblocksize += nodesize[n->type];
8018 switch (n->type) {
8019 case NCMD:
8020 calcsize(n->ncmd.redirect);
8021 calcsize(n->ncmd.args);
8022 calcsize(n->ncmd.assign);
8023 break;
8024 case NPIPE:
8025 sizenodelist(n->npipe.cmdlist);
8026 break;
8027 case NREDIR:
8028 case NBACKGND:
8029 case NSUBSHELL:
8030 calcsize(n->nredir.redirect);
8031 calcsize(n->nredir.n);
8032 break;
8033 case NAND:
8034 case NOR:
8035 case NSEMI:
8036 case NWHILE:
8037 case NUNTIL:
8038 calcsize(n->nbinary.ch2);
8039 calcsize(n->nbinary.ch1);
8040 break;
8041 case NIF:
8042 calcsize(n->nif.elsepart);
8043 calcsize(n->nif.ifpart);
8044 calcsize(n->nif.test);
8045 break;
8046 case NFOR:
8047 funcstringsize += strlen(n->nfor.var) + 1;
8048 calcsize(n->nfor.body);
8049 calcsize(n->nfor.args);
8050 break;
8051 case NCASE:
8052 calcsize(n->ncase.cases);
8053 calcsize(n->ncase.expr);
8054 break;
8055 case NCLIST:
8056 calcsize(n->nclist.body);
8057 calcsize(n->nclist.pattern);
8058 calcsize(n->nclist.next);
8059 break;
8060 case NDEFUN:
8061 case NARG:
8062 sizenodelist(n->narg.backquote);
8063 funcstringsize += strlen(n->narg.text) + 1;
8064 calcsize(n->narg.next);
8065 break;
8066 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008067#if ENABLE_ASH_BASH_COMPAT
8068 case NTO2:
8069#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008070 case NCLOBBER:
8071 case NFROM:
8072 case NFROMTO:
8073 case NAPPEND:
8074 calcsize(n->nfile.fname);
8075 calcsize(n->nfile.next);
8076 break;
8077 case NTOFD:
8078 case NFROMFD:
8079 calcsize(n->ndup.vname);
8080 calcsize(n->ndup.next);
8081 break;
8082 case NHERE:
8083 case NXHERE:
8084 calcsize(n->nhere.doc);
8085 calcsize(n->nhere.next);
8086 break;
8087 case NNOT:
8088 calcsize(n->nnot.com);
8089 break;
8090 };
8091}
8092
8093static char *
8094nodeckstrdup(char *s)
8095{
8096 char *rtn = funcstring;
8097
8098 strcpy(funcstring, s);
8099 funcstring += strlen(s) + 1;
8100 return rtn;
8101}
8102
8103static union node *copynode(union node *);
8104
8105static struct nodelist *
8106copynodelist(struct nodelist *lp)
8107{
8108 struct nodelist *start;
8109 struct nodelist **lpp;
8110
8111 lpp = &start;
8112 while (lp) {
8113 *lpp = funcblock;
8114 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8115 (*lpp)->n = copynode(lp->n);
8116 lp = lp->next;
8117 lpp = &(*lpp)->next;
8118 }
8119 *lpp = NULL;
8120 return start;
8121}
8122
8123static union node *
8124copynode(union node *n)
8125{
8126 union node *new;
8127
8128 if (n == NULL)
8129 return NULL;
8130 new = funcblock;
8131 funcblock = (char *) funcblock + nodesize[n->type];
8132
8133 switch (n->type) {
8134 case NCMD:
8135 new->ncmd.redirect = copynode(n->ncmd.redirect);
8136 new->ncmd.args = copynode(n->ncmd.args);
8137 new->ncmd.assign = copynode(n->ncmd.assign);
8138 break;
8139 case NPIPE:
8140 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008141 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008142 break;
8143 case NREDIR:
8144 case NBACKGND:
8145 case NSUBSHELL:
8146 new->nredir.redirect = copynode(n->nredir.redirect);
8147 new->nredir.n = copynode(n->nredir.n);
8148 break;
8149 case NAND:
8150 case NOR:
8151 case NSEMI:
8152 case NWHILE:
8153 case NUNTIL:
8154 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8155 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8156 break;
8157 case NIF:
8158 new->nif.elsepart = copynode(n->nif.elsepart);
8159 new->nif.ifpart = copynode(n->nif.ifpart);
8160 new->nif.test = copynode(n->nif.test);
8161 break;
8162 case NFOR:
8163 new->nfor.var = nodeckstrdup(n->nfor.var);
8164 new->nfor.body = copynode(n->nfor.body);
8165 new->nfor.args = copynode(n->nfor.args);
8166 break;
8167 case NCASE:
8168 new->ncase.cases = copynode(n->ncase.cases);
8169 new->ncase.expr = copynode(n->ncase.expr);
8170 break;
8171 case NCLIST:
8172 new->nclist.body = copynode(n->nclist.body);
8173 new->nclist.pattern = copynode(n->nclist.pattern);
8174 new->nclist.next = copynode(n->nclist.next);
8175 break;
8176 case NDEFUN:
8177 case NARG:
8178 new->narg.backquote = copynodelist(n->narg.backquote);
8179 new->narg.text = nodeckstrdup(n->narg.text);
8180 new->narg.next = copynode(n->narg.next);
8181 break;
8182 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008183#if ENABLE_ASH_BASH_COMPAT
8184 case NTO2:
8185#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008186 case NCLOBBER:
8187 case NFROM:
8188 case NFROMTO:
8189 case NAPPEND:
8190 new->nfile.fname = copynode(n->nfile.fname);
8191 new->nfile.fd = n->nfile.fd;
8192 new->nfile.next = copynode(n->nfile.next);
8193 break;
8194 case NTOFD:
8195 case NFROMFD:
8196 new->ndup.vname = copynode(n->ndup.vname);
8197 new->ndup.dupfd = n->ndup.dupfd;
8198 new->ndup.fd = n->ndup.fd;
8199 new->ndup.next = copynode(n->ndup.next);
8200 break;
8201 case NHERE:
8202 case NXHERE:
8203 new->nhere.doc = copynode(n->nhere.doc);
8204 new->nhere.fd = n->nhere.fd;
8205 new->nhere.next = copynode(n->nhere.next);
8206 break;
8207 case NNOT:
8208 new->nnot.com = copynode(n->nnot.com);
8209 break;
8210 };
8211 new->type = n->type;
8212 return new;
8213}
8214
8215/*
8216 * Make a copy of a parse tree.
8217 */
8218static struct funcnode *
8219copyfunc(union node *n)
8220{
8221 struct funcnode *f;
8222 size_t blocksize;
8223
8224 funcblocksize = offsetof(struct funcnode, n);
8225 funcstringsize = 0;
8226 calcsize(n);
8227 blocksize = funcblocksize;
8228 f = ckmalloc(blocksize + funcstringsize);
8229 funcblock = (char *) f + offsetof(struct funcnode, n);
8230 funcstring = (char *) f + blocksize;
8231 copynode(n);
8232 f->count = 0;
8233 return f;
8234}
8235
8236/*
8237 * Define a shell function.
8238 */
8239static void
8240defun(char *name, union node *func)
8241{
8242 struct cmdentry entry;
8243
8244 INT_OFF;
8245 entry.cmdtype = CMDFUNCTION;
8246 entry.u.func = copyfunc(func);
8247 addcmdentry(name, &entry);
8248 INT_ON;
8249}
8250
Denis Vlasenko4b875702009-03-19 13:30:04 +00008251/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008252#define SKIPBREAK (1 << 0)
8253#define SKIPCONT (1 << 1)
8254#define SKIPFUNC (1 << 2)
8255#define SKIPFILE (1 << 3)
8256#define SKIPEVAL (1 << 4)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008257static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008258static int skipcount; /* number of levels to skip */
8259static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008260static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008261
Denis Vlasenko4b875702009-03-19 13:30:04 +00008262/* Forward decl way out to parsing code - dotrap needs it */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008263static int evalstring(char *s, int mask);
8264
Denis Vlasenko4b875702009-03-19 13:30:04 +00008265/* Called to execute a trap.
8266 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008267 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008268 *
8269 * Perhaps we should avoid entering new trap handlers
8270 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008271 */
8272static int
8273dotrap(void)
8274{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008275 uint8_t *g;
8276 int sig;
8277 uint8_t savestatus;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008278
8279 savestatus = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008280 pending_sig = 0;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008281 xbarrier();
8282
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008283 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008284 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
8285 int want_exexit;
8286 char *t;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008287
Denis Vlasenko4b875702009-03-19 13:30:04 +00008288 if (*g == 0)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008289 continue;
Denis Vlasenko4b875702009-03-19 13:30:04 +00008290 t = trap[sig];
8291 /* non-trapped SIGINT is handled separately by raise_interrupt,
8292 * don't upset it by resetting gotsig[SIGINT-1] */
8293 if (sig == SIGINT && !t)
8294 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008295
8296 TRACE(("sig %d is active, will run handler '%s'\n", sig, t));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008297 *g = 0;
8298 if (!t)
8299 continue;
8300 want_exexit = evalstring(t, SKIPEVAL);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008301 exitstatus = savestatus;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008302 if (want_exexit) {
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008303 TRACE(("dotrap returns %d\n", want_exexit));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008304 return want_exexit;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008305 }
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008306 }
8307
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008308 TRACE(("dotrap returns 0\n"));
Denis Vlasenko991a1da2008-02-10 19:02:53 +00008309 return 0;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008310}
8311
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008312/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008313static void evalloop(union node *, int);
8314static void evalfor(union node *, int);
8315static void evalcase(union node *, int);
8316static void evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008317static void expredir(union node *);
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008318static void evalpipe(union node *, int);
8319static void evalcommand(union node *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008320static int evalbltin(const struct builtincmd *, int, char **);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008321static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008322
Eric Andersen62483552001-07-10 06:09:16 +00008323/*
Eric Andersenc470f442003-07-28 09:56:35 +00008324 * Evaluate a parse tree. The value is left in the global variable
8325 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008326 */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008327static void
Eric Andersenc470f442003-07-28 09:56:35 +00008328evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008329{
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008330 struct jmploc *volatile savehandler = exception_handler;
8331 struct jmploc jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00008332 int checkexit = 0;
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008333 void (*evalfn)(union node *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008334 int status;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008335 int int_level;
8336
8337 SAVE_INT(int_level);
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008338
Eric Andersenc470f442003-07-28 09:56:35 +00008339 if (n == NULL) {
8340 TRACE(("evaltree(NULL) called\n"));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008341 goto out1;
Eric Andersen62483552001-07-10 06:09:16 +00008342 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008343 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008344
8345 exception_handler = &jmploc;
8346 {
8347 int err = setjmp(jmploc.loc);
8348 if (err) {
8349 /* if it was a signal, check for trap handlers */
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008350 if (exception_type == EXSIG) {
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008351 TRACE(("exception %d (EXSIG) in evaltree, err=%d\n",
8352 exception_type, err));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008353 goto out;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008354 }
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008355 /* continue on the way out */
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008356 TRACE(("exception %d in evaltree, propagating err=%d\n",
8357 exception_type, err));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008358 exception_handler = savehandler;
8359 longjmp(exception_handler->loc, err);
8360 }
8361 }
8362
Eric Andersenc470f442003-07-28 09:56:35 +00008363 switch (n->type) {
8364 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008365#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008366 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008367 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008368 break;
8369#endif
8370 case NNOT:
8371 evaltree(n->nnot.com, EV_TESTED);
8372 status = !exitstatus;
8373 goto setstatus;
8374 case NREDIR:
8375 expredir(n->nredir.redirect);
8376 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8377 if (!status) {
8378 evaltree(n->nredir.n, flags & EV_TESTED);
8379 status = exitstatus;
8380 }
Denis Vlasenko34c73c42008-08-16 11:48:02 +00008381 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
Eric Andersenc470f442003-07-28 09:56:35 +00008382 goto setstatus;
8383 case NCMD:
8384 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008385 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008386 if (eflag && !(flags & EV_TESTED))
8387 checkexit = ~0;
8388 goto calleval;
8389 case NFOR:
8390 evalfn = evalfor;
8391 goto calleval;
8392 case NWHILE:
8393 case NUNTIL:
8394 evalfn = evalloop;
8395 goto calleval;
8396 case NSUBSHELL:
8397 case NBACKGND:
8398 evalfn = evalsubshell;
8399 goto calleval;
8400 case NPIPE:
8401 evalfn = evalpipe;
8402 goto checkexit;
8403 case NCASE:
8404 evalfn = evalcase;
8405 goto calleval;
8406 case NAND:
8407 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008408 case NSEMI: {
8409
Eric Andersenc470f442003-07-28 09:56:35 +00008410#if NAND + 1 != NOR
8411#error NAND + 1 != NOR
8412#endif
8413#if NOR + 1 != NSEMI
8414#error NOR + 1 != NSEMI
8415#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008416 unsigned is_or = n->type - NAND;
Eric Andersenc470f442003-07-28 09:56:35 +00008417 evaltree(
8418 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008419 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008420 );
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008421 if (!exitstatus == is_or)
Eric Andersenc470f442003-07-28 09:56:35 +00008422 break;
8423 if (!evalskip) {
8424 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008425 evaln:
Eric Andersenc470f442003-07-28 09:56:35 +00008426 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008427 calleval:
Eric Andersenc470f442003-07-28 09:56:35 +00008428 evalfn(n, flags);
8429 break;
8430 }
8431 break;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008432 }
Eric Andersenc470f442003-07-28 09:56:35 +00008433 case NIF:
8434 evaltree(n->nif.test, EV_TESTED);
8435 if (evalskip)
8436 break;
8437 if (exitstatus == 0) {
8438 n = n->nif.ifpart;
8439 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008440 }
8441 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008442 n = n->nif.elsepart;
8443 goto evaln;
8444 }
8445 goto success;
8446 case NDEFUN:
8447 defun(n->narg.text, n->narg.next);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008448 success:
Eric Andersenc470f442003-07-28 09:56:35 +00008449 status = 0;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008450 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00008451 exitstatus = status;
8452 break;
8453 }
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008454
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008455 out:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008456 exception_handler = savehandler;
Denys Vlasenkob563f622010-09-25 17:15:13 +02008457
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008458 out1:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008459 /* Order of checks below is important:
8460 * signal handlers trigger before exit caused by "set -e".
8461 */
8462 if (pending_sig && dotrap())
8463 goto exexit;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008464 if (checkexit & exitstatus)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008465 evalskip |= SKIPEVAL;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008466
8467 if (flags & EV_EXIT) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008468 exexit:
Denis Vlasenkob012b102007-02-19 22:43:01 +00008469 raise_exception(EXEXIT);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008470 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008471
8472 RESTORE_INT(int_level);
8473 TRACE(("leaving evaltree (no interrupts)\n"));
Eric Andersen62483552001-07-10 06:09:16 +00008474}
8475
Eric Andersenc470f442003-07-28 09:56:35 +00008476#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8477static
8478#endif
8479void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
8480
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008481static void
Eric Andersenc470f442003-07-28 09:56:35 +00008482evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008483{
8484 int status;
8485
8486 loopnest++;
8487 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008488 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00008489 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00008490 int i;
8491
Eric Andersencb57d552001-06-28 07:25:16 +00008492 evaltree(n->nbinary.ch1, EV_TESTED);
8493 if (evalskip) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008494 skipping:
8495 if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00008496 evalskip = 0;
8497 continue;
8498 }
8499 if (evalskip == SKIPBREAK && --skipcount <= 0)
8500 evalskip = 0;
8501 break;
8502 }
Eric Andersenc470f442003-07-28 09:56:35 +00008503 i = exitstatus;
8504 if (n->type != NWHILE)
8505 i = !i;
8506 if (i != 0)
8507 break;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008508 evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008509 status = exitstatus;
8510 if (evalskip)
8511 goto skipping;
8512 }
8513 loopnest--;
8514 exitstatus = status;
8515}
8516
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008517static void
Eric Andersenc470f442003-07-28 09:56:35 +00008518evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008519{
8520 struct arglist arglist;
8521 union node *argp;
8522 struct strlist *sp;
8523 struct stackmark smark;
8524
8525 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008526 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008527 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008528 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02008529 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00008530 /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00008531 if (evalskip)
8532 goto out;
8533 }
8534 *arglist.lastp = NULL;
8535
8536 exitstatus = 0;
8537 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008538 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008539 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008540 setvar0(n->nfor.var, sp->text);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008541 evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008542 if (evalskip) {
8543 if (evalskip == SKIPCONT && --skipcount <= 0) {
8544 evalskip = 0;
8545 continue;
8546 }
8547 if (evalskip == SKIPBREAK && --skipcount <= 0)
8548 evalskip = 0;
8549 break;
8550 }
8551 }
8552 loopnest--;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008553 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008554 popstackmark(&smark);
8555}
8556
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008557static void
Eric Andersenc470f442003-07-28 09:56:35 +00008558evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008559{
8560 union node *cp;
8561 union node *patp;
8562 struct arglist arglist;
8563 struct stackmark smark;
8564
8565 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008566 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008567 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00008568 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00008569 exitstatus = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008570 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8571 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008572 if (casematch(patp, arglist.list->text)) {
8573 if (evalskip == 0) {
8574 evaltree(cp->nclist.body, flags);
8575 }
8576 goto out;
8577 }
8578 }
8579 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008580 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008581 popstackmark(&smark);
8582}
8583
Eric Andersenc470f442003-07-28 09:56:35 +00008584/*
8585 * Kick off a subshell to evaluate a tree.
8586 */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008587static void
Eric Andersenc470f442003-07-28 09:56:35 +00008588evalsubshell(union node *n, int flags)
8589{
8590 struct job *jp;
8591 int backgnd = (n->type == NBACKGND);
8592 int status;
8593
8594 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02008595 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00008596 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008597 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008598 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008599 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02008600 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008601 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008602 flags |= EV_EXIT;
8603 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02008604 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00008605 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00008606 redirect(n->nredir.redirect, 0);
8607 evaltreenr(n->nredir.n, flags);
8608 /* never returns */
8609 }
8610 status = 0;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008611 if (!backgnd)
Eric Andersenc470f442003-07-28 09:56:35 +00008612 status = waitforjob(jp);
8613 exitstatus = status;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008614 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008615}
8616
Eric Andersenc470f442003-07-28 09:56:35 +00008617/*
8618 * Compute the names of the files in a redirection list.
8619 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00008620static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008621static void
8622expredir(union node *n)
8623{
8624 union node *redir;
8625
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008626 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00008627 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008628
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008629 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008630 fn.lastp = &fn.list;
8631 switch (redir->type) {
8632 case NFROMTO:
8633 case NFROM:
8634 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008635#if ENABLE_ASH_BASH_COMPAT
8636 case NTO2:
8637#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008638 case NCLOBBER:
8639 case NAPPEND:
8640 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02008641 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denis Vlasenko559691a2008-10-05 18:39:31 +00008642#if ENABLE_ASH_BASH_COMPAT
8643 store_expfname:
8644#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008645#if 0
8646// By the design of stack allocator, the loop of this kind:
8647// while true; do while true; do break; done </dev/null; done
8648// will look like a memory leak: ash plans to free expfname's
8649// of "/dev/null" as soon as it finishes running the loop
8650// (in this case, never).
8651// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01008652 if (redir->nfile.expfname)
8653 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008654// It results in corrupted state of stacked allocations.
8655#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008656 redir->nfile.expfname = fn.list->text;
8657 break;
8658 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008659 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00008660 if (redir->ndup.vname) {
8661 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008662 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008663 ash_msg_and_raise_error("redir error");
Denis Vlasenko559691a2008-10-05 18:39:31 +00008664#if ENABLE_ASH_BASH_COMPAT
8665//FIXME: we used expandarg with different args!
8666 if (!isdigit_str9(fn.list->text)) {
8667 /* >&file, not >&fd */
8668 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8669 ash_msg_and_raise_error("redir error");
8670 redir->type = NTO2;
8671 goto store_expfname;
8672 }
8673#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008674 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008675 }
8676 break;
8677 }
8678 }
8679}
8680
Eric Andersencb57d552001-06-28 07:25:16 +00008681/*
Eric Andersencb57d552001-06-28 07:25:16 +00008682 * Evaluate a pipeline. All the processes in the pipeline are children
8683 * of the process creating the pipeline. (This differs from some versions
8684 * of the shell, which make the last process in a pipeline the parent
8685 * of all the rest.)
8686 */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008687static void
Eric Andersenc470f442003-07-28 09:56:35 +00008688evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008689{
8690 struct job *jp;
8691 struct nodelist *lp;
8692 int pipelen;
8693 int prevfd;
8694 int pip[2];
8695
Eric Andersenc470f442003-07-28 09:56:35 +00008696 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00008697 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008698 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00008699 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008700 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008701 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008702 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00008703 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008704 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008705 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00008706 pip[1] = -1;
8707 if (lp->next) {
8708 if (pipe(pip) < 0) {
8709 close(prevfd);
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00008710 ash_msg_and_raise_error("pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00008711 }
8712 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008713 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00008714 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00008715 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008716 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00008717 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008718 if (prevfd > 0) {
8719 dup2(prevfd, 0);
8720 close(prevfd);
8721 }
8722 if (pip[1] > 1) {
8723 dup2(pip[1], 1);
8724 close(pip[1]);
8725 }
Eric Andersenc470f442003-07-28 09:56:35 +00008726 evaltreenr(lp->n, flags);
8727 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00008728 }
8729 if (prevfd >= 0)
8730 close(prevfd);
8731 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00008732 /* Don't want to trigger debugging */
8733 if (pip[1] != -1)
8734 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00008735 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008736 if (n->npipe.pipe_backgnd == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00008737 exitstatus = waitforjob(jp);
8738 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
Eric Andersencb57d552001-06-28 07:25:16 +00008739 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00008740 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00008741}
8742
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008743/*
8744 * Controls whether the shell is interactive or not.
8745 */
8746static void
8747setinteractive(int on)
8748{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008749 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008750
8751 if (++on == is_interactive)
8752 return;
8753 is_interactive = on;
8754 setsignal(SIGINT);
8755 setsignal(SIGQUIT);
8756 setsignal(SIGTERM);
8757#if !ENABLE_FEATURE_SH_EXTRA_QUIET
8758 if (is_interactive > 1) {
8759 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008760 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008761
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008762 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008763 /* note: ash and hush share this string */
8764 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02008765 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
8766 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008767 bb_banner,
8768 "built-in shell (ash)"
8769 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008770 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008771 }
8772 }
8773#endif
8774}
8775
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008776static void
8777optschanged(void)
8778{
8779#if DEBUG
8780 opentrace();
8781#endif
8782 setinteractive(iflag);
8783 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008784#if ENABLE_FEATURE_EDITING_VI
8785 if (viflag)
8786 line_input_state->flags |= VI_MODE;
8787 else
8788 line_input_state->flags &= ~VI_MODE;
8789#else
8790 viflag = 0; /* forcibly keep the option off */
8791#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008792}
8793
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008794static struct localvar *localvars;
8795
8796/*
8797 * Called after a function returns.
8798 * Interrupts must be off.
8799 */
8800static void
8801poplocalvars(void)
8802{
8803 struct localvar *lvp;
8804 struct var *vp;
8805
8806 while ((lvp = localvars) != NULL) {
8807 localvars = lvp->next;
8808 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02008809 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008810 if (vp == NULL) { /* $- saved */
8811 memcpy(optlist, lvp->text, sizeof(optlist));
8812 free((char*)lvp->text);
8813 optschanged();
8814 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008815 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008816 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008817 if (vp->var_func)
8818 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008819 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008820 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008821 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008822 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008823 }
8824 free(lvp);
8825 }
8826}
8827
8828static int
8829evalfun(struct funcnode *func, int argc, char **argv, int flags)
8830{
8831 volatile struct shparam saveparam;
8832 struct localvar *volatile savelocalvars;
8833 struct jmploc *volatile savehandler;
8834 struct jmploc jmploc;
8835 int e;
8836
8837 saveparam = shellparam;
8838 savelocalvars = localvars;
8839 e = setjmp(jmploc.loc);
8840 if (e) {
8841 goto funcdone;
8842 }
8843 INT_OFF;
8844 savehandler = exception_handler;
8845 exception_handler = &jmploc;
8846 localvars = NULL;
Denis Vlasenko01631112007-12-16 17:20:38 +00008847 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008848 func->count++;
8849 funcnest++;
8850 INT_ON;
8851 shellparam.nparam = argc - 1;
8852 shellparam.p = argv + 1;
8853#if ENABLE_ASH_GETOPTS
8854 shellparam.optind = 1;
8855 shellparam.optoff = -1;
8856#endif
8857 evaltree(&func->n, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00008858 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008859 INT_OFF;
8860 funcnest--;
8861 freefunc(func);
8862 poplocalvars();
8863 localvars = savelocalvars;
8864 freeparam(&shellparam);
8865 shellparam = saveparam;
8866 exception_handler = savehandler;
8867 INT_ON;
8868 evalskip &= ~SKIPFUNC;
8869 return e;
8870}
8871
Denis Vlasenko131ae172007-02-18 13:00:19 +00008872#if ENABLE_ASH_CMDCMD
Denis Vlasenkoaa744452007-02-23 01:04:22 +00008873static char **
8874parse_command_args(char **argv, const char **path)
Eric Andersenc470f442003-07-28 09:56:35 +00008875{
8876 char *cp, c;
8877
8878 for (;;) {
8879 cp = *++argv;
8880 if (!cp)
8881 return 0;
8882 if (*cp++ != '-')
8883 break;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008884 c = *cp++;
8885 if (!c)
Eric Andersenc470f442003-07-28 09:56:35 +00008886 break;
8887 if (c == '-' && !*cp) {
8888 argv++;
8889 break;
8890 }
8891 do {
8892 switch (c) {
8893 case 'p':
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00008894 *path = bb_default_path;
Eric Andersenc470f442003-07-28 09:56:35 +00008895 break;
8896 default:
8897 /* run 'typecmd' for other options */
8898 return 0;
8899 }
Denis Vlasenko9650f362007-02-23 01:04:37 +00008900 c = *cp++;
8901 } while (c);
Eric Andersenc470f442003-07-28 09:56:35 +00008902 }
8903 return argv;
8904}
8905#endif
8906
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008907/*
8908 * Make a variable a local variable. When a variable is made local, it's
8909 * value and flags are saved in a localvar structure. The saved values
8910 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02008911 * "-" as a special case: it makes changes to "set +-options" local
8912 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008913 */
8914static void
8915mklocal(char *name)
8916{
8917 struct localvar *lvp;
8918 struct var **vpp;
8919 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008920 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008921
8922 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008923 /* Cater for duplicate "local". Examples:
8924 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
8925 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
8926 */
8927 lvp = localvars;
8928 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02008929 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008930 if (eq)
8931 setvareq(name, 0);
8932 /* else:
8933 * it's a duplicate "local VAR" declaration, do nothing
8934 */
8935 return;
8936 }
8937 lvp = lvp->next;
8938 }
8939
8940 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008941 if (LONE_DASH(name)) {
8942 char *p;
8943 p = ckmalloc(sizeof(optlist));
8944 lvp->text = memcpy(p, optlist, sizeof(optlist));
8945 vp = NULL;
8946 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008947 vpp = hashvar(name);
8948 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008949 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008950 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008951 if (eq)
8952 setvareq(name, VSTRFIXED);
8953 else
8954 setvar(name, NULL, VSTRFIXED);
8955 vp = *vpp; /* the new variable */
8956 lvp->flags = VUNSET;
8957 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008958 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008959 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008960 /* make sure neither "struct var" nor string gets freed
8961 * during (un)setting:
8962 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008963 vp->flags |= VSTRFIXED|VTEXTFIXED;
8964 if (eq)
8965 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01008966 else
8967 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008968 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008969 }
8970 }
8971 lvp->vp = vp;
8972 lvp->next = localvars;
8973 localvars = lvp;
8974 INT_ON;
8975}
8976
8977/*
8978 * The "local" command.
8979 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008980static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008981localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008982{
8983 char *name;
8984
8985 argv = argptr;
8986 while ((name = *argv++) != NULL) {
8987 mklocal(name);
8988 }
8989 return 0;
8990}
8991
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008992static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008993falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00008994{
8995 return 1;
8996}
8997
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008998static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008999truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009000{
9001 return 0;
9002}
9003
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009004static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009005execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009006{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009007 if (argv[1]) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009008 iflag = 0; /* exit on error */
9009 mflag = 0;
9010 optschanged();
9011 shellexec(argv + 1, pathval(), 0);
9012 }
9013 return 0;
9014}
9015
9016/*
9017 * The return command.
9018 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009019static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009020returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009021{
9022 /*
9023 * If called outside a function, do what ksh does;
9024 * skip the rest of the file.
9025 */
9026 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
9027 return argv[1] ? number(argv[1]) : exitstatus;
9028}
9029
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009030/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009031static int breakcmd(int, char **) FAST_FUNC;
9032static int dotcmd(int, char **) FAST_FUNC;
9033static int evalcmd(int, char **) FAST_FUNC;
9034static int exitcmd(int, char **) FAST_FUNC;
9035static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009036#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009037static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009038#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009039#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009040static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009041#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009042#if MAX_HISTORY
9043static int historycmd(int, char **) FAST_FUNC;
9044#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009045#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009046static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009047#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009048static int readcmd(int, char **) FAST_FUNC;
9049static int setcmd(int, char **) FAST_FUNC;
9050static int shiftcmd(int, char **) FAST_FUNC;
9051static int timescmd(int, char **) FAST_FUNC;
9052static int trapcmd(int, char **) FAST_FUNC;
9053static int umaskcmd(int, char **) FAST_FUNC;
9054static int unsetcmd(int, char **) FAST_FUNC;
9055static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009056
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009057#define BUILTIN_NOSPEC "0"
9058#define BUILTIN_SPECIAL "1"
9059#define BUILTIN_REGULAR "2"
9060#define BUILTIN_SPEC_REG "3"
9061#define BUILTIN_ASSIGN "4"
9062#define BUILTIN_SPEC_ASSG "5"
9063#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009064#define BUILTIN_SPEC_REG_ASSG "7"
9065
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009066/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009067#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009068static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009069#endif
9070#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009071static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009072#endif
9073#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009074static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009075#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009076
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009077/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009078static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009079 { BUILTIN_SPEC_REG "." , dotcmd },
9080 { BUILTIN_SPEC_REG ":" , truecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009081#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009082 { BUILTIN_REGULAR "[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009083#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009084 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009085#endif
Denis Vlasenko80591b02008-03-25 07:49:43 +00009086#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009087#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009088 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009089#endif
9090#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009091 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009092#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009093 { BUILTIN_SPEC_REG "break" , breakcmd },
9094 { BUILTIN_REGULAR "cd" , cdcmd },
9095 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009096#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009097 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009098#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009099 { BUILTIN_SPEC_REG "continue", breakcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009100#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009101 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009102#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009103 { BUILTIN_SPEC_REG "eval" , evalcmd },
9104 { BUILTIN_SPEC_REG "exec" , execcmd },
9105 { BUILTIN_SPEC_REG "exit" , exitcmd },
9106 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9107 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009108#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009109 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009110#endif
9111#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009112 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009113#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009114 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009115#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009116 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009117#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009118#if MAX_HISTORY
9119 { BUILTIN_NOSPEC "history" , historycmd },
9120#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009121#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009122 { BUILTIN_REGULAR "jobs" , jobscmd },
9123 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009124#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009125#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009126 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009127#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009128 { BUILTIN_ASSIGN "local" , localcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009129#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009130 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009131#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009132 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9133 { BUILTIN_REGULAR "read" , readcmd },
9134 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9135 { BUILTIN_SPEC_REG "return" , returncmd },
9136 { BUILTIN_SPEC_REG "set" , setcmd },
9137 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009138#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009139 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009140#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009141#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009142 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009143#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009144 { BUILTIN_SPEC_REG "times" , timescmd },
9145 { BUILTIN_SPEC_REG "trap" , trapcmd },
9146 { BUILTIN_REGULAR "true" , truecmd },
9147 { BUILTIN_NOSPEC "type" , typecmd },
9148 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9149 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009150#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009151 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009152#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009153 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9154 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009155};
9156
Denis Vlasenko80591b02008-03-25 07:49:43 +00009157/* Should match the above table! */
9158#define COMMANDCMD (builtintab + \
9159 2 + \
9160 1 * ENABLE_ASH_BUILTIN_TEST + \
9161 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9162 1 * ENABLE_ASH_ALIAS + \
9163 1 * ENABLE_ASH_JOB_CONTROL + \
9164 3)
9165#define EXECCMD (builtintab + \
9166 2 + \
9167 1 * ENABLE_ASH_BUILTIN_TEST + \
9168 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9169 1 * ENABLE_ASH_ALIAS + \
9170 1 * ENABLE_ASH_JOB_CONTROL + \
9171 3 + \
9172 1 * ENABLE_ASH_CMDCMD + \
9173 1 + \
9174 ENABLE_ASH_BUILTIN_ECHO + \
9175 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009176
9177/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009178 * Search the table of builtin commands.
9179 */
9180static struct builtincmd *
9181find_builtin(const char *name)
9182{
9183 struct builtincmd *bp;
9184
9185 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009186 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009187 pstrcmp
9188 );
9189 return bp;
9190}
9191
9192/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009193 * Execute a simple command.
9194 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009195static int
9196isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009197{
9198 const char *q = endofname(p);
9199 if (p == q)
9200 return 0;
9201 return *q == '=';
9202}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009203static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009204bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009205{
9206 /* Preserve exitstatus of a previous possible redirection
9207 * as POSIX mandates */
9208 return back_exitstatus;
9209}
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02009210static void
Eric Andersenc470f442003-07-28 09:56:35 +00009211evalcommand(union node *cmd, int flags)
9212{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009213 static const struct builtincmd null_bltin = {
9214 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009215 };
Eric Andersenc470f442003-07-28 09:56:35 +00009216 struct stackmark smark;
9217 union node *argp;
9218 struct arglist arglist;
9219 struct arglist varlist;
9220 char **argv;
9221 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009222 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009223 struct cmdentry cmdentry;
9224 struct job *jp;
9225 char *lastarg;
9226 const char *path;
9227 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009228 int status;
9229 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00009230 struct builtincmd *bcmd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009231 smallint cmd_is_exec;
9232 smallint pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009233
9234 /* First expand the arguments. */
9235 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9236 setstackmark(&smark);
9237 back_exitstatus = 0;
9238
9239 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009240 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009241 varlist.lastp = &varlist.list;
9242 *varlist.lastp = NULL;
9243 arglist.lastp = &arglist.list;
9244 *arglist.lastp = NULL;
9245
9246 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009247 if (cmd->ncmd.args) {
Paul Foxc3850c82005-07-20 18:23:39 +00009248 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9249 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9250 }
9251
Eric Andersenc470f442003-07-28 09:56:35 +00009252 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9253 struct strlist **spp;
9254
9255 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00009256 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00009257 expandarg(argp, &arglist, EXP_VARTILDE);
9258 else
9259 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9260
Eric Andersenc470f442003-07-28 09:56:35 +00009261 for (sp = *spp; sp; sp = sp->next)
9262 argc++;
9263 }
9264
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009265 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009266 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009267 TRACE(("evalcommand arg: %s\n", sp->text));
9268 *nargv++ = sp->text;
9269 }
9270 *nargv = NULL;
9271
9272 lastarg = NULL;
9273 if (iflag && funcnest == 0 && argc > 0)
9274 lastarg = nargv[-1];
9275
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009276 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009277 expredir(cmd->ncmd.redirect);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009278 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009279
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009280 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009281 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9282 struct strlist **spp;
9283 char *p;
9284
9285 spp = varlist.lastp;
9286 expandarg(argp, &varlist, EXP_VARTILDE);
9287
9288 /*
9289 * Modify the command lookup path, if a PATH= assignment
9290 * is present
9291 */
9292 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009293 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009294 path = p;
9295 }
9296
9297 /* Print the command if xflag is set. */
9298 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009299 int n;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009300 const char *p = " %s" + 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009301
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009302 fdprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009303 sp = varlist.list;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009304 for (n = 0; n < 2; n++) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009305 while (sp) {
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009306 fdprintf(preverrout_fd, p, sp->text);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009307 sp = sp->next;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009308 p = " %s";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009309 }
9310 sp = arglist.list;
9311 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009312 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009313 }
9314
9315 cmd_is_exec = 0;
9316 spclbltin = -1;
9317
9318 /* Now locate the command. */
9319 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009320 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02009321#if ENABLE_ASH_CMDCMD
9322 const char *oldpath = path + 5;
9323#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009324 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009325 for (;;) {
9326 find_command(argv[0], &cmdentry, cmd_flag, path);
9327 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009328 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009329 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009330 goto bail;
9331 }
9332
9333 /* implement bltin and command here */
9334 if (cmdentry.cmdtype != CMDBUILTIN)
9335 break;
9336 if (spclbltin < 0)
9337 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9338 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009339 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009340#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009341 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009342 path = oldpath;
9343 nargv = parse_command_args(argv, &path);
9344 if (!nargv)
9345 break;
9346 argc -= nargv - argv;
9347 argv = nargv;
9348 cmd_flag |= DO_NOFUNC;
9349 } else
9350#endif
9351 break;
9352 }
9353 }
9354
9355 if (status) {
9356 /* We have a redirection error. */
9357 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009358 raise_exception(EXERROR);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009359 bail:
Eric Andersenc470f442003-07-28 09:56:35 +00009360 exitstatus = status;
9361 goto out;
9362 }
9363
9364 /* Execute the command. */
9365 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009366 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009367
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009368#if ENABLE_FEATURE_SH_NOFORK
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009369/* (1) BUG: if variables are set, we need to fork, or save/restore them
9370 * around run_nofork_applet() call.
9371 * (2) Should this check also be done in forkshell()?
9372 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9373 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009374 /* find_command() encodes applet_no as (-2 - applet_no) */
9375 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009376 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009377 listsetvar(varlist.list, VEXPORT|VSTACK);
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009378 /* run <applet>_main() */
9379 exitstatus = run_nofork_applet(applet_no, argv);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009380 break;
9381 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009382#endif
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009383 /* Can we avoid forking off? For example, very last command
9384 * in a script or a subshell does not need forking,
9385 * we can just exec it.
9386 */
Denys Vlasenko238bf182010-05-18 15:49:07 +02009387 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009388 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009389 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00009390 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009391 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009392 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00009393 exitstatus = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009394 INT_ON;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009395 TRACE(("forked child exited with %d\n", exitstatus));
Eric Andersenc470f442003-07-28 09:56:35 +00009396 break;
9397 }
Denys Vlasenko238bf182010-05-18 15:49:07 +02009398 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009399 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +02009400 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +00009401 }
9402 listsetvar(varlist.list, VEXPORT|VSTACK);
9403 shellexec(argv, path, cmdentry.u.index);
9404 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009405 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +00009406 case CMDBUILTIN:
9407 cmdenviron = varlist.list;
9408 if (cmdenviron) {
9409 struct strlist *list = cmdenviron;
9410 int i = VNOSET;
9411 if (spclbltin > 0 || argc == 0) {
9412 i = 0;
9413 if (cmd_is_exec && argc > 1)
9414 i = VEXPORT;
9415 }
9416 listsetvar(list, i);
9417 }
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009418 /* Tight loop with builtins only:
9419 * "while kill -0 $child; do true; done"
9420 * will never exit even if $child died, unless we do this
9421 * to reap the zombie and make kill detect that it's gone: */
9422 dowait(DOWAIT_NONBLOCK, NULL);
9423
Eric Andersenc470f442003-07-28 09:56:35 +00009424 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
9425 int exit_status;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00009426 int i = exception_type;
Eric Andersenc470f442003-07-28 09:56:35 +00009427 if (i == EXEXIT)
9428 goto raise;
Eric Andersenc470f442003-07-28 09:56:35 +00009429 exit_status = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009430 if (i == EXINT)
Denis Vlasenko991a1da2008-02-10 19:02:53 +00009431 exit_status = 128 + SIGINT;
Eric Andersenc470f442003-07-28 09:56:35 +00009432 if (i == EXSIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009433 exit_status = 128 + pending_sig;
Eric Andersenc470f442003-07-28 09:56:35 +00009434 exitstatus = exit_status;
Eric Andersenc470f442003-07-28 09:56:35 +00009435 if (i == EXINT || spclbltin > 0) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009436 raise:
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009437 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009438 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009439 FORCE_INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009440 }
9441 break;
9442
9443 case CMDFUNCTION:
9444 listsetvar(varlist.list, 0);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009445 /* See above for the rationale */
9446 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009447 if (evalfun(cmdentry.u.func, argc, argv, flags))
9448 goto raise;
9449 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009450 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +00009451
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009452 out:
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009453 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009454 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +00009455 /* dsl: I think this is intended to be used to support
9456 * '_' in 'vi' command mode during line editing...
9457 * However I implemented that within libedit itself.
9458 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009459 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009460 }
Eric Andersenc470f442003-07-28 09:56:35 +00009461 popstackmark(&smark);
9462}
9463
9464static int
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009465evalbltin(const struct builtincmd *cmd, int argc, char **argv)
9466{
Eric Andersenc470f442003-07-28 09:56:35 +00009467 char *volatile savecmdname;
9468 struct jmploc *volatile savehandler;
9469 struct jmploc jmploc;
9470 int i;
9471
9472 savecmdname = commandname;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009473 i = setjmp(jmploc.loc);
9474 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +00009475 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009476 savehandler = exception_handler;
9477 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00009478 commandname = argv[0];
9479 argptr = argv + 1;
9480 optptr = NULL; /* initialize nextopt */
9481 exitstatus = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009482 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009483 cmddone:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009484 exitstatus |= ferror(stdout);
Rob Landleyf296f0b2006-07-06 01:09:21 +00009485 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009486 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009487 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +00009488
9489 return i;
9490}
9491
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009492static int
9493goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009494{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02009495 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009496}
9497
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009498
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009499/*
9500 * Search for a command. This is called before we fork so that the
9501 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009502 * the child. The check for "goodname" is an overly conservative
9503 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009504 */
Eric Andersenc470f442003-07-28 09:56:35 +00009505static void
9506prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009507{
9508 struct cmdentry entry;
9509
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009510 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9511 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009512}
9513
Eric Andersencb57d552001-06-28 07:25:16 +00009514
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009515/* ============ Builtin commands
9516 *
9517 * Builtin commands whose functions are closely tied to evaluation
9518 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +00009519 */
9520
9521/*
Eric Andersencb57d552001-06-28 07:25:16 +00009522 * Handle break and continue commands. Break, continue, and return are
9523 * all handled by setting the evalskip flag. The evaluation routines
9524 * above all check this flag, and if it is set they start skipping
9525 * commands rather than executing them. The variable skipcount is
9526 * the number of loops to break/continue, or the number of function
9527 * levels to return. (The latter is always 1.) It should probably
9528 * be an error to break out of more loops than exist, but it isn't
9529 * in the standard shell so we don't make it one here.
9530 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009531static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009532breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009533{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009534 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009535
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00009536 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009537 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009538 if (n > loopnest)
9539 n = loopnest;
9540 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009541 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00009542 skipcount = n;
9543 }
9544 return 0;
9545}
9546
Eric Andersenc470f442003-07-28 09:56:35 +00009547
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009548/* ============ input.c
9549 *
Eric Andersen90898442003-08-06 11:20:52 +00009550 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00009551 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009552
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009553enum {
9554 INPUT_PUSH_FILE = 1,
9555 INPUT_NOFILE_OK = 2,
9556};
Eric Andersencb57d552001-06-28 07:25:16 +00009557
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009558static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009559/* values of checkkwd variable */
9560#define CHKALIAS 0x1
9561#define CHKKWD 0x2
9562#define CHKNL 0x4
9563
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009564/*
9565 * Push a string back onto the input at this current parsefile level.
9566 * We handle aliases this way.
9567 */
9568#if !ENABLE_ASH_ALIAS
9569#define pushstring(s, ap) pushstring(s)
9570#endif
9571static void
9572pushstring(char *s, struct alias *ap)
9573{
9574 struct strpush *sp;
9575 int len;
9576
9577 len = strlen(s);
9578 INT_OFF;
9579 if (g_parsefile->strpush) {
9580 sp = ckzalloc(sizeof(*sp));
9581 sp->prev = g_parsefile->strpush;
9582 } else {
9583 sp = &(g_parsefile->basestrpush);
9584 }
9585 g_parsefile->strpush = sp;
9586 sp->prev_string = g_parsefile->next_to_pgetc;
9587 sp->prev_left_in_line = g_parsefile->left_in_line;
9588#if ENABLE_ASH_ALIAS
9589 sp->ap = ap;
9590 if (ap) {
9591 ap->flag |= ALIASINUSE;
9592 sp->string = s;
9593 }
9594#endif
9595 g_parsefile->next_to_pgetc = s;
9596 g_parsefile->left_in_line = len;
9597 INT_ON;
9598}
9599
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009600static void
9601popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009602{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009603 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +00009604
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009605 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009606#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009607 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009608 if (g_parsefile->next_to_pgetc[-1] == ' '
9609 || g_parsefile->next_to_pgetc[-1] == '\t'
9610 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009611 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009612 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009613 if (sp->string != sp->ap->val) {
9614 free(sp->string);
9615 }
9616 sp->ap->flag &= ~ALIASINUSE;
9617 if (sp->ap->flag & ALIASDEAD) {
9618 unalias(sp->ap->name);
9619 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009620 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009621#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009622 g_parsefile->next_to_pgetc = sp->prev_string;
9623 g_parsefile->left_in_line = sp->prev_left_in_line;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009624 g_parsefile->strpush = sp->prev;
9625 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009626 free(sp);
9627 INT_ON;
9628}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009629
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009630//FIXME: BASH_COMPAT with "...&" does TWO pungetc():
9631//it peeks whether it is &>, and then pushes back both chars.
9632//This function needs to save last *next_to_pgetc to buf[0]
9633//to make two pungetc() reliable. Currently,
9634// pgetc (out of buf: does preadfd), pgetc, pungetc, pungetc won't work...
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009635static int
9636preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009637{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009638 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00009639 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009640
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009641 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +00009642#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +00009643 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009644 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +01009645 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009646 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009647 int timeout = -1;
9648# if ENABLE_ASH_IDLE_TIMEOUT
9649 if (iflag) {
9650 const char *tmout_var = lookupvar("TMOUT");
9651 if (tmout_var) {
9652 timeout = atoi(tmout_var) * 1000;
9653 if (timeout <= 0)
9654 timeout = -1;
9655 }
9656 }
9657# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009658# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009659 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009660# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02009661 reinit_unicode_for_ash();
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009662 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009663 if (nr == 0) {
9664 /* Ctrl+C pressed */
9665 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009666 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009667 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009668 raise(SIGINT);
9669 return 1;
9670 }
Eric Andersenc470f442003-07-28 09:56:35 +00009671 goto retry;
9672 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009673 if (nr < 0) {
9674 if (errno == 0) {
9675 /* Ctrl+D pressed */
9676 nr = 0;
9677 }
9678# if ENABLE_ASH_IDLE_TIMEOUT
9679 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +02009680 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009681 exitshell();
9682 }
9683# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009684 }
Eric Andersencb57d552001-06-28 07:25:16 +00009685 }
9686#else
Ron Yorston61d6ae22015-04-19 10:50:25 +01009687 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00009688#endif
9689
Denys Vlasenko80c5b682011-05-08 21:21:10 +02009690#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +00009691 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00009692 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +00009693 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +00009694 if (flags >= 0 && (flags & O_NONBLOCK)) {
9695 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00009696 if (fcntl(0, F_SETFL, flags) >= 0) {
9697 out2str("sh: turning off NDELAY mode\n");
9698 goto retry;
9699 }
9700 }
9701 }
9702 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +00009703#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009704 return nr;
9705}
9706
9707/*
9708 * Refill the input buffer and return the next input character:
9709 *
9710 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009711 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9712 * or we are reading from a string so we can't refill the buffer,
9713 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +02009714 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +00009715 * 4) Process input up to the next newline, deleting nul characters.
9716 */
Denis Vlasenko727752d2008-11-28 03:41:47 +00009717//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9718#define pgetc_debug(...) ((void)0)
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009719static int
Eric Andersenc470f442003-07-28 09:56:35 +00009720preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009721{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009722 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +00009723 int more;
Eric Andersencb57d552001-06-28 07:25:16 +00009724
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009725 while (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +00009726#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009727 if (g_parsefile->left_in_line == -1
9728 && g_parsefile->strpush->ap
9729 && g_parsefile->next_to_pgetc[-1] != ' '
9730 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +00009731 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009732 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +00009733 return PEOA;
9734 }
Eric Andersen2870d962001-07-02 17:27:21 +00009735#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009736 popstring();
Denis Vlasenko727752d2008-11-28 03:41:47 +00009737 /* try "pgetc" now: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009738 pgetc_debug("preadbuffer internal pgetc at %d:%p'%s'",
9739 g_parsefile->left_in_line,
9740 g_parsefile->next_to_pgetc,
9741 g_parsefile->next_to_pgetc);
9742 if (--g_parsefile->left_in_line >= 0)
9743 return (unsigned char)(*g_parsefile->next_to_pgetc++);
Eric Andersencb57d552001-06-28 07:25:16 +00009744 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009745 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009746 * "pgetc" needs refilling.
9747 */
9748
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009749 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009750 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009751 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009752 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009753 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009754 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009755 /* even in failure keep left_in_line and next_to_pgetc
9756 * in lock step, for correct multi-layer pungetc.
9757 * left_in_line was decremented before preadbuffer(),
9758 * must inc next_to_pgetc: */
9759 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009760 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009761 }
Eric Andersencb57d552001-06-28 07:25:16 +00009762
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009763 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009764 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009765 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009766 again:
9767 more = preadfd();
9768 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009769 /* don't try reading again */
9770 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009771 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009772 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009773 return PEOF;
9774 }
9775 }
9776
Denis Vlasenko727752d2008-11-28 03:41:47 +00009777 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009778 * Set g_parsefile->left_in_line
9779 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009780 * NUL chars are deleted.
9781 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009782 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009783 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009784 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00009785
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009786 more--;
Eric Andersenc470f442003-07-28 09:56:35 +00009787
Denis Vlasenko727752d2008-11-28 03:41:47 +00009788 c = *q;
9789 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009790 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009791 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009792 q++;
9793 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009794 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009795 break;
9796 }
Eric Andersencb57d552001-06-28 07:25:16 +00009797 }
9798
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009799 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009800 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9801 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00009802 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009803 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009804 }
9805 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009806 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +00009807
Eric Andersencb57d552001-06-28 07:25:16 +00009808 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009809 char save = *q;
9810 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009811 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009812 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +00009813 }
9814
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009815 pgetc_debug("preadbuffer at %d:%p'%s'",
9816 g_parsefile->left_in_line,
9817 g_parsefile->next_to_pgetc,
9818 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +01009819 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009820}
9821
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009822#define pgetc_as_macro() \
9823 (--g_parsefile->left_in_line >= 0 \
Denys Vlasenkocd716832009-11-28 22:14:02 +01009824 ? (unsigned char)*g_parsefile->next_to_pgetc++ \
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009825 : preadbuffer() \
9826 )
Denis Vlasenko727752d2008-11-28 03:41:47 +00009827
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009828static int
9829pgetc(void)
9830{
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009831 pgetc_debug("pgetc_fast at %d:%p'%s'",
9832 g_parsefile->left_in_line,
9833 g_parsefile->next_to_pgetc,
9834 g_parsefile->next_to_pgetc);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009835 return pgetc_as_macro();
9836}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00009837
9838#if ENABLE_ASH_OPTIMIZE_FOR_SIZE
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009839# define pgetc_fast() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009840#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009841# define pgetc_fast() pgetc_as_macro()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009842#endif
9843
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009844#if ENABLE_ASH_ALIAS
9845static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009846pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009847{
9848 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009849 do {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009850 pgetc_debug("pgetc_fast at %d:%p'%s'",
9851 g_parsefile->left_in_line,
9852 g_parsefile->next_to_pgetc,
9853 g_parsefile->next_to_pgetc);
Denis Vlasenko834dee72008-10-07 09:18:30 +00009854 c = pgetc_fast();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009855 } while (c == PEOA);
9856 return c;
9857}
9858#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009859# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009860#endif
9861
9862/*
9863 * Read a line from the script.
9864 */
9865static char *
9866pfgets(char *line, int len)
9867{
9868 char *p = line;
9869 int nleft = len;
9870 int c;
9871
9872 while (--nleft > 0) {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009873 c = pgetc_without_PEOA();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009874 if (c == PEOF) {
9875 if (p == line)
9876 return NULL;
9877 break;
9878 }
9879 *p++ = c;
9880 if (c == '\n')
9881 break;
9882 }
9883 *p = '\0';
9884 return line;
9885}
9886
Eric Andersenc470f442003-07-28 09:56:35 +00009887/*
9888 * Undo the last call to pgetc. Only one character may be pushed back.
9889 * PEOF may be pushed back.
9890 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009891static void
Eric Andersenc470f442003-07-28 09:56:35 +00009892pungetc(void)
9893{
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009894 g_parsefile->left_in_line++;
9895 g_parsefile->next_to_pgetc--;
9896 pgetc_debug("pushed back to %d:%p'%s'",
9897 g_parsefile->left_in_line,
9898 g_parsefile->next_to_pgetc,
9899 g_parsefile->next_to_pgetc);
Eric Andersencb57d552001-06-28 07:25:16 +00009900}
9901
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009902/*
9903 * To handle the "." command, a stack of input files is used. Pushfile
9904 * adds a new entry to the stack and popfile restores the previous level.
9905 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009906static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009907pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009908{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009909 struct parsefile *pf;
9910
Denis Vlasenko597906c2008-02-20 16:38:54 +00009911 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009912 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009913 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +00009914 /*pf->strpush = NULL; - ckzalloc did it */
9915 /*pf->basestrpush.prev = NULL;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009916 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009917}
9918
9919static void
9920popfile(void)
9921{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009922 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +00009923
Denis Vlasenkob012b102007-02-19 22:43:01 +00009924 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009925 if (pf->pf_fd >= 0)
9926 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +00009927 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009928 while (pf->strpush)
9929 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009930 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009931 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009932 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009933}
9934
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009935/*
9936 * Return to top level.
9937 */
9938static void
9939popallfiles(void)
9940{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009941 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009942 popfile();
9943}
9944
9945/*
9946 * Close the file(s) that the shell is reading commands from. Called
9947 * after a fork is done.
9948 */
9949static void
9950closescript(void)
9951{
9952 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009953 if (g_parsefile->pf_fd > 0) {
9954 close(g_parsefile->pf_fd);
9955 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009956 }
9957}
9958
9959/*
9960 * Like setinputfile, but takes an open file descriptor. Call this with
9961 * interrupts off.
9962 */
9963static void
9964setinputfd(int fd, int push)
9965{
Denis Vlasenko96e1b382007-09-30 23:50:48 +00009966 close_on_exec_on(fd);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009967 if (push) {
9968 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +00009969 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009970 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009971 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009972 if (g_parsefile->buf == NULL)
9973 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009974 g_parsefile->left_in_buffer = 0;
9975 g_parsefile->left_in_line = 0;
9976 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009977}
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009978
Eric Andersenc470f442003-07-28 09:56:35 +00009979/*
9980 * Set the input to take input from a file. If push is set, push the
9981 * old input onto the stack first.
9982 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009983static int
9984setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +00009985{
9986 int fd;
9987 int fd2;
9988
Denis Vlasenkob012b102007-02-19 22:43:01 +00009989 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009990 fd = open(fname, O_RDONLY);
9991 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009992 if (flags & INPUT_NOFILE_OK)
9993 goto out;
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00009994 ash_msg_and_raise_error("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009995 }
Eric Andersenc470f442003-07-28 09:56:35 +00009996 if (fd < 10) {
9997 fd2 = copyfd(fd, 10);
9998 close(fd);
9999 if (fd2 < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010000 ash_msg_and_raise_error("out of file descriptors");
Eric Andersenc470f442003-07-28 09:56:35 +000010001 fd = fd2;
10002 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010003 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010004 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010005 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010006 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010007}
10008
Eric Andersencb57d552001-06-28 07:25:16 +000010009/*
10010 * Like setinputfile, but takes input from a string.
10011 */
Eric Andersenc470f442003-07-28 09:56:35 +000010012static void
10013setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010014{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010015 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010016 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010017 g_parsefile->next_to_pgetc = string;
10018 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010019 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010020 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010021 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010022}
10023
10024
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010025/* ============ mail.c
10026 *
10027 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010028 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010029
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010030#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010031
Denys Vlasenko23841622015-10-09 15:52:03 +020010032/* Hash of mtimes of mailboxes */
10033static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010034/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010035static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010036
Eric Andersencb57d552001-06-28 07:25:16 +000010037/*
Eric Andersenc470f442003-07-28 09:56:35 +000010038 * Print appropriate message(s) if mail has arrived.
10039 * If mail_var_path_changed is set,
10040 * then the value of MAIL has mail_var_path_changed,
10041 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010042 */
Eric Andersenc470f442003-07-28 09:56:35 +000010043static void
10044chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010045{
Eric Andersencb57d552001-06-28 07:25:16 +000010046 const char *mpath;
10047 char *p;
10048 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010049 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010050 struct stackmark smark;
10051 struct stat statb;
10052
Eric Andersencb57d552001-06-28 07:25:16 +000010053 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010054 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010055 new_hash = 0;
10056 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010057 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010058 if (p == NULL)
10059 break;
10060 if (*p == '\0')
10061 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010062 for (q = p; *q; q++)
10063 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010064#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010065 if (q[-1] != '/')
10066 abort();
10067#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010068 q[-1] = '\0'; /* delete trailing '/' */
10069 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010070 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010071 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010072 /* Very simplistic "hash": just a sum of all mtimes */
10073 new_hash += (unsigned)statb.st_mtime;
10074 }
10075 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010076 if (mailtime_hash != 0)
10077 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010078 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010079 }
Eric Andersenc470f442003-07-28 09:56:35 +000010080 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010081 popstackmark(&smark);
10082}
Eric Andersencb57d552001-06-28 07:25:16 +000010083
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010084static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010085changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010086{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010087 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010088}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010089
Denis Vlasenko131ae172007-02-18 13:00:19 +000010090#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010091
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010092
10093/* ============ ??? */
10094
Eric Andersencb57d552001-06-28 07:25:16 +000010095/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010096 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010097 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010098static void
10099setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010100{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010101 char **newparam;
10102 char **ap;
10103 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010104
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010105 for (nparam = 0; argv[nparam]; nparam++)
10106 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010107 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10108 while (*argv) {
10109 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010110 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010111 *ap = NULL;
10112 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010113 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010114 shellparam.nparam = nparam;
10115 shellparam.p = newparam;
10116#if ENABLE_ASH_GETOPTS
10117 shellparam.optind = 1;
10118 shellparam.optoff = -1;
10119#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010120}
10121
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010122/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010123 * Process shell options. The global variable argptr contains a pointer
10124 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010125 *
10126 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10127 * For a non-interactive shell, an error condition encountered
10128 * by a special built-in ... shall cause the shell to write a diagnostic message
10129 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010130 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010131 * ...
10132 * Utility syntax error (option or operand error) Shall exit
10133 * ...
10134 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10135 * we see that bash does not do that (set "finishes" with error code 1 instead,
10136 * and shell continues), and people rely on this behavior!
10137 * Testcase:
10138 * set -o barfoo 2>/dev/null
10139 * echo $?
10140 *
10141 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010142 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010143static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010144plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010145{
10146 int i;
10147
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010148 if (name) {
10149 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010150 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010151 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010152 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010153 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010154 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010155 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010156 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010157 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010158 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010159 if (val) {
10160 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10161 } else {
10162 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10163 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010164 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010165 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010166}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010167static void
10168setoption(int flag, int val)
10169{
10170 int i;
10171
10172 for (i = 0; i < NOPTS; i++) {
10173 if (optletters(i) == flag) {
10174 optlist[i] = val;
10175 return;
10176 }
10177 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010178 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010179 /* NOTREACHED */
10180}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010181static int
Eric Andersenc470f442003-07-28 09:56:35 +000010182options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +000010183{
10184 char *p;
10185 int val;
10186 int c;
10187
10188 if (cmdline)
10189 minusc = NULL;
10190 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010191 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010192 if (c != '-' && c != '+')
10193 break;
10194 argptr++;
10195 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010196 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010197 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010198 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010199 if (!cmdline) {
10200 /* "-" means turn off -x and -v */
10201 if (p[0] == '\0')
10202 xflag = vflag = 0;
10203 /* "--" means reset params */
10204 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010205 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010206 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010207 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010208 }
Eric Andersencb57d552001-06-28 07:25:16 +000010209 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010210 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010211 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010212 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010213 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010214 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010215 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010216 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010217 /* it already printed err message */
10218 return 1; /* error */
10219 }
Eric Andersencb57d552001-06-28 07:25:16 +000010220 if (*argptr)
10221 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010222 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10223 isloginsh = 1;
10224 /* bash does not accept +-login, we also won't */
10225 } else if (cmdline && val && (c == '-')) { /* long options */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010226 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +000010227 isloginsh = 1;
10228 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010229 } else {
10230 setoption(c, val);
10231 }
10232 }
10233 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010234 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010235}
10236
Eric Andersencb57d552001-06-28 07:25:16 +000010237/*
Eric Andersencb57d552001-06-28 07:25:16 +000010238 * The shift builtin command.
10239 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010240static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010241shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010242{
10243 int n;
10244 char **ap1, **ap2;
10245
10246 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010247 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010248 n = number(argv[1]);
10249 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010250 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010251 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010252 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010253 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010254 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010255 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010256 }
10257 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010258 while ((*ap2++ = *ap1++) != NULL)
10259 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010260#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010261 shellparam.optind = 1;
10262 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010263#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010264 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010265 return 0;
10266}
10267
Eric Andersencb57d552001-06-28 07:25:16 +000010268/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010269 * POSIX requires that 'set' (but not export or readonly) output the
10270 * variables in lexicographic order - by the locale's collating order (sigh).
10271 * Maybe we could keep them in an ordered balanced binary tree
10272 * instead of hashed lists.
10273 * For now just roll 'em through qsort for printing...
10274 */
10275static int
10276showvars(const char *sep_prefix, int on, int off)
10277{
10278 const char *sep;
10279 char **ep, **epend;
10280
10281 ep = listvars(on, off, &epend);
10282 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10283
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010284 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010285
10286 for (; ep < epend; ep++) {
10287 const char *p;
10288 const char *q;
10289
10290 p = strchrnul(*ep, '=');
10291 q = nullstr;
10292 if (*p)
10293 q = single_quote(++p);
10294 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10295 }
10296 return 0;
10297}
10298
10299/*
Eric Andersencb57d552001-06-28 07:25:16 +000010300 * The set command builtin.
10301 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010302static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010303setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010304{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010305 int retval;
10306
Denis Vlasenko68404f12008-03-17 09:00:54 +000010307 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010308 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010309
Denis Vlasenkob012b102007-02-19 22:43:01 +000010310 INT_OFF;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010311 retval = options(/*cmdline:*/ 0);
10312 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010313 optschanged();
10314 if (*argptr != NULL) {
10315 setparam(argptr);
10316 }
Eric Andersencb57d552001-06-28 07:25:16 +000010317 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010318 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010319 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010320}
10321
Denis Vlasenko131ae172007-02-18 13:00:19 +000010322#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010323static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010324change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010325{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010326 uint32_t t;
10327
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010328 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010329 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010330 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010331 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010332 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010333 vrandom.flags &= ~VNOFUNC;
10334 } else {
10335 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010336 t = strtoul(value, NULL, 10);
10337 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010338 }
Eric Andersenef02f822004-03-11 13:34:24 +000010339}
Eric Andersen16767e22004-03-16 05:14:10 +000010340#endif
10341
Denis Vlasenko131ae172007-02-18 13:00:19 +000010342#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010343static int
Eric Andersenc470f442003-07-28 09:56:35 +000010344getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +000010345{
10346 char *p, *q;
10347 char c = '?';
10348 int done = 0;
10349 int err = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010350 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000010351 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +000010352
Denys Vlasenko9c541002015-10-07 15:44:36 +020010353 sbuf[1] = '\0';
10354
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010355 if (*param_optind < 1)
Eric Andersena48b0a32003-10-22 10:56:47 +000010356 return 1;
10357 optnext = optfirst + *param_optind - 1;
10358
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010359 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +000010360 p = NULL;
10361 else
Eric Andersena48b0a32003-10-22 10:56:47 +000010362 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010363 if (p == NULL || *p == '\0') {
10364 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010365 p = *optnext;
10366 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010367 atend:
Eric Andersencb57d552001-06-28 07:25:16 +000010368 p = NULL;
10369 done = 1;
10370 goto out;
10371 }
10372 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010373 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010374 goto atend;
10375 }
10376
10377 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010378 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010379 if (*q == '\0') {
10380 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010381 sbuf[0] = c;
10382 /*sbuf[1] = '\0'; - already is */
10383 err |= setvarsafe("OPTARG", sbuf, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010384 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010385 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010386 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010387 }
10388 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010389 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010390 }
10391 if (*++q == ':')
10392 q++;
10393 }
10394
10395 if (*++q == ':') {
10396 if (*p == '\0' && (p = *optnext) == NULL) {
10397 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010398 sbuf[0] = c;
10399 /*sbuf[1] = '\0'; - already is */
10400 err |= setvarsafe("OPTARG", sbuf, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010401 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010402 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010403 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010404 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010405 c = '?';
10406 }
Eric Andersenc470f442003-07-28 09:56:35 +000010407 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010408 }
10409
10410 if (p == *optnext)
10411 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +000010412 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010413 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010414 } else
Eric Andersenc470f442003-07-28 09:56:35 +000010415 err |= setvarsafe("OPTARG", nullstr, 0);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010416 out:
Eric Andersencb57d552001-06-28 07:25:16 +000010417 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010418 *param_optind = optnext - optfirst + 1;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010419 err |= setvarsafe("OPTIND", itoa(*param_optind), VNOFUNC);
10420 sbuf[0] = c;
10421 /*sbuf[1] = '\0'; - already is */
10422 err |= setvarsafe(optvar, sbuf, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010423 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +000010424 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010425 *optoff = -1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010426 flush_stdout_stderr();
10427 raise_exception(EXERROR);
Eric Andersencb57d552001-06-28 07:25:16 +000010428 }
10429 return done;
10430}
Eric Andersenc470f442003-07-28 09:56:35 +000010431
10432/*
10433 * The getopts builtin. Shellparam.optnext points to the next argument
10434 * to be processed. Shellparam.optptr points to the next character to
10435 * be processed in the current argument. If shellparam.optnext is NULL,
10436 * then it's the first time getopts has been called.
10437 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010438static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000010439getoptscmd(int argc, char **argv)
10440{
10441 char **optbase;
10442
10443 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010444 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010445 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000010446 optbase = shellparam.p;
10447 if (shellparam.optind > shellparam.nparam + 1) {
10448 shellparam.optind = 1;
10449 shellparam.optoff = -1;
10450 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010451 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010452 optbase = &argv[3];
10453 if (shellparam.optind > argc - 2) {
10454 shellparam.optind = 1;
10455 shellparam.optoff = -1;
10456 }
10457 }
10458
10459 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010460 &shellparam.optoff);
Eric Andersenc470f442003-07-28 09:56:35 +000010461}
Denis Vlasenko131ae172007-02-18 13:00:19 +000010462#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000010463
Eric Andersencb57d552001-06-28 07:25:16 +000010464
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010465/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000010466
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010467struct heredoc {
10468 struct heredoc *next; /* next here document in list */
10469 union node *here; /* redirection node */
10470 char *eofmark; /* string indicating end of input */
10471 smallint striptabs; /* if set, strip leading tabs */
10472};
10473
10474static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010475static smallint quoteflag; /* set if (part of) last token was quoted */
10476static token_id_t lasttoken; /* last token read (integer id Txxx) */
10477static struct heredoc *heredoclist; /* list of here documents to read */
10478static char *wordtext; /* text of last word returned by readtoken */
10479static struct nodelist *backquotelist;
10480static union node *redirnode;
10481static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010482
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010483static const char *
10484tokname(char *buf, int tok)
10485{
10486 if (tok < TSEMI)
10487 return tokname_array[tok] + 1;
10488 sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
10489 return buf;
10490}
10491
10492/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010493 * Called when an unexpected token is read during the parse. The argument
10494 * is the token that is expected, or -1 if more than one type of token can
10495 * occur at this point.
10496 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010497static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010498static void
10499raise_error_unexpected_syntax(int token)
10500{
10501 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010502 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010503 int l;
10504
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010505 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010506 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010507 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010508 raise_error_syntax(msg);
10509 /* NOTREACHED */
10510}
Eric Andersencb57d552001-06-28 07:25:16 +000010511
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010512#define EOFMARKLEN 79
Eric Andersencb57d552001-06-28 07:25:16 +000010513
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010514/* parsing is heavily cross-recursive, need these forward decls */
10515static union node *andor(void);
10516static union node *pipeline(void);
10517static union node *parse_command(void);
10518static void parseheredoc(void);
Denys Vlasenko7e661022015-02-05 21:00:17 +010010519static char nexttoken_ends_list(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010520static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000010521
Eric Andersenc470f442003-07-28 09:56:35 +000010522static union node *
10523list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000010524{
10525 union node *n1, *n2, *n3;
10526 int tok;
10527
Eric Andersenc470f442003-07-28 09:56:35 +000010528 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko7e661022015-02-05 21:00:17 +010010529 if (nlflag == 2 && nexttoken_ends_list())
Eric Andersencb57d552001-06-28 07:25:16 +000010530 return NULL;
10531 n1 = NULL;
10532 for (;;) {
10533 n2 = andor();
10534 tok = readtoken();
10535 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000010536 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010537 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010538 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010539 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010540 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000010541 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010542 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010543 n2 = n3;
10544 }
10545 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000010546 }
10547 }
10548 if (n1 == NULL) {
10549 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010550 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010551 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010552 n3->type = NSEMI;
10553 n3->nbinary.ch1 = n1;
10554 n3->nbinary.ch2 = n2;
10555 n1 = n3;
10556 }
10557 switch (tok) {
10558 case TBACKGND:
10559 case TSEMI:
10560 tok = readtoken();
10561 /* fall through */
10562 case TNL:
10563 if (tok == TNL) {
10564 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +000010565 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +000010566 return n1;
10567 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010568 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010569 }
Eric Andersenc470f442003-07-28 09:56:35 +000010570 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko7e661022015-02-05 21:00:17 +010010571 if (nexttoken_ends_list()) {
10572 /* Testcase: "<<EOF; then <W".
10573 * It used to segfault w/o this check:
10574 */
10575 if (heredoclist) {
10576 raise_error_unexpected_syntax(-1);
10577 }
Eric Andersencb57d552001-06-28 07:25:16 +000010578 return n1;
Denys Vlasenko7e661022015-02-05 21:00:17 +010010579 }
Eric Andersencb57d552001-06-28 07:25:16 +000010580 break;
10581 case TEOF:
10582 if (heredoclist)
10583 parseheredoc();
10584 else
Eric Andersenc470f442003-07-28 09:56:35 +000010585 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +000010586 return n1;
10587 default:
Eric Andersenc470f442003-07-28 09:56:35 +000010588 if (nlflag == 1)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010589 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010590 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010591 return n1;
10592 }
10593 }
10594}
10595
Eric Andersenc470f442003-07-28 09:56:35 +000010596static union node *
10597andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010598{
Eric Andersencb57d552001-06-28 07:25:16 +000010599 union node *n1, *n2, *n3;
10600 int t;
10601
Eric Andersencb57d552001-06-28 07:25:16 +000010602 n1 = pipeline();
10603 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010604 t = readtoken();
10605 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000010606 t = NAND;
10607 } else if (t == TOR) {
10608 t = NOR;
10609 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010610 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010611 return n1;
10612 }
Eric Andersenc470f442003-07-28 09:56:35 +000010613 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010614 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010615 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010616 n3->type = t;
10617 n3->nbinary.ch1 = n1;
10618 n3->nbinary.ch2 = n2;
10619 n1 = n3;
10620 }
10621}
10622
Eric Andersenc470f442003-07-28 09:56:35 +000010623static union node *
10624pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010625{
Eric Andersencb57d552001-06-28 07:25:16 +000010626 union node *n1, *n2, *pipenode;
10627 struct nodelist *lp, *prev;
10628 int negate;
10629
10630 negate = 0;
10631 TRACE(("pipeline: entered\n"));
10632 if (readtoken() == TNOT) {
10633 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000010634 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010635 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010636 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010637 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010638 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010639 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000010640 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010641 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010642 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000010643 pipenode->npipe.cmdlist = lp;
10644 lp->n = n1;
10645 do {
10646 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010647 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000010648 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010649 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010650 prev->next = lp;
10651 } while (readtoken() == TPIPE);
10652 lp->next = NULL;
10653 n1 = pipenode;
10654 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010655 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010656 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010657 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000010658 n2->type = NNOT;
10659 n2->nnot.com = n1;
10660 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010661 }
10662 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000010663}
10664
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010665static union node *
10666makename(void)
10667{
10668 union node *n;
10669
Denis Vlasenko597906c2008-02-20 16:38:54 +000010670 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010671 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010672 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010673 n->narg.text = wordtext;
10674 n->narg.backquote = backquotelist;
10675 return n;
10676}
10677
10678static void
10679fixredir(union node *n, const char *text, int err)
10680{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010681 int fd;
10682
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010683 TRACE(("Fix redir %s %d\n", text, err));
10684 if (!err)
10685 n->ndup.vname = NULL;
10686
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010687 fd = bb_strtou(text, NULL, 10);
10688 if (!errno && fd >= 0)
10689 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010690 else if (LONE_DASH(text))
10691 n->ndup.dupfd = -1;
10692 else {
10693 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010694 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010695 n->ndup.vname = makename();
10696 }
10697}
10698
10699/*
10700 * Returns true if the text contains nothing to expand (no dollar signs
10701 * or backquotes).
10702 */
10703static int
Denis Vlasenko68819d12008-12-15 11:26:36 +000010704noexpand(const char *text)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010705{
Denys Vlasenkocd716832009-11-28 22:14:02 +010010706 unsigned char c;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010707
Denys Vlasenkocd716832009-11-28 22:14:02 +010010708 while ((c = *text++) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010709 if (c == CTLQUOTEMARK)
10710 continue;
10711 if (c == CTLESC)
Denys Vlasenkocd716832009-11-28 22:14:02 +010010712 text++;
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010010713 else if (SIT(c, BASESYNTAX) == CCTL)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010714 return 0;
10715 }
10716 return 1;
10717}
10718
10719static void
10720parsefname(void)
10721{
10722 union node *n = redirnode;
10723
10724 if (readtoken() != TWORD)
10725 raise_error_unexpected_syntax(-1);
10726 if (n->type == NHERE) {
10727 struct heredoc *here = heredoc;
10728 struct heredoc *p;
10729 int i;
10730
10731 if (quoteflag == 0)
10732 n->type = NXHERE;
10733 TRACE(("Here document %d\n", n->type));
10734 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010735 raise_error_syntax("illegal eof marker for << redirection");
Denys Vlasenkob6c84342009-08-29 20:23:20 +020010736 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010737 here->eofmark = wordtext;
10738 here->next = NULL;
10739 if (heredoclist == NULL)
10740 heredoclist = here;
10741 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010742 for (p = heredoclist; p->next; p = p->next)
10743 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010744 p->next = here;
10745 }
10746 } else if (n->type == NTOFD || n->type == NFROMFD) {
10747 fixredir(n, wordtext, 0);
10748 } else {
10749 n->nfile.fname = makename();
10750 }
10751}
Eric Andersencb57d552001-06-28 07:25:16 +000010752
Eric Andersenc470f442003-07-28 09:56:35 +000010753static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010754simplecmd(void)
10755{
10756 union node *args, **app;
10757 union node *n = NULL;
10758 union node *vars, **vpp;
10759 union node **rpp, *redir;
10760 int savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010761#if ENABLE_ASH_BASH_COMPAT
10762 smallint double_brackets_flag = 0;
10763#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010764
10765 args = NULL;
10766 app = &args;
10767 vars = NULL;
10768 vpp = &vars;
10769 redir = NULL;
10770 rpp = &redir;
10771
10772 savecheckkwd = CHKALIAS;
10773 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000010774 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010775 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010776 t = readtoken();
10777 switch (t) {
10778#if ENABLE_ASH_BASH_COMPAT
10779 case TAND: /* "&&" */
10780 case TOR: /* "||" */
10781 if (!double_brackets_flag) {
10782 tokpushback = 1;
10783 goto out;
10784 }
10785 wordtext = (char *) (t == TAND ? "-a" : "-o");
10786#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010787 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000010788 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010789 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010790 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010791 n->narg.text = wordtext;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010792#if ENABLE_ASH_BASH_COMPAT
10793 if (strcmp("[[", wordtext) == 0)
10794 double_brackets_flag = 1;
10795 else if (strcmp("]]", wordtext) == 0)
10796 double_brackets_flag = 0;
10797#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010798 n->narg.backquote = backquotelist;
10799 if (savecheckkwd && isassignment(wordtext)) {
10800 *vpp = n;
10801 vpp = &n->narg.next;
10802 } else {
10803 *app = n;
10804 app = &n->narg.next;
10805 savecheckkwd = 0;
10806 }
10807 break;
10808 case TREDIR:
10809 *rpp = n = redirnode;
10810 rpp = &n->nfile.next;
10811 parsefname(); /* read name of redirection file */
10812 break;
10813 case TLP:
10814 if (args && app == &args->narg.next
10815 && !vars && !redir
10816 ) {
10817 struct builtincmd *bcmd;
10818 const char *name;
10819
10820 /* We have a function */
10821 if (readtoken() != TRP)
10822 raise_error_unexpected_syntax(TRP);
10823 name = n->narg.text;
10824 if (!goodname(name)
10825 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10826 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000010827 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010828 }
10829 n->type = NDEFUN;
10830 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10831 n->narg.next = parse_command();
10832 return n;
10833 }
10834 /* fall through */
10835 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010836 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010837 goto out;
10838 }
10839 }
10840 out:
10841 *app = NULL;
10842 *vpp = NULL;
10843 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010844 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010845 n->type = NCMD;
10846 n->ncmd.args = args;
10847 n->ncmd.assign = vars;
10848 n->ncmd.redirect = redir;
10849 return n;
10850}
10851
10852static union node *
10853parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010854{
Eric Andersencb57d552001-06-28 07:25:16 +000010855 union node *n1, *n2;
10856 union node *ap, **app;
10857 union node *cp, **cpp;
10858 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000010859 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000010860 int t;
10861
10862 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000010863 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000010864
Eric Andersencb57d552001-06-28 07:25:16 +000010865 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000010866 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010867 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000010868 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000010869 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010870 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000010871 n1->type = NIF;
10872 n1->nif.test = list(0);
10873 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010874 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000010875 n1->nif.ifpart = list(0);
10876 n2 = n1;
10877 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010878 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000010879 n2 = n2->nif.elsepart;
10880 n2->type = NIF;
10881 n2->nif.test = list(0);
10882 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010883 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000010884 n2->nif.ifpart = list(0);
10885 }
10886 if (lasttoken == TELSE)
10887 n2->nif.elsepart = list(0);
10888 else {
10889 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010890 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010891 }
Eric Andersenc470f442003-07-28 09:56:35 +000010892 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000010893 break;
10894 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010895 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000010896 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010897 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010898 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000010899 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010900 got = readtoken();
10901 if (got != TDO) {
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010902 TRACE(("expecting DO got '%s' %s\n", tokname_array[got] + 1,
Denis Vlasenko131ae172007-02-18 13:00:19 +000010903 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010904 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000010905 }
10906 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000010907 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000010908 break;
10909 }
10910 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010911 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000010912 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010913 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000010914 n1->type = NFOR;
10915 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +000010916 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010917 if (readtoken() == TIN) {
10918 app = &ap;
10919 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010920 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000010921 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010922 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000010923 n2->narg.text = wordtext;
10924 n2->narg.backquote = backquotelist;
10925 *app = n2;
10926 app = &n2->narg.next;
10927 }
10928 *app = NULL;
10929 n1->nfor.args = ap;
10930 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010931 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000010932 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010933 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000010934 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010935 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010936 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010937 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000010938 n1->nfor.args = n2;
10939 /*
10940 * Newline or semicolon here is optional (but note
10941 * that the original Bourne shell only allowed NL).
10942 */
10943 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010944 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010945 }
Eric Andersenc470f442003-07-28 09:56:35 +000010946 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010947 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010948 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000010949 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000010950 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000010951 break;
10952 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010953 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000010954 n1->type = NCASE;
10955 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010956 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000010957 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000010958 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010959 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000010960 n2->narg.text = wordtext;
10961 n2->narg.backquote = backquotelist;
Eric Andersencb57d552001-06-28 07:25:16 +000010962 do {
Eric Andersenc470f442003-07-28 09:56:35 +000010963 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010964 } while (readtoken() == TNL);
10965 if (lasttoken != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010966 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000010967 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010968 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000010969 checkkwd = CHKNL | CHKKWD;
10970 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010971 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000010972 if (lasttoken == TLP)
10973 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010974 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000010975 cp->type = NCLIST;
10976 app = &cp->nclist.pattern;
10977 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010978 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000010979 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010980 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000010981 ap->narg.text = wordtext;
10982 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000010983 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000010984 break;
10985 app = &ap->narg.next;
10986 readtoken();
10987 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000010988 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000010989 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010990 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000010991 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010992
Eric Andersenc470f442003-07-28 09:56:35 +000010993 cpp = &cp->nclist.next;
10994
10995 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010996 t = readtoken();
10997 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000010998 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010999 raise_error_unexpected_syntax(TENDCASE);
11000 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011001 }
Eric Andersenc470f442003-07-28 09:56:35 +000011002 }
Eric Andersencb57d552001-06-28 07:25:16 +000011003 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011004 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011005 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011006 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011007 n1->type = NSUBSHELL;
11008 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011009 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011010 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011011 break;
11012 case TBEGIN:
11013 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011014 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011015 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011016 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011017 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011018 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011019 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011020 }
11021
Eric Andersenc470f442003-07-28 09:56:35 +000011022 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011023 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011024
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011025 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011026 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011027 checkkwd = CHKKWD | CHKALIAS;
11028 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011029 while (readtoken() == TREDIR) {
11030 *rpp = n2 = redirnode;
11031 rpp = &n2->nfile.next;
11032 parsefname();
11033 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011034 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011035 *rpp = NULL;
11036 if (redir) {
11037 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011038 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011039 n2->type = NREDIR;
11040 n2->nredir.n = n1;
11041 n1 = n2;
11042 }
11043 n1->nredir.redirect = redir;
11044 }
Eric Andersencb57d552001-06-28 07:25:16 +000011045 return n1;
11046}
11047
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011048#if ENABLE_ASH_BASH_COMPAT
11049static int decode_dollar_squote(void)
11050{
11051 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11052 int c, cnt;
11053 char *p;
11054 char buf[4];
11055
11056 c = pgetc();
11057 p = strchr(C_escapes, c);
11058 if (p) {
11059 buf[0] = c;
11060 p = buf;
11061 cnt = 3;
11062 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11063 do {
11064 c = pgetc();
11065 *++p = c;
11066 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11067 pungetc();
11068 } else if (c == 'x') { /* \xHH */
11069 do {
11070 c = pgetc();
11071 *++p = c;
11072 } while (isxdigit(c) && --cnt);
11073 pungetc();
11074 if (cnt == 3) { /* \x but next char is "bad" */
11075 c = 'x';
11076 goto unrecognized;
11077 }
11078 } else { /* simple seq like \\ or \t */
11079 p++;
11080 }
11081 *p = '\0';
11082 p = buf;
11083 c = bb_process_escape_sequence((void*)&p);
11084 } else { /* unrecognized "\z": print both chars unless ' or " */
11085 if (c != '\'' && c != '"') {
11086 unrecognized:
11087 c |= 0x100; /* "please encode \, then me" */
11088 }
11089 }
11090 return c;
11091}
11092#endif
11093
Eric Andersencb57d552001-06-28 07:25:16 +000011094/*
11095 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11096 * is not NULL, read a here document. In the latter case, eofmark is the
11097 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011098 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011099 * is the first character of the input token or document.
11100 *
11101 * Because C does not have internal subroutines, I have simulated them
11102 * using goto's to implement the subroutine linkage. The following macros
11103 * will run code that appears at the end of readtoken1.
11104 */
Eric Andersen2870d962001-07-02 17:27:21 +000011105#define CHECKEND() {goto checkend; checkend_return:;}
11106#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11107#define PARSESUB() {goto parsesub; parsesub_return:;}
11108#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11109#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11110#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011111static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011112readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011113{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011114 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011115 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011116 char *out;
11117 int len;
11118 char line[EOFMARKLEN + 1];
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011119 struct nodelist *bqlist;
11120 smallint quotef;
11121 smallint dblquote;
11122 smallint oldstyle;
11123 smallint prevsyntax; /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011124#if ENABLE_ASH_EXPAND_PRMT
11125 smallint pssyntax; /* we are expanding a prompt string */
11126#endif
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011127 int varnest; /* levels of variables expansion */
11128 int arinest; /* levels of arithmetic expansion */
11129 int parenlevel; /* levels of parens in arithmetic */
11130 int dqvarnest; /* levels of variables expansion within double quotes */
11131
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011132 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011133
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011134 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011135 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011136 quotef = 0;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011137 prevsyntax = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000011138#if ENABLE_ASH_EXPAND_PRMT
11139 pssyntax = (syntax == PSSYNTAX);
11140 if (pssyntax)
11141 syntax = DQSYNTAX;
11142#endif
11143 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011144 varnest = 0;
11145 arinest = 0;
11146 parenlevel = 0;
11147 dqvarnest = 0;
11148
11149 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011150 loop:
11151 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011152 CHECKEND(); /* set c to PEOF if at end of here document */
11153 for (;;) { /* until end of line or end of word */
11154 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11155 switch (SIT(c, syntax)) {
11156 case CNL: /* '\n' */
11157 if (syntax == BASESYNTAX)
11158 goto endword; /* exit outer loop */
11159 USTPUTC(c, out);
11160 g_parsefile->linno++;
11161 setprompt_if(doprompt, 2);
11162 c = pgetc();
11163 goto loop; /* continue outer loop */
11164 case CWORD:
11165 USTPUTC(c, out);
11166 break;
11167 case CCTL:
11168 if (eofmark == NULL || dblquote)
11169 USTPUTC(CTLESC, out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011170#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011171 if (c == '\\' && bash_dollar_squote) {
11172 c = decode_dollar_squote();
11173 if (c & 0x100) {
11174 USTPUTC('\\', out);
11175 c = (unsigned char)c;
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011176 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011177 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011178#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011179 USTPUTC(c, out);
11180 break;
11181 case CBACK: /* backslash */
11182 c = pgetc_without_PEOA();
11183 if (c == PEOF) {
11184 USTPUTC(CTLESC, out);
11185 USTPUTC('\\', out);
11186 pungetc();
11187 } else if (c == '\n') {
11188 setprompt_if(doprompt, 2);
11189 } else {
11190#if ENABLE_ASH_EXPAND_PRMT
11191 if (c == '$' && pssyntax) {
Eric Andersenc470f442003-07-28 09:56:35 +000011192 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011193 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011194 }
Denis Vlasenko46a53062007-09-24 18:30:02 +000011195#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011196 /* Backslash is retained if we are in "str" and next char isn't special */
11197 if (dblquote
11198 && c != '\\'
11199 && c != '`'
11200 && c != '$'
11201 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011202 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011203 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011204 }
Ron Yorston549deab2015-05-18 09:57:51 +020011205 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011206 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011207 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011208 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011209 break;
11210 case CSQUOTE:
11211 syntax = SQSYNTAX;
11212 quotemark:
11213 if (eofmark == NULL) {
11214 USTPUTC(CTLQUOTEMARK, out);
11215 }
11216 break;
11217 case CDQUOTE:
11218 syntax = DQSYNTAX;
11219 dblquote = 1;
11220 goto quotemark;
11221 case CENDQUOTE:
11222 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020011223 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011224 USTPUTC(c, out);
11225 } else {
11226 if (dqvarnest == 0) {
11227 syntax = BASESYNTAX;
11228 dblquote = 0;
11229 }
11230 quotef = 1;
11231 goto quotemark;
11232 }
11233 break;
11234 case CVAR: /* '$' */
11235 PARSESUB(); /* parse substitution */
11236 break;
11237 case CENDVAR: /* '}' */
11238 if (varnest > 0) {
11239 varnest--;
11240 if (dqvarnest > 0) {
11241 dqvarnest--;
11242 }
11243 c = CTLENDVAR;
11244 }
11245 USTPUTC(c, out);
11246 break;
11247#if ENABLE_SH_MATH_SUPPORT
11248 case CLP: /* '(' in arithmetic */
11249 parenlevel++;
11250 USTPUTC(c, out);
11251 break;
11252 case CRP: /* ')' in arithmetic */
11253 if (parenlevel > 0) {
11254 parenlevel--;
11255 } else {
11256 if (pgetc() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020011257 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011258 if (--arinest == 0) {
11259 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011260 }
11261 } else {
11262 /*
11263 * unbalanced parens
11264 * (don't 2nd guess - no error)
11265 */
11266 pungetc();
11267 }
11268 }
11269 USTPUTC(c, out);
11270 break;
11271#endif
11272 case CBQUOTE: /* '`' */
11273 PARSEBACKQOLD();
11274 break;
11275 case CENDFILE:
11276 goto endword; /* exit outer loop */
11277 case CIGN:
11278 break;
11279 default:
11280 if (varnest == 0) {
11281#if ENABLE_ASH_BASH_COMPAT
11282 if (c == '&') {
11283 if (pgetc() == '>')
11284 c = 0x100 + '>'; /* flag &> */
11285 pungetc();
11286 }
11287#endif
11288 goto endword; /* exit outer loop */
11289 }
11290 IF_ASH_ALIAS(if (c != PEOA))
11291 USTPUTC(c, out);
11292 }
11293 c = pgetc_fast();
11294 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011295 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011296
Mike Frysinger98c52642009-04-02 10:02:37 +000011297#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011298 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011299 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011300#endif
Ron Yorston0e056f72015-07-01 16:45:40 +010011301 if (syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011302 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011303 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011304 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011305 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011306 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011307 }
11308 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011309 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011310 out = stackblock();
11311 if (eofmark == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011312 if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011313 && quotef == 0
11314 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011315 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011316 PARSEREDIR(); /* passed as params: out, c */
11317 lasttoken = TREDIR;
11318 return lasttoken;
11319 }
11320 /* else: non-number X seen, interpret it
11321 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011322 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011323 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011324 }
11325 quoteflag = quotef;
11326 backquotelist = bqlist;
11327 grabstackblock(len);
11328 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011329 lasttoken = TWORD;
11330 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011331/* end of readtoken routine */
11332
Eric Andersencb57d552001-06-28 07:25:16 +000011333/*
11334 * Check to see whether we are at the end of the here document. When this
11335 * is called, c is set to the first character of the next input line. If
11336 * we are at the end of the here document, this routine sets the c to PEOF.
11337 */
Eric Andersenc470f442003-07-28 09:56:35 +000011338checkend: {
11339 if (eofmark) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000011340#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011341 if (c == PEOA)
11342 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011343#endif
11344 if (striptabs) {
11345 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011346 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011347 }
Eric Andersenc470f442003-07-28 09:56:35 +000011348 }
11349 if (c == *eofmark) {
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011350 if (pfgets(line, sizeof(line)) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000011351 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000011352
Eric Andersenc470f442003-07-28 09:56:35 +000011353 p = line;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011354 for (q = eofmark + 1; *q && *p == *q; p++, q++)
11355 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000011356 if (*p == '\n' && *q == '\0') {
11357 c = PEOF;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011358 g_parsefile->linno++;
Eric Andersenc470f442003-07-28 09:56:35 +000011359 needprompt = doprompt;
11360 } else {
11361 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011362 }
11363 }
11364 }
11365 }
Eric Andersenc470f442003-07-28 09:56:35 +000011366 goto checkend_return;
11367}
Eric Andersencb57d552001-06-28 07:25:16 +000011368
Eric Andersencb57d552001-06-28 07:25:16 +000011369/*
11370 * Parse a redirection operator. The variable "out" points to a string
11371 * specifying the fd to be redirected. The variable "c" contains the
11372 * first character of the redirection operator.
11373 */
Eric Andersenc470f442003-07-28 09:56:35 +000011374parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011375 /* out is already checked to be a valid number or "" */
11376 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000011377 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000011378
Denis Vlasenko597906c2008-02-20 16:38:54 +000011379 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000011380 if (c == '>') {
11381 np->nfile.fd = 1;
11382 c = pgetc();
11383 if (c == '>')
11384 np->type = NAPPEND;
11385 else if (c == '|')
11386 np->type = NCLOBBER;
11387 else if (c == '&')
11388 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011389 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000011390 else {
11391 np->type = NTO;
11392 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011393 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000011394 }
11395#if ENABLE_ASH_BASH_COMPAT
11396 else if (c == 0x100 + '>') { /* this flags &> redirection */
11397 np->nfile.fd = 1;
11398 pgetc(); /* this is '>', no need to check */
11399 np->type = NTO2;
11400 }
11401#endif
11402 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000011403 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011404 c = pgetc();
11405 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000011406 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011407 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011408 np = stzalloc(sizeof(struct nhere));
11409 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011410 }
11411 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011412 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000011413 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011414 c = pgetc();
11415 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000011416 heredoc->striptabs = 1;
11417 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011418 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011419 pungetc();
11420 }
11421 break;
11422
11423 case '&':
11424 np->type = NFROMFD;
11425 break;
11426
11427 case '>':
11428 np->type = NFROMTO;
11429 break;
11430
11431 default:
11432 np->type = NFROM;
11433 pungetc();
11434 break;
11435 }
Eric Andersencb57d552001-06-28 07:25:16 +000011436 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011437 if (fd >= 0)
11438 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011439 redirnode = np;
11440 goto parseredir_return;
11441}
Eric Andersencb57d552001-06-28 07:25:16 +000011442
Eric Andersencb57d552001-06-28 07:25:16 +000011443/*
11444 * Parse a substitution. At this point, we have read the dollar sign
11445 * and nothing else.
11446 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000011447
11448/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11449 * (assuming ascii char codes, as the original implementation did) */
11450#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011451 (((unsigned)(c) - 33 < 32) \
11452 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000011453parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010011454 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011455 int typeloc;
11456 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +000011457
Eric Andersenc470f442003-07-28 09:56:35 +000011458 c = pgetc();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011459 if (c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011460 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000011461 ) {
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011462#if ENABLE_ASH_BASH_COMPAT
11463 if (c == '\'')
11464 bash_dollar_squote = 1;
11465 else
11466#endif
11467 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011468 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011469 } else if (c == '(') {
11470 /* $(command) or $((arith)) */
Eric Andersenc470f442003-07-28 09:56:35 +000011471 if (pgetc() == '(') {
Mike Frysinger98c52642009-04-02 10:02:37 +000011472#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000011473 PARSEARITH();
11474#else
Mike Frysinger98a6f562008-06-09 09:38:45 +000011475 raise_error_syntax("you disabled math support for $((arith)) syntax");
Eric Andersenc470f442003-07-28 09:56:35 +000011476#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011477 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011478 pungetc();
11479 PARSEBACKQNEW();
11480 }
11481 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011482 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000011483 USTPUTC(CTLVAR, out);
11484 typeloc = out - (char *)stackblock();
11485 USTPUTC(VSNORMAL, out);
11486 subtype = VSNORMAL;
11487 if (c == '{') {
11488 c = pgetc();
11489 if (c == '#') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011490 c = pgetc();
11491 if (c == '}')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011492 c = '#'; /* ${#} - same as $# */
Eric Andersenc470f442003-07-28 09:56:35 +000011493 else
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011494 subtype = VSLENGTH; /* ${#VAR} */
11495 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011496 subtype = 0;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011497 }
Eric Andersenc470f442003-07-28 09:56:35 +000011498 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011499 if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011500 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011501 do {
11502 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011503 c = pgetc();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011504 } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011505 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011506 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011507 do {
11508 STPUTC(c, out);
11509 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011510 } while (isdigit(c));
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011511 } else if (is_special(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011512 /* $[{[#]]<specialchar>[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011513 USTPUTC(c, out);
11514 c = pgetc();
Denis Vlasenko559691a2008-10-05 18:39:31 +000011515 } else {
11516 badsub:
11517 raise_error_syntax("bad substitution");
11518 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011519 if (c != '}' && subtype == VSLENGTH) {
11520 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020011521 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011522 }
Eric Andersencb57d552001-06-28 07:25:16 +000011523
Eric Andersenc470f442003-07-28 09:56:35 +000011524 STPUTC('=', out);
11525 flags = 0;
11526 if (subtype == 0) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011527 /* ${VAR...} but not $VAR or ${#VAR} */
11528 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000011529 switch (c) {
11530 case ':':
Eric Andersenc470f442003-07-28 09:56:35 +000011531 c = pgetc();
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011532#if ENABLE_ASH_BASH_COMPAT
11533 if (c == ':' || c == '$' || isdigit(c)) {
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011534//TODO: support more general format ${v:EXPR:EXPR},
11535// where EXPR follows $(()) rules
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011536 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011537 pungetc();
11538 break; /* "goto do_pungetc" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011539 }
11540#endif
11541 flags = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000011542 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011543 default: {
11544 static const char types[] ALIGN1 = "}-+?=";
11545 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000011546 if (p == NULL)
11547 goto badsub;
11548 subtype = p - types + VSNORMAL;
11549 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011550 }
Eric Andersenc470f442003-07-28 09:56:35 +000011551 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011552 case '#': {
11553 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011554 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011555 c = pgetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011556 if (c != cc)
11557 goto do_pungetc;
11558 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011559 break;
11560 }
11561#if ENABLE_ASH_BASH_COMPAT
11562 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011563 /* ${v/[/]pattern/repl} */
11564//TODO: encode pattern and repl separately.
11565// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011566 subtype = VSREPLACE;
11567 c = pgetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011568 if (c != '/')
11569 goto do_pungetc;
11570 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011571 break;
11572#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011573 }
Eric Andersenc470f442003-07-28 09:56:35 +000011574 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011575 do_pungetc:
Eric Andersenc470f442003-07-28 09:56:35 +000011576 pungetc();
11577 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011578 ((unsigned char *)stackblock())[typeloc] = subtype | flags;
Eric Andersenc470f442003-07-28 09:56:35 +000011579 if (subtype != VSNORMAL) {
11580 varnest++;
Ron Yorston7e4ed262015-05-18 09:54:43 +020011581 if (dblquote) {
Eric Andersenc470f442003-07-28 09:56:35 +000011582 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000011583 }
11584 }
11585 }
Eric Andersenc470f442003-07-28 09:56:35 +000011586 goto parsesub_return;
11587}
Eric Andersencb57d552001-06-28 07:25:16 +000011588
Eric Andersencb57d552001-06-28 07:25:16 +000011589/*
11590 * Called to parse command substitutions. Newstyle is set if the command
11591 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11592 * list of commands (passed by reference), and savelen is the number of
11593 * characters on the top of the stack which must be preserved.
11594 */
Eric Andersenc470f442003-07-28 09:56:35 +000011595parsebackq: {
11596 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011597 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010011598 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000011599 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011600 smallint saveprompt = 0;
11601
Eric Andersenc470f442003-07-28 09:56:35 +000011602 str = NULL;
11603 savelen = out - (char *)stackblock();
11604 if (savelen > 0) {
Ron Yorston072fc602015-07-01 16:46:18 +010011605 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000011606 memcpy(str, stackblock(), savelen);
11607 }
Eric Andersenc470f442003-07-28 09:56:35 +000011608 if (oldstyle) {
11609 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010011610 * treatment to some slashes, and then push the string and
11611 * reread it as input, interpreting it normally.
11612 */
Eric Andersenc470f442003-07-28 09:56:35 +000011613 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000011614 size_t psavelen;
11615 char *pstr;
11616
Eric Andersenc470f442003-07-28 09:56:35 +000011617 STARTSTACKSTR(pout);
11618 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011619 int pc;
11620
11621 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011622 pc = pgetc();
11623 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000011624 case '`':
11625 goto done;
11626
11627 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011628 pc = pgetc();
11629 if (pc == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011630 g_parsefile->linno++;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011631 setprompt_if(doprompt, 2);
Eric Andersenc470f442003-07-28 09:56:35 +000011632 /*
11633 * If eating a newline, avoid putting
11634 * the newline into the new character
11635 * stream (via the STPUTC after the
11636 * switch).
11637 */
11638 continue;
11639 }
11640 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011641 && (!dblquote || pc != '"')
11642 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000011643 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011644 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011645 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000011646 break;
11647 }
11648 /* fall through */
11649
11650 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011651 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011652 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011653 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000011654
11655 case '\n':
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011656 g_parsefile->linno++;
Eric Andersenc470f442003-07-28 09:56:35 +000011657 needprompt = doprompt;
11658 break;
11659
11660 default:
11661 break;
11662 }
11663 STPUTC(pc, pout);
11664 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011665 done:
Eric Andersenc470f442003-07-28 09:56:35 +000011666 STPUTC('\0', pout);
11667 psavelen = pout - (char *)stackblock();
11668 if (psavelen > 0) {
11669 pstr = grabstackstr(pout);
11670 setinputstring(pstr);
11671 }
11672 }
11673 nlpp = &bqlist;
11674 while (*nlpp)
11675 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011676 *nlpp = stzalloc(sizeof(**nlpp));
11677 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011678
11679 if (oldstyle) {
11680 saveprompt = doprompt;
11681 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011682 }
11683
Eric Andersenc470f442003-07-28 09:56:35 +000011684 n = list(2);
11685
11686 if (oldstyle)
11687 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011688 else if (readtoken() != TRP)
11689 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011690
11691 (*nlpp)->n = n;
11692 if (oldstyle) {
11693 /*
11694 * Start reading from old file again, ignoring any pushed back
11695 * tokens left from the backquote parsing
11696 */
11697 popfile();
11698 tokpushback = 0;
11699 }
11700 while (stackblocksize() <= savelen)
11701 growstackblock();
11702 STARTSTACKSTR(out);
11703 if (str) {
11704 memcpy(out, str, savelen);
11705 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011706 }
Ron Yorston549deab2015-05-18 09:57:51 +020011707 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011708 if (oldstyle)
11709 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011710 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000011711}
11712
Mike Frysinger98c52642009-04-02 10:02:37 +000011713#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011714/*
11715 * Parse an arithmetic expansion (indicate start of one and set state)
11716 */
Eric Andersenc470f442003-07-28 09:56:35 +000011717parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000011718 if (++arinest == 1) {
11719 prevsyntax = syntax;
11720 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000011721 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020011722 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011723 goto parsearith_return;
11724}
11725#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011726} /* end of readtoken */
11727
Eric Andersencb57d552001-06-28 07:25:16 +000011728/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011729 * Read the next input token.
11730 * If the token is a word, we set backquotelist to the list of cmds in
11731 * backquotes. We set quoteflag to true if any part of the word was
11732 * quoted.
11733 * If the token is TREDIR, then we set redirnode to a structure containing
11734 * the redirection.
11735 * In all cases, the variable startlinno is set to the number of the line
11736 * on which the token starts.
11737 *
11738 * [Change comment: here documents and internal procedures]
11739 * [Readtoken shouldn't have any arguments. Perhaps we should make the
11740 * word parsing code into a separate routine. In this case, readtoken
11741 * doesn't need to have any internal procedures, but parseword does.
11742 * We could also make parseoperator in essence the main routine, and
11743 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000011744 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011745#define NEW_xxreadtoken
11746#ifdef NEW_xxreadtoken
11747/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011748static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000011749 '\n', '(', ')', /* singles */
11750 '&', '|', ';', /* doubles */
11751 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011752};
Eric Andersencb57d552001-06-28 07:25:16 +000011753
Denis Vlasenko834dee72008-10-07 09:18:30 +000011754#define xxreadtoken_singles 3
11755#define xxreadtoken_doubles 3
11756
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011757static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011758 TNL, TLP, TRP, /* only single occurrence allowed */
11759 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11760 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011761 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011762};
11763
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011764static int
11765xxreadtoken(void)
11766{
11767 int c;
11768
11769 if (tokpushback) {
11770 tokpushback = 0;
11771 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011772 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011773 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011774 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011775 for (;;) { /* until token or start of word found */
Denis Vlasenko834dee72008-10-07 09:18:30 +000011776 c = pgetc_fast();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011777 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011778 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011779
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011780 if (c == '#') {
11781 while ((c = pgetc()) != '\n' && c != PEOF)
11782 continue;
11783 pungetc();
11784 } else if (c == '\\') {
11785 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011786 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000011787 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011788 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011789 startlinno = ++g_parsefile->linno;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011790 setprompt_if(doprompt, 2);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011791 } else {
11792 const char *p;
11793
11794 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11795 if (c != PEOF) {
11796 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011797 g_parsefile->linno++;
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011798 needprompt = doprompt;
11799 }
11800
11801 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000011802 if (p == NULL)
11803 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011804
Denis Vlasenko834dee72008-10-07 09:18:30 +000011805 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
11806 int cc = pgetc();
11807 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011808 p += xxreadtoken_doubles + 1;
11809 } else {
11810 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000011811#if ENABLE_ASH_BASH_COMPAT
11812 if (c == '&' && cc == '>') /* &> */
11813 break; /* return readtoken1(...) */
11814#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011815 }
11816 }
11817 }
11818 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
11819 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011820 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011821 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000011822
11823 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011824}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011825#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011826#define RETURN(token) return lasttoken = token
11827static int
11828xxreadtoken(void)
11829{
11830 int c;
11831
11832 if (tokpushback) {
11833 tokpushback = 0;
11834 return lasttoken;
11835 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011836 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011837 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011838 for (;;) { /* until token or start of word found */
Denis Vlasenko834dee72008-10-07 09:18:30 +000011839 c = pgetc_fast();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011840 switch (c) {
11841 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011842 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011843 continue;
11844 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011845 while ((c = pgetc()) != '\n' && c != PEOF)
11846 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011847 pungetc();
11848 continue;
11849 case '\\':
11850 if (pgetc() == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011851 startlinno = ++g_parsefile->linno;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011852 setprompt_if(doprompt, 2);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011853 continue;
11854 }
11855 pungetc();
11856 goto breakloop;
11857 case '\n':
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011858 g_parsefile->linno++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011859 needprompt = doprompt;
11860 RETURN(TNL);
11861 case PEOF:
11862 RETURN(TEOF);
11863 case '&':
11864 if (pgetc() == '&')
11865 RETURN(TAND);
11866 pungetc();
11867 RETURN(TBACKGND);
11868 case '|':
11869 if (pgetc() == '|')
11870 RETURN(TOR);
11871 pungetc();
11872 RETURN(TPIPE);
11873 case ';':
11874 if (pgetc() == ';')
11875 RETURN(TENDCASE);
11876 pungetc();
11877 RETURN(TSEMI);
11878 case '(':
11879 RETURN(TLP);
11880 case ')':
11881 RETURN(TRP);
11882 default:
11883 goto breakloop;
11884 }
11885 }
11886 breakloop:
11887 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
11888#undef RETURN
11889}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011890#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011891
11892static int
11893readtoken(void)
11894{
11895 int t;
11896#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011897 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011898#endif
11899
11900#if ENABLE_ASH_ALIAS
11901 top:
11902#endif
11903
11904 t = xxreadtoken();
11905
11906 /*
11907 * eat newlines
11908 */
11909 if (checkkwd & CHKNL) {
11910 while (t == TNL) {
11911 parseheredoc();
11912 t = xxreadtoken();
11913 }
11914 }
11915
11916 if (t != TWORD || quoteflag) {
11917 goto out;
11918 }
11919
11920 /*
11921 * check for keywords
11922 */
11923 if (checkkwd & CHKKWD) {
11924 const char *const *pp;
11925
11926 pp = findkwd(wordtext);
11927 if (pp) {
11928 lasttoken = t = pp - tokname_array;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011929 TRACE(("keyword '%s' recognized\n", tokname_array[t] + 1));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011930 goto out;
11931 }
11932 }
11933
11934 if (checkkwd & CHKALIAS) {
11935#if ENABLE_ASH_ALIAS
11936 struct alias *ap;
11937 ap = lookupalias(wordtext, 1);
11938 if (ap != NULL) {
11939 if (*ap->val) {
11940 pushstring(ap->val, ap);
11941 }
11942 goto top;
11943 }
11944#endif
11945 }
11946 out:
11947 checkkwd = 0;
11948#if DEBUG
11949 if (!alreadyseen)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011950 TRACE(("token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011951 else
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011952 TRACE(("reread token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011953#endif
11954 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000011955}
11956
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011957static char
Denys Vlasenko7e661022015-02-05 21:00:17 +010011958nexttoken_ends_list(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011959{
11960 int t;
11961
11962 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011963 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011964 return tokname_array[t][0];
11965}
Eric Andersencb57d552001-06-28 07:25:16 +000011966
11967/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020011968 * Read and parse a command. Returns NODE_EOF on end of file.
11969 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000011970 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011971static union node *
11972parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000011973{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011974 int t;
Eric Andersencb57d552001-06-28 07:25:16 +000011975
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011976 tokpushback = 0;
11977 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011978 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011979 needprompt = 0;
11980 t = readtoken();
11981 if (t == TEOF)
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020011982 return NODE_EOF;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011983 if (t == TNL)
11984 return NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011985 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011986 return list(1);
11987}
11988
11989/*
11990 * Input any here documents.
11991 */
11992static void
11993parseheredoc(void)
11994{
11995 struct heredoc *here;
11996 union node *n;
11997
11998 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011999 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012000
12001 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012002 setprompt_if(needprompt, 2);
12003 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012004 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012005 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012006 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012007 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012008 n->narg.text = wordtext;
12009 n->narg.backquote = backquotelist;
12010 here->here->nhere.doc = n;
12011 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012012 }
Eric Andersencb57d552001-06-28 07:25:16 +000012013}
12014
12015
12016/*
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012017 * called by editline -- any expansions to the prompt should be added here.
Eric Andersencb57d552001-06-28 07:25:16 +000012018 */
Denis Vlasenko131ae172007-02-18 13:00:19 +000012019#if ENABLE_ASH_EXPAND_PRMT
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012020static const char *
12021expandstr(const char *ps)
12022{
12023 union node n;
12024
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000012025 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12026 * and token processing _can_ alter it (delete NULs etc). */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012027 setinputstring((char *)ps);
Denis Vlasenko46a53062007-09-24 18:30:02 +000012028 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012029 popfile();
12030
12031 n.narg.type = NARG;
12032 n.narg.next = NULL;
12033 n.narg.text = wordtext;
12034 n.narg.backquote = backquotelist;
12035
Ron Yorston549deab2015-05-18 09:57:51 +020012036 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012037 return stackblock();
12038}
12039#endif
12040
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012041/*
12042 * Execute a command or commands contained in a string.
12043 */
12044static int
12045evalstring(char *s, int mask)
Eric Andersenc470f442003-07-28 09:56:35 +000012046{
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012047 union node *n;
12048 struct stackmark smark;
12049 int skip;
12050
12051 setinputstring(s);
12052 setstackmark(&smark);
12053
12054 skip = 0;
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012055 while ((n = parsecmd(0)) != NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012056 evaltree(n, 0);
12057 popstackmark(&smark);
12058 skip = evalskip;
12059 if (skip)
12060 break;
12061 }
12062 popfile();
12063
12064 skip &= mask;
12065 evalskip = skip;
12066 return skip;
Eric Andersenc470f442003-07-28 09:56:35 +000012067}
12068
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012069/*
12070 * The eval command.
12071 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012072static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012073evalcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012074{
12075 char *p;
12076 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012077
Denis Vlasenko68404f12008-03-17 09:00:54 +000012078 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012079 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012080 argv += 2;
12081 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012082 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012083 for (;;) {
12084 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012085 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012086 if (p == NULL)
12087 break;
12088 STPUTC(' ', concat);
12089 }
12090 STPUTC('\0', concat);
12091 p = grabstackstr(concat);
12092 }
12093 evalstring(p, ~SKIPEVAL);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012094 }
12095 return exitstatus;
12096}
12097
12098/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012099 * Read and execute commands.
12100 * "Top" is nonzero for the top level command loop;
12101 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012102 */
12103static int
12104cmdloop(int top)
12105{
12106 union node *n;
12107 struct stackmark smark;
12108 int inter;
12109 int numeof = 0;
12110
12111 TRACE(("cmdloop(%d) called\n", top));
12112 for (;;) {
12113 int skip;
12114
12115 setstackmark(&smark);
12116#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012117 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020012118 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012119#endif
12120 inter = 0;
12121 if (iflag && top) {
12122 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012123 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012124 }
12125 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012126#if DEBUG
12127 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012128 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012129#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012130 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012131 if (!top || numeof >= 50)
12132 break;
12133 if (!stoppedjobs()) {
12134 if (!Iflag)
12135 break;
12136 out2str("\nUse \"exit\" to leave shell.\n");
12137 }
12138 numeof++;
12139 } else if (nflag == 0) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012140 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12141 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012142 numeof = 0;
12143 evaltree(n, 0);
12144 }
12145 popstackmark(&smark);
12146 skip = evalskip;
12147
12148 if (skip) {
12149 evalskip = 0;
12150 return skip & SKIPEVAL;
12151 }
12152 }
12153 return 0;
12154}
12155
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012156/*
12157 * Take commands from a file. To be compatible we should do a path
12158 * search for the file, which is necessary to find sub-commands.
12159 */
12160static char *
12161find_dot_file(char *name)
12162{
12163 char *fullname;
12164 const char *path = pathval();
12165 struct stat statb;
12166
12167 /* don't try this for absolute or relative paths */
12168 if (strchr(name, '/'))
12169 return name;
12170
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012171 /* IIRC standards do not say whether . is to be searched.
12172 * And it is even smaller this way, making it unconditional for now:
12173 */
12174 if (1) { /* ENABLE_ASH_BASH_COMPAT */
12175 fullname = name;
12176 goto try_cur_dir;
12177 }
12178
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012179 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012180 try_cur_dir:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012181 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12182 /*
12183 * Don't bother freeing here, since it will
12184 * be freed by the caller.
12185 */
12186 return fullname;
12187 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012188 if (fullname != name)
12189 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012190 }
12191
12192 /* not found in the PATH */
12193 ash_msg_and_raise_error("%s: not found", name);
12194 /* NOTREACHED */
12195}
12196
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012197static int FAST_FUNC
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012198dotcmd(int argc, char **argv)
12199{
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012200 char *fullname;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012201 struct strlist *sp;
12202 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012203
12204 for (sp = cmdenviron; sp; sp = sp->next)
Denis Vlasenko4222ae42007-02-25 02:37:49 +000012205 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012206
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012207 if (!argv[1]) {
12208 /* bash says: "bash: .: filename argument required" */
12209 return 2; /* bash compat */
12210 }
12211
Denys Vlasenkocd10dc42010-05-17 17:10:46 +020012212 /* "false; . empty_file; echo $?" should print 0, not 1: */
12213 exitstatus = 0;
12214
Denys Vlasenko091f8312013-03-17 14:25:22 +010012215 /* This aborts if file isn't found, which is POSIXly correct.
12216 * bash returns exitcode 1 instead.
12217 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012218 fullname = find_dot_file(argv[1]);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012219 argv += 2;
12220 argc -= 2;
12221 if (argc) { /* argc > 0, argv[0] != NULL */
12222 saveparam = shellparam;
12223 shellparam.malloced = 0;
12224 shellparam.nparam = argc;
12225 shellparam.p = argv;
12226 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012227
Denys Vlasenko091f8312013-03-17 14:25:22 +010012228 /* This aborts if file can't be opened, which is POSIXly correct.
12229 * bash returns exitcode 1 instead.
12230 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012231 setinputfile(fullname, INPUT_PUSH_FILE);
12232 commandname = fullname;
12233 cmdloop(0);
12234 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012235
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012236 if (argc) {
12237 freeparam(&shellparam);
12238 shellparam = saveparam;
12239 };
12240
Denys Vlasenkocd10dc42010-05-17 17:10:46 +020012241 return exitstatus;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012242}
12243
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012244static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012245exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012246{
12247 if (stoppedjobs())
12248 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012249 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012250 exitstatus = number(argv[1]);
12251 raise_exception(EXEXIT);
12252 /* NOTREACHED */
12253}
12254
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012255/*
12256 * Read a file containing shell functions.
12257 */
12258static void
12259readcmdfile(char *name)
12260{
12261 setinputfile(name, INPUT_PUSH_FILE);
12262 cmdloop(0);
12263 popfile();
12264}
12265
12266
Denis Vlasenkocc571512007-02-23 21:10:35 +000012267/* ============ find_command inplementation */
12268
12269/*
12270 * Resolve a command name. If you change this routine, you may have to
12271 * change the shellexec routine as well.
12272 */
12273static void
12274find_command(char *name, struct cmdentry *entry, int act, const char *path)
12275{
12276 struct tblentry *cmdp;
12277 int idx;
12278 int prev;
12279 char *fullname;
12280 struct stat statb;
12281 int e;
12282 int updatetbl;
12283 struct builtincmd *bcmd;
12284
12285 /* If name contains a slash, don't use PATH or hash table */
12286 if (strchr(name, '/') != NULL) {
12287 entry->u.index = -1;
12288 if (act & DO_ABS) {
12289 while (stat(name, &statb) < 0) {
12290#ifdef SYSV
12291 if (errno == EINTR)
12292 continue;
12293#endif
12294 entry->cmdtype = CMDUNKNOWN;
12295 return;
12296 }
12297 }
12298 entry->cmdtype = CMDNORMAL;
12299 return;
12300 }
12301
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012302/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012303
12304 updatetbl = (path == pathval());
12305 if (!updatetbl) {
12306 act |= DO_ALTPATH;
12307 if (strstr(path, "%builtin") != NULL)
12308 act |= DO_ALTBLTIN;
12309 }
12310
12311 /* If name is in the table, check answer will be ok */
12312 cmdp = cmdlookup(name, 0);
12313 if (cmdp != NULL) {
12314 int bit;
12315
12316 switch (cmdp->cmdtype) {
12317 default:
12318#if DEBUG
12319 abort();
12320#endif
12321 case CMDNORMAL:
12322 bit = DO_ALTPATH;
12323 break;
12324 case CMDFUNCTION:
12325 bit = DO_NOFUNC;
12326 break;
12327 case CMDBUILTIN:
12328 bit = DO_ALTBLTIN;
12329 break;
12330 }
12331 if (act & bit) {
12332 updatetbl = 0;
12333 cmdp = NULL;
12334 } else if (cmdp->rehash == 0)
12335 /* if not invalidated by cd, we're done */
12336 goto success;
12337 }
12338
12339 /* If %builtin not in path, check for builtin next */
12340 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012341 if (bcmd) {
12342 if (IS_BUILTIN_REGULAR(bcmd))
12343 goto builtin_success;
12344 if (act & DO_ALTPATH) {
12345 if (!(act & DO_ALTBLTIN))
12346 goto builtin_success;
12347 } else if (builtinloc <= 0) {
12348 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000012349 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012350 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000012351
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012352#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000012353 {
12354 int applet_no = find_applet_by_name(name);
12355 if (applet_no >= 0) {
12356 entry->cmdtype = CMDNORMAL;
12357 entry->u.index = -2 - applet_no;
12358 return;
12359 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012360 }
12361#endif
12362
Denis Vlasenkocc571512007-02-23 21:10:35 +000012363 /* We have to search path. */
12364 prev = -1; /* where to start */
12365 if (cmdp && cmdp->rehash) { /* doing a rehash */
12366 if (cmdp->cmdtype == CMDBUILTIN)
12367 prev = builtinloc;
12368 else
12369 prev = cmdp->param.index;
12370 }
12371
12372 e = ENOENT;
12373 idx = -1;
12374 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012375 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000012376 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012377 /* NB: code below will still use fullname
12378 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012379 idx++;
12380 if (pathopt) {
12381 if (prefix(pathopt, "builtin")) {
12382 if (bcmd)
12383 goto builtin_success;
12384 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000012385 }
12386 if ((act & DO_NOFUNC)
12387 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020012388 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012389 continue;
12390 }
12391 }
12392 /* if rehash, don't redo absolute path names */
12393 if (fullname[0] == '/' && idx <= prev) {
12394 if (idx < prev)
12395 continue;
12396 TRACE(("searchexec \"%s\": no change\n", name));
12397 goto success;
12398 }
12399 while (stat(fullname, &statb) < 0) {
12400#ifdef SYSV
12401 if (errno == EINTR)
12402 continue;
12403#endif
12404 if (errno != ENOENT && errno != ENOTDIR)
12405 e = errno;
12406 goto loop;
12407 }
12408 e = EACCES; /* if we fail, this will be the error */
12409 if (!S_ISREG(statb.st_mode))
12410 continue;
12411 if (pathopt) { /* this is a %func directory */
12412 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012413 /* NB: stalloc will return space pointed by fullname
12414 * (because we don't have any intervening allocations
12415 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012416 readcmdfile(fullname);
12417 cmdp = cmdlookup(name, 0);
12418 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12419 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12420 stunalloc(fullname);
12421 goto success;
12422 }
12423 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12424 if (!updatetbl) {
12425 entry->cmdtype = CMDNORMAL;
12426 entry->u.index = idx;
12427 return;
12428 }
12429 INT_OFF;
12430 cmdp = cmdlookup(name, 1);
12431 cmdp->cmdtype = CMDNORMAL;
12432 cmdp->param.index = idx;
12433 INT_ON;
12434 goto success;
12435 }
12436
12437 /* We failed. If there was an entry for this command, delete it */
12438 if (cmdp && updatetbl)
12439 delete_cmd_entry();
12440 if (act & DO_ERR)
12441 ash_msg("%s: %s", name, errmsg(e, "not found"));
12442 entry->cmdtype = CMDUNKNOWN;
12443 return;
12444
12445 builtin_success:
12446 if (!updatetbl) {
12447 entry->cmdtype = CMDBUILTIN;
12448 entry->u.cmd = bcmd;
12449 return;
12450 }
12451 INT_OFF;
12452 cmdp = cmdlookup(name, 1);
12453 cmdp->cmdtype = CMDBUILTIN;
12454 cmdp->param.cmd = bcmd;
12455 INT_ON;
12456 success:
12457 cmdp->rehash = 0;
12458 entry->cmdtype = cmdp->cmdtype;
12459 entry->u = cmdp->param;
12460}
12461
12462
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012463/* ============ trap.c */
Eric Andersenc470f442003-07-28 09:56:35 +000012464
Eric Andersencb57d552001-06-28 07:25:16 +000012465/*
Eric Andersencb57d552001-06-28 07:25:16 +000012466 * The trap builtin.
12467 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012468static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012469trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012470{
12471 char *action;
12472 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012473 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012474
Eric Andersenc470f442003-07-28 09:56:35 +000012475 nextopt(nullstr);
12476 ap = argptr;
12477 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012478 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012479 char *tr = trap_ptr[signo];
12480 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012481 /* note: bash adds "SIG", but only if invoked
12482 * as "bash". If called as "sh", or if set -o posix,
12483 * then it prints short signal names.
12484 * We are printing short names: */
12485 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012486 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012487 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012488 /* trap_ptr != trap only if we are in special-cased `trap` code.
12489 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012490 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012491 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000012492 }
12493 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012494 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012495 if (trap_ptr != trap) {
12496 free(trap_ptr);
12497 trap_ptr = trap;
12498 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012499 */
Eric Andersencb57d552001-06-28 07:25:16 +000012500 return 0;
12501 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012502
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012503 action = NULL;
12504 if (ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000012505 action = *ap++;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012506 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012507 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012508 signo = get_signum(*ap);
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012509 if (signo < 0) {
12510 /* Mimic bash message exactly */
12511 ash_msg("%s: invalid signal specification", *ap);
12512 exitcode = 1;
12513 goto next;
12514 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000012515 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000012516 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000012517 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000012518 action = NULL;
12519 else
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012520 action = ckstrdup(action);
Eric Andersencb57d552001-06-28 07:25:16 +000012521 }
Denis Vlasenko60818682007-09-28 22:07:23 +000012522 free(trap[signo]);
Denys Vlasenko238bf182010-05-18 15:49:07 +020012523 if (action)
12524 may_have_traps = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012525 trap[signo] = action;
12526 if (signo != 0)
12527 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012528 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012529 next:
Eric Andersencb57d552001-06-28 07:25:16 +000012530 ap++;
12531 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012532 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012533}
12534
Eric Andersenc470f442003-07-28 09:56:35 +000012535
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012536/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000012537
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012538#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012539static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012540helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012541{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000012542 unsigned col;
12543 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000012544
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020012545 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000012546 "Built-in commands:\n"
12547 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000012548 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012549 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000012550 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000012551 if (col > 60) {
12552 out1fmt("\n");
12553 col = 0;
12554 }
12555 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012556# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000012557 {
12558 const char *a = applet_names;
12559 while (*a) {
12560 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12561 if (col > 60) {
12562 out1fmt("\n");
12563 col = 0;
12564 }
12565 a += strlen(a) + 1;
Eric Andersenc470f442003-07-28 09:56:35 +000012566 }
12567 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012568# endif
Eric Andersenc470f442003-07-28 09:56:35 +000012569 out1fmt("\n\n");
12570 return EXIT_SUCCESS;
12571}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012572#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012573
Flemming Madsend96ffda2013-04-07 18:47:24 +020012574#if MAX_HISTORY
12575static int FAST_FUNC
12576historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12577{
12578 show_history(line_input_state);
12579 return EXIT_SUCCESS;
12580}
12581#endif
12582
Eric Andersencb57d552001-06-28 07:25:16 +000012583/*
Eric Andersencb57d552001-06-28 07:25:16 +000012584 * The export and readonly commands.
12585 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012586static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012587exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012588{
12589 struct var *vp;
12590 char *name;
12591 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012592 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020012593 char opt;
12594 int flag;
12595 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000012596
Denys Vlasenkod5275882012-10-01 13:41:17 +020012597 /* "readonly" in bash accepts, but ignores -n.
12598 * We do the same: it saves a conditional in nextopt's param.
12599 */
12600 flag_off = 0;
12601 while ((opt = nextopt("np")) != '\0') {
12602 if (opt == 'n')
12603 flag_off = VEXPORT;
12604 }
12605 flag = VEXPORT;
12606 if (argv[0][0] == 'r') {
12607 flag = VREADONLY;
12608 flag_off = 0; /* readonly ignores -n */
12609 }
12610 flag_off = ~flag_off;
12611
12612 /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */
12613 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012614 aptr = argptr;
12615 name = *aptr;
12616 if (name) {
12617 do {
12618 p = strchr(name, '=');
12619 if (p != NULL) {
12620 p++;
12621 } else {
12622 vp = *findvar(hashvar(name), name);
12623 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020012624 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012625 continue;
12626 }
Eric Andersencb57d552001-06-28 07:25:16 +000012627 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012628 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012629 } while ((name = *++aptr) != NULL);
12630 return 0;
12631 }
Eric Andersencb57d552001-06-28 07:25:16 +000012632 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012633
12634 /* No arguments. Show the list of exported or readonly vars.
12635 * -n is ignored.
12636 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012637 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012638 return 0;
12639}
12640
Eric Andersencb57d552001-06-28 07:25:16 +000012641/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012642 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000012643 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000012644static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012645unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012646{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012647 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000012648
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012649 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012650 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012651 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000012652}
12653
Eric Andersencb57d552001-06-28 07:25:16 +000012654/*
Eric Andersencb57d552001-06-28 07:25:16 +000012655 * The unset builtin command. We unset the function before we unset the
12656 * variable to allow a function to be unset when there is a readonly variable
12657 * with the same name.
12658 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012659static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012660unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012661{
12662 char **ap;
12663 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012664 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012665 int ret = 0;
12666
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012667 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000012668 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012669 }
Eric Andersencb57d552001-06-28 07:25:16 +000012670
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012671 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012672 if (flag != 'f') {
12673 i = unsetvar(*ap);
12674 ret |= i;
12675 if (!(i & 2))
12676 continue;
12677 }
12678 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012679 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012680 }
Eric Andersenc470f442003-07-28 09:56:35 +000012681 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012682}
12683
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012684static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012685 ' ', offsetof(struct tms, tms_utime),
12686 '\n', offsetof(struct tms, tms_stime),
12687 ' ', offsetof(struct tms, tms_cutime),
12688 '\n', offsetof(struct tms, tms_cstime),
12689 0
12690};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012691static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012692timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012693{
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012694 unsigned long clk_tck, s, t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012695 const unsigned char *p;
12696 struct tms buf;
12697
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020012698 clk_tck = bb_clk_tck();
Eric Andersencb57d552001-06-28 07:25:16 +000012699 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012700
12701 p = timescmd_str;
12702 do {
12703 t = *(clock_t *)(((char *) &buf) + p[1]);
12704 s = t / clk_tck;
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012705 t = t % clk_tck;
12706 out1fmt("%lum%lu.%03lus%c",
12707 s / 60, s % 60,
12708 (t * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012709 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012710 p += 2;
12711 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012712
Eric Andersencb57d552001-06-28 07:25:16 +000012713 return 0;
12714}
12715
Mike Frysinger98c52642009-04-02 10:02:37 +000012716#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000012717/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012718 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012719 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000012720 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012721 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012722 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012723static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012724letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012725{
Denis Vlasenko68404f12008-03-17 09:00:54 +000012726 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000012727
Denis Vlasenko68404f12008-03-17 09:00:54 +000012728 argv++;
12729 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000012730 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000012731 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012732 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012733 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000012734
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000012735 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000012736}
Eric Andersenc470f442003-07-28 09:56:35 +000012737#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012738
Eric Andersenc470f442003-07-28 09:56:35 +000012739/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012740 * The read builtin. Options:
12741 * -r Do not interpret '\' specially
12742 * -s Turn off echo (tty only)
12743 * -n NCHARS Read NCHARS max
12744 * -p PROMPT Display PROMPT on stderr (if input is from tty)
12745 * -t SECONDS Timeout after SECONDS (tty or pipe only)
12746 * -u FD Read from given FD instead of fd 0
Eric Andersenc470f442003-07-28 09:56:35 +000012747 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012748 * TODO: bash also has:
12749 * -a ARRAY Read into array[0],[1],etc
12750 * -d DELIM End on DELIM char, not newline
12751 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000012752 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012753static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012754readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012755{
Denys Vlasenko73067272010-01-12 22:11:24 +010012756 char *opt_n = NULL;
12757 char *opt_p = NULL;
12758 char *opt_t = NULL;
12759 char *opt_u = NULL;
12760 int read_flags = 0;
12761 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000012762 int i;
12763
Denys Vlasenko73067272010-01-12 22:11:24 +010012764 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000012765 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000012766 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010012767 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012768 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012769 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010012770 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012771 break;
12772 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010012773 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000012774 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012775 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010012776 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012777 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012778 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010012779 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000012780 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012781 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010012782 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012783 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012784 default:
12785 break;
12786 }
Eric Andersenc470f442003-07-28 09:56:35 +000012787 }
Paul Fox02eb9342005-09-07 16:56:02 +000012788
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020012789 /* "read -s" needs to save/restore termios, can't allow ^C
12790 * to jump out of it.
12791 */
12792 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020012793 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010012794 argptr,
12795 bltinlookup("IFS"), /* can be NULL */
12796 read_flags,
12797 opt_n,
12798 opt_p,
12799 opt_t,
12800 opt_u
12801 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020012802 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000012803
Denys Vlasenko73067272010-01-12 22:11:24 +010012804 if ((uintptr_t)r > 1)
12805 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000012806
Denys Vlasenko73067272010-01-12 22:11:24 +010012807 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000012808}
12809
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012810static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020012811umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012812{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020012813 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000012814
Eric Andersenc470f442003-07-28 09:56:35 +000012815 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000012816 int symbolic_mode = 0;
12817
12818 while (nextopt("S") != '\0') {
12819 symbolic_mode = 1;
12820 }
12821
Denis Vlasenkob012b102007-02-19 22:43:01 +000012822 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012823 mask = umask(0);
12824 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012825 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000012826
Denys Vlasenko6283f982015-10-07 16:56:20 +020012827 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012828 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020012829 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000012830 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020012831 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012832
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020012833 i = 2;
12834 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020012835 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000012836 *p++ = permuser[i];
12837 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020012838 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020012839 if (!(mask & 0400)) *p++ = 'r';
12840 if (!(mask & 0200)) *p++ = 'w';
12841 if (!(mask & 0100)) *p++ = 'x';
12842 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020012843 if (--i < 0)
12844 break;
Eric Andersenc470f442003-07-28 09:56:35 +000012845 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020012846 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020012847 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000012848 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020012849 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000012850 }
12851 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020012852 char *modestr = *argptr;
12853 /* numeric umasks are taken as-is */
12854 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
12855 if (!isdigit(modestr[0]))
12856 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020012857 mask = bb_parse_mode(modestr, mask);
12858 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020012859 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000012860 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020012861 if (!isdigit(modestr[0]))
12862 mask ^= 0777;
12863 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000012864 }
12865 return 0;
12866}
12867
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012868static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010012869ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012870{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010012871 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000012872}
12873
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012874/* ============ main() and helpers */
12875
12876/*
12877 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012878 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012879static void
12880exitshell(void)
12881{
12882 struct jmploc loc;
12883 char *p;
12884 int status;
12885
Denys Vlasenkobede2152011-09-04 16:12:33 +020012886#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
12887 save_history(line_input_state);
12888#endif
12889
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012890 status = exitstatus;
12891 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
12892 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000012893 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012894/* dash bug: it just does _exit(exitstatus) here
12895 * but we have to do setjobctl(0) first!
12896 * (bug is still not fixed in dash-0.5.3 - if you run dash
12897 * under Midnight Commander, on exit from dash MC is backgrounded) */
12898 status = exitstatus;
12899 goto out;
12900 }
12901 exception_handler = &loc;
12902 p = trap[0];
12903 if (p) {
12904 trap[0] = NULL;
12905 evalstring(p, 0);
Denys Vlasenko0800e3a2009-09-24 03:09:26 +020012906 free(p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012907 }
12908 flush_stdout_stderr();
12909 out:
12910 setjobctl(0);
12911 _exit(status);
12912 /* NOTREACHED */
12913}
12914
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000012915static void
12916init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012917{
12918 /* from input.c: */
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020012919 /* we will never free this */
12920 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012921
12922 /* from trap.c: */
12923 signal(SIGCHLD, SIG_DFL);
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010012924 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
12925 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
12926 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020012927 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012928
12929 /* from var.c: */
12930 {
12931 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012932 const char *p;
12933 struct stat st1, st2;
12934
12935 initvar();
12936 for (envp = environ; envp && *envp; envp++) {
12937 if (strchr(*envp, '=')) {
12938 setvareq(*envp, VEXPORT|VTEXTFIXED);
12939 }
12940 }
12941
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020012942 setvar0("PPID", utoa(getppid()));
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010012943#if ENABLE_ASH_BASH_COMPAT
12944 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010012945 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020012946 if (!lookupvar("HOSTNAME")) {
12947 struct utsname uts;
12948 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020012949 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020012950 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010012951#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012952 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010012953 if (p) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012954 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010012955 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
12956 ) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012957 p = '\0';
Denys Vlasenkob0b83432011-03-07 12:34:59 +010012958 }
12959 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012960 setpwd(p, 0);
12961 }
12962}
12963
Denys Vlasenkob0b83432011-03-07 12:34:59 +010012964
12965//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010012966//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010012967//usage:#define ash_full_usage "\n\n"
12968//usage: "Unix shell interpreter"
12969
12970//usage:#if ENABLE_FEATURE_SH_IS_ASH
12971//usage:# define sh_trivial_usage ash_trivial_usage
12972//usage:# define sh_full_usage ash_full_usage
12973//usage:#endif
12974//usage:#if ENABLE_FEATURE_BASH_IS_ASH
12975//usage:# define bash_trivial_usage ash_trivial_usage
12976//usage:# define bash_full_usage ash_full_usage
12977//usage:#endif
12978
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012979/*
12980 * Process the shell command line arguments.
12981 */
12982static void
Denis Vlasenko68404f12008-03-17 09:00:54 +000012983procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012984{
12985 int i;
12986 const char *xminusc;
12987 char **xargv;
12988
12989 xargv = argv;
12990 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012991 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012992 xargv++;
12993 for (i = 0; i < NOPTS; i++)
12994 optlist[i] = 2;
12995 argptr = xargv;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010012996 if (options(/*cmdline:*/ 1)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000012997 /* it already printed err message */
12998 raise_exception(EXERROR);
12999 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013000 xargv = argptr;
13001 xminusc = minusc;
13002 if (*xargv == NULL) {
13003 if (xminusc)
13004 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13005 sflag = 1;
13006 }
13007 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13008 iflag = 1;
13009 if (mflag == 2)
13010 mflag = iflag;
13011 for (i = 0; i < NOPTS; i++)
13012 if (optlist[i] == 2)
13013 optlist[i] = 0;
13014#if DEBUG == 2
13015 debug = 1;
13016#endif
13017 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13018 if (xminusc) {
13019 minusc = *xargv++;
13020 if (*xargv)
13021 goto setarg0;
13022 } else if (!sflag) {
13023 setinputfile(*xargv, 0);
13024 setarg0:
13025 arg0 = *xargv++;
13026 commandname = arg0;
13027 }
13028
13029 shellparam.p = xargv;
13030#if ENABLE_ASH_GETOPTS
13031 shellparam.optind = 1;
13032 shellparam.optoff = -1;
13033#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013034 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013035 while (*xargv) {
13036 shellparam.nparam++;
13037 xargv++;
13038 }
13039 optschanged();
13040}
13041
13042/*
13043 * Read /etc/profile or .profile.
13044 */
13045static void
13046read_profile(const char *name)
13047{
13048 int skip;
13049
13050 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13051 return;
13052 skip = cmdloop(0);
13053 popfile();
13054 if (skip)
13055 exitshell();
13056}
13057
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013058/*
13059 * This routine is called when an error or an interrupt occurs in an
13060 * interactive shell and control is returned to the main command loop.
13061 */
13062static void
13063reset(void)
13064{
13065 /* from eval.c: */
13066 evalskip = 0;
13067 loopnest = 0;
13068 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013069 g_parsefile->left_in_buffer = 0;
13070 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013071 popallfiles();
13072 /* from parser.c: */
13073 tokpushback = 0;
13074 checkkwd = 0;
13075 /* from redir.c: */
Denis Vlasenko34c73c42008-08-16 11:48:02 +000013076 clearredir(/*drop:*/ 0);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013077}
13078
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013079#if PROFILE
13080static short profile_buf[16384];
13081extern int etext();
13082#endif
13083
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013084/*
13085 * Main routine. We initialize things, parse the arguments, execute
13086 * profiles if we're a login shell, and then call cmdloop to execute
13087 * commands. The setjmp call sets up the location to jump to when an
13088 * exception occurs. When an exception occurs the variable "state"
13089 * is used to figure out how far we had gotten.
13090 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013091int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013092int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013093{
Mike Frysinger98c52642009-04-02 10:02:37 +000013094 const char *shinit;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013095 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013096 struct jmploc jmploc;
13097 struct stackmark smark;
13098
Denis Vlasenko01631112007-12-16 17:20:38 +000013099 /* Initialize global data */
13100 INIT_G_misc();
13101 INIT_G_memstack();
13102 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013103#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013104 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013105#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013106 INIT_G_cmdtable();
13107
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013108#if PROFILE
13109 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13110#endif
13111
13112#if ENABLE_FEATURE_EDITING
13113 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13114#endif
13115 state = 0;
13116 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013117 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013118 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013119
13120 reset();
13121
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013122 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013123 if (e == EXERROR)
13124 exitstatus = 2;
13125 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013126 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013127 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013128 }
13129 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020013130 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013131 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013132
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013133 popstackmark(&smark);
13134 FORCE_INT_ON; /* enable interrupts */
13135 if (s == 1)
13136 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013137 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013138 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013139 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013140 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013141 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013142 }
13143 exception_handler = &jmploc;
13144#if DEBUG
13145 opentrace();
Denis Vlasenko653d8e72009-03-19 21:59:35 +000013146 TRACE(("Shell args: "));
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013147 trace_puts_args(argv);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013148#endif
13149 rootpid = getpid();
13150
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013151 init();
13152 setstackmark(&smark);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013153 procargs(argv);
13154
Denys Vlasenko6088e132010-12-25 23:58:42 +010013155 if (argv[0] && argv[0][0] == '-')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013156 isloginsh = 1;
13157 if (isloginsh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013158 const char *hp;
13159
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013160 state = 1;
13161 read_profile("/etc/profile");
13162 state1:
13163 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013164 hp = lookupvar("HOME");
13165 if (hp) {
13166 hp = concat_path_file(hp, ".profile");
13167 read_profile(hp);
13168 free((char*)hp);
13169 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013170 }
13171 state2:
13172 state = 3;
13173 if (
13174#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013175 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013176#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013177 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013178 ) {
13179 shinit = lookupvar("ENV");
13180 if (shinit != NULL && *shinit != '\0') {
13181 read_profile(shinit);
13182 }
13183 }
13184 state3:
13185 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013186 if (minusc) {
13187 /* evalstring pushes parsefile stack.
13188 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013189 * is one of stacked source fds.
13190 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013191 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013192 // ^^ not necessary since now we special-case fd 0
13193 // in is_hidden_fd() to not be considered "hidden fd"
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013194 evalstring(minusc, 0);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013195 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013196
13197 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020013198#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013199 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013200 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013201 if (!hp) {
13202 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013203 if (hp) {
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013204 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013205 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013206 free((char*)hp);
13207 hp = lookupvar("HISTFILE");
13208 }
13209 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013210 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013211 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013212# if ENABLE_FEATURE_SH_HISTFILESIZE
13213 hp = lookupvar("HISTFILESIZE");
13214 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13215# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013216 }
13217#endif
13218 state4: /* XXX ??? - why isn't this before the "if" statement */
13219 cmdloop(1);
13220 }
13221#if PROFILE
13222 monitor(0);
13223#endif
13224#ifdef GPROF
13225 {
13226 extern void _mcleanup(void);
13227 _mcleanup();
13228 }
13229#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013230 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013231 exitshell();
13232 /* NOTREACHED */
13233}
13234
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013235
Eric Andersendf82f612001-06-28 07:46:40 +000013236/*-
13237 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013238 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013239 *
13240 * This code is derived from software contributed to Berkeley by
13241 * Kenneth Almquist.
13242 *
13243 * Redistribution and use in source and binary forms, with or without
13244 * modification, are permitted provided that the following conditions
13245 * are met:
13246 * 1. Redistributions of source code must retain the above copyright
13247 * notice, this list of conditions and the following disclaimer.
13248 * 2. Redistributions in binary form must reproduce the above copyright
13249 * notice, this list of conditions and the following disclaimer in the
13250 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013251 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013252 * may be used to endorse or promote products derived from this software
13253 * without specific prior written permission.
13254 *
13255 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13256 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13257 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13258 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13259 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13260 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13261 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13262 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13263 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13264 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13265 * SUCH DAMAGE.
13266 */