blob: f756428688cdeb055453aa5b6768aed2e1918393 [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 <setjmp.h>
41#include <fnmatch.h>
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020042#include <sys/times.h>
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020043#include <sys/utsname.h> /* for setting $HOSTNAME */
Denys Vlasenko73067272010-01-12 22:11:24 +010044
Denys Vlasenko20704f02011-03-23 17:59:27 +010045#include "busybox.h" /* for applet_names */
Denys Vlasenko20704f02011-03-23 17:59:27 +010046
Denys Vlasenko514b51d2016-10-01 14:33:08 +020047#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
48/* Bionic at least up to version 24 has no glob() */
49# undef ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenko08089c72016-10-01 14:47:52 +020050# define ENABLE_ASH_INTERNAL_GLOB 1
Denys Vlasenko514b51d2016-10-01 14:33:08 +020051#endif
52
53#if !ENABLE_ASH_INTERNAL_GLOB
54# include <glob.h>
55#endif
56
57#include "unicode.h"
Denys Vlasenko73067272010-01-12 22:11:24 +010058#include "shell_common.h"
Denys Vlasenko26777aa2010-11-22 23:49:10 +010059#if ENABLE_SH_MATH_SUPPORT
60# include "math.h"
61#endif
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020062#if ENABLE_ASH_RANDOM_SUPPORT
63# include "random.h"
Denys Vlasenko36df0482009-10-19 16:07:28 +020064#else
65# define CLEAR_RANDOM_T(rnd) ((void)0)
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020066#endif
Denis Vlasenko61befda2008-11-25 01:36:03 +000067
Denys Vlasenko1fcbff22010-06-26 02:40:08 +020068#include "NUM_APPLETS.h"
Denys Vlasenko14974842010-03-23 01:08:26 +010069#if NUM_APPLETS == 1
Denis Vlasenko61befda2008-11-25 01:36:03 +000070/* STANDALONE does not make sense, and won't compile */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020071# undef CONFIG_FEATURE_SH_STANDALONE
72# undef ENABLE_FEATURE_SH_STANDALONE
73# undef IF_FEATURE_SH_STANDALONE
Denys Vlasenko14974842010-03-23 01:08:26 +010074# undef IF_NOT_FEATURE_SH_STANDALONE
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020075# define ENABLE_FEATURE_SH_STANDALONE 0
76# define IF_FEATURE_SH_STANDALONE(...)
77# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
Eric Andersencb57d552001-06-28 07:25:16 +000078#endif
79
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000080#ifndef PIPE_BUF
Denis Vlasenko653d8e72009-03-19 21:59:35 +000081# define PIPE_BUF 4096 /* amount of buffering in a pipe */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000082#endif
83
Denys Vlasenko153fcaa2010-02-21 05:17:41 +010084#if !BB_MMU
Denis Vlasenko653d8e72009-03-19 21:59:35 +000085# error "Do not even bother, ash will not run on NOMMU machine"
Denis Vlasenkob012b102007-02-19 22:43:01 +000086#endif
87
Denys Vlasenko771f1992010-07-16 14:31:34 +020088//config:config ASH
89//config: bool "ash"
90//config: default y
91//config: depends on !NOMMU
92//config: help
93//config: Tha 'ash' shell adds about 60k in the default configuration and is
94//config: the most complete and most pedantically correct shell included with
95//config: busybox. This shell is actually a derivative of the Debian 'dash'
96//config: shell (by Herbert Xu), which was created by porting the 'ash' shell
97//config: (written by Kenneth Almquist) from NetBSD.
98//config:
Denys Vlasenko514b51d2016-10-01 14:33:08 +020099//config:config ASH_OPTIMIZE_FOR_SIZE
100//config: bool "Optimize for size instead of speed"
101//config: default y
102//config: depends on ASH
103//config: help
104//config: Compile ash for reduced size at the price of speed.
105//config:
106//config:config ASH_INTERNAL_GLOB
107//config: bool "Use internal glob() implementation"
108//config: default n
109//config: depends on ASH
110//config: help
111//config: Do not use glob() function from libc, use internal implementation.
112//config: Use this if you are getting "glob.h: No such file or directory"
113//config: or similar build errors.
114//config:
115//config:config ASH_RANDOM_SUPPORT
116//config: bool "Pseudorandom generator and $RANDOM variable"
117//config: default y
118//config: depends on ASH
119//config: help
120//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
121//config: Each read of "$RANDOM" will generate a new pseudorandom value.
122//config: You can reset the generator by using a specified start value.
123//config: After "unset RANDOM" the generator will switch off and this
124//config: variable will no longer have special treatment.
125//config:
126//config:config ASH_EXPAND_PRMT
127//config: bool "Expand prompt string"
128//config: default y
129//config: depends on ASH
130//config: help
131//config: "PS#" may contain volatile content, such as backquote commands.
132//config: This option recreates the prompt string from the environment
133//config: variable each time it is displayed.
134//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200135//config:config ASH_BASH_COMPAT
136//config: bool "bash-compatible extensions"
137//config: default y
138//config: depends on ASH
139//config: help
140//config: Enable bash-compatible extensions.
141//config:
Denys Vlasenko046341e2011-02-04 17:53:59 +0100142//config:config ASH_IDLE_TIMEOUT
143//config: bool "Idle timeout variable"
144//config: default n
145//config: depends on ASH
146//config: help
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100147//config: Enables bash-like auto-logout after $TMOUT seconds of idle time.
Denys Vlasenko046341e2011-02-04 17:53:59 +0100148//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200149//config:config ASH_JOB_CONTROL
150//config: bool "Job control"
151//config: default y
152//config: depends on ASH
153//config: help
154//config: Enable job control in the ash shell.
155//config:
156//config:config ASH_ALIAS
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100157//config: bool "Alias support"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200158//config: default y
159//config: depends on ASH
160//config: help
161//config: Enable alias support in the ash shell.
162//config:
163//config:config ASH_GETOPTS
164//config: bool "Builtin getopt to parse positional parameters"
165//config: default y
166//config: depends on ASH
167//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100168//config: Enable support for getopts builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200169//config:
170//config:config ASH_BUILTIN_ECHO
171//config: bool "Builtin version of 'echo'"
172//config: default y
173//config: depends on ASH
174//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100175//config: Enable support for echo builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200176//config:
177//config:config ASH_BUILTIN_PRINTF
178//config: bool "Builtin version of 'printf'"
179//config: default y
180//config: depends on ASH
181//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100182//config: Enable support for printf builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200183//config:
184//config:config ASH_BUILTIN_TEST
185//config: bool "Builtin version of 'test'"
186//config: default y
187//config: depends on ASH
188//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100189//config: Enable support for test builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200190//config:
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200191//config:config ASH_HELP
192//config: bool "help builtin"
193//config: default y
194//config: depends on ASH
195//config: help
196//config: Enable help builtin in ash.
197//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200198//config:config ASH_CMDCMD
199//config: bool "'command' command to override shell builtins"
200//config: default y
201//config: depends on ASH
202//config: help
203//config: Enable support for the ash 'command' builtin, which allows
204//config: you to run the specified command with the specified arguments,
205//config: even when there is an ash builtin command with the same name.
206//config:
207//config:config ASH_MAIL
208//config: bool "Check for new mail on interactive shells"
209//config: default n
210//config: depends on ASH
211//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100212//config: Enable "check for new mail" function in the ash shell.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200213//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200214
Denys Vlasenko20704f02011-03-23 17:59:27 +0100215//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
216//applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, sh))
217//applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, bash))
218
219//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
220//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
221
Denis Vlasenkob012b102007-02-19 22:43:01 +0000222
Denis Vlasenko01631112007-12-16 17:20:38 +0000223/* ============ Hash table sizes. Configurable. */
224
225#define VTABSIZE 39
226#define ATABSIZE 39
227#define CMDTABLESIZE 31 /* should be prime */
228
229
Denis Vlasenkob012b102007-02-19 22:43:01 +0000230/* ============ Shell options */
231
232static const char *const optletters_optnames[] = {
233 "e" "errexit",
234 "f" "noglob",
235 "I" "ignoreeof",
236 "i" "interactive",
237 "m" "monitor",
238 "n" "noexec",
239 "s" "stdin",
240 "x" "xtrace",
241 "v" "verbose",
242 "C" "noclobber",
243 "a" "allexport",
244 "b" "notify",
245 "u" "nounset",
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100246 "\0" "vi"
Michael Abbott359da5e2009-12-04 23:03:29 +0100247#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100248 ,"\0" "pipefail"
Michael Abbott359da5e2009-12-04 23:03:29 +0100249#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000250#if DEBUG
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000251 ,"\0" "nolog"
252 ,"\0" "debug"
Denis Vlasenkob012b102007-02-19 22:43:01 +0000253#endif
254};
255
Denys Vlasenko285ad152009-12-04 23:02:27 +0100256#define optletters(n) optletters_optnames[n][0]
257#define optnames(n) (optletters_optnames[n] + 1)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000258
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000259enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
Denis Vlasenkob012b102007-02-19 22:43:01 +0000260
Eric Andersenc470f442003-07-28 09:56:35 +0000261
Denis Vlasenkob012b102007-02-19 22:43:01 +0000262/* ============ Misc data */
Eric Andersenc470f442003-07-28 09:56:35 +0000263
Denys Vlasenkoea8b2522010-06-02 12:57:26 +0200264#define msg_illnum "Illegal number: %s"
Denis Vlasenkoaa744452007-02-23 01:04:22 +0000265
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +0000266/*
Eric Andersenc470f442003-07-28 09:56:35 +0000267 * We enclose jmp_buf in a structure so that we can declare pointers to
268 * jump locations. The global variable handler contains the location to
Denis Vlasenkof1733952009-03-19 23:21:55 +0000269 * jump to when an exception occurs, and the global variable exception_type
Eric Andersenaff114c2004-04-14 17:51:38 +0000270 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000271 * exception handlers, the user should save the value of handler on entry
272 * to an inner scope, set handler to point to a jmploc structure for the
273 * inner scope, and restore handler on exit from the scope.
274 */
Eric Andersenc470f442003-07-28 09:56:35 +0000275struct jmploc {
276 jmp_buf loc;
277};
Denis Vlasenko01631112007-12-16 17:20:38 +0000278
279struct globals_misc {
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200280 uint8_t exitstatus; /* exit status of last command */
281 uint8_t back_exitstatus;/* exit status of backquoted command */
282 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
283 int rootpid; /* pid of main shell */
Denis Vlasenko01631112007-12-16 17:20:38 +0000284 /* shell level: 0 for the main shell, 1 for its children, and so on */
285 int shlvl;
286#define rootshell (!shlvl)
287 char *minusc; /* argument to -c option */
288
289 char *curdir; // = nullstr; /* current working directory */
290 char *physdir; // = nullstr; /* physical working directory */
291
292 char *arg0; /* value of $0 */
293
294 struct jmploc *exception_handler;
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000295
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200296 volatile int suppress_int; /* counter */
297 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200298 volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +0200299 volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000300 smallint exception_type; /* kind of exception (0..5) */
Denis Vlasenko01631112007-12-16 17:20:38 +0000301 /* exceptions */
Eric Andersenc470f442003-07-28 09:56:35 +0000302#define EXINT 0 /* SIGINT received */
303#define EXERROR 1 /* a generic error */
Eric Andersenc470f442003-07-28 09:56:35 +0000304#define EXEXIT 4 /* exit the shell */
Eric Andersen2870d962001-07-02 17:27:21 +0000305
Denis Vlasenko01631112007-12-16 17:20:38 +0000306 smallint isloginsh;
Denis Vlasenkob07a4962008-06-22 13:16:23 +0000307 char nullstr[1]; /* zero length string */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000308
309 char optlist[NOPTS];
310#define eflag optlist[0]
311#define fflag optlist[1]
312#define Iflag optlist[2]
313#define iflag optlist[3]
314#define mflag optlist[4]
315#define nflag optlist[5]
316#define sflag optlist[6]
317#define xflag optlist[7]
318#define vflag optlist[8]
319#define Cflag optlist[9]
320#define aflag optlist[10]
321#define bflag optlist[11]
322#define uflag optlist[12]
323#define viflag optlist[13]
Michael Abbott359da5e2009-12-04 23:03:29 +0100324#if ENABLE_ASH_BASH_COMPAT
325# define pipefail optlist[14]
326#else
327# define pipefail 0
328#endif
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000329#if DEBUG
Michael Abbott359da5e2009-12-04 23:03:29 +0100330# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT]
331# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT]
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000332#endif
333
334 /* trap handler commands */
Denis Vlasenko01631112007-12-16 17:20:38 +0000335 /*
336 * Sigmode records the current value of the signal handlers for the various
337 * modes. A value of zero means that the current handler is not known.
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000338 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
Denis Vlasenko01631112007-12-16 17:20:38 +0000339 */
340 char sigmode[NSIG - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000341#define S_DFL 1 /* default signal handling (SIG_DFL) */
342#define S_CATCH 2 /* signal is caught */
343#define S_IGN 3 /* signal is ignored (SIG_IGN) */
Denys Vlasenkoe5814a52016-07-16 18:33:55 +0200344#define S_HARD_IGN 4 /* signal is ignored permanently */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000345
Denis Vlasenko01631112007-12-16 17:20:38 +0000346 /* indicates specified signal received */
Denis Vlasenko4b875702009-03-19 13:30:04 +0000347 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
Denys Vlasenko238bf182010-05-18 15:49:07 +0200348 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000349 char *trap[NSIG];
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200350 char **trap_ptr; /* used only by "trap hack" */
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000351
352 /* Rarely referenced stuff */
353#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200354 random_t random_gen;
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000355#endif
356 pid_t backgndpid; /* pid of last background process */
Denis Vlasenko01631112007-12-16 17:20:38 +0000357};
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000358extern struct globals_misc *const ash_ptr_to_globals_misc;
359#define G_misc (*ash_ptr_to_globals_misc)
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200360#define exitstatus (G_misc.exitstatus )
361#define back_exitstatus (G_misc.back_exitstatus )
362#define job_warning (G_misc.job_warning)
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000363#define rootpid (G_misc.rootpid )
364#define shlvl (G_misc.shlvl )
365#define minusc (G_misc.minusc )
366#define curdir (G_misc.curdir )
367#define physdir (G_misc.physdir )
368#define arg0 (G_misc.arg0 )
Denis Vlasenko01631112007-12-16 17:20:38 +0000369#define exception_handler (G_misc.exception_handler)
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000370#define exception_type (G_misc.exception_type )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200371#define suppress_int (G_misc.suppress_int )
372#define pending_int (G_misc.pending_int )
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200373#define got_sigchld (G_misc.got_sigchld )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200374#define pending_sig (G_misc.pending_sig )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000375#define isloginsh (G_misc.isloginsh )
376#define nullstr (G_misc.nullstr )
377#define optlist (G_misc.optlist )
378#define sigmode (G_misc.sigmode )
379#define gotsig (G_misc.gotsig )
Denys Vlasenko238bf182010-05-18 15:49:07 +0200380#define may_have_traps (G_misc.may_have_traps )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000381#define trap (G_misc.trap )
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200382#define trap_ptr (G_misc.trap_ptr )
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200383#define random_gen (G_misc.random_gen )
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000384#define backgndpid (G_misc.backgndpid )
Denis Vlasenko01631112007-12-16 17:20:38 +0000385#define INIT_G_misc() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000386 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
387 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +0000388 curdir = nullstr; \
389 physdir = nullstr; \
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200390 trap_ptr = trap; \
Denis Vlasenko01631112007-12-16 17:20:38 +0000391} while (0)
392
393
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000394/* ============ DEBUG */
395#if DEBUG
396static void trace_printf(const char *fmt, ...);
397static void trace_vprintf(const char *fmt, va_list va);
398# define TRACE(param) trace_printf param
399# define TRACEV(param) trace_vprintf param
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000400# define close(fd) do { \
401 int dfd = (fd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000402 if (close(dfd) < 0) \
Denys Vlasenko883cea42009-07-11 15:31:59 +0200403 bb_error_msg("bug on %d: closing %d(0x%x)", \
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000404 __LINE__, dfd, dfd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000405} while (0)
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000406#else
407# define TRACE(param)
408# define TRACEV(param)
409#endif
410
411
Denis Vlasenko559691a2008-10-05 18:39:31 +0000412/* ============ Utility functions */
Denys Vlasenko1961aea2013-02-26 00:36:53 +0100413#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
414#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
415
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200416static int
417isdigit_str9(const char *str)
Denis Vlasenko559691a2008-10-05 18:39:31 +0000418{
419 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
420 while (--maxlen && isdigit(*str))
421 str++;
422 return (*str == '\0');
423}
Denis Vlasenko01631112007-12-16 17:20:38 +0000424
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200425static const char *
426var_end(const char *var)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +0200427{
428 while (*var)
429 if (*var++ == '=')
430 break;
431 return var;
432}
433
Denis Vlasenko559691a2008-10-05 18:39:31 +0000434
435/* ============ Interrupts / exceptions */
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100436
437static void exitshell(void) NORETURN;
438
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000439/*
Eric Andersen2870d962001-07-02 17:27:21 +0000440 * These macros allow the user to suspend the handling of interrupt signals
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000441 * over a period of time. This is similar to SIGHOLD or to sigblock, but
Eric Andersen2870d962001-07-02 17:27:21 +0000442 * much more efficient and portable. (But hacking the kernel is so much
443 * more fun than worrying about efficiency and portability. :-))
444 */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000445#define INT_OFF do { \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200446 suppress_int++; \
Denys Vlasenkode892052016-10-02 01:49:13 +0200447 barrier(); \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000448} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000449
450/*
451 * Called to raise an exception. Since C doesn't include exceptions, we
452 * just do a longjmp to the exception handler. The type of exception is
Denis Vlasenko4b875702009-03-19 13:30:04 +0000453 * stored in the global variable "exception_type".
Denis Vlasenkob012b102007-02-19 22:43:01 +0000454 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000455static void raise_exception(int) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000456static void
457raise_exception(int e)
458{
459#if DEBUG
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000460 if (exception_handler == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000461 abort();
462#endif
463 INT_OFF;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000464 exception_type = e;
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000465 longjmp(exception_handler->loc, 1);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000466}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000467#if DEBUG
468#define raise_exception(e) do { \
469 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
470 raise_exception(e); \
471} while (0)
472#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000473
474/*
Denys Vlasenkof37e1152016-10-07 03:17:28 +0200475 * Called when a SIGINT is received. (If the user specifies
Denis Vlasenkob012b102007-02-19 22:43:01 +0000476 * that SIGINT is to be trapped or ignored using the trap builtin, then
477 * this routine is not called.) Suppressint is nonzero when interrupts
478 * are held using the INT_OFF macro. (The test for iflag is just
479 * defensive programming.)
480 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000481static void raise_interrupt(void) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000482static void
483raise_interrupt(void)
484{
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200485 pending_int = 0;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000486 /* Signal is not automatically unmasked after it is raised,
487 * do it ourself - unmask all signals */
Denis Vlasenko3f165fa2008-03-17 08:29:08 +0000488 sigprocmask_allsigs(SIG_UNBLOCK);
Denys Vlasenko238bf182010-05-18 15:49:07 +0200489 /* pending_sig = 0; - now done in signal_handler() */
Denis Vlasenko7c139b42007-03-21 20:17:27 +0000490
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200491 if (!(rootshell && iflag)) {
492 /* Kill ourself with SIGINT */
493 signal(SIGINT, SIG_DFL);
494 raise(SIGINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000495 }
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200496 /* bash: ^C even on empty command line sets $? */
497 exitstatus = SIGINT + 128;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200498 raise_exception(EXINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000499 /* NOTREACHED */
500}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000501#if DEBUG
502#define raise_interrupt() do { \
503 TRACE(("raising interrupt on line %d\n", __LINE__)); \
504 raise_interrupt(); \
505} while (0)
506#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000507
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000508static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000509int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000510{
Denys Vlasenkode892052016-10-02 01:49:13 +0200511 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200512 if (--suppress_int == 0 && pending_int) {
Denis Vlasenkob012b102007-02-19 22:43:01 +0000513 raise_interrupt();
514 }
515}
516#define INT_ON int_on()
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000517static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000518force_int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000519{
Denys Vlasenkode892052016-10-02 01:49:13 +0200520 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200521 suppress_int = 0;
522 if (pending_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000523 raise_interrupt();
524}
525#define FORCE_INT_ON force_int_on()
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000526
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200527#define SAVE_INT(v) ((v) = suppress_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000528
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000529#define RESTORE_INT(v) do { \
Denys Vlasenkode892052016-10-02 01:49:13 +0200530 barrier(); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200531 suppress_int = (v); \
532 if (suppress_int == 0 && pending_int) \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000533 raise_interrupt(); \
534} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000535
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000536
Denis Vlasenkobc54cff2007-02-23 01:05:52 +0000537/* ============ Stdout/stderr output */
Eric Andersenc470f442003-07-28 09:56:35 +0000538
Eric Andersenc470f442003-07-28 09:56:35 +0000539static void
Denis Vlasenkob012b102007-02-19 22:43:01 +0000540outstr(const char *p, FILE *file)
Denis Vlasenkoe5570da2007-02-19 22:41:55 +0000541{
Denis Vlasenkob012b102007-02-19 22:43:01 +0000542 INT_OFF;
543 fputs(p, file);
544 INT_ON;
545}
546
547static void
548flush_stdout_stderr(void)
549{
550 INT_OFF;
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100551 fflush_all();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000552 INT_ON;
553}
554
Denys Vlasenko9c541002015-10-07 15:44:36 +0200555/* Was called outcslow(c,FILE*), but c was always '\n' */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000556static void
Denys Vlasenko9c541002015-10-07 15:44:36 +0200557newline_and_flush(FILE *dest)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000558{
559 INT_OFF;
Denys Vlasenko9c541002015-10-07 15:44:36 +0200560 putc('\n', dest);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000561 fflush(dest);
562 INT_ON;
563}
564
565static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
566static int
567out1fmt(const char *fmt, ...)
568{
569 va_list ap;
570 int r;
571
572 INT_OFF;
573 va_start(ap, fmt);
574 r = vprintf(fmt, ap);
575 va_end(ap);
576 INT_ON;
577 return r;
578}
579
580static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
581static int
582fmtstr(char *outbuf, size_t length, const char *fmt, ...)
583{
584 va_list ap;
585 int ret;
586
587 va_start(ap, fmt);
588 INT_OFF;
589 ret = vsnprintf(outbuf, length, fmt, ap);
590 va_end(ap);
591 INT_ON;
592 return ret;
593}
594
595static void
596out1str(const char *p)
597{
598 outstr(p, stdout);
599}
600
601static void
602out2str(const char *p)
603{
604 outstr(p, stderr);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100605 flush_stdout_stderr();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000606}
607
608
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000609/* ============ Parser structures */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +0000610
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000611/* control characters in argument strings */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100612#define CTL_FIRST CTLESC
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200613#define CTLESC ((unsigned char)'\201') /* escape next character */
614#define CTLVAR ((unsigned char)'\202') /* variable defn */
615#define CTLENDVAR ((unsigned char)'\203')
616#define CTLBACKQ ((unsigned char)'\204')
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200617#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
618#define CTLENDARI ((unsigned char)'\207')
619#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100620#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000621
622/* variable substitution byte (follows CTLVAR) */
623#define VSTYPE 0x0f /* type of variable substitution */
624#define VSNUL 0x10 /* colon--treat the empty string as unset */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000625
626/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000627#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
628#define VSMINUS 0x2 /* ${var-text} */
629#define VSPLUS 0x3 /* ${var+text} */
630#define VSQUESTION 0x4 /* ${var?message} */
631#define VSASSIGN 0x5 /* ${var=text} */
632#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
633#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
634#define VSTRIMLEFT 0x8 /* ${var#pattern} */
635#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
636#define VSLENGTH 0xa /* ${#var} */
637#if ENABLE_ASH_BASH_COMPAT
638#define VSSUBSTR 0xc /* ${var:position:length} */
639#define VSREPLACE 0xd /* ${var/pattern/replacement} */
640#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
641#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000642
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000643static const char dolatstr[] ALIGN1 = {
Ron Yorston549deab2015-05-18 09:57:51 +0200644 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000645};
Ron Yorston549deab2015-05-18 09:57:51 +0200646#define DOLATSTRLEN 6
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000647
Denis Vlasenko559691a2008-10-05 18:39:31 +0000648#define NCMD 0
649#define NPIPE 1
650#define NREDIR 2
651#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000652#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000653#define NAND 5
654#define NOR 6
655#define NSEMI 7
656#define NIF 8
657#define NWHILE 9
658#define NUNTIL 10
659#define NFOR 11
660#define NCASE 12
661#define NCLIST 13
662#define NDEFUN 14
663#define NARG 15
664#define NTO 16
665#if ENABLE_ASH_BASH_COMPAT
666#define NTO2 17
667#endif
668#define NCLOBBER 18
669#define NFROM 19
670#define NFROMTO 20
671#define NAPPEND 21
672#define NTOFD 22
673#define NFROMFD 23
674#define NHERE 24
675#define NXHERE 25
676#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000677#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000678
679union node;
680
681struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000682 smallint type; /* Nxxxx */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000683 union node *assign;
684 union node *args;
685 union node *redirect;
686};
687
688struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000689 smallint type;
690 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000691 struct nodelist *cmdlist;
692};
693
694struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000695 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000696 union node *n;
697 union node *redirect;
698};
699
700struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000701 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000702 union node *ch1;
703 union node *ch2;
704};
705
706struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000707 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000708 union node *test;
709 union node *ifpart;
710 union node *elsepart;
711};
712
713struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000714 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000715 union node *args;
716 union node *body;
717 char *var;
718};
719
720struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000721 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000722 union node *expr;
723 union node *cases;
724};
725
726struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000727 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000728 union node *next;
729 union node *pattern;
730 union node *body;
731};
732
733struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000734 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000735 union node *next;
736 char *text;
737 struct nodelist *backquote;
738};
739
Denis Vlasenko559691a2008-10-05 18:39:31 +0000740/* nfile and ndup layout must match!
741 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
742 * that it is actually NTO2 (>&file), and change its type.
743 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000744struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000745 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000746 union node *next;
747 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000748 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000749 union node *fname;
750 char *expfname;
751};
752
753struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000754 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000755 union node *next;
756 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000757 int dupfd;
758 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000759 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000760};
761
762struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000763 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000764 union node *next;
765 int fd;
766 union node *doc;
767};
768
769struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000770 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000771 union node *com;
772};
773
774union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000775 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000776 struct ncmd ncmd;
777 struct npipe npipe;
778 struct nredir nredir;
779 struct nbinary nbinary;
780 struct nif nif;
781 struct nfor nfor;
782 struct ncase ncase;
783 struct nclist nclist;
784 struct narg narg;
785 struct nfile nfile;
786 struct ndup ndup;
787 struct nhere nhere;
788 struct nnot nnot;
789};
790
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200791/*
792 * NODE_EOF is returned by parsecmd when it encounters an end of file.
793 * It must be distinct from NULL.
794 */
795#define NODE_EOF ((union node *) -1L)
796
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000797struct nodelist {
798 struct nodelist *next;
799 union node *n;
800};
801
802struct funcnode {
803 int count;
804 union node n;
805};
806
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000807/*
808 * Free a parse tree.
809 */
810static void
811freefunc(struct funcnode *f)
812{
813 if (f && --f->count < 0)
814 free(f);
815}
816
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000817
818/* ============ Debugging output */
819
820#if DEBUG
821
822static FILE *tracefile;
823
824static void
825trace_printf(const char *fmt, ...)
826{
827 va_list va;
828
829 if (debug != 1)
830 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000831 if (DEBUG_TIME)
832 fprintf(tracefile, "%u ", (int) time(NULL));
833 if (DEBUG_PID)
834 fprintf(tracefile, "[%u] ", (int) getpid());
835 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200836 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000837 va_start(va, fmt);
838 vfprintf(tracefile, fmt, va);
839 va_end(va);
840}
841
842static void
843trace_vprintf(const char *fmt, va_list va)
844{
845 if (debug != 1)
846 return;
847 vfprintf(tracefile, fmt, va);
Denys Vlasenko474ed062016-10-30 18:30:29 +0100848 fprintf(tracefile, "\n");
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000849}
850
851static void
852trace_puts(const char *s)
853{
854 if (debug != 1)
855 return;
856 fputs(s, tracefile);
857}
858
859static void
860trace_puts_quoted(char *s)
861{
862 char *p;
863 char c;
864
865 if (debug != 1)
866 return;
867 putc('"', tracefile);
868 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100869 switch ((unsigned char)*p) {
870 case '\n': c = 'n'; goto backslash;
871 case '\t': c = 't'; goto backslash;
872 case '\r': c = 'r'; goto backslash;
873 case '\"': c = '\"'; goto backslash;
874 case '\\': c = '\\'; goto backslash;
875 case CTLESC: c = 'e'; goto backslash;
876 case CTLVAR: c = 'v'; goto backslash;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100877 case CTLBACKQ: c = 'q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000878 backslash:
879 putc('\\', tracefile);
880 putc(c, tracefile);
881 break;
882 default:
883 if (*p >= ' ' && *p <= '~')
884 putc(*p, tracefile);
885 else {
886 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +0100887 putc((*p >> 6) & 03, tracefile);
888 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000889 putc(*p & 07, tracefile);
890 }
891 break;
892 }
893 }
894 putc('"', tracefile);
895}
896
897static void
898trace_puts_args(char **ap)
899{
900 if (debug != 1)
901 return;
902 if (!*ap)
903 return;
904 while (1) {
905 trace_puts_quoted(*ap);
906 if (!*++ap) {
907 putc('\n', tracefile);
908 break;
909 }
910 putc(' ', tracefile);
911 }
912}
913
914static void
915opentrace(void)
916{
917 char s[100];
918#ifdef O_APPEND
919 int flags;
920#endif
921
922 if (debug != 1) {
923 if (tracefile)
924 fflush(tracefile);
925 /* leave open because libedit might be using it */
926 return;
927 }
928 strcpy(s, "./trace");
929 if (tracefile) {
930 if (!freopen(s, "a", tracefile)) {
931 fprintf(stderr, "Can't re-open %s\n", s);
932 debug = 0;
933 return;
934 }
935 } else {
936 tracefile = fopen(s, "a");
937 if (tracefile == NULL) {
938 fprintf(stderr, "Can't open %s\n", s);
939 debug = 0;
940 return;
941 }
942 }
943#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000944 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000945 if (flags >= 0)
946 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
947#endif
948 setlinebuf(tracefile);
949 fputs("\nTracing started.\n", tracefile);
950}
951
952static void
953indent(int amount, char *pfx, FILE *fp)
954{
955 int i;
956
957 for (i = 0; i < amount; i++) {
958 if (pfx && i == amount - 1)
959 fputs(pfx, fp);
960 putc('\t', fp);
961 }
962}
963
964/* little circular references here... */
965static void shtree(union node *n, int ind, char *pfx, FILE *fp);
966
967static void
968sharg(union node *arg, FILE *fp)
969{
970 char *p;
971 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100972 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000973
974 if (arg->type != NARG) {
975 out1fmt("<node type %d>\n", arg->type);
976 abort();
977 }
978 bqlist = arg->narg.backquote;
979 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100980 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000981 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -0700982 p++;
983 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000984 break;
985 case CTLVAR:
986 putc('$', fp);
987 putc('{', fp);
988 subtype = *++p;
989 if (subtype == VSLENGTH)
990 putc('#', fp);
991
Dan Fandrich77d48722010-09-07 23:38:28 -0700992 while (*p != '=') {
993 putc(*p, fp);
994 p++;
995 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000996
997 if (subtype & VSNUL)
998 putc(':', fp);
999
1000 switch (subtype & VSTYPE) {
1001 case VSNORMAL:
1002 putc('}', fp);
1003 break;
1004 case VSMINUS:
1005 putc('-', fp);
1006 break;
1007 case VSPLUS:
1008 putc('+', fp);
1009 break;
1010 case VSQUESTION:
1011 putc('?', fp);
1012 break;
1013 case VSASSIGN:
1014 putc('=', fp);
1015 break;
1016 case VSTRIMLEFT:
1017 putc('#', fp);
1018 break;
1019 case VSTRIMLEFTMAX:
1020 putc('#', fp);
1021 putc('#', fp);
1022 break;
1023 case VSTRIMRIGHT:
1024 putc('%', fp);
1025 break;
1026 case VSTRIMRIGHTMAX:
1027 putc('%', fp);
1028 putc('%', fp);
1029 break;
1030 case VSLENGTH:
1031 break;
1032 default:
1033 out1fmt("<subtype %d>", subtype);
1034 }
1035 break;
1036 case CTLENDVAR:
1037 putc('}', fp);
1038 break;
1039 case CTLBACKQ:
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001040 putc('$', fp);
1041 putc('(', fp);
1042 shtree(bqlist->n, -1, NULL, fp);
1043 putc(')', fp);
1044 break;
1045 default:
1046 putc(*p, fp);
1047 break;
1048 }
1049 }
1050}
1051
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001052static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001053shcmd(union node *cmd, FILE *fp)
1054{
1055 union node *np;
1056 int first;
1057 const char *s;
1058 int dftfd;
1059
1060 first = 1;
1061 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001062 if (!first)
1063 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001064 sharg(np, fp);
1065 first = 0;
1066 }
1067 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001068 if (!first)
1069 putc(' ', fp);
1070 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001071 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001072 case NTO: s = ">>"+1; dftfd = 1; break;
1073 case NCLOBBER: s = ">|"; dftfd = 1; break;
1074 case NAPPEND: s = ">>"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001075#if ENABLE_ASH_BASH_COMPAT
1076 case NTO2:
1077#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001078 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001079 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001080 case NFROMFD: s = "<&"; break;
1081 case NFROMTO: s = "<>"; break;
1082 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001083 }
1084 if (np->nfile.fd != dftfd)
1085 fprintf(fp, "%d", np->nfile.fd);
1086 fputs(s, fp);
1087 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1088 fprintf(fp, "%d", np->ndup.dupfd);
1089 } else {
1090 sharg(np->nfile.fname, fp);
1091 }
1092 first = 0;
1093 }
1094}
1095
1096static void
1097shtree(union node *n, int ind, char *pfx, FILE *fp)
1098{
1099 struct nodelist *lp;
1100 const char *s;
1101
1102 if (n == NULL)
1103 return;
1104
1105 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001106
1107 if (n == NODE_EOF) {
1108 fputs("<EOF>", fp);
1109 return;
1110 }
1111
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001112 switch (n->type) {
1113 case NSEMI:
1114 s = "; ";
1115 goto binop;
1116 case NAND:
1117 s = " && ";
1118 goto binop;
1119 case NOR:
1120 s = " || ";
1121 binop:
1122 shtree(n->nbinary.ch1, ind, NULL, fp);
1123 /* if (ind < 0) */
1124 fputs(s, fp);
1125 shtree(n->nbinary.ch2, ind, NULL, fp);
1126 break;
1127 case NCMD:
1128 shcmd(n, fp);
1129 if (ind >= 0)
1130 putc('\n', fp);
1131 break;
1132 case NPIPE:
1133 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001134 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001135 if (lp->next)
1136 fputs(" | ", fp);
1137 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001138 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001139 fputs(" &", fp);
1140 if (ind >= 0)
1141 putc('\n', fp);
1142 break;
1143 default:
1144 fprintf(fp, "<node type %d>", n->type);
1145 if (ind >= 0)
1146 putc('\n', fp);
1147 break;
1148 }
1149}
1150
1151static void
1152showtree(union node *n)
1153{
1154 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001155 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001156}
1157
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001158#endif /* DEBUG */
1159
1160
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001161/* ============ Parser data */
1162
1163/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001164 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1165 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001166struct strlist {
1167 struct strlist *next;
1168 char *text;
1169};
1170
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001171struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001172
Denis Vlasenkob012b102007-02-19 22:43:01 +00001173struct strpush {
1174 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001175 char *prev_string;
1176 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001177#if ENABLE_ASH_ALIAS
1178 struct alias *ap; /* if push was associated with an alias */
1179#endif
1180 char *string; /* remember the string since it may change */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001181
1182 /* Remember last two characters for pungetc. */
1183 int lastc[2];
1184
1185 /* Number of outstanding calls to pungetc. */
1186 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001187};
1188
1189struct parsefile {
1190 struct parsefile *prev; /* preceding file on stack */
1191 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001192 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001193 int left_in_line; /* number of chars left in this line */
1194 int left_in_buffer; /* number of chars left in this buffer past the line */
1195 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001196 char *buf; /* input buffer */
1197 struct strpush *strpush; /* for pushing strings at this level */
1198 struct strpush basestrpush; /* so pushing one is fast */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001199
1200 /* Remember last two characters for pungetc. */
1201 int lastc[2];
1202
1203 /* Number of outstanding calls to pungetc. */
1204 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001205};
1206
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001207static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001208static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001209static int startlinno; /* line # where last token started */
1210static char *commandname; /* currently executing command */
1211static struct strlist *cmdenviron; /* environment for builtin command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001212
1213
1214/* ============ Message printing */
1215
1216static void
1217ash_vmsg(const char *msg, va_list ap)
1218{
1219 fprintf(stderr, "%s: ", arg0);
1220 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001221 if (strcmp(arg0, commandname))
1222 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001223 if (!iflag || g_parsefile->pf_fd > 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001224 fprintf(stderr, "line %d: ", startlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001225 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001226 vfprintf(stderr, msg, ap);
Denys Vlasenko9c541002015-10-07 15:44:36 +02001227 newline_and_flush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001228}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001229
1230/*
1231 * Exverror is called to raise the error exception. If the second argument
1232 * is not NULL then error prints an error message using printf style
1233 * formatting. It then raises the error exception.
1234 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001235static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001236static void
1237ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001238{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001239#if DEBUG
1240 if (msg) {
Denys Vlasenko474ed062016-10-30 18:30:29 +01001241 TRACE(("ash_vmsg_and_raise(%d):", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001242 TRACEV((msg, ap));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001243 } else
Denys Vlasenko474ed062016-10-30 18:30:29 +01001244 TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001245 if (msg)
1246#endif
1247 ash_vmsg(msg, ap);
1248
1249 flush_stdout_stderr();
1250 raise_exception(cond);
1251 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001252}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001253
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001254static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001255static void
1256ash_msg_and_raise_error(const char *msg, ...)
1257{
1258 va_list ap;
1259
1260 va_start(ap, msg);
1261 ash_vmsg_and_raise(EXERROR, msg, ap);
1262 /* NOTREACHED */
1263 va_end(ap);
1264}
1265
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001266static void raise_error_syntax(const char *) NORETURN;
1267static void
1268raise_error_syntax(const char *msg)
1269{
1270 ash_msg_and_raise_error("syntax error: %s", msg);
1271 /* NOTREACHED */
1272}
1273
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001274static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001275static void
1276ash_msg_and_raise(int cond, const char *msg, ...)
1277{
1278 va_list ap;
1279
1280 va_start(ap, msg);
1281 ash_vmsg_and_raise(cond, msg, ap);
1282 /* NOTREACHED */
1283 va_end(ap);
1284}
1285
1286/*
1287 * error/warning routines for external builtins
1288 */
1289static void
1290ash_msg(const char *fmt, ...)
1291{
1292 va_list ap;
1293
1294 va_start(ap, fmt);
1295 ash_vmsg(fmt, ap);
1296 va_end(ap);
1297}
1298
1299/*
1300 * Return a string describing an error. The returned string may be a
1301 * pointer to a static buffer that will be overwritten on the next call.
1302 * Action describes the operation that got the error.
1303 */
1304static const char *
1305errmsg(int e, const char *em)
1306{
1307 if (e == ENOENT || e == ENOTDIR) {
1308 return em;
1309 }
1310 return strerror(e);
1311}
1312
1313
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001314/* ============ Memory allocation */
1315
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001316#if 0
1317/* I consider these wrappers nearly useless:
1318 * ok, they return you to nearest exception handler, but
1319 * how much memory do you leak in the process, making
1320 * memory starvation worse?
1321 */
1322static void *
1323ckrealloc(void * p, size_t nbytes)
1324{
1325 p = realloc(p, nbytes);
1326 if (!p)
1327 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1328 return p;
1329}
1330
1331static void *
1332ckmalloc(size_t nbytes)
1333{
1334 return ckrealloc(NULL, nbytes);
1335}
1336
1337static void *
1338ckzalloc(size_t nbytes)
1339{
1340 return memset(ckmalloc(nbytes), 0, nbytes);
1341}
1342
1343static char *
1344ckstrdup(const char *s)
1345{
1346 char *p = strdup(s);
1347 if (!p)
1348 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1349 return p;
1350}
1351#else
1352/* Using bbox equivalents. They exit if out of memory */
1353# define ckrealloc xrealloc
1354# define ckmalloc xmalloc
1355# define ckzalloc xzalloc
1356# define ckstrdup xstrdup
1357#endif
1358
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001359/*
1360 * It appears that grabstackstr() will barf with such alignments
1361 * because stalloc() will return a string allocated in a new stackblock.
1362 */
1363#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1364enum {
1365 /* Most machines require the value returned from malloc to be aligned
1366 * in some way. The following macro will get this right
1367 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001368 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001369 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001370 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001371};
1372
1373struct stack_block {
1374 struct stack_block *prev;
1375 char space[MINSIZE];
1376};
1377
1378struct stackmark {
1379 struct stack_block *stackp;
1380 char *stacknxt;
1381 size_t stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001382};
1383
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001384
Denis Vlasenko01631112007-12-16 17:20:38 +00001385struct globals_memstack {
1386 struct stack_block *g_stackp; // = &stackbase;
Denis Vlasenko01631112007-12-16 17:20:38 +00001387 char *g_stacknxt; // = stackbase.space;
1388 char *sstrend; // = stackbase.space + MINSIZE;
1389 size_t g_stacknleft; // = MINSIZE;
Denis Vlasenko01631112007-12-16 17:20:38 +00001390 struct stack_block stackbase;
1391};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001392extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1393#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001394#define g_stackp (G_memstack.g_stackp )
Denis Vlasenko01631112007-12-16 17:20:38 +00001395#define g_stacknxt (G_memstack.g_stacknxt )
1396#define sstrend (G_memstack.sstrend )
1397#define g_stacknleft (G_memstack.g_stacknleft)
Denis Vlasenko01631112007-12-16 17:20:38 +00001398#define stackbase (G_memstack.stackbase )
1399#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001400 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1401 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001402 g_stackp = &stackbase; \
1403 g_stacknxt = stackbase.space; \
1404 g_stacknleft = MINSIZE; \
1405 sstrend = stackbase.space + MINSIZE; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001406} while (0)
1407
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001408
Denis Vlasenko01631112007-12-16 17:20:38 +00001409#define stackblock() ((void *)g_stacknxt)
1410#define stackblocksize() g_stacknleft
1411
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001412/*
1413 * Parse trees for commands are allocated in lifo order, so we use a stack
1414 * to make this more efficient, and also to avoid all sorts of exception
1415 * handling code to handle interrupts in the middle of a parse.
1416 *
1417 * The size 504 was chosen because the Ultrix malloc handles that size
1418 * well.
1419 */
1420static void *
1421stalloc(size_t nbytes)
1422{
1423 char *p;
1424 size_t aligned;
1425
1426 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001427 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001428 size_t len;
1429 size_t blocksize;
1430 struct stack_block *sp;
1431
1432 blocksize = aligned;
1433 if (blocksize < MINSIZE)
1434 blocksize = MINSIZE;
1435 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1436 if (len < blocksize)
1437 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1438 INT_OFF;
1439 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001440 sp->prev = g_stackp;
1441 g_stacknxt = sp->space;
1442 g_stacknleft = blocksize;
1443 sstrend = g_stacknxt + blocksize;
1444 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001445 INT_ON;
1446 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001447 p = g_stacknxt;
1448 g_stacknxt += aligned;
1449 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001450 return p;
1451}
1452
Denis Vlasenko597906c2008-02-20 16:38:54 +00001453static void *
1454stzalloc(size_t nbytes)
1455{
1456 return memset(stalloc(nbytes), 0, nbytes);
1457}
1458
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001459static void
1460stunalloc(void *p)
1461{
1462#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001463 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001464 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001465 abort();
1466 }
1467#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001468 g_stacknleft += g_stacknxt - (char *)p;
1469 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001470}
1471
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001472/*
1473 * Like strdup but works with the ash stack.
1474 */
1475static char *
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02001476sstrdup(const char *p)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001477{
1478 size_t len = strlen(p) + 1;
1479 return memcpy(stalloc(len), p, len);
1480}
1481
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001482static inline void
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001483grabstackblock(size_t len)
1484{
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001485 stalloc(len);
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001486}
1487
1488static void
1489pushstackmark(struct stackmark *mark, size_t len)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001490{
Denis Vlasenko01631112007-12-16 17:20:38 +00001491 mark->stackp = g_stackp;
1492 mark->stacknxt = g_stacknxt;
1493 mark->stacknleft = g_stacknleft;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001494 grabstackblock(len);
1495}
1496
1497static void
1498setstackmark(struct stackmark *mark)
1499{
1500 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001501}
1502
1503static void
1504popstackmark(struct stackmark *mark)
1505{
1506 struct stack_block *sp;
1507
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001508 if (!mark->stackp)
1509 return;
1510
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001511 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001512 while (g_stackp != mark->stackp) {
1513 sp = g_stackp;
1514 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001515 free(sp);
1516 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001517 g_stacknxt = mark->stacknxt;
1518 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001519 sstrend = mark->stacknxt + mark->stacknleft;
1520 INT_ON;
1521}
1522
1523/*
1524 * When the parser reads in a string, it wants to stick the string on the
1525 * stack and only adjust the stack pointer when it knows how big the
1526 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1527 * of space on top of the stack and stackblocklen returns the length of
1528 * this block. Growstackblock will grow this space by at least one byte,
1529 * possibly moving it (like realloc). Grabstackblock actually allocates the
1530 * part of the block that has been used.
1531 */
1532static void
1533growstackblock(void)
1534{
1535 size_t newlen;
1536
Denis Vlasenko01631112007-12-16 17:20:38 +00001537 newlen = g_stacknleft * 2;
1538 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001539 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1540 if (newlen < 128)
1541 newlen += 128;
1542
Denis Vlasenko01631112007-12-16 17:20:38 +00001543 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001544 struct stack_block *sp;
1545 struct stack_block *prevstackp;
1546 size_t grosslen;
1547
1548 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001549 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001550 prevstackp = sp->prev;
1551 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1552 sp = ckrealloc(sp, grosslen);
1553 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001554 g_stackp = sp;
1555 g_stacknxt = sp->space;
1556 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001557 sstrend = sp->space + newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001558 INT_ON;
1559 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001560 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001561 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001562 char *p = stalloc(newlen);
1563
1564 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001565 g_stacknxt = memcpy(p, oldspace, oldlen);
1566 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001567 }
1568}
1569
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001570/*
1571 * The following routines are somewhat easier to use than the above.
1572 * The user declares a variable of type STACKSTR, which may be declared
1573 * to be a register. The macro STARTSTACKSTR initializes things. Then
1574 * the user uses the macro STPUTC to add characters to the string. In
1575 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1576 * grown as necessary. When the user is done, she can just leave the
1577 * string there and refer to it using stackblock(). Or she can allocate
1578 * the space for it using grabstackstr(). If it is necessary to allow
1579 * someone else to use the stack temporarily and then continue to grow
1580 * the string, the user should use grabstack to allocate the space, and
1581 * then call ungrabstr(p) to return to the previous mode of operation.
1582 *
1583 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1584 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1585 * is space for at least one character.
1586 */
1587static void *
1588growstackstr(void)
1589{
1590 size_t len = stackblocksize();
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001591 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001592 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001593}
1594
1595/*
1596 * Called from CHECKSTRSPACE.
1597 */
1598static char *
1599makestrspace(size_t newlen, char *p)
1600{
Denis Vlasenko01631112007-12-16 17:20:38 +00001601 size_t len = p - g_stacknxt;
Denys Vlasenko53d6e032016-09-30 11:24:12 +02001602 size_t size;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001603
1604 for (;;) {
1605 size_t nleft;
1606
1607 size = stackblocksize();
1608 nleft = size - len;
1609 if (nleft >= newlen)
1610 break;
1611 growstackblock();
1612 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001613 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001614}
1615
1616static char *
1617stack_nputstr(const char *s, size_t n, char *p)
1618{
1619 p = makestrspace(n, p);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001620 p = (char *)memcpy(p, s, n) + n;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001621 return p;
1622}
1623
1624static char *
1625stack_putstr(const char *s, char *p)
1626{
1627 return stack_nputstr(s, strlen(s), p);
1628}
1629
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001630static char *
1631_STPUTC(int c, char *p)
1632{
1633 if (p == sstrend)
1634 p = growstackstr();
1635 *p++ = c;
1636 return p;
1637}
1638
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001639#define STARTSTACKSTR(p) ((p) = stackblock())
1640#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001641#define CHECKSTRSPACE(n, p) do { \
1642 char *q = (p); \
1643 size_t l = (n); \
1644 size_t m = sstrend - q; \
1645 if (l > m) \
1646 (p) = makestrspace(l, q); \
1647} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001648#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001649#define STACKSTRNUL(p) do { \
1650 if ((p) == sstrend) \
1651 (p) = growstackstr(); \
1652 *(p) = '\0'; \
1653} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001654#define STUNPUTC(p) (--(p))
1655#define STTOPC(p) ((p)[-1])
1656#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001657
1658#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001659#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001660#define stackstrend() ((void *)sstrend)
1661
1662
1663/* ============ String helpers */
1664
1665/*
1666 * prefix -- see if pfx is a prefix of string.
1667 */
1668static char *
1669prefix(const char *string, const char *pfx)
1670{
1671 while (*pfx) {
1672 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001673 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001674 }
1675 return (char *) string;
1676}
1677
1678/*
1679 * Check for a valid number. This should be elsewhere.
1680 */
1681static int
1682is_number(const char *p)
1683{
1684 do {
1685 if (!isdigit(*p))
1686 return 0;
1687 } while (*++p != '\0');
1688 return 1;
1689}
1690
1691/*
1692 * Convert a string of digits to an integer, printing an error message on
1693 * failure.
1694 */
1695static int
1696number(const char *s)
1697{
1698 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001699 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001700 return atoi(s);
1701}
1702
1703/*
1704 * Produce a possibly single quoted string suitable as input to the shell.
1705 * The return string is allocated on the stack.
1706 */
1707static char *
1708single_quote(const char *s)
1709{
1710 char *p;
1711
1712 STARTSTACKSTR(p);
1713
1714 do {
1715 char *q;
1716 size_t len;
1717
1718 len = strchrnul(s, '\'') - s;
1719
1720 q = p = makestrspace(len + 3, p);
1721
1722 *q++ = '\'';
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001723 q = (char *)memcpy(q, s, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001724 *q++ = '\'';
1725 s += len;
1726
1727 STADJUST(q - p, p);
1728
Denys Vlasenkocd716832009-11-28 22:14:02 +01001729 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001730 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001731 len = 0;
1732 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001733
1734 q = p = makestrspace(len + 3, p);
1735
1736 *q++ = '"';
Denys Vlasenkocd716832009-11-28 22:14:02 +01001737 q = (char *)memcpy(q, s - len, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001738 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001739
1740 STADJUST(q - p, p);
1741 } while (*s);
1742
Denys Vlasenkocd716832009-11-28 22:14:02 +01001743 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001744
1745 return stackblock();
1746}
1747
1748
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001749/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001750
1751static char **argptr; /* argument list for builtin commands */
1752static char *optionarg; /* set by nextopt (like getopt) */
1753static char *optptr; /* used by nextopt */
1754
1755/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001756 * XXX - should get rid of. Have all builtins use getopt(3).
1757 * The library getopt must have the BSD extension static variable
1758 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001759 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001760 * Standard option processing (a la getopt) for builtin routines.
1761 * The only argument that is passed to nextopt is the option string;
1762 * the other arguments are unnecessary. It returns the character,
1763 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001764 */
1765static int
1766nextopt(const char *optstring)
1767{
1768 char *p;
1769 const char *q;
1770 char c;
1771
1772 p = optptr;
1773 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001774 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001775 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001776 if (p == NULL)
1777 return '\0';
1778 if (*p != '-')
1779 return '\0';
1780 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001781 return '\0';
1782 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001783 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001784 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001785 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001786 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001787 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001788 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001789 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001790 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001791 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001792 if (*++q == ':')
1793 q++;
1794 }
1795 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001796 if (*p == '\0') {
1797 p = *argptr++;
1798 if (p == NULL)
1799 ash_msg_and_raise_error("no arg for -%c option", c);
1800 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001801 optionarg = p;
1802 p = NULL;
1803 }
1804 optptr = p;
1805 return c;
1806}
1807
1808
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001809/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001810
Denis Vlasenko01631112007-12-16 17:20:38 +00001811/*
1812 * The parsefile structure pointed to by the global variable parsefile
1813 * contains information about the current file being read.
1814 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001815struct shparam {
1816 int nparam; /* # of positional parameters (without $0) */
1817#if ENABLE_ASH_GETOPTS
1818 int optind; /* next parameter to be processed by getopts */
1819 int optoff; /* used by getopts */
1820#endif
1821 unsigned char malloced; /* if parameter list dynamically allocated */
1822 char **p; /* parameter list */
1823};
1824
1825/*
1826 * Free the list of positional parameters.
1827 */
1828static void
1829freeparam(volatile struct shparam *param)
1830{
Denis Vlasenko01631112007-12-16 17:20:38 +00001831 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001832 char **ap, **ap1;
1833 ap = ap1 = param->p;
1834 while (*ap)
1835 free(*ap++);
1836 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001837 }
1838}
1839
1840#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001841static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001842#endif
1843
1844struct var {
1845 struct var *next; /* next entry in hash list */
1846 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001847 const char *var_text; /* name=value */
1848 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001849 /* the variable gets set/unset */
1850};
1851
1852struct localvar {
1853 struct localvar *next; /* next local variable in list */
1854 struct var *vp; /* the variable that was made local */
1855 int flags; /* saved flags */
1856 const char *text; /* saved text */
1857};
1858
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001859/* flags */
1860#define VEXPORT 0x01 /* variable is exported */
1861#define VREADONLY 0x02 /* variable cannot be modified */
1862#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1863#define VTEXTFIXED 0x08 /* text is statically allocated */
1864#define VSTACK 0x10 /* text is allocated on the stack */
1865#define VUNSET 0x20 /* the variable is not set */
1866#define VNOFUNC 0x40 /* don't call the callback function */
1867#define VNOSET 0x80 /* do not set variable - just readonly test */
1868#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001869#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001870# define VDYNAMIC 0x200 /* dynamic variable */
1871#else
1872# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001873#endif
1874
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001875
Denis Vlasenko01631112007-12-16 17:20:38 +00001876/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001877#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001878static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001879change_lc_all(const char *value)
1880{
1881 if (value && *value != '\0')
1882 setlocale(LC_ALL, value);
1883}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001884static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001885change_lc_ctype(const char *value)
1886{
1887 if (value && *value != '\0')
1888 setlocale(LC_CTYPE, value);
1889}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001890#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001891#if ENABLE_ASH_MAIL
1892static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01001893static void changemail(const char *var_value) FAST_FUNC;
1894#else
1895# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001896#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001897static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001898#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001899static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001900#endif
1901
Denis Vlasenko01631112007-12-16 17:20:38 +00001902static const struct {
1903 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001904 const char *var_text;
1905 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00001906} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02001907 /*
1908 * Note: VEXPORT would not work correctly here for NOFORK applets:
1909 * some environment strings may be constant.
1910 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001911 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001912#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001913 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
1914 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001915#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001916 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1917 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1918 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1919 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001920#if ENABLE_ASH_GETOPTS
Denys Vlasenkoe627ac92016-09-30 14:36:59 +02001921 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001922#endif
1923#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001924 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001925#endif
1926#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001927 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
1928 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001929#endif
1930#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001931 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001932#endif
1933};
1934
Denis Vlasenko0b769642008-07-24 07:54:57 +00001935struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00001936
1937struct globals_var {
1938 struct shparam shellparam; /* $@ current positional parameters */
1939 struct redirtab *redirlist;
Denis Vlasenko01631112007-12-16 17:20:38 +00001940 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1941 struct var *vartab[VTABSIZE];
1942 struct var varinit[ARRAY_SIZE(varinit_data)];
1943};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001944extern struct globals_var *const ash_ptr_to_globals_var;
1945#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00001946#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00001947//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00001948#define preverrout_fd (G_var.preverrout_fd)
1949#define vartab (G_var.vartab )
1950#define varinit (G_var.varinit )
1951#define INIT_G_var() do { \
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00001952 unsigned i; \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001953 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1954 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001955 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001956 varinit[i].flags = varinit_data[i].flags; \
1957 varinit[i].var_text = varinit_data[i].var_text; \
1958 varinit[i].var_func = varinit_data[i].var_func; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001959 } \
1960} while (0)
1961
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001962#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001963#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001964# define vmail (&vifs)[1]
1965# define vmpath (&vmail)[1]
1966# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001967#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001968# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001969#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001970#define vps1 (&vpath)[1]
1971#define vps2 (&vps1)[1]
1972#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001973#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001974# define voptind (&vps4)[1]
1975# if ENABLE_ASH_RANDOM_SUPPORT
1976# define vrandom (&voptind)[1]
1977# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001978#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001979# if ENABLE_ASH_RANDOM_SUPPORT
1980# define vrandom (&vps4)[1]
1981# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001982#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001983
1984/*
1985 * The following macros access the values of the above variables.
1986 * They have to skip over the name. They return the null string
1987 * for unset variables.
1988 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001989#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001990#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001991#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001992# define mailval() (vmail.var_text + 5)
1993# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001994# define mpathset() ((vmpath.flags & VUNSET) == 0)
1995#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001996#define pathval() (vpath.var_text + 5)
1997#define ps1val() (vps1.var_text + 4)
1998#define ps2val() (vps2.var_text + 4)
1999#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002000#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002001# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002002#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002003
Denis Vlasenko01631112007-12-16 17:20:38 +00002004#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002005static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002006getoptsreset(const char *value)
2007{
Denys Vlasenkoa513bf32016-10-26 02:03:37 +02002008 shellparam.optind = number(value) ?: 1;
Denis Vlasenko01631112007-12-16 17:20:38 +00002009 shellparam.optoff = -1;
2010}
2011#endif
2012
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002013/*
2014 * Compares two strings up to the first = or '\0'. The first
2015 * string must be terminated by '='; the second may be terminated by
2016 * either '=' or '\0'.
2017 */
2018static int
2019varcmp(const char *p, const char *q)
2020{
2021 int c, d;
2022
2023 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002024 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002025 goto out;
2026 p++;
2027 q++;
2028 }
2029 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002030 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002031 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002032 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002033 out:
2034 return c - d;
2035}
2036
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002037/*
2038 * Find the appropriate entry in the hash table from the name.
2039 */
2040static struct var **
2041hashvar(const char *p)
2042{
2043 unsigned hashval;
2044
2045 hashval = ((unsigned char) *p) << 4;
2046 while (*p && *p != '=')
2047 hashval += (unsigned char) *p++;
2048 return &vartab[hashval % VTABSIZE];
2049}
2050
2051static int
2052vpcmp(const void *a, const void *b)
2053{
2054 return varcmp(*(const char **)a, *(const char **)b);
2055}
2056
2057/*
2058 * This routine initializes the builtin variables.
2059 */
2060static void
2061initvar(void)
2062{
2063 struct var *vp;
2064 struct var *end;
2065 struct var **vpp;
2066
2067 /*
2068 * PS1 depends on uid
2069 */
2070#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002071 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002072#else
2073 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002074 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002075#endif
2076 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002077 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002078 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002079 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002080 vp->next = *vpp;
2081 *vpp = vp;
2082 } while (++vp < end);
2083}
2084
2085static struct var **
2086findvar(struct var **vpp, const char *name)
2087{
2088 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002089 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002090 break;
2091 }
2092 }
2093 return vpp;
2094}
2095
2096/*
2097 * Find the value of a variable. Returns NULL if not set.
2098 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002099static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002100lookupvar(const char *name)
2101{
2102 struct var *v;
2103
2104 v = *findvar(hashvar(name), name);
2105 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002106#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002107 /*
2108 * Dynamic variables are implemented roughly the same way they are
2109 * in bash. Namely, they're "special" so long as they aren't unset.
2110 * As soon as they're unset, they're no longer dynamic, and dynamic
2111 * lookup will no longer happen at that point. -- PFM.
2112 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002113 if (v->flags & VDYNAMIC)
2114 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002115#endif
2116 if (!(v->flags & VUNSET))
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002117 return var_end(v->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002118 }
2119 return NULL;
2120}
2121
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02002122static void
2123reinit_unicode_for_ash(void)
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002124{
2125 /* Unicode support should be activated even if LANG is set
2126 * _during_ shell execution, not only if it was set when
2127 * shell was started. Therefore, re-check LANG every time:
2128 */
2129 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2130 || ENABLE_UNICODE_USING_LOCALE
2131 ) {
2132 const char *s = lookupvar("LC_ALL");
2133 if (!s) s = lookupvar("LC_CTYPE");
2134 if (!s) s = lookupvar("LANG");
2135 reinit_unicode(s);
2136 }
2137}
2138
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002139/*
2140 * Search the environment of a builtin command.
2141 */
Mike Frysinger98c52642009-04-02 10:02:37 +00002142static const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002143bltinlookup(const char *name)
2144{
2145 struct strlist *sp;
2146
2147 for (sp = cmdenviron; sp; sp = sp->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002148 if (varcmp(sp->text, name) == 0)
2149 return var_end(sp->text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002150 }
2151 return lookupvar(name);
2152}
2153
2154/*
2155 * Same as setvar except that the variable and value are passed in
2156 * the first argument as name=value. Since the first argument will
2157 * be actually stored in the table, it should not be a string that
2158 * will go away.
2159 * Called with interrupts off.
2160 */
2161static void
2162setvareq(char *s, int flags)
2163{
2164 struct var *vp, **vpp;
2165
2166 vpp = hashvar(s);
2167 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2168 vp = *findvar(vpp, s);
2169 if (vp) {
2170 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2171 const char *n;
2172
2173 if (flags & VNOSAVE)
2174 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002175 n = vp->var_text;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02002176 exitstatus = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002177 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2178 }
2179
2180 if (flags & VNOSET)
2181 return;
2182
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002183 if (vp->var_func && !(flags & VNOFUNC))
2184 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002185
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002186 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2187 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002188
2189 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2190 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002191 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002192 if (flags & VNOSET)
2193 return;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002194 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002195 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002196 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002197 *vpp = vp;
2198 }
2199 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2200 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002201 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002202 vp->flags = flags;
2203}
2204
2205/*
2206 * Set the value of a variable. The flags argument is ored with the
2207 * flags of the variable. If val is NULL, the variable is unset.
2208 */
2209static void
2210setvar(const char *name, const char *val, int flags)
2211{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002212 const char *q;
2213 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002214 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002215 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002216 size_t vallen;
2217
2218 q = endofname(name);
2219 p = strchrnul(q, '=');
2220 namelen = p - name;
2221 if (!namelen || p != q)
2222 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2223 vallen = 0;
2224 if (val == NULL) {
2225 flags |= VUNSET;
2226 } else {
2227 vallen = strlen(val);
2228 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002229
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002230 INT_OFF;
2231 nameeq = ckmalloc(namelen + vallen + 2);
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002232 p = memcpy(nameeq, name, namelen) + namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002233 if (val) {
2234 *p++ = '=';
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002235 p = memcpy(p, val, vallen) + vallen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002236 }
2237 *p = '\0';
2238 setvareq(nameeq, flags | VNOSAVE);
2239 INT_ON;
2240}
2241
Denys Vlasenko03dad222010-01-12 23:29:57 +01002242static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002243setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002244{
2245 setvar(name, val, 0);
2246}
2247
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002248/*
2249 * Unset the specified variable.
2250 */
2251static int
2252unsetvar(const char *s)
2253{
2254 struct var **vpp;
2255 struct var *vp;
2256 int retval;
2257
2258 vpp = findvar(hashvar(s), s);
2259 vp = *vpp;
2260 retval = 2;
2261 if (vp) {
2262 int flags = vp->flags;
2263
2264 retval = 1;
2265 if (flags & VREADONLY)
2266 goto out;
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002267#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002268 vp->flags &= ~VDYNAMIC;
2269#endif
2270 if (flags & VUNSET)
2271 goto ok;
2272 if ((flags & VSTRFIXED) == 0) {
2273 INT_OFF;
2274 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002275 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002276 *vpp = vp->next;
2277 free(vp);
2278 INT_ON;
2279 } else {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002280 setvar0(s, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002281 vp->flags &= ~VEXPORT;
2282 }
2283 ok:
2284 retval = 0;
2285 }
2286 out:
2287 return retval;
2288}
2289
2290/*
2291 * Process a linked list of variable assignments.
2292 */
2293static void
2294listsetvar(struct strlist *list_set_var, int flags)
2295{
2296 struct strlist *lp = list_set_var;
2297
2298 if (!lp)
2299 return;
2300 INT_OFF;
2301 do {
2302 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002303 lp = lp->next;
2304 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002305 INT_ON;
2306}
2307
2308/*
2309 * Generate a list of variables satisfying the given conditions.
2310 */
2311static char **
2312listvars(int on, int off, char ***end)
2313{
2314 struct var **vpp;
2315 struct var *vp;
2316 char **ep;
2317 int mask;
2318
2319 STARTSTACKSTR(ep);
2320 vpp = vartab;
2321 mask = on | off;
2322 do {
2323 for (vp = *vpp; vp; vp = vp->next) {
2324 if ((vp->flags & mask) == on) {
2325 if (ep == stackstrend())
2326 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002327 *ep++ = (char*)vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002328 }
2329 }
2330 } while (++vpp < vartab + VTABSIZE);
2331 if (ep == stackstrend())
2332 ep = growstackstr();
2333 if (end)
2334 *end = ep;
2335 *ep++ = NULL;
2336 return grabstackstr(ep);
2337}
2338
2339
2340/* ============ Path search helper
2341 *
2342 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002343 * of the path before the first call; path_advance will update
2344 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002345 * the possible path expansions in sequence. If an option (indicated by
2346 * a percent sign) appears in the path entry then the global variable
2347 * pathopt will be set to point to it; otherwise pathopt will be set to
2348 * NULL.
2349 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002350static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002351
2352static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002353path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002354{
2355 const char *p;
2356 char *q;
2357 const char *start;
2358 size_t len;
2359
2360 if (*path == NULL)
2361 return NULL;
2362 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002363 for (p = start; *p && *p != ':' && *p != '%'; p++)
2364 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002365 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2366 while (stackblocksize() < len)
2367 growstackblock();
2368 q = stackblock();
2369 if (p != start) {
2370 memcpy(q, start, p - start);
2371 q += p - start;
2372 *q++ = '/';
2373 }
2374 strcpy(q, name);
2375 pathopt = NULL;
2376 if (*p == '%') {
2377 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002378 while (*p && *p != ':')
2379 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002380 }
2381 if (*p == ':')
2382 *path = p + 1;
2383 else
2384 *path = NULL;
2385 return stalloc(len);
2386}
2387
2388
2389/* ============ Prompt */
2390
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002391static smallint doprompt; /* if set, prompt the user */
2392static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002393
2394#if ENABLE_FEATURE_EDITING
2395static line_input_t *line_input_state;
2396static const char *cmdedit_prompt;
2397static void
2398putprompt(const char *s)
2399{
2400 if (ENABLE_ASH_EXPAND_PRMT) {
2401 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002402 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002403 return;
2404 }
2405 cmdedit_prompt = s;
2406}
2407#else
2408static void
2409putprompt(const char *s)
2410{
2411 out2str(s);
2412}
2413#endif
2414
2415#if ENABLE_ASH_EXPAND_PRMT
2416/* expandstr() needs parsing machinery, so it is far away ahead... */
2417static const char *expandstr(const char *ps);
2418#else
2419#define expandstr(s) s
2420#endif
2421
2422static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002423setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002424{
2425 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002426 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2427
2428 if (!do_set)
2429 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002430
2431 needprompt = 0;
2432
2433 switch (whichprompt) {
2434 case 1:
2435 prompt = ps1val();
2436 break;
2437 case 2:
2438 prompt = ps2val();
2439 break;
2440 default: /* 0 */
2441 prompt = nullstr;
2442 }
2443#if ENABLE_ASH_EXPAND_PRMT
Denys Vlasenko60ca8342016-09-30 11:21:21 +02002444 pushstackmark(&smark, stackblocksize());
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002445#endif
2446 putprompt(expandstr(prompt));
2447#if ENABLE_ASH_EXPAND_PRMT
2448 popstackmark(&smark);
2449#endif
2450}
2451
2452
2453/* ============ The cd and pwd commands */
2454
2455#define CD_PHYSICAL 1
2456#define CD_PRINT 2
2457
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002458static int
2459cdopt(void)
2460{
2461 int flags = 0;
2462 int i, j;
2463
2464 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002465 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002466 if (i != j) {
2467 flags ^= CD_PHYSICAL;
2468 j = i;
2469 }
2470 }
2471
2472 return flags;
2473}
2474
2475/*
2476 * Update curdir (the name of the current directory) in response to a
2477 * cd command.
2478 */
2479static const char *
2480updatepwd(const char *dir)
2481{
2482 char *new;
2483 char *p;
2484 char *cdcomppath;
2485 const char *lim;
2486
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02002487 cdcomppath = sstrdup(dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002488 STARTSTACKSTR(new);
2489 if (*dir != '/') {
2490 if (curdir == nullstr)
2491 return 0;
2492 new = stack_putstr(curdir, new);
2493 }
2494 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002495 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002496 if (*dir != '/') {
2497 if (new[-1] != '/')
2498 USTPUTC('/', new);
2499 if (new > lim && *lim == '/')
2500 lim++;
2501 } else {
2502 USTPUTC('/', new);
2503 cdcomppath++;
2504 if (dir[1] == '/' && dir[2] != '/') {
2505 USTPUTC('/', new);
2506 cdcomppath++;
2507 lim++;
2508 }
2509 }
2510 p = strtok(cdcomppath, "/");
2511 while (p) {
2512 switch (*p) {
2513 case '.':
2514 if (p[1] == '.' && p[2] == '\0') {
2515 while (new > lim) {
2516 STUNPUTC(new);
2517 if (new[-1] == '/')
2518 break;
2519 }
2520 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002521 }
2522 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002523 break;
2524 /* fall through */
2525 default:
2526 new = stack_putstr(p, new);
2527 USTPUTC('/', new);
2528 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002529 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002530 }
2531 if (new > lim)
2532 STUNPUTC(new);
2533 *new = 0;
2534 return stackblock();
2535}
2536
2537/*
2538 * Find out what the current directory is. If we already know the current
2539 * directory, this routine returns immediately.
2540 */
2541static char *
2542getpwd(void)
2543{
Denis Vlasenko01631112007-12-16 17:20:38 +00002544 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002545 return dir ? dir : nullstr;
2546}
2547
2548static void
2549setpwd(const char *val, int setold)
2550{
2551 char *oldcur, *dir;
2552
2553 oldcur = dir = curdir;
2554
2555 if (setold) {
2556 setvar("OLDPWD", oldcur, VEXPORT);
2557 }
2558 INT_OFF;
2559 if (physdir != nullstr) {
2560 if (physdir != oldcur)
2561 free(physdir);
2562 physdir = nullstr;
2563 }
2564 if (oldcur == val || !val) {
2565 char *s = getpwd();
2566 physdir = s;
2567 if (!val)
2568 dir = s;
2569 } else
2570 dir = ckstrdup(val);
2571 if (oldcur != dir && oldcur != nullstr) {
2572 free(oldcur);
2573 }
2574 curdir = dir;
2575 INT_ON;
2576 setvar("PWD", dir, VEXPORT);
2577}
2578
2579static void hashcd(void);
2580
2581/*
Denys Vlasenko70392332016-10-27 02:31:55 +02002582 * Actually do the chdir. We also call hashcd to let other routines
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002583 * know that the current directory has changed.
2584 */
2585static int
2586docd(const char *dest, int flags)
2587{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002588 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002589 int err;
2590
2591 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2592
2593 INT_OFF;
2594 if (!(flags & CD_PHYSICAL)) {
2595 dir = updatepwd(dest);
2596 if (dir)
2597 dest = dir;
2598 }
2599 err = chdir(dest);
2600 if (err)
2601 goto out;
2602 setpwd(dir, 1);
2603 hashcd();
2604 out:
2605 INT_ON;
2606 return err;
2607}
2608
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002609static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002610cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002611{
2612 const char *dest;
2613 const char *path;
2614 const char *p;
2615 char c;
2616 struct stat statb;
2617 int flags;
2618
2619 flags = cdopt();
2620 dest = *argptr;
2621 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002622 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002623 else if (LONE_DASH(dest)) {
2624 dest = bltinlookup("OLDPWD");
2625 flags |= CD_PRINT;
2626 }
2627 if (!dest)
2628 dest = nullstr;
2629 if (*dest == '/')
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002630 goto step6;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002631 if (*dest == '.') {
2632 c = dest[1];
2633 dotdot:
2634 switch (c) {
2635 case '\0':
2636 case '/':
2637 goto step6;
2638 case '.':
2639 c = dest[2];
2640 if (c != '.')
2641 goto dotdot;
2642 }
2643 }
2644 if (!*dest)
2645 dest = ".";
2646 path = bltinlookup("CDPATH");
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002647 while (path) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002648 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002649 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002650 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2651 if (c && c != ':')
2652 flags |= CD_PRINT;
2653 docd:
2654 if (!docd(p, flags))
2655 goto out;
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002656 goto err;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002657 }
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002658 }
2659
2660 step6:
2661 p = dest;
2662 goto docd;
2663
2664 err:
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002665 ash_msg_and_raise_error("can't cd to %s", dest);
2666 /* NOTREACHED */
2667 out:
2668 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002669 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002670 return 0;
2671}
2672
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002673static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002674pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002675{
2676 int flags;
2677 const char *dir = curdir;
2678
2679 flags = cdopt();
2680 if (flags) {
2681 if (physdir == nullstr)
2682 setpwd(dir, 0);
2683 dir = physdir;
2684 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002685 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002686 return 0;
2687}
2688
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002689
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002690/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002691
Denis Vlasenko834dee72008-10-07 09:18:30 +00002692
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002693#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002694
Eric Andersenc470f442003-07-28 09:56:35 +00002695/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002696#define CWORD 0 /* character is nothing special */
2697#define CNL 1 /* newline character */
2698#define CBACK 2 /* a backslash character */
2699#define CSQUOTE 3 /* single quote */
2700#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002701#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002702#define CBQUOTE 6 /* backwards single quote */
2703#define CVAR 7 /* a dollar sign */
2704#define CENDVAR 8 /* a '}' character */
2705#define CLP 9 /* a left paren in arithmetic */
2706#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002707#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002708#define CCTL 12 /* like CWORD, except it must be escaped */
2709#define CSPCL 13 /* these terminate a word */
2710#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002711
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002712#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002713#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002714# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002715#endif
2716
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002717#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002718
Mike Frysinger98c52642009-04-02 10:02:37 +00002719#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002720# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002721#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002722# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002723#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002724static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002725#if ENABLE_ASH_ALIAS
2726 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2727#endif
2728 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2729 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2730 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2731 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2732 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2733 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2734 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2735 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2736 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2737 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2738 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002739#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002740 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2741 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2742 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2743#endif
2744#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002745};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002746/* Constants below must match table above */
2747enum {
2748#if ENABLE_ASH_ALIAS
2749 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2750#endif
2751 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2752 CNL_CNL_CNL_CNL , /* 2 */
2753 CWORD_CCTL_CCTL_CWORD , /* 3 */
2754 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2755 CVAR_CVAR_CWORD_CVAR , /* 5 */
2756 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2757 CSPCL_CWORD_CWORD_CLP , /* 7 */
2758 CSPCL_CWORD_CWORD_CRP , /* 8 */
2759 CBACK_CBACK_CCTL_CBACK , /* 9 */
2760 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2761 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2762 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2763 CWORD_CWORD_CWORD_CWORD , /* 13 */
2764 CCTL_CCTL_CCTL_CCTL , /* 14 */
2765};
Eric Andersen2870d962001-07-02 17:27:21 +00002766
Denys Vlasenkocd716832009-11-28 22:14:02 +01002767/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2768 * caller must ensure proper cast on it if c is *char_ptr!
2769 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002770/* Values for syntax param */
2771#define BASESYNTAX 0 /* not in quotes */
2772#define DQSYNTAX 1 /* in double quotes */
2773#define SQSYNTAX 2 /* in single quotes */
2774#define ARISYNTAX 3 /* in arithmetic */
2775#define PSSYNTAX 4 /* prompt. never passed to SIT() */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002776
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002777#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002778
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002779static int
2780SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002781{
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002782 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2783 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2784 /*
2785 * This causes '/' to be prepended with CTLESC in dquoted string,
2786 * making "./file"* treated incorrectly because we feed
2787 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2788 * The "homegrown" glob implementation is okay with that,
2789 * but glibc one isn't. With '/' always treated as CWORD,
2790 * both work fine.
2791 */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002792# if ENABLE_ASH_ALIAS
2793 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002794 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002795 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002796 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2797 11, 3 /* "}~" */
2798 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002799# else
2800 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002801 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002802 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002803 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2804 10, 2 /* "}~" */
2805 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002806# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002807 const char *s;
2808 int indx;
2809
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002810 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002811 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002812# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002813 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002814 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002815 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002816# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002817 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002818 /* Cast is purely for paranoia here,
2819 * just in case someone passed signed char to us */
2820 if ((unsigned char)c >= CTL_FIRST
2821 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002822 ) {
2823 return CCTL;
2824 }
2825 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002826 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002827 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002828 indx = syntax_index_table[s - spec_symbls];
2829 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002830 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002831}
2832
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002833#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002834
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002835static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002836 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002837 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2838 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2839 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2840 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2841 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2842 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2843 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2844 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2845 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2846 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2847 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2848 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2849 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2850 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2851 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2852 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2853 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2854 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2855 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2856 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2857 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2858 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2859 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2860 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2861 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2862 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2867 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2870 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2871 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2872 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2873 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2874 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2875 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2876 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2877 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2878 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2879 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2880 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2881 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2882 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2883 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002884/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
2885 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkocd716832009-11-28 22:14:02 +01002886 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2887 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2888 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2889 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2890 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2891 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2892 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2893 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2894 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2895 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2896 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2897 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2898 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2899 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2900 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2901 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2902 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2903 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2904 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2905 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2906 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2907 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2908 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2909 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2910 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2911 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2912 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2913 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2914 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2915 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2916 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2917 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2918 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2919 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2920 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2921 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2922 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2923 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2924 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2925 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2926 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2927 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2928 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2929 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2930 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2931 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2932 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2935 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
2963 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2964 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
2965 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
2966 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2967 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2968 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2969 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2970 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2971 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2972 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2973 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2974 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2975 /* 137 */ CWORD_CWORD_CWORD_CWORD,
2976 /* 138 */ CWORD_CWORD_CWORD_CWORD,
2977 /* 139 */ CWORD_CWORD_CWORD_CWORD,
2978 /* 140 */ CWORD_CWORD_CWORD_CWORD,
2979 /* 141 */ CWORD_CWORD_CWORD_CWORD,
2980 /* 142 */ CWORD_CWORD_CWORD_CWORD,
2981 /* 143 */ CWORD_CWORD_CWORD_CWORD,
2982 /* 144 */ CWORD_CWORD_CWORD_CWORD,
2983 /* 145 */ CWORD_CWORD_CWORD_CWORD,
2984 /* 146 */ CWORD_CWORD_CWORD_CWORD,
2985 /* 147 */ CWORD_CWORD_CWORD_CWORD,
2986 /* 148 */ CWORD_CWORD_CWORD_CWORD,
2987 /* 149 */ CWORD_CWORD_CWORD_CWORD,
2988 /* 150 */ CWORD_CWORD_CWORD_CWORD,
2989 /* 151 */ CWORD_CWORD_CWORD_CWORD,
2990 /* 152 */ CWORD_CWORD_CWORD_CWORD,
2991 /* 153 */ CWORD_CWORD_CWORD_CWORD,
2992 /* 154 */ CWORD_CWORD_CWORD_CWORD,
2993 /* 155 */ CWORD_CWORD_CWORD_CWORD,
2994 /* 156 */ CWORD_CWORD_CWORD_CWORD,
2995 /* 157 */ CWORD_CWORD_CWORD_CWORD,
2996 /* 158 */ CWORD_CWORD_CWORD_CWORD,
2997 /* 159 */ CWORD_CWORD_CWORD_CWORD,
2998 /* 160 */ CWORD_CWORD_CWORD_CWORD,
2999 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3000 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3001 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3002 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3003 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3004 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3005 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3006 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3007 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3008 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3009 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3010 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3011 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3012 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3013 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3014 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3015 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3016 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3017 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3018 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3019 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3020 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3021 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3029 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3042 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3047 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003094 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003095# if ENABLE_ASH_ALIAS
3096 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3097# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003098};
3099
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003100# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003101
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003102#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003103
Eric Andersen2870d962001-07-02 17:27:21 +00003104
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003105/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003106
Denis Vlasenko131ae172007-02-18 13:00:19 +00003107#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003108
3109#define ALIASINUSE 1
3110#define ALIASDEAD 2
3111
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003112struct alias {
3113 struct alias *next;
3114 char *name;
3115 char *val;
3116 int flag;
3117};
3118
Denis Vlasenko01631112007-12-16 17:20:38 +00003119
3120static struct alias **atab; // [ATABSIZE];
3121#define INIT_G_alias() do { \
3122 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3123} while (0)
3124
Eric Andersen2870d962001-07-02 17:27:21 +00003125
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003126static struct alias **
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02003127__lookupalias(const char *name)
3128{
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003129 unsigned int hashval;
3130 struct alias **app;
3131 const char *p;
3132 unsigned int ch;
3133
3134 p = name;
3135
3136 ch = (unsigned char)*p;
3137 hashval = ch << 4;
3138 while (ch) {
3139 hashval += ch;
3140 ch = (unsigned char)*++p;
3141 }
3142 app = &atab[hashval % ATABSIZE];
3143
3144 for (; *app; app = &(*app)->next) {
3145 if (strcmp(name, (*app)->name) == 0) {
3146 break;
3147 }
3148 }
3149
3150 return app;
3151}
3152
3153static struct alias *
3154lookupalias(const char *name, int check)
3155{
3156 struct alias *ap = *__lookupalias(name);
3157
3158 if (check && ap && (ap->flag & ALIASINUSE))
3159 return NULL;
3160 return ap;
3161}
3162
3163static struct alias *
3164freealias(struct alias *ap)
3165{
3166 struct alias *next;
3167
3168 if (ap->flag & ALIASINUSE) {
3169 ap->flag |= ALIASDEAD;
3170 return ap;
3171 }
3172
3173 next = ap->next;
3174 free(ap->name);
3175 free(ap->val);
3176 free(ap);
3177 return next;
3178}
Eric Andersencb57d552001-06-28 07:25:16 +00003179
Eric Andersenc470f442003-07-28 09:56:35 +00003180static void
3181setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003182{
3183 struct alias *ap, **app;
3184
3185 app = __lookupalias(name);
3186 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003187 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003188 if (ap) {
3189 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003190 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003191 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003192 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003193 ap->flag &= ~ALIASDEAD;
3194 } else {
3195 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003196 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003197 ap->name = ckstrdup(name);
3198 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003199 /*ap->flag = 0; - ckzalloc did it */
3200 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003201 *app = ap;
3202 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003203 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003204}
3205
Eric Andersenc470f442003-07-28 09:56:35 +00003206static int
3207unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003208{
Eric Andersencb57d552001-06-28 07:25:16 +00003209 struct alias **app;
3210
3211 app = __lookupalias(name);
3212
3213 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003214 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003215 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003216 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003217 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003218 }
3219
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003220 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003221}
3222
Eric Andersenc470f442003-07-28 09:56:35 +00003223static void
3224rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003225{
Eric Andersencb57d552001-06-28 07:25:16 +00003226 struct alias *ap, **app;
3227 int i;
3228
Denis Vlasenkob012b102007-02-19 22:43:01 +00003229 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003230 for (i = 0; i < ATABSIZE; i++) {
3231 app = &atab[i];
3232 for (ap = *app; ap; ap = *app) {
3233 *app = freealias(*app);
3234 if (ap == *app) {
3235 app = &ap->next;
3236 }
3237 }
3238 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003239 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003240}
3241
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003242static void
3243printalias(const struct alias *ap)
3244{
3245 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3246}
3247
Eric Andersencb57d552001-06-28 07:25:16 +00003248/*
3249 * TODO - sort output
3250 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003251static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003252aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003253{
3254 char *n, *v;
3255 int ret = 0;
3256 struct alias *ap;
3257
Denis Vlasenko68404f12008-03-17 09:00:54 +00003258 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003259 int i;
3260
Denis Vlasenko68404f12008-03-17 09:00:54 +00003261 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003262 for (ap = atab[i]; ap; ap = ap->next) {
3263 printalias(ap);
3264 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003265 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003266 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003267 }
3268 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003269 v = strchr(n+1, '=');
3270 if (v == NULL) { /* n+1: funny ksh stuff */
3271 ap = *__lookupalias(n);
3272 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003273 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003274 ret = 1;
3275 } else
3276 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003277 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003278 *v++ = '\0';
3279 setalias(n, v);
3280 }
3281 }
3282
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003283 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003284}
3285
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003286static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003287unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003288{
3289 int i;
3290
3291 while ((i = nextopt("a")) != '\0') {
3292 if (i == 'a') {
3293 rmaliases();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003294 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003295 }
3296 }
3297 for (i = 0; *argptr; argptr++) {
3298 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003299 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003300 i = 1;
3301 }
3302 }
3303
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003304 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003305}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003306
Denis Vlasenko131ae172007-02-18 13:00:19 +00003307#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003308
Eric Andersenc470f442003-07-28 09:56:35 +00003309
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003310/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003311#define FORK_FG 0
3312#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003313#define FORK_NOJOB 2
3314
3315/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003316#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3317#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3318#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003319#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003320
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003321/*
3322 * A job structure contains information about a job. A job is either a
3323 * single process or a set of processes contained in a pipeline. In the
3324 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3325 * array of pids.
3326 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003327struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003328 pid_t ps_pid; /* process id */
3329 int ps_status; /* last process status from wait() */
3330 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003331};
3332
3333struct job {
3334 struct procstat ps0; /* status of process */
3335 struct procstat *ps; /* status or processes when more than one */
3336#if JOBS
3337 int stopstatus; /* status of a stopped job */
3338#endif
3339 uint32_t
3340 nprocs: 16, /* number of processes */
3341 state: 8,
3342#define JOBRUNNING 0 /* at least one proc running */
3343#define JOBSTOPPED 1 /* all procs are stopped */
3344#define JOBDONE 2 /* all procs are completed */
3345#if JOBS
3346 sigint: 1, /* job was killed by SIGINT */
3347 jobctl: 1, /* job running under job control */
3348#endif
3349 waited: 1, /* true if this entry has been waited for */
3350 used: 1, /* true if this entry is in used */
3351 changed: 1; /* true if status has changed */
3352 struct job *prev_job; /* previous job */
3353};
3354
Denis Vlasenko68404f12008-03-17 09:00:54 +00003355static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003356static int forkshell(struct job *, union node *, int);
3357static int waitforjob(struct job *);
3358
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003359#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003360enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003361#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003362#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003363static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003364static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003365#endif
3366
3367/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003368 * Ignore a signal.
3369 */
3370static void
3371ignoresig(int signo)
3372{
3373 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3374 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3375 /* No, need to do it */
3376 signal(signo, SIG_IGN);
3377 }
3378 sigmode[signo - 1] = S_HARD_IGN;
3379}
3380
3381/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003382 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003383 */
3384static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003385signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003386{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003387 if (signo == SIGCHLD) {
3388 got_sigchld = 1;
3389 if (!trap[SIGCHLD])
3390 return;
3391 }
3392
Denis Vlasenko4b875702009-03-19 13:30:04 +00003393 gotsig[signo - 1] = 1;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003394 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003395
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003396 if (signo == SIGINT && !trap[SIGINT]) {
3397 if (!suppress_int) {
3398 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003399 raise_interrupt(); /* does not return */
3400 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003401 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003402 }
3403}
3404
3405/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003406 * Set the signal handler for the specified signal. The routine figures
3407 * out what it should be set to.
3408 */
3409static void
3410setsignal(int signo)
3411{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003412 char *t;
3413 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003414 struct sigaction act;
3415
3416 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003417 new_act = S_DFL;
3418 if (t != NULL) { /* trap for this sig is set */
3419 new_act = S_CATCH;
3420 if (t[0] == '\0') /* trap is "": ignore this sig */
3421 new_act = S_IGN;
3422 }
3423
3424 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003425 switch (signo) {
3426 case SIGINT:
3427 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003428 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003429 break;
3430 case SIGQUIT:
3431#if DEBUG
3432 if (debug)
3433 break;
3434#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003435 /* man bash:
3436 * "In all cases, bash ignores SIGQUIT. Non-builtin
3437 * commands run by bash have signal handlers
3438 * set to the values inherited by the shell
3439 * from its parent". */
3440 new_act = S_IGN;
3441 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003442 case SIGTERM:
3443 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003444 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003445 break;
3446#if JOBS
3447 case SIGTSTP:
3448 case SIGTTOU:
3449 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003450 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003451 break;
3452#endif
3453 }
3454 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003455//TODO: if !rootshell, we reset SIGQUIT to DFL,
3456//whereas we have to restore it to what shell got on entry
3457//from the parent. See comment above
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003458
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003459 if (signo == SIGCHLD)
3460 new_act = S_CATCH;
3461
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003462 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003463 cur_act = *t;
3464 if (cur_act == 0) {
3465 /* current setting is not yet known */
3466 if (sigaction(signo, NULL, &act)) {
3467 /* pretend it worked; maybe we should give a warning,
3468 * but other shells don't. We don't alter sigmode,
3469 * so we retry every time.
3470 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003471 return;
3472 }
3473 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003474 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003475 if (mflag
3476 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3477 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003478 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003479 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003480 }
3481 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003482 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003483 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003484
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003485 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003486 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003487 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003488 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003489 break;
3490 case S_IGN:
3491 act.sa_handler = SIG_IGN;
3492 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003493 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003494
3495 /* flags and mask matter only if !DFL and !IGN, but we do it
3496 * for all cases for more deterministic behavior:
3497 */
3498 act.sa_flags = 0;
3499 sigfillset(&act.sa_mask);
3500
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003501 sigaction_set(signo, &act);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003502
3503 *t = new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003504}
3505
3506/* mode flags for set_curjob */
3507#define CUR_DELETE 2
3508#define CUR_RUNNING 1
3509#define CUR_STOPPED 0
3510
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003511#if JOBS
3512/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003513static int initialpgrp; //references:2
3514static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003515#endif
3516/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003517static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003518/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003519static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003520/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003521static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003522/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003523static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003524
3525static void
3526set_curjob(struct job *jp, unsigned mode)
3527{
3528 struct job *jp1;
3529 struct job **jpp, **curp;
3530
3531 /* first remove from list */
3532 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003533 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003534 jp1 = *jpp;
3535 if (jp1 == jp)
3536 break;
3537 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003538 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003539 *jpp = jp1->prev_job;
3540
3541 /* Then re-insert in correct position */
3542 jpp = curp;
3543 switch (mode) {
3544 default:
3545#if DEBUG
3546 abort();
3547#endif
3548 case CUR_DELETE:
3549 /* job being deleted */
3550 break;
3551 case CUR_RUNNING:
3552 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003553 * put after all stopped jobs.
3554 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003555 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003556 jp1 = *jpp;
3557#if JOBS
3558 if (!jp1 || jp1->state != JOBSTOPPED)
3559#endif
3560 break;
3561 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003562 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003563 /* FALLTHROUGH */
3564#if JOBS
3565 case CUR_STOPPED:
3566#endif
3567 /* newly stopped job - becomes curjob */
3568 jp->prev_job = *jpp;
3569 *jpp = jp;
3570 break;
3571 }
3572}
3573
3574#if JOBS || DEBUG
3575static int
3576jobno(const struct job *jp)
3577{
3578 return jp - jobtab + 1;
3579}
3580#endif
3581
3582/*
3583 * Convert a job name to a job structure.
3584 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003585#if !JOBS
3586#define getjob(name, getctl) getjob(name)
3587#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003588static struct job *
3589getjob(const char *name, int getctl)
3590{
3591 struct job *jp;
3592 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003593 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003594 unsigned num;
3595 int c;
3596 const char *p;
3597 char *(*match)(const char *, const char *);
3598
3599 jp = curjob;
3600 p = name;
3601 if (!p)
3602 goto currentjob;
3603
3604 if (*p != '%')
3605 goto err;
3606
3607 c = *++p;
3608 if (!c)
3609 goto currentjob;
3610
3611 if (!p[1]) {
3612 if (c == '+' || c == '%') {
3613 currentjob:
3614 err_msg = "No current job";
3615 goto check;
3616 }
3617 if (c == '-') {
3618 if (jp)
3619 jp = jp->prev_job;
3620 err_msg = "No previous job";
3621 check:
3622 if (!jp)
3623 goto err;
3624 goto gotit;
3625 }
3626 }
3627
3628 if (is_number(p)) {
3629 num = atoi(p);
Denys Vlasenko46a45ce2016-09-29 01:10:08 +02003630 if (num > 0 && num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003631 jp = jobtab + num - 1;
3632 if (jp->used)
3633 goto gotit;
3634 goto err;
3635 }
3636 }
3637
3638 match = prefix;
3639 if (*p == '?') {
3640 match = strstr;
3641 p++;
3642 }
3643
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003644 found = NULL;
3645 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003646 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003647 if (found)
3648 goto err;
3649 found = jp;
3650 err_msg = "%s: ambiguous";
3651 }
3652 jp = jp->prev_job;
3653 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003654 if (!found)
3655 goto err;
3656 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003657
3658 gotit:
3659#if JOBS
3660 err_msg = "job %s not created under job control";
3661 if (getctl && jp->jobctl == 0)
3662 goto err;
3663#endif
3664 return jp;
3665 err:
3666 ash_msg_and_raise_error(err_msg, name);
3667}
3668
3669/*
3670 * Mark a job structure as unused.
3671 */
3672static void
3673freejob(struct job *jp)
3674{
3675 struct procstat *ps;
3676 int i;
3677
3678 INT_OFF;
3679 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003680 if (ps->ps_cmd != nullstr)
3681 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003682 }
3683 if (jp->ps != &jp->ps0)
3684 free(jp->ps);
3685 jp->used = 0;
3686 set_curjob(jp, CUR_DELETE);
3687 INT_ON;
3688}
3689
3690#if JOBS
3691static void
3692xtcsetpgrp(int fd, pid_t pgrp)
3693{
3694 if (tcsetpgrp(fd, pgrp))
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003695 ash_msg_and_raise_error("can't set tty process group (%m)");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003696}
3697
3698/*
3699 * Turn job control on and off.
3700 *
3701 * Note: This code assumes that the third arg to ioctl is a character
3702 * pointer, which is true on Berkeley systems but not System V. Since
3703 * System V doesn't have job control yet, this isn't a problem now.
3704 *
3705 * Called with interrupts off.
3706 */
3707static void
3708setjobctl(int on)
3709{
3710 int fd;
3711 int pgrp;
3712
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003713 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003714 return;
3715 if (on) {
3716 int ofd;
3717 ofd = fd = open(_PATH_TTY, O_RDWR);
3718 if (fd < 0) {
3719 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3720 * That sometimes helps to acquire controlling tty.
3721 * Obviously, a workaround for bugs when someone
3722 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003723 fd = 2;
3724 while (!isatty(fd))
3725 if (--fd < 0)
3726 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003727 }
Denys Vlasenko64774602016-10-26 15:24:30 +02003728 /* fd is a tty at this point */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003729 fd = fcntl(fd, F_DUPFD, 10);
Denys Vlasenko64774602016-10-26 15:24:30 +02003730 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, dont */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003731 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003732 if (fd < 0)
Denys Vlasenko64774602016-10-26 15:24:30 +02003733 goto out; /* F_DUPFD failed */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003734 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003735 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003736 pgrp = tcgetpgrp(fd);
3737 if (pgrp < 0) {
3738 out:
3739 ash_msg("can't access tty; job control turned off");
3740 mflag = on = 0;
3741 goto close;
3742 }
3743 if (pgrp == getpgrp())
3744 break;
3745 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003746 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003747 initialpgrp = pgrp;
3748
3749 setsignal(SIGTSTP);
3750 setsignal(SIGTTOU);
3751 setsignal(SIGTTIN);
3752 pgrp = rootpid;
3753 setpgid(0, pgrp);
3754 xtcsetpgrp(fd, pgrp);
3755 } else {
3756 /* turning job control off */
3757 fd = ttyfd;
3758 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003759 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003760 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003761 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003762 setpgid(0, pgrp);
3763 setsignal(SIGTSTP);
3764 setsignal(SIGTTOU);
3765 setsignal(SIGTTIN);
3766 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003767 if (fd >= 0)
3768 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003769 fd = -1;
3770 }
3771 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003772 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003773}
3774
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003775static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003776killcmd(int argc, char **argv)
3777{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003778 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003779 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003780 do {
3781 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003782 /*
3783 * "kill %N" - job kill
3784 * Converting to pgrp / pid kill
3785 */
3786 struct job *jp;
3787 char *dst;
3788 int j, n;
3789
3790 jp = getjob(argv[i], 0);
3791 /*
3792 * In jobs started under job control, we signal
3793 * entire process group by kill -PGRP_ID.
3794 * This happens, f.e., in interactive shell.
3795 *
3796 * Otherwise, we signal each child via
3797 * kill PID1 PID2 PID3.
3798 * Testcases:
3799 * sh -c 'sleep 1|sleep 1 & kill %1'
3800 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3801 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3802 */
3803 n = jp->nprocs; /* can't be 0 (I hope) */
3804 if (jp->jobctl)
3805 n = 1;
3806 dst = alloca(n * sizeof(int)*4);
3807 argv[i] = dst;
3808 for (j = 0; j < n; j++) {
3809 struct procstat *ps = &jp->ps[j];
3810 /* Skip non-running and not-stopped members
3811 * (i.e. dead members) of the job
3812 */
3813 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3814 continue;
3815 /*
3816 * kill_main has matching code to expect
3817 * leading space. Needed to not confuse
3818 * negative pids with "kill -SIGNAL_NO" syntax
3819 */
3820 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3821 }
3822 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003823 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003824 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003825 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003826 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003827}
3828
3829static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01003830showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003831{
Denys Vlasenko285ad152009-12-04 23:02:27 +01003832 struct procstat *ps;
3833 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003834
Denys Vlasenko285ad152009-12-04 23:02:27 +01003835 psend = jp->ps + jp->nprocs;
3836 for (ps = jp->ps + 1; ps < psend; ps++)
3837 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003838 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003839 flush_stdout_stderr();
3840}
3841
3842
3843static int
3844restartjob(struct job *jp, int mode)
3845{
3846 struct procstat *ps;
3847 int i;
3848 int status;
3849 pid_t pgid;
3850
3851 INT_OFF;
3852 if (jp->state == JOBDONE)
3853 goto out;
3854 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003855 pgid = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003856 if (mode == FORK_FG)
3857 xtcsetpgrp(ttyfd, pgid);
3858 killpg(pgid, SIGCONT);
3859 ps = jp->ps;
3860 i = jp->nprocs;
3861 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003862 if (WIFSTOPPED(ps->ps_status)) {
3863 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003864 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003865 ps++;
3866 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003867 out:
3868 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3869 INT_ON;
3870 return status;
3871}
3872
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003873static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003874fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003875{
3876 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003877 int mode;
3878 int retval;
3879
3880 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3881 nextopt(nullstr);
3882 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003883 do {
3884 jp = getjob(*argv, 1);
3885 if (mode == FORK_BG) {
3886 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01003887 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003888 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003889 out1str(jp->ps[0].ps_cmd);
3890 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003891 retval = restartjob(jp, mode);
3892 } while (*argv && *++argv);
3893 return retval;
3894}
3895#endif
3896
3897static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02003898sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003899{
3900 int col;
3901 int st;
3902
3903 col = 0;
3904 if (!WIFEXITED(status)) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003905 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003906 st = WSTOPSIG(status);
3907 else
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003908 st = WTERMSIG(status);
3909 if (sigonly) {
3910 if (st == SIGINT || st == SIGPIPE)
3911 goto out;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003912 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003913 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003914 }
3915 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01003916//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003917 col = fmtstr(s, 32, strsignal(st));
3918 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02003919 strcpy(s + col, " (core dumped)");
3920 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003921 }
3922 } else if (!sigonly) {
3923 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003924 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003925 }
3926 out:
3927 return col;
3928}
3929
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003930static int
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003931wait_block_or_sig(int *status)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003932{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003933 int pid;
3934
3935 do {
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01003936 sigset_t mask;
3937
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003938 /* Poll all children for changes in their state */
3939 got_sigchld = 0;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003940 /* if job control is active, accept stopped processes too */
3941 pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003942 if (pid != 0)
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003943 break; /* Error (e.g. EINTR, ECHILD) or pid */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003944
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003945 /* Children exist, but none are ready. Sleep until interesting signal */
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01003946#if 1
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003947 sigfillset(&mask);
3948 sigprocmask(SIG_SETMASK, &mask, &mask);
3949 while (!got_sigchld && !pending_sig)
3950 sigsuspend(&mask);
3951 sigprocmask(SIG_SETMASK, &mask, NULL);
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01003952#else /* unsafe: a signal can set pending_sig after check, but before pause() */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003953 while (!got_sigchld && !pending_sig)
3954 pause();
3955#endif
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003956
3957 /* If it was SIGCHLD, poll children again */
3958 } while (got_sigchld);
3959
3960 return pid;
3961}
3962
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003963#define DOWAIT_NONBLOCK 0
3964#define DOWAIT_BLOCK 1
3965#define DOWAIT_BLOCK_OR_SIG 2
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003966
3967static int
Denys Vlasenkob543bda2016-10-27 20:08:28 +02003968dowait(int block, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003969{
3970 int pid;
3971 int status;
3972 struct job *jp;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003973 struct job *thisjob = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003974
Denys Vlasenkob543bda2016-10-27 20:08:28 +02003975 TRACE(("dowait(0x%x) called\n", block));
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00003976
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003977 /* It's wrong to call waitpid() outside of INT_OFF region:
3978 * signal can arrive just after syscall return and handler can
3979 * longjmp away, losing stop/exit notification processing.
3980 * Thus, for "jobs" builtin, and for waiting for a fg job,
3981 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
3982 *
3983 * However, for "wait" builtin it is wrong to simply call waitpid()
3984 * in INT_OFF region: "wait" needs to wait for any running job
3985 * to change state, but should exit on any trap too.
3986 * In INT_OFF region, a signal just before syscall entry can set
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003987 * pending_sig variables, but we can't check them, and we would
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003988 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003989 *
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003990 * Because of this, we run inside INT_OFF, but use a special routine
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01003991 * which combines waitpid() and sigsuspend().
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003992 * This is the reason why we need to have a handler for SIGCHLD:
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01003993 * SIG_DFL handler does not wake sigsuspend().
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003994 */
3995 INT_OFF;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003996 if (block == DOWAIT_BLOCK_OR_SIG) {
3997 pid = wait_block_or_sig(&status);
3998 } else {
3999 int wait_flags = 0;
4000 if (block == DOWAIT_NONBLOCK)
4001 wait_flags = WNOHANG;
4002 /* if job control is active, accept stopped processes too */
4003 if (doing_jobctl)
4004 wait_flags |= WUNTRACED;
4005 /* NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004006 pid = waitpid(-1, &status, wait_flags);
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004007 }
Denis Vlasenkob21f3792009-03-19 23:09:58 +00004008 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4009 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004010 if (pid <= 0)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004011 goto out;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004012
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004013 thisjob = NULL;
4014 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004015 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004016 struct procstat *ps;
4017 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004018 if (jp->state == JOBDONE)
4019 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004020 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004021 ps = jp->ps;
4022 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004023 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004024 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004025 TRACE(("Job %d: changing status of proc %d "
4026 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01004027 jobno(jp), pid, ps->ps_status, status));
4028 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004029 thisjob = jp;
4030 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004031 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004032 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004033#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004034 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004035 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004036 if (WIFSTOPPED(ps->ps_status)) {
4037 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004038 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004039 }
4040#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004041 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004042 if (!thisjob)
4043 continue;
4044
4045 /* Found the job where one of its processes changed its state.
4046 * Is there at least one live and running process in this job? */
4047 if (jobstate != JOBRUNNING) {
4048 /* No. All live processes in the job are stopped
4049 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4050 */
4051 thisjob->changed = 1;
4052 if (thisjob->state != jobstate) {
4053 TRACE(("Job %d: changing state from %d to %d\n",
4054 jobno(thisjob), thisjob->state, jobstate));
4055 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004056#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004057 if (jobstate == JOBSTOPPED)
4058 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004059#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004060 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004061 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004062 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004063 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004064 /* The process wasn't found in job list */
4065 if (JOBS && !WIFSTOPPED(status))
4066 jobless--;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004067 out:
4068 INT_ON;
4069
4070 if (thisjob && thisjob == job) {
4071 char s[48 + 1];
4072 int len;
4073
Denys Vlasenko9c541002015-10-07 15:44:36 +02004074 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004075 if (len) {
4076 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004077 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004078 out2str(s);
4079 }
4080 }
4081 return pid;
4082}
4083
4084#if JOBS
4085static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004086showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004087{
4088 struct procstat *ps;
4089 struct procstat *psend;
4090 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004091 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004092 char s[16 + 16 + 48];
4093 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004094
4095 ps = jp->ps;
4096
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004097 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004098 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004099 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004100 return;
4101 }
4102
4103 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004104 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004105
4106 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004107 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004108 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004109 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004110
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004111 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004112 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004113
4114 psend = ps + jp->nprocs;
4115
4116 if (jp->state == JOBRUNNING) {
4117 strcpy(s + col, "Running");
4118 col += sizeof("Running") - 1;
4119 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004120 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004121 if (jp->state == JOBSTOPPED)
4122 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004123 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004124 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004125 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004126
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004127 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4128 * or prints several "PID | <cmdN>" lines,
4129 * depending on SHOW_PIDS bit.
4130 * We do not print status of individual processes
4131 * between PID and <cmdN>. bash does it, but not very well:
4132 * first line shows overall job status, not process status,
4133 * making it impossible to know 1st process status.
4134 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004135 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004136 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004137 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004138 s[0] = '\0';
4139 col = 33;
4140 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004141 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004142 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004143 fprintf(out, "%s%*c%s%s",
4144 s,
4145 33 - col >= 0 ? 33 - col : 0, ' ',
4146 ps == jp->ps ? "" : "| ",
4147 ps->ps_cmd
4148 );
4149 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004150 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004151
4152 jp->changed = 0;
4153
4154 if (jp->state == JOBDONE) {
4155 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4156 freejob(jp);
4157 }
4158}
4159
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004160/*
4161 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4162 * statuses have changed since the last call to showjobs.
4163 */
4164static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004165showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004166{
4167 struct job *jp;
4168
Denys Vlasenko883cea42009-07-11 15:31:59 +02004169 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004170
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004171 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004172 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004173 continue;
4174
4175 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004176 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004177 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004178 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004179 }
4180}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004181
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004182static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004183jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004184{
4185 int mode, m;
4186
4187 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004188 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004189 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004190 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004191 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004192 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004193 }
4194
4195 argv = argptr;
4196 if (*argv) {
4197 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004198 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004199 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004200 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004201 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004202 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004203
4204 return 0;
4205}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004206#endif /* JOBS */
4207
Michael Abbott359da5e2009-12-04 23:03:29 +01004208/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004209static int
4210getstatus(struct job *job)
4211{
4212 int status;
4213 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004214 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004215
Michael Abbott359da5e2009-12-04 23:03:29 +01004216 /* Fetch last member's status */
4217 ps = job->ps + job->nprocs - 1;
4218 status = ps->ps_status;
4219 if (pipefail) {
4220 /* "set -o pipefail" mode: use last _nonzero_ status */
4221 while (status == 0 && --ps >= job->ps)
4222 status = ps->ps_status;
4223 }
4224
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004225 retval = WEXITSTATUS(status);
4226 if (!WIFEXITED(status)) {
4227#if JOBS
4228 retval = WSTOPSIG(status);
4229 if (!WIFSTOPPED(status))
4230#endif
4231 {
4232 /* XXX: limits number of signals */
4233 retval = WTERMSIG(status);
4234#if JOBS
4235 if (retval == SIGINT)
4236 job->sigint = 1;
4237#endif
4238 }
4239 retval += 128;
4240 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004241 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004242 jobno(job), job->nprocs, status, retval));
4243 return retval;
4244}
4245
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004246static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004247waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004248{
4249 struct job *job;
4250 int retval;
4251 struct job *jp;
4252
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004253 nextopt(nullstr);
4254 retval = 0;
4255
4256 argv = argptr;
4257 if (!*argv) {
4258 /* wait for all jobs */
4259 for (;;) {
4260 jp = curjob;
4261 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004262 if (!jp) /* no running procs */
4263 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004264 if (jp->state == JOBRUNNING)
4265 break;
4266 jp->waited = 1;
4267 jp = jp->prev_job;
4268 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004269 /* man bash:
4270 * "When bash is waiting for an asynchronous command via
4271 * the wait builtin, the reception of a signal for which a trap
4272 * has been set will cause the wait builtin to return immediately
4273 * with an exit status greater than 128, immediately after which
4274 * the trap is executed."
Denys Vlasenko69188112016-10-27 20:18:18 +02004275 */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004276 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004277 /* if child sends us a signal *and immediately exits*,
4278 * dowait() returns pid > 0. Check this case,
4279 * not "if (dowait() < 0)"!
4280 */
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004281 if (pending_sig)
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004282 goto sigout;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004283 }
4284 }
4285
4286 retval = 127;
4287 do {
4288 if (**argv != '%') {
4289 pid_t pid = number(*argv);
4290 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004291 while (1) {
4292 if (!job)
4293 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004294 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004295 break;
4296 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004297 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004298 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004299 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004300 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004301 /* loop until process terminated or stopped */
Denys Vlasenko69188112016-10-27 20:18:18 +02004302 while (job->state == JOBRUNNING) {
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004303 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004304 if (pending_sig)
4305 goto sigout;
Denys Vlasenko69188112016-10-27 20:18:18 +02004306 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004307 job->waited = 1;
4308 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004309 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004310 } while (*++argv);
4311
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004312 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004313 return retval;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004314 sigout:
4315 retval = 128 + pending_sig;
4316 return retval;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004317}
4318
4319static struct job *
4320growjobtab(void)
4321{
4322 size_t len;
4323 ptrdiff_t offset;
4324 struct job *jp, *jq;
4325
4326 len = njobs * sizeof(*jp);
4327 jq = jobtab;
4328 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4329
4330 offset = (char *)jp - (char *)jq;
4331 if (offset) {
4332 /* Relocate pointers */
4333 size_t l = len;
4334
4335 jq = (struct job *)((char *)jq + l);
4336 while (l) {
4337 l -= sizeof(*jp);
4338 jq--;
4339#define joff(p) ((struct job *)((char *)(p) + l))
4340#define jmove(p) (p) = (void *)((char *)(p) + offset)
4341 if (joff(jp)->ps == &jq->ps0)
4342 jmove(joff(jp)->ps);
4343 if (joff(jp)->prev_job)
4344 jmove(joff(jp)->prev_job);
4345 }
4346 if (curjob)
4347 jmove(curjob);
4348#undef joff
4349#undef jmove
4350 }
4351
4352 njobs += 4;
4353 jobtab = jp;
4354 jp = (struct job *)((char *)jp + len);
4355 jq = jp + 3;
4356 do {
4357 jq->used = 0;
4358 } while (--jq >= jp);
4359 return jp;
4360}
4361
4362/*
4363 * Return a new job structure.
4364 * Called with interrupts off.
4365 */
4366static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004367makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004368{
4369 int i;
4370 struct job *jp;
4371
4372 for (i = njobs, jp = jobtab; ; jp++) {
4373 if (--i < 0) {
4374 jp = growjobtab();
4375 break;
4376 }
4377 if (jp->used == 0)
4378 break;
4379 if (jp->state != JOBDONE || !jp->waited)
4380 continue;
4381#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004382 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004383 continue;
4384#endif
4385 freejob(jp);
4386 break;
4387 }
4388 memset(jp, 0, sizeof(*jp));
4389#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004390 /* jp->jobctl is a bitfield.
4391 * "jp->jobctl |= jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004392 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004393 jp->jobctl = 1;
4394#endif
4395 jp->prev_job = curjob;
4396 curjob = jp;
4397 jp->used = 1;
4398 jp->ps = &jp->ps0;
4399 if (nprocs > 1) {
4400 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4401 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004402 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004403 jobno(jp)));
4404 return jp;
4405}
4406
4407#if JOBS
4408/*
4409 * Return a string identifying a command (to be printed by the
4410 * jobs command).
4411 */
4412static char *cmdnextc;
4413
4414static void
4415cmdputs(const char *s)
4416{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004417 static const char vstype[VSTYPE + 1][3] = {
4418 "", "}", "-", "+", "?", "=",
4419 "%", "%%", "#", "##"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00004420 IF_ASH_BASH_COMPAT(, ":", "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004421 };
4422
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004423 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004424 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004425 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004426 unsigned char c;
4427 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004428 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004429
Denys Vlasenko46a14772009-12-10 21:27:13 +01004430 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004431 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4432 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004433 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004434 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004435 switch (c) {
4436 case CTLESC:
4437 c = *p++;
4438 break;
4439 case CTLVAR:
4440 subtype = *p++;
4441 if ((subtype & VSTYPE) == VSLENGTH)
4442 str = "${#";
4443 else
4444 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004445 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004446 case CTLENDVAR:
4447 str = "\"}" + !(quoted & 1);
4448 quoted >>= 1;
4449 subtype = 0;
4450 goto dostr;
4451 case CTLBACKQ:
4452 str = "$(...)";
4453 goto dostr;
Mike Frysinger98c52642009-04-02 10:02:37 +00004454#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004455 case CTLARI:
4456 str = "$((";
4457 goto dostr;
4458 case CTLENDARI:
4459 str = "))";
4460 goto dostr;
4461#endif
4462 case CTLQUOTEMARK:
4463 quoted ^= 1;
4464 c = '"';
4465 break;
4466 case '=':
4467 if (subtype == 0)
4468 break;
4469 if ((subtype & VSTYPE) != VSNORMAL)
4470 quoted <<= 1;
4471 str = vstype[subtype & VSTYPE];
4472 if (subtype & VSNUL)
4473 c = ':';
4474 else
4475 goto checkstr;
4476 break;
4477 case '\'':
4478 case '\\':
4479 case '"':
4480 case '$':
4481 /* These can only happen inside quotes */
4482 cc[0] = c;
4483 str = cc;
4484 c = '\\';
4485 break;
4486 default:
4487 break;
4488 }
4489 USTPUTC(c, nextc);
4490 checkstr:
4491 if (!str)
4492 continue;
4493 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004494 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004495 USTPUTC(c, nextc);
4496 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004497 } /* while *p++ not NUL */
4498
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004499 if (quoted & 1) {
4500 USTPUTC('"', nextc);
4501 }
4502 *nextc = 0;
4503 cmdnextc = nextc;
4504}
4505
4506/* cmdtxt() and cmdlist() call each other */
4507static void cmdtxt(union node *n);
4508
4509static void
4510cmdlist(union node *np, int sep)
4511{
4512 for (; np; np = np->narg.next) {
4513 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004514 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004515 cmdtxt(np);
4516 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004517 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004518 }
4519}
4520
4521static void
4522cmdtxt(union node *n)
4523{
4524 union node *np;
4525 struct nodelist *lp;
4526 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004527
4528 if (!n)
4529 return;
4530 switch (n->type) {
4531 default:
4532#if DEBUG
4533 abort();
4534#endif
4535 case NPIPE:
4536 lp = n->npipe.cmdlist;
4537 for (;;) {
4538 cmdtxt(lp->n);
4539 lp = lp->next;
4540 if (!lp)
4541 break;
4542 cmdputs(" | ");
4543 }
4544 break;
4545 case NSEMI:
4546 p = "; ";
4547 goto binop;
4548 case NAND:
4549 p = " && ";
4550 goto binop;
4551 case NOR:
4552 p = " || ";
4553 binop:
4554 cmdtxt(n->nbinary.ch1);
4555 cmdputs(p);
4556 n = n->nbinary.ch2;
4557 goto donode;
4558 case NREDIR:
4559 case NBACKGND:
4560 n = n->nredir.n;
4561 goto donode;
4562 case NNOT:
4563 cmdputs("!");
4564 n = n->nnot.com;
4565 donode:
4566 cmdtxt(n);
4567 break;
4568 case NIF:
4569 cmdputs("if ");
4570 cmdtxt(n->nif.test);
4571 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004572 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004573 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004574 cmdputs("; else ");
4575 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004576 } else {
4577 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004578 }
4579 p = "; fi";
4580 goto dotail;
4581 case NSUBSHELL:
4582 cmdputs("(");
4583 n = n->nredir.n;
4584 p = ")";
4585 goto dotail;
4586 case NWHILE:
4587 p = "while ";
4588 goto until;
4589 case NUNTIL:
4590 p = "until ";
4591 until:
4592 cmdputs(p);
4593 cmdtxt(n->nbinary.ch1);
4594 n = n->nbinary.ch2;
4595 p = "; done";
4596 dodo:
4597 cmdputs("; do ");
4598 dotail:
4599 cmdtxt(n);
4600 goto dotail2;
4601 case NFOR:
4602 cmdputs("for ");
4603 cmdputs(n->nfor.var);
4604 cmdputs(" in ");
4605 cmdlist(n->nfor.args, 1);
4606 n = n->nfor.body;
4607 p = "; done";
4608 goto dodo;
4609 case NDEFUN:
4610 cmdputs(n->narg.text);
4611 p = "() { ... }";
4612 goto dotail2;
4613 case NCMD:
4614 cmdlist(n->ncmd.args, 1);
4615 cmdlist(n->ncmd.redirect, 0);
4616 break;
4617 case NARG:
4618 p = n->narg.text;
4619 dotail2:
4620 cmdputs(p);
4621 break;
4622 case NHERE:
4623 case NXHERE:
4624 p = "<<...";
4625 goto dotail2;
4626 case NCASE:
4627 cmdputs("case ");
4628 cmdputs(n->ncase.expr->narg.text);
4629 cmdputs(" in ");
4630 for (np = n->ncase.cases; np; np = np->nclist.next) {
4631 cmdtxt(np->nclist.pattern);
4632 cmdputs(") ");
4633 cmdtxt(np->nclist.body);
4634 cmdputs(";; ");
4635 }
4636 p = "esac";
4637 goto dotail2;
4638 case NTO:
4639 p = ">";
4640 goto redir;
4641 case NCLOBBER:
4642 p = ">|";
4643 goto redir;
4644 case NAPPEND:
4645 p = ">>";
4646 goto redir;
Denis Vlasenko559691a2008-10-05 18:39:31 +00004647#if ENABLE_ASH_BASH_COMPAT
4648 case NTO2:
4649#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004650 case NTOFD:
4651 p = ">&";
4652 goto redir;
4653 case NFROM:
4654 p = "<";
4655 goto redir;
4656 case NFROMFD:
4657 p = "<&";
4658 goto redir;
4659 case NFROMTO:
4660 p = "<>";
4661 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004662 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004663 cmdputs(p);
4664 if (n->type == NTOFD || n->type == NFROMFD) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004665 cmdputs(utoa(n->ndup.dupfd));
4666 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004667 }
4668 n = n->nfile.fname;
4669 goto donode;
4670 }
4671}
4672
4673static char *
4674commandtext(union node *n)
4675{
4676 char *name;
4677
4678 STARTSTACKSTR(cmdnextc);
4679 cmdtxt(n);
4680 name = stackblock();
Denys Vlasenko6a94cee2016-10-25 17:40:25 +02004681 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004682 return ckstrdup(name);
4683}
4684#endif /* JOBS */
4685
4686/*
4687 * Fork off a subshell. If we are doing job control, give the subshell its
4688 * own process group. Jp is a job structure that the job is to be added to.
4689 * N is the command that will be evaluated by the child. Both jp and n may
4690 * be NULL. The mode parameter can be one of the following:
4691 * FORK_FG - Fork off a foreground process.
4692 * FORK_BG - Fork off a background process.
4693 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4694 * process group even if job control is on.
4695 *
4696 * When job control is turned off, background processes have their standard
4697 * input redirected to /dev/null (except for the second and later processes
4698 * in a pipeline).
4699 *
4700 * Called with interrupts off.
4701 */
4702/*
4703 * Clear traps on a fork.
4704 */
4705static void
4706clear_traps(void)
4707{
4708 char **tp;
4709
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004710 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004711 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004712 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004713 if (trap_ptr == trap)
4714 free(*tp);
4715 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004716 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004717 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004718 setsignal(tp - trap);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004719 }
4720 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004721 may_have_traps = 0;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004722 INT_ON;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004723}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004724
4725/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004726static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004727
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004728/* Called after fork(), in child */
Denys Vlasenko70392332016-10-27 02:31:55 +02004729/* jp and n are NULL when called by openhere() for heredoc support */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004730static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004731forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004732{
4733 int oldlvl;
4734
4735 TRACE(("Child shell %d\n", getpid()));
4736 oldlvl = shlvl;
4737 shlvl++;
4738
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004739 /* man bash: "Non-builtin commands run by bash have signal handlers
4740 * set to the values inherited by the shell from its parent".
4741 * Do we do it correctly? */
4742
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004743 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004744
4745 if (mode == FORK_NOJOB /* is it `xxx` ? */
4746 && n && n->type == NCMD /* is it single cmd? */
4747 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004748 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004749 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4750 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4751 ) {
4752 TRACE(("Trap hack\n"));
4753 /* Awful hack for `trap` or $(trap).
4754 *
4755 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4756 * contains an example where "trap" is executed in a subshell:
4757 *
4758 * save_traps=$(trap)
4759 * ...
4760 * eval "$save_traps"
4761 *
4762 * Standard does not say that "trap" in subshell shall print
4763 * parent shell's traps. It only says that its output
4764 * must have suitable form, but then, in the above example
4765 * (which is not supposed to be normative), it implies that.
4766 *
4767 * bash (and probably other shell) does implement it
4768 * (traps are reset to defaults, but "trap" still shows them),
4769 * but as a result, "trap" logic is hopelessly messed up:
4770 *
4771 * # trap
4772 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4773 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4774 * # true | trap <--- trap is in subshell - no output (ditto)
4775 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4776 * trap -- 'echo Ho' SIGWINCH
4777 * # echo `(trap)` <--- in subshell in subshell - output
4778 * trap -- 'echo Ho' SIGWINCH
4779 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4780 * trap -- 'echo Ho' SIGWINCH
4781 *
4782 * The rules when to forget and when to not forget traps
4783 * get really complex and nonsensical.
4784 *
4785 * Our solution: ONLY bare $(trap) or `trap` is special.
4786 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004787 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02004788 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004789 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004790 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004791 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004792#if JOBS
4793 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004794 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004795 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004796 pid_t pgrp;
4797
4798 if (jp->nprocs == 0)
4799 pgrp = getpid();
4800 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004801 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004802 /* this can fail because we are doing it in the parent also */
4803 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004804 if (mode == FORK_FG)
4805 xtcsetpgrp(ttyfd, pgrp);
4806 setsignal(SIGTSTP);
4807 setsignal(SIGTTOU);
4808 } else
4809#endif
4810 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004811 /* man bash: "When job control is not in effect,
4812 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004813 ignoresig(SIGINT);
4814 ignoresig(SIGQUIT);
4815 if (jp->nprocs == 0) {
4816 close(0);
4817 if (open(bb_dev_null, O_RDONLY) != 0)
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00004818 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004819 }
4820 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004821 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004822 if (iflag) { /* why if iflag only? */
4823 setsignal(SIGINT);
4824 setsignal(SIGTERM);
4825 }
4826 /* man bash:
4827 * "In all cases, bash ignores SIGQUIT. Non-builtin
4828 * commands run by bash have signal handlers
4829 * set to the values inherited by the shell
4830 * from its parent".
4831 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004832 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004833 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004834#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02004835 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01004836 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004837 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004838 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02004839 /* "jobs": we do not want to clear job list for it,
4840 * instead we remove only _its_ own_ job from job list.
4841 * This makes "jobs .... | cat" more useful.
4842 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004843 freejob(curjob);
4844 return;
4845 }
4846#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004847 for (jp = curjob; jp; jp = jp->prev_job)
4848 freejob(jp);
4849 jobless = 0;
4850}
4851
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004852/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00004853#if !JOBS
4854#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4855#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004856static void
4857forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4858{
4859 TRACE(("In parent shell: child = %d\n", pid));
4860 if (!jp) {
Denys Vlasenko70392332016-10-27 02:31:55 +02004861 /* jp is NULL when called by openhere() for heredoc support */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004862 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4863 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004864 jobless++;
4865 return;
4866 }
4867#if JOBS
4868 if (mode != FORK_NOJOB && jp->jobctl) {
4869 int pgrp;
4870
4871 if (jp->nprocs == 0)
4872 pgrp = pid;
4873 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004874 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004875 /* This can fail because we are doing it in the child also */
4876 setpgid(pid, pgrp);
4877 }
4878#endif
4879 if (mode == FORK_BG) {
4880 backgndpid = pid; /* set $! */
4881 set_curjob(jp, CUR_RUNNING);
4882 }
4883 if (jp) {
4884 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01004885 ps->ps_pid = pid;
4886 ps->ps_status = -1;
4887 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004888#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004889 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004890 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004891#endif
4892 }
4893}
4894
Denys Vlasenko70392332016-10-27 02:31:55 +02004895/* jp and n are NULL when called by openhere() for heredoc support */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004896static int
4897forkshell(struct job *jp, union node *n, int mode)
4898{
4899 int pid;
4900
4901 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4902 pid = fork();
4903 if (pid < 0) {
4904 TRACE(("Fork failed, errno=%d", errno));
4905 if (jp)
4906 freejob(jp);
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +00004907 ash_msg_and_raise_error("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004908 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02004909 if (pid == 0) {
4910 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004911 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004912 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004913 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004914 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004915 return pid;
4916}
4917
4918/*
4919 * Wait for job to finish.
4920 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004921 * Under job control we have the problem that while a child process
4922 * is running interrupts generated by the user are sent to the child
4923 * but not to the shell. This means that an infinite loop started by
4924 * an interactive user may be hard to kill. With job control turned off,
4925 * an interactive user may place an interactive program inside a loop.
4926 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004927 * these interrupts to also abort the loop. The approach we take here
4928 * is to have the shell ignore interrupt signals while waiting for a
4929 * foreground process to terminate, and then send itself an interrupt
4930 * signal if the child process was terminated by an interrupt signal.
4931 * Unfortunately, some programs want to do a bit of cleanup and then
4932 * exit on interrupt; unless these processes terminate themselves by
4933 * sending a signal to themselves (instead of calling exit) they will
4934 * confuse this approach.
4935 *
4936 * Called with interrupts off.
4937 */
4938static int
4939waitforjob(struct job *jp)
4940{
4941 int st;
4942
4943 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004944
4945 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004946 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004947 /* In non-interactive shells, we _can_ get
4948 * a keyboard signal here and be EINTRed,
4949 * but we just loop back, waiting for command to complete.
4950 *
4951 * man bash:
4952 * "If bash is waiting for a command to complete and receives
4953 * a signal for which a trap has been set, the trap
4954 * will not be executed until the command completes."
4955 *
4956 * Reality is that even if trap is not set, bash
4957 * will not act on the signal until command completes.
4958 * Try this. sleep5intoff.c:
4959 * #include <signal.h>
4960 * #include <unistd.h>
4961 * int main() {
4962 * sigset_t set;
4963 * sigemptyset(&set);
4964 * sigaddset(&set, SIGINT);
4965 * sigaddset(&set, SIGQUIT);
4966 * sigprocmask(SIG_BLOCK, &set, NULL);
4967 * sleep(5);
4968 * return 0;
4969 * }
4970 * $ bash -c './sleep5intoff; echo hi'
4971 * ^C^C^C^C <--- pressing ^C once a second
4972 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004973 * $ bash -c './sleep5intoff; echo hi'
4974 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
4975 * $ _
4976 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004977 dowait(DOWAIT_BLOCK, jp);
4978 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004979 INT_ON;
4980
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004981 st = getstatus(jp);
4982#if JOBS
4983 if (jp->jobctl) {
4984 xtcsetpgrp(ttyfd, rootpid);
4985 /*
4986 * This is truly gross.
4987 * If we're doing job control, then we did a TIOCSPGRP which
4988 * caused us (the shell) to no longer be in the controlling
4989 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4990 * intuit from the subprocess exit status whether a SIGINT
4991 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4992 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004993 if (jp->sigint) /* TODO: do the same with all signals */
4994 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004995 }
4996 if (jp->state == JOBDONE)
4997#endif
4998 freejob(jp);
4999 return st;
5000}
5001
5002/*
5003 * return 1 if there are stopped jobs, otherwise 0
5004 */
5005static int
5006stoppedjobs(void)
5007{
5008 struct job *jp;
5009 int retval;
5010
5011 retval = 0;
5012 if (job_warning)
5013 goto out;
5014 jp = curjob;
5015 if (jp && jp->state == JOBSTOPPED) {
5016 out2str("You have stopped jobs.\n");
5017 job_warning = 2;
5018 retval++;
5019 }
5020 out:
5021 return retval;
5022}
5023
5024
Denys Vlasenko70392332016-10-27 02:31:55 +02005025/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005026 * Code for dealing with input/output redirection.
5027 */
5028
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005029#undef EMPTY
5030#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005031#define EMPTY -2 /* marks an unused slot in redirtab */
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005032#define CLOSED -3 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005033
5034/*
5035 * Open a file in noclobber mode.
5036 * The code was copied from bash.
5037 */
5038static int
5039noclobberopen(const char *fname)
5040{
5041 int r, fd;
5042 struct stat finfo, finfo2;
5043
5044 /*
5045 * If the file exists and is a regular file, return an error
5046 * immediately.
5047 */
5048 r = stat(fname, &finfo);
5049 if (r == 0 && S_ISREG(finfo.st_mode)) {
5050 errno = EEXIST;
5051 return -1;
5052 }
5053
5054 /*
5055 * If the file was not present (r != 0), make sure we open it
5056 * exclusively so that if it is created before we open it, our open
5057 * will fail. Make sure that we do not truncate an existing file.
5058 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5059 * file was not a regular file, we leave O_EXCL off.
5060 */
5061 if (r != 0)
5062 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5063 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5064
5065 /* If the open failed, return the file descriptor right away. */
5066 if (fd < 0)
5067 return fd;
5068
5069 /*
5070 * OK, the open succeeded, but the file may have been changed from a
5071 * non-regular file to a regular file between the stat and the open.
5072 * We are assuming that the O_EXCL open handles the case where FILENAME
5073 * did not exist and is symlinked to an existing file between the stat
5074 * and open.
5075 */
5076
5077 /*
5078 * If we can open it and fstat the file descriptor, and neither check
5079 * revealed that it was a regular file, and the file has not been
5080 * replaced, return the file descriptor.
5081 */
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005082 if (fstat(fd, &finfo2) == 0
5083 && !S_ISREG(finfo2.st_mode)
5084 && finfo.st_dev == finfo2.st_dev
5085 && finfo.st_ino == finfo2.st_ino
5086 ) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005087 return fd;
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005088 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005089
5090 /* The file has been replaced. badness. */
5091 close(fd);
5092 errno = EEXIST;
5093 return -1;
5094}
5095
5096/*
5097 * Handle here documents. Normally we fork off a process to write the
5098 * data to a pipe. If the document is short, we can stuff the data in
5099 * the pipe without forking.
5100 */
5101/* openhere needs this forward reference */
5102static void expandhere(union node *arg, int fd);
5103static int
5104openhere(union node *redir)
5105{
5106 int pip[2];
5107 size_t len = 0;
5108
5109 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005110 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005111 if (redir->type == NHERE) {
5112 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005113 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005114 full_write(pip[1], redir->nhere.doc->narg.text, len);
5115 goto out;
5116 }
5117 }
5118 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005119 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005120 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005121 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5122 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5123 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5124 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005125 signal(SIGPIPE, SIG_DFL);
5126 if (redir->type == NHERE)
5127 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005128 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005129 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005130 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005131 }
5132 out:
5133 close(pip[1]);
5134 return pip[0];
5135}
5136
5137static int
5138openredirect(union node *redir)
5139{
5140 char *fname;
5141 int f;
5142
5143 switch (redir->nfile.type) {
Denys Vlasenko557482c2016-09-25 21:24:04 +02005144/* Can't happen, our single caller does this itself */
5145// case NTOFD:
5146// case NFROMFD:
5147// return -1;
5148 case NHERE:
5149 case NXHERE:
5150 return openhere(redir);
5151 }
5152
5153 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5154 * allocated space. Do it only when we know it is safe.
5155 */
5156 fname = redir->nfile.expfname;
5157
5158 switch (redir->nfile.type) {
5159 default:
5160#if DEBUG
5161 abort();
5162#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005163 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005164 f = open(fname, O_RDONLY);
5165 if (f < 0)
5166 goto eopen;
5167 break;
5168 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005169 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005170 if (f < 0)
5171 goto ecreate;
5172 break;
5173 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00005174#if ENABLE_ASH_BASH_COMPAT
5175 case NTO2:
5176#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005177 /* Take care of noclobber mode. */
5178 if (Cflag) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005179 f = noclobberopen(fname);
5180 if (f < 0)
5181 goto ecreate;
5182 break;
5183 }
5184 /* FALLTHROUGH */
5185 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005186 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5187 if (f < 0)
5188 goto ecreate;
5189 break;
5190 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005191 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5192 if (f < 0)
5193 goto ecreate;
5194 break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005195 }
5196
5197 return f;
5198 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005199 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005200 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005201 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005202}
5203
5204/*
Denys Vlasenko64774602016-10-26 15:24:30 +02005205 * Copy a file descriptor to be >= 10. Throws exception on error.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005206 */
5207static int
Denys Vlasenko64774602016-10-26 15:24:30 +02005208savefd(int from)
5209{
5210 int newfd;
5211 int err;
5212
5213 newfd = fcntl(from, F_DUPFD, 10);
5214 err = newfd < 0 ? errno : 0;
5215 if (err != EBADF) {
5216 if (err)
5217 ash_msg_and_raise_error("%d: %m", from);
5218 close(from);
5219 fcntl(newfd, F_SETFD, FD_CLOEXEC);
5220 }
5221
5222 return newfd;
5223}
5224static int
5225dup2_or_raise(int from, int to)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005226{
5227 int newfd;
5228
Denys Vlasenko64774602016-10-26 15:24:30 +02005229 newfd = (from != to) ? dup2(from, to) : to;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005230 if (newfd < 0) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005231 /* Happens when source fd is not open: try "echo >&99" */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005232 ash_msg_and_raise_error("%d: %m", from);
5233 }
5234 return newfd;
5235}
5236
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005237/* Struct def and variable are moved down to the first usage site */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005238struct two_fd_t {
5239 int orig, copy;
5240};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005241struct redirtab {
5242 struct redirtab *next;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005243 int pair_count;
Denys Vlasenko606291b2009-09-23 23:15:43 +02005244 struct two_fd_t two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005245};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005246#define redirlist (G_var.redirlist)
Denys Vlasenko64774602016-10-26 15:24:30 +02005247enum {
5248 COPYFD_RESTORE = (int)~(INT_MAX),
5249};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005250
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005251static int
5252need_to_remember(struct redirtab *rp, int fd)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005253{
5254 int i;
5255
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005256 if (!rp) /* remembering was not requested */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005257 return 0;
5258
5259 for (i = 0; i < rp->pair_count; i++) {
5260 if (rp->two_fd[i].orig == fd) {
5261 /* already remembered */
5262 return 0;
5263 }
5264 }
5265 return 1;
5266}
5267
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005268/* "hidden" fd is a fd used to read scripts, or a copy of such */
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005269static int
5270is_hidden_fd(struct redirtab *rp, int fd)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005271{
5272 int i;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005273 struct parsefile *pf;
5274
5275 if (fd == -1)
5276 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005277 /* Check open scripts' fds */
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005278 pf = g_parsefile;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005279 while (pf) {
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005280 /* We skip pf_fd == 0 case because of the following case:
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005281 * $ ash # running ash interactively
5282 * $ . ./script.sh
5283 * and in script.sh: "exec 9>&0".
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005284 * Even though top-level pf_fd _is_ 0,
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005285 * it's still ok to use it: "read" builtin uses it,
5286 * why should we cripple "exec" builtin?
5287 */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005288 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005289 return 1;
5290 }
5291 pf = pf->prev;
5292 }
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005293
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005294 if (!rp)
5295 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005296 /* Check saved fds of redirects */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005297 fd |= COPYFD_RESTORE;
5298 for (i = 0; i < rp->pair_count; i++) {
5299 if (rp->two_fd[i].copy == fd) {
5300 return 1;
5301 }
5302 }
5303 return 0;
5304}
5305
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005306/*
5307 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5308 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005309 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005310 */
5311/* flags passed to redirect */
5312#define REDIR_PUSH 01 /* save previous values of file descriptors */
5313#define REDIR_SAVEFD2 03 /* set preverrout */
5314static void
5315redirect(union node *redir, int flags)
5316{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005317 struct redirtab *sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005318 int sv_pos;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005319 int i;
5320 int fd;
5321 int newfd;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005322 int copied_fd2 = -1;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005323
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005324 if (!redir) {
5325 return;
5326 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005327
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005328 sv = NULL;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005329 sv_pos = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005330 INT_OFF;
5331 if (flags & REDIR_PUSH) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005332 union node *tmp = redir;
5333 do {
5334 sv_pos++;
Denis Vlasenko559691a2008-10-05 18:39:31 +00005335#if ENABLE_ASH_BASH_COMPAT
Chris Metcalfc3c1fb62010-01-08 13:18:06 +01005336 if (tmp->nfile.type == NTO2)
Denis Vlasenko559691a2008-10-05 18:39:31 +00005337 sv_pos++;
5338#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005339 tmp = tmp->nfile.next;
5340 } while (tmp);
5341 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005342 sv->next = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005343 sv->pair_count = sv_pos;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005344 redirlist = sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005345 while (sv_pos > 0) {
5346 sv_pos--;
5347 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5348 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005349 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005350
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005351 do {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005352 int right_fd = -1;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005353 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005354 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005355 right_fd = redir->ndup.dupfd;
5356 //bb_error_msg("doing %d > %d", fd, right_fd);
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005357 /* redirect from/to same file descriptor? */
5358 if (right_fd == fd)
5359 continue;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005360 /* "echo >&10" and 10 is a fd opened to a sh script? */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005361 if (is_hidden_fd(sv, right_fd)) {
5362 errno = EBADF; /* as if it is closed */
5363 ash_msg_and_raise_error("%d: %m", right_fd);
5364 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005365 newfd = -1;
5366 } else {
5367 newfd = openredirect(redir); /* always >= 0 */
5368 if (fd == newfd) {
5369 /* Descriptor wasn't open before redirect.
5370 * Mark it for close in the future */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005371 if (need_to_remember(sv, fd)) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005372 goto remember_to_close;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005373 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005374 continue;
5375 }
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005376 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005377#if ENABLE_ASH_BASH_COMPAT
5378 redirect_more:
5379#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005380 if (need_to_remember(sv, fd)) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005381 /* Copy old descriptor */
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005382 /* Careful to not accidentally "save"
5383 * to the same fd as right side fd in N>&M */
5384 int minfd = right_fd < 10 ? 10 : right_fd + 1;
5385 i = fcntl(fd, F_DUPFD, minfd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005386/* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5387 * are closed in popredir() in the child, preventing them from leaking
5388 * into child. (popredir() also cleans up the mess in case of failures)
5389 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005390 if (i == -1) {
5391 i = errno;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005392 if (i != EBADF) {
5393 /* Strange error (e.g. "too many files" EMFILE?) */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005394 if (newfd >= 0)
5395 close(newfd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005396 errno = i;
5397 ash_msg_and_raise_error("%d: %m", fd);
5398 /* NOTREACHED */
5399 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005400 /* EBADF: it is not open - good, remember to close it */
5401 remember_to_close:
5402 i = CLOSED;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005403 } else { /* fd is open, save its copy */
5404 /* "exec fd>&-" should not close fds
5405 * which point to script file(s).
5406 * Force them to be restored afterwards */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005407 if (is_hidden_fd(sv, fd))
5408 i |= COPYFD_RESTORE;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005409 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005410 if (fd == 2)
5411 copied_fd2 = i;
5412 sv->two_fd[sv_pos].orig = fd;
5413 sv->two_fd[sv_pos].copy = i;
5414 sv_pos++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005415 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005416 if (newfd < 0) {
5417 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005418 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005419 /* Don't want to trigger debugging */
5420 if (fd != -1)
5421 close(fd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005422 } else {
Denys Vlasenko64774602016-10-26 15:24:30 +02005423 dup2_or_raise(redir->ndup.dupfd, fd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005424 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005425 } else if (fd != newfd) { /* move newfd to fd */
Denys Vlasenko64774602016-10-26 15:24:30 +02005426 dup2_or_raise(newfd, fd);
Denis Vlasenko559691a2008-10-05 18:39:31 +00005427#if ENABLE_ASH_BASH_COMPAT
5428 if (!(redir->nfile.type == NTO2 && fd == 2))
5429#endif
5430 close(newfd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005431 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005432#if ENABLE_ASH_BASH_COMPAT
5433 if (redir->nfile.type == NTO2 && fd == 1) {
5434 /* We already redirected it to fd 1, now copy it to 2 */
5435 newfd = 1;
5436 fd = 2;
5437 goto redirect_more;
5438 }
5439#endif
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005440 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005441
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005442 INT_ON;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005443 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5444 preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005445}
5446
5447/*
5448 * Undo the effects of the last redirection.
5449 */
5450static void
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005451popredir(int drop, int restore)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005452{
5453 struct redirtab *rp;
5454 int i;
5455
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02005456 if (redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005457 return;
5458 INT_OFF;
5459 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005460 for (i = 0; i < rp->pair_count; i++) {
5461 int fd = rp->two_fd[i].orig;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005462 int copy = rp->two_fd[i].copy;
5463 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005464 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005465 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005466 continue;
5467 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005468 if (copy != EMPTY) {
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005469 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
Denis Vlasenko22f74142008-07-24 22:34:43 +00005470 copy &= ~COPYFD_RESTORE;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005471 /*close(fd);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02005472 dup2_or_raise(copy, fd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005473 }
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005474 close(copy & ~COPYFD_RESTORE);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005475 }
5476 }
5477 redirlist = rp->next;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005478 free(rp);
5479 INT_ON;
5480}
5481
5482/*
5483 * Undo all redirections. Called on error or interrupt.
5484 */
5485
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005486static int
5487redirectsafe(union node *redir, int flags)
5488{
5489 int err;
5490 volatile int saveint;
5491 struct jmploc *volatile savehandler = exception_handler;
5492 struct jmploc jmploc;
5493
5494 SAVE_INT(saveint);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005495 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5496 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005497 if (!err) {
5498 exception_handler = &jmploc;
5499 redirect(redir, flags);
5500 }
5501 exception_handler = savehandler;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00005502 if (err && exception_type != EXERROR)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005503 longjmp(exception_handler->loc, 1);
5504 RESTORE_INT(saveint);
5505 return err;
5506}
5507
5508
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005509/* ============ Routines to expand arguments to commands
5510 *
5511 * We have to deal with backquotes, shell variables, and file metacharacters.
5512 */
5513
Mike Frysinger98c52642009-04-02 10:02:37 +00005514#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005515static arith_t
5516ash_arith(const char *s)
5517{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005518 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005519 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005520
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005521 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005522 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005523 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005524
5525 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005526 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005527 if (math_state.errmsg)
5528 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005529 INT_ON;
5530
5531 return result;
5532}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005533#endif
5534
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005535/*
5536 * expandarg flags
5537 */
5538#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5539#define EXP_TILDE 0x2 /* do normal tilde expansion */
5540#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5541#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
Denys Vlasenkodb74c6c2016-10-24 21:12:33 +02005542/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5543 * POSIX says for this case:
5544 * Pathname expansion shall not be performed on the word by a
5545 * non-interactive shell; an interactive shell may perform it, but shall
5546 * do so only when the expansion would result in one word.
5547 * Currently, our code complies to the above rule by never globbing
5548 * redirection filenames.
5549 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5550 * (this means that on a typical Linux distro, bash almost always
5551 * performs globbing, and thus diverges from what we do).
5552 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005553#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Ron Yorston549deab2015-05-18 09:57:51 +02005554#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005555#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5556#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005557#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005558/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005559 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005560 */
5561#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5562#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005563#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5564#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Ron Yorston417622c2015-05-18 09:59:14 +02005565#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005566
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005567/* Add CTLESC when necessary. */
Ron Yorston549deab2015-05-18 09:57:51 +02005568#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005569/* Do not skip NUL characters. */
5570#define QUOTES_KEEPNUL EXP_TILDE
5571
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005572/*
5573 * Structure specifying which parts of the string should be searched
5574 * for IFS characters.
5575 */
5576struct ifsregion {
5577 struct ifsregion *next; /* next region in list */
5578 int begoff; /* offset of start of region */
5579 int endoff; /* offset of end of region */
5580 int nulonly; /* search for nul bytes only */
5581};
5582
5583struct arglist {
5584 struct strlist *list;
5585 struct strlist **lastp;
5586};
5587
5588/* output of current string */
5589static char *expdest;
5590/* list of back quote expressions */
5591static struct nodelist *argbackq;
5592/* first struct in list of ifs regions */
5593static struct ifsregion ifsfirst;
5594/* last struct in list */
5595static struct ifsregion *ifslastp;
5596/* holds expanded arg list */
5597static struct arglist exparg;
5598
5599/*
5600 * Our own itoa().
5601 */
Denys Vlasenko26777aa2010-11-22 23:49:10 +01005602#if !ENABLE_SH_MATH_SUPPORT
5603/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5604typedef long arith_t;
5605# define ARITH_FMT "%ld"
5606#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005607static int
5608cvtnum(arith_t num)
5609{
5610 int len;
5611
Denys Vlasenko9c541002015-10-07 15:44:36 +02005612 expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest);
5613 len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005614 STADJUST(len, expdest);
5615 return len;
5616}
5617
Denys Vlasenko455e4222016-10-27 14:45:13 +02005618/*
5619 * Break the argument string into pieces based upon IFS and add the
5620 * strings to the argument list. The regions of the string to be
5621 * searched for IFS characters have been stored by recordregion.
5622 */
5623static void
5624ifsbreakup(char *string, struct arglist *arglist)
5625{
5626 struct ifsregion *ifsp;
5627 struct strlist *sp;
5628 char *start;
5629 char *p;
5630 char *q;
5631 const char *ifs, *realifs;
5632 int ifsspc;
5633 int nulonly;
5634
5635 start = string;
5636 if (ifslastp != NULL) {
5637 ifsspc = 0;
5638 nulonly = 0;
5639 realifs = ifsset() ? ifsval() : defifs;
5640 ifsp = &ifsfirst;
5641 do {
5642 p = string + ifsp->begoff;
5643 nulonly = ifsp->nulonly;
5644 ifs = nulonly ? nullstr : realifs;
5645 ifsspc = 0;
5646 while (p < string + ifsp->endoff) {
5647 q = p;
5648 if ((unsigned char)*p == CTLESC)
5649 p++;
5650 if (!strchr(ifs, *p)) {
5651 p++;
5652 continue;
5653 }
5654 if (!nulonly)
5655 ifsspc = (strchr(defifs, *p) != NULL);
5656 /* Ignore IFS whitespace at start */
5657 if (q == start && ifsspc) {
5658 p++;
5659 start = p;
5660 continue;
5661 }
5662 *q = '\0';
5663 sp = stzalloc(sizeof(*sp));
5664 sp->text = start;
5665 *arglist->lastp = sp;
5666 arglist->lastp = &sp->next;
5667 p++;
5668 if (!nulonly) {
5669 for (;;) {
5670 if (p >= string + ifsp->endoff) {
5671 break;
5672 }
5673 q = p;
5674 if ((unsigned char)*p == CTLESC)
5675 p++;
5676 if (strchr(ifs, *p) == NULL) {
5677 p = q;
5678 break;
5679 }
5680 if (strchr(defifs, *p) == NULL) {
5681 if (ifsspc) {
5682 p++;
5683 ifsspc = 0;
5684 } else {
5685 p = q;
5686 break;
5687 }
5688 } else
5689 p++;
5690 }
5691 }
5692 start = p;
5693 } /* while */
5694 ifsp = ifsp->next;
5695 } while (ifsp != NULL);
5696 if (nulonly)
5697 goto add;
5698 }
5699
5700 if (!*start)
5701 return;
5702
5703 add:
5704 sp = stzalloc(sizeof(*sp));
5705 sp->text = start;
5706 *arglist->lastp = sp;
5707 arglist->lastp = &sp->next;
5708}
5709
5710static void
5711ifsfree(void)
5712{
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005713 struct ifsregion *p = ifsfirst.next;
5714
5715 if (!p)
5716 goto out;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005717
5718 INT_OFF;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005719 do {
5720 struct ifsregion *ifsp;
5721 ifsp = p->next;
5722 free(p);
5723 p = ifsp;
5724 } while (p);
Denys Vlasenko455e4222016-10-27 14:45:13 +02005725 ifsfirst.next = NULL;
5726 INT_ON;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005727 out:
5728 ifslastp = NULL;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005729}
5730
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005731static size_t
5732esclen(const char *start, const char *p)
5733{
5734 size_t esc = 0;
5735
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005736 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005737 esc++;
5738 }
5739 return esc;
5740}
5741
5742/*
5743 * Remove any CTLESC characters from a string.
5744 */
5745static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005746rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005747{
Ron Yorston417622c2015-05-18 09:59:14 +02005748 static const char qchars[] ALIGN1 = {
5749 IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005750
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005751 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005752 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005753 unsigned protect_against_glob;
5754 unsigned globbing;
Ron Yorston417622c2015-05-18 09:59:14 +02005755 IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005756
Ron Yorston417622c2015-05-18 09:59:14 +02005757 p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005758 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005759 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005760
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005761 q = p;
5762 r = str;
5763 if (flag & RMESCAPE_ALLOC) {
5764 size_t len = p - str;
5765 size_t fulllen = len + strlen(p) + 1;
5766
5767 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005768 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005769 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005770 /* p and str may be invalidated by makestrspace */
5771 str = (char *)stackblock() + strloc;
5772 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005773 } else if (flag & RMESCAPE_HEAP) {
5774 r = ckmalloc(fulllen);
5775 } else {
5776 r = stalloc(fulllen);
5777 }
5778 q = r;
5779 if (len > 0) {
Denis Vlasenko29eb3592008-05-18 14:06:08 +00005780 q = (char *)memcpy(q, str, len) + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005781 }
5782 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005783
Ron Yorston549deab2015-05-18 09:57:51 +02005784 inquotes = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005785 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005786 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005787 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005788 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005789// Note: both inquotes and protect_against_glob only affect whether
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005790 inquotes = ~inquotes;
5791 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005792 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005793 continue;
5794 }
Ron Yorston549deab2015-05-18 09:57:51 +02005795 if ((unsigned char)*p == CTLESC) {
5796 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02005797#if DEBUG
5798 if (*p == '\0')
5799 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
5800#endif
Ron Yorston549deab2015-05-18 09:57:51 +02005801 if (protect_against_glob) {
5802 *q++ = '\\';
5803 }
5804 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005805 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005806 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005807 goto copy;
5808 }
Ron Yorston417622c2015-05-18 09:59:14 +02005809#if ENABLE_ASH_BASH_COMPAT
5810 else if (*p == '/' && slash) {
5811 /* stop handling globbing and mark location of slash */
5812 globbing = slash = 0;
5813 *p = CTLESC;
5814 }
5815#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005816 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005817 copy:
5818 *q++ = *p++;
5819 }
5820 *q = '\0';
5821 if (flag & RMESCAPE_GROW) {
5822 expdest = r;
5823 STADJUST(q - r + 1, expdest);
5824 }
5825 return r;
5826}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005827#define pmatch(a, b) !fnmatch((a), (b), 0)
5828
5829/*
5830 * Prepare a pattern for a expmeta (internal glob(3)) call.
5831 *
5832 * Returns an stalloced string.
5833 */
5834static char *
Ron Yorston549deab2015-05-18 09:57:51 +02005835preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005836{
Ron Yorston549deab2015-05-18 09:57:51 +02005837 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005838}
5839
5840/*
5841 * Put a string on the stack.
5842 */
5843static void
5844memtodest(const char *p, size_t len, int syntax, int quotes)
5845{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005846 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005847
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005848 if (!len)
5849 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005850
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005851 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
5852
5853 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005854 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005855 if (c) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005856 int n = SIT(c, syntax);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02005857 if ((quotes & QUOTES_ESC)
5858 && ((n == CCTL)
5859 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
5860 && n == CBACK)
5861 )
5862 ) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005863 USTPUTC(CTLESC, q);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02005864 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005865 } else if (!(quotes & QUOTES_KEEPNUL))
5866 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005867 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005868 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005869
5870 expdest = q;
5871}
5872
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005873static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005874strtodest(const char *p, int syntax, int quotes)
5875{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005876 size_t len = strlen(p);
5877 memtodest(p, len, syntax, quotes);
5878 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005879}
5880
5881/*
5882 * Record the fact that we have to scan this region of the
5883 * string for IFS characters.
5884 */
5885static void
5886recordregion(int start, int end, int nulonly)
5887{
5888 struct ifsregion *ifsp;
5889
5890 if (ifslastp == NULL) {
5891 ifsp = &ifsfirst;
5892 } else {
5893 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00005894 ifsp = ckzalloc(sizeof(*ifsp));
5895 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005896 ifslastp->next = ifsp;
5897 INT_ON;
5898 }
5899 ifslastp = ifsp;
5900 ifslastp->begoff = start;
5901 ifslastp->endoff = end;
5902 ifslastp->nulonly = nulonly;
5903}
5904
5905static void
5906removerecordregions(int endoff)
5907{
5908 if (ifslastp == NULL)
5909 return;
5910
5911 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005912 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005913 struct ifsregion *ifsp;
5914 INT_OFF;
5915 ifsp = ifsfirst.next->next;
5916 free(ifsfirst.next);
5917 ifsfirst.next = ifsp;
5918 INT_ON;
5919 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005920 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005921 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005922 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005923 ifslastp = &ifsfirst;
5924 ifsfirst.endoff = endoff;
5925 }
5926 return;
5927 }
5928
5929 ifslastp = &ifsfirst;
5930 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005931 ifslastp = ifslastp->next;
5932 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005933 struct ifsregion *ifsp;
5934 INT_OFF;
5935 ifsp = ifslastp->next->next;
5936 free(ifslastp->next);
5937 ifslastp->next = ifsp;
5938 INT_ON;
5939 }
5940 if (ifslastp->endoff > endoff)
5941 ifslastp->endoff = endoff;
5942}
5943
5944static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005945exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005946{
Denys Vlasenkocd716832009-11-28 22:14:02 +01005947 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005948 char *name;
5949 struct passwd *pw;
5950 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005951 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005952
5953 name = p + 1;
5954
5955 while ((c = *++p) != '\0') {
5956 switch (c) {
5957 case CTLESC:
5958 return startp;
5959 case CTLQUOTEMARK:
5960 return startp;
5961 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005962 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005963 goto done;
5964 break;
5965 case '/':
5966 case CTLENDVAR:
5967 goto done;
5968 }
5969 }
5970 done:
5971 *p = '\0';
5972 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02005973 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005974 } else {
5975 pw = getpwnam(name);
5976 if (pw == NULL)
5977 goto lose;
5978 home = pw->pw_dir;
5979 }
5980 if (!home || !*home)
5981 goto lose;
5982 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005983 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005984 return p;
5985 lose:
5986 *p = c;
5987 return startp;
5988}
5989
5990/*
5991 * Execute a command inside back quotes. If it's a builtin command, we
5992 * want to save its output in a block obtained from malloc. Otherwise
5993 * we fork off a subprocess and get the output of the command via a pipe.
5994 * Should be called with interrupts off.
5995 */
5996struct backcmd { /* result of evalbackcmd */
5997 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005998 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005999 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006000 struct job *jp; /* job structure for command */
6001};
6002
6003/* These forward decls are needed to use "eval" code for backticks handling: */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006004#define EV_EXIT 01 /* exit after evaluating tree */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02006005static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006006
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02006007static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006008evalbackcmd(union node *n, struct backcmd *result)
6009{
Denys Vlasenko579ad102016-10-25 21:10:20 +02006010 int pip[2];
6011 struct job *jp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006012
6013 result->fd = -1;
6014 result->buf = NULL;
6015 result->nleft = 0;
6016 result->jp = NULL;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006017 if (n == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006018 goto out;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006019 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006020
Denys Vlasenko579ad102016-10-25 21:10:20 +02006021 if (pipe(pip) < 0)
6022 ash_msg_and_raise_error("pipe call failed");
6023 jp = makejob(/*n,*/ 1);
6024 if (forkshell(jp, n, FORK_NOJOB) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02006025 /* child */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006026 FORCE_INT_ON;
6027 close(pip[0]);
6028 if (pip[1] != 1) {
6029 /*close(1);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02006030 dup2_or_raise(pip[1], 1);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006031 close(pip[1]);
6032 }
Denys Vlasenko960ca382016-10-25 18:12:15 +02006033/* TODO: eflag clearing makes the following not abort:
6034 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6035 * which is what bash does (unless it is in POSIX mode).
6036 * dash deleted "eflag = 0" line in the commit
6037 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6038 * [EVAL] Don't clear eflag in evalbackcmd
6039 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6040 */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006041 eflag = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006042 ifsfree();
Denys Vlasenko579ad102016-10-25 21:10:20 +02006043 evaltree(n, EV_EXIT); /* actually evaltreenr... */
6044 /* NOTREACHED */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006045 }
Denys Vlasenko70392332016-10-27 02:31:55 +02006046 /* parent */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006047 close(pip[1]);
6048 result->fd = pip[0];
6049 result->jp = jp;
6050
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006051 out:
6052 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6053 result->fd, result->buf, result->nleft, result->jp));
6054}
6055
6056/*
6057 * Expand stuff in backwards quotes.
6058 */
6059static void
Ron Yorston549deab2015-05-18 09:57:51 +02006060expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006061{
6062 struct backcmd in;
6063 int i;
6064 char buf[128];
6065 char *p;
6066 char *dest;
6067 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02006068 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006069 struct stackmark smark;
6070
6071 INT_OFF;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02006072 startloc = expdest - (char *)stackblock();
6073 pushstackmark(&smark, startloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006074 evalbackcmd(cmd, &in);
6075 popstackmark(&smark);
6076
6077 p = in.buf;
6078 i = in.nleft;
6079 if (i == 0)
6080 goto read;
6081 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02006082 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006083 read:
6084 if (in.fd < 0)
6085 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01006086 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006087 TRACE(("expbackq: read returns %d\n", i));
6088 if (i <= 0)
6089 break;
6090 p = buf;
6091 }
6092
Denis Vlasenko60818682007-09-28 22:07:23 +00006093 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006094 if (in.fd >= 0) {
6095 close(in.fd);
6096 back_exitstatus = waitforjob(in.jp);
6097 }
6098 INT_ON;
6099
6100 /* Eat all trailing newlines */
6101 dest = expdest;
6102 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6103 STUNPUTC(dest);
6104 expdest = dest;
6105
Ron Yorston549deab2015-05-18 09:57:51 +02006106 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006107 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006108 TRACE(("evalbackq: size:%d:'%.*s'\n",
6109 (int)((dest - (char *)stackblock()) - startloc),
6110 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006111 stackblock() + startloc));
6112}
6113
Mike Frysinger98c52642009-04-02 10:02:37 +00006114#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006115/*
6116 * Expand arithmetic expression. Backup to start of expression,
6117 * evaluate, place result in (backed up) result, adjust string position.
6118 */
6119static void
Ron Yorston549deab2015-05-18 09:57:51 +02006120expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006121{
6122 char *p, *start;
6123 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006124 int len;
6125
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006126 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006127
6128 /*
6129 * This routine is slightly over-complicated for
6130 * efficiency. Next we scan backwards looking for the
6131 * start of arithmetic.
6132 */
6133 start = stackblock();
6134 p = expdest - 1;
6135 *p = '\0';
6136 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006137 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006138 int esc;
6139
Denys Vlasenkocd716832009-11-28 22:14:02 +01006140 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006141 p--;
6142#if DEBUG
6143 if (p < start) {
6144 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6145 }
6146#endif
6147 }
6148
6149 esc = esclen(start, p);
6150 if (!(esc % 2)) {
6151 break;
6152 }
6153
6154 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006155 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006156
6157 begoff = p - start;
6158
6159 removerecordregions(begoff);
6160
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006161 expdest = p;
6162
Ron Yorston549deab2015-05-18 09:57:51 +02006163 if (flag & QUOTES_ESC)
6164 rmescapes(p + 1, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006165
Ron Yorston549deab2015-05-18 09:57:51 +02006166 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006167
Ron Yorston549deab2015-05-18 09:57:51 +02006168 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006169 recordregion(begoff, begoff + len, 0);
6170}
6171#endif
6172
6173/* argstr needs it */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006174static char *evalvar(char *p, int flags, struct strlist *var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006175
6176/*
6177 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6178 * characters to allow for further processing. Otherwise treat
6179 * $@ like $* since no splitting will be performed.
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006180 *
6181 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
6182 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
6183 * for correct expansion of "B=$A" word.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006184 */
6185static void
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006186argstr(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006187{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006188 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006189 '=',
6190 ':',
6191 CTLQUOTEMARK,
6192 CTLENDVAR,
6193 CTLESC,
6194 CTLVAR,
6195 CTLBACKQ,
Mike Frysinger98c52642009-04-02 10:02:37 +00006196#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006197 CTLENDARI,
6198#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006199 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006200 };
6201 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006202 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006203 int inquotes;
6204 size_t length;
6205 int startloc;
6206
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006207 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006208 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006209 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006210 reject++;
6211 }
6212 inquotes = 0;
6213 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006214 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006215 char *q;
6216
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006217 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006218 tilde:
6219 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006220 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006221 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006222 }
6223 start:
6224 startloc = expdest - (char *)stackblock();
6225 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006226 unsigned char c;
6227
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006228 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006229 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006230 if (c) {
6231 if (!(c & 0x80)
Denys Vlasenko958581a2010-09-12 15:04:27 +02006232 IF_SH_MATH_SUPPORT(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006233 ) {
6234 /* c == '=' || c == ':' || c == CTLENDARI */
6235 length++;
6236 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006237 }
6238 if (length > 0) {
6239 int newloc;
6240 expdest = stack_nputstr(p, length, expdest);
6241 newloc = expdest - (char *)stackblock();
6242 if (breakall && !inquotes && newloc > startloc) {
6243 recordregion(startloc, newloc, 0);
6244 }
6245 startloc = newloc;
6246 }
6247 p += length + 1;
6248 length = 0;
6249
6250 switch (c) {
6251 case '\0':
6252 goto breakloop;
6253 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006254 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006255 p--;
6256 continue;
6257 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006258 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006259 reject++;
6260 /* fall through */
6261 case ':':
6262 /*
6263 * sort of a hack - expand tildes in variable
6264 * assignments (after the first '=' and after ':'s).
6265 */
6266 if (*--p == '~') {
6267 goto tilde;
6268 }
6269 continue;
6270 }
6271
6272 switch (c) {
6273 case CTLENDVAR: /* ??? */
6274 goto breakloop;
6275 case CTLQUOTEMARK:
Ron Yorston549deab2015-05-18 09:57:51 +02006276 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006277 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006278 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6279 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006280 goto start;
6281 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006282 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006283 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006284 p--;
6285 length++;
6286 startloc++;
6287 }
6288 break;
6289 case CTLESC:
6290 startloc++;
6291 length++;
Ron Yorston549deab2015-05-18 09:57:51 +02006292
6293 /*
6294 * Quoted parameter expansion pattern: remove quote
6295 * unless inside inner quotes or we have a literal
6296 * backslash.
6297 */
6298 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6299 EXP_QPAT && *p != '\\')
6300 break;
6301
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006302 goto addquote;
6303 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006304 TRACE(("argstr: evalvar('%s')\n", p));
Ron Yorston549deab2015-05-18 09:57:51 +02006305 p = evalvar(p, flags | inquotes, var_str_list);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006306 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006307 goto start;
6308 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006309 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006310 argbackq = argbackq->next;
6311 goto start;
Mike Frysinger98c52642009-04-02 10:02:37 +00006312#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006313 case CTLENDARI:
6314 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006315 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006316 goto start;
6317#endif
6318 }
6319 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006320 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006321}
6322
6323static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006324scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6325 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006326{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006327 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006328 char c;
6329
6330 loc = startp;
6331 loc2 = rmesc;
6332 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006333 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006334 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006335
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006336 c = *loc2;
6337 if (zero) {
6338 *loc2 = '\0';
6339 s = rmesc;
6340 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006341 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006342
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006343 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006344 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006345 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006346 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006347 loc++;
6348 loc++;
6349 loc2++;
6350 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006351 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006352}
6353
6354static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006355scanright(char *startp, char *rmesc, char *rmescend,
6356 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006357{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006358#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6359 int try2optimize = match_at_start;
6360#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006361 int esc = 0;
6362 char *loc;
6363 char *loc2;
6364
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006365 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6366 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6367 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6368 * Logic:
6369 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6370 * and on each iteration they go back two/one char until they reach the beginning.
6371 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6372 */
6373 /* TODO: document in what other circumstances we are called. */
6374
6375 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006376 int match;
6377 char c = *loc2;
6378 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006379 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006380 *loc2 = '\0';
6381 s = rmesc;
6382 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006383 match = pmatch(pattern, s);
6384 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006385 *loc2 = c;
6386 if (match)
6387 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006388#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6389 if (try2optimize) {
6390 /* Maybe we can optimize this:
6391 * if pattern ends with unescaped *, we can avoid checking
6392 * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6393 * it wont match truncated "raw_value_of_" strings too.
6394 */
6395 unsigned plen = strlen(pattern);
6396 /* Does it end with "*"? */
6397 if (plen != 0 && pattern[--plen] == '*') {
6398 /* "xxxx*" is not escaped */
6399 /* "xxx\*" is escaped */
6400 /* "xx\\*" is not escaped */
6401 /* "x\\\*" is escaped */
6402 int slashes = 0;
6403 while (plen != 0 && pattern[--plen] == '\\')
6404 slashes++;
6405 if (!(slashes & 1))
6406 break; /* ends with unescaped "*" */
6407 }
6408 try2optimize = 0;
6409 }
6410#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006411 loc--;
6412 if (quotes) {
6413 if (--esc < 0) {
6414 esc = esclen(startp, loc);
6415 }
6416 if (esc % 2) {
6417 esc--;
6418 loc--;
6419 }
6420 }
6421 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006422 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006423}
6424
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006425static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006426static void
6427varunset(const char *end, const char *var, const char *umsg, int varflags)
6428{
6429 const char *msg;
6430 const char *tail;
6431
6432 tail = nullstr;
6433 msg = "parameter not set";
6434 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006435 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006436 if (varflags & VSNUL)
6437 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006438 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006439 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006440 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006441 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006442 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006443}
6444
6445static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006446subevalvar(char *p, char *varname, int strloc, int subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006447 int startloc, int varflags, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006448{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006449 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006450 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006451 char *startp;
6452 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006453 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006454 char *str;
Ron Yorston417622c2015-05-18 09:59:14 +02006455 IF_ASH_BASH_COMPAT(char *repl = NULL;)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006456 IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006457 int amount, resetloc;
6458 IF_ASH_BASH_COMPAT(int workloc;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006459 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006460 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006461
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006462 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6463 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006464
Ron Yorstoneb6b48b2015-05-18 09:51:35 +02006465 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
Ron Yorston549deab2015-05-18 09:57:51 +02006466 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6467 var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006468 STPUTC('\0', expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006469 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006470 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006471
6472 switch (subtype) {
6473 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006474 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006475 amount = startp - expdest;
6476 STADJUST(amount, expdest);
6477 return startp;
6478
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006479 case VSQUESTION:
6480 varunset(p, varname, startp, varflags);
6481 /* NOTREACHED */
6482
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006483#if ENABLE_ASH_BASH_COMPAT
6484 case VSSUBSTR:
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +02006485//TODO: support more general format ${v:EXPR:EXPR},
6486// where EXPR follows $(()) rules
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006487 loc = str = stackblock() + strloc;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006488 /* Read POS in ${var:POS:LEN} */
6489 pos = atoi(loc); /* number(loc) errors out on "1:4" */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006490 len = str - startp - 1;
6491
6492 /* *loc != '\0', guaranteed by parser */
6493 if (quotes) {
6494 char *ptr;
6495
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006496 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006497 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006498 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006499 len--;
6500 ptr++;
6501 }
6502 }
6503 }
6504 orig_len = len;
6505
6506 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006507 /* ${var::LEN} */
6508 len = number(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006509 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006510 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006511 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006512 while (*loc && *loc != ':') {
6513 /* TODO?
6514 * bash complains on: var=qwe; echo ${var:1a:123}
6515 if (!isdigit(*loc))
6516 ash_msg_and_raise_error(msg_illnum, str);
6517 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006518 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006519 }
6520 if (*loc++ == ':') {
6521 len = number(loc);
6522 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006523 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006524 if (pos < 0) {
6525 /* ${VAR:$((-n)):l} starts n chars from the end */
6526 pos = orig_len + pos;
6527 }
6528 if ((unsigned)pos >= orig_len) {
6529 /* apart from obvious ${VAR:999999:l},
6530 * covers ${VAR:$((-9999999)):l} - result is ""
6531 * (bash-compat)
6532 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006533 pos = 0;
6534 len = 0;
6535 }
6536 if (len > (orig_len - pos))
6537 len = orig_len - pos;
6538
6539 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006540 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006541 str++;
6542 }
6543 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006544 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006545 *loc++ = *str++;
6546 *loc++ = *str++;
6547 }
6548 *loc = '\0';
6549 amount = loc - expdest;
6550 STADJUST(amount, expdest);
6551 return loc;
6552#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006553 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006554
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006555 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006556
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006557 /* We'll comeback here if we grow the stack while handling
6558 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6559 * stack will need rebasing, and we'll need to remove our work
6560 * areas each time
6561 */
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006562 IF_ASH_BASH_COMPAT(restart:)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006563
6564 amount = expdest - ((char *)stackblock() + resetloc);
6565 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006566 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006567
6568 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006569 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006570 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006571 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006572 if (rmesc != startp) {
6573 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006574 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006575 }
6576 }
6577 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006578 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02006579 /*
6580 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6581 * The result is a_\_z_c (not a\_\_z_c)!
6582 *
6583 * The search pattern and replace string treat backslashes differently!
6584 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6585 * and string. It's only used on the first call.
6586 */
6587 preglob(str, IF_ASH_BASH_COMPAT(
6588 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
6589 RMESCAPE_SLASH :) 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006590
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006591#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006592 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006593 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006594 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006595
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006596 if (!repl) {
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006597 repl = strchr(str, CTLESC);
6598 if (repl)
Ron Yorston417622c2015-05-18 09:59:14 +02006599 *repl++ = '\0';
6600 else
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006601 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006602 }
Ron Yorston417622c2015-05-18 09:59:14 +02006603 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006604
6605 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006606 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006607 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006608
6609 len = 0;
6610 idx = startp;
6611 end = str - 1;
6612 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006613 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006614 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006615 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006616 if (!loc) {
6617 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006618 char *restart_detect = stackblock();
6619 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006620 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006621 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006622 idx++;
6623 len++;
6624 STPUTC(*idx, expdest);
6625 }
6626 if (stackblock() != restart_detect)
6627 goto restart;
6628 idx++;
6629 len++;
6630 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006631 /* continue; - prone to quadratic behavior, smarter code: */
6632 if (idx >= end)
6633 break;
6634 if (str[0] == '*') {
6635 /* Pattern is "*foo". If "*foo" does not match "long_string",
6636 * it would never match "ong_string" etc, no point in trying.
6637 */
6638 goto skip_matching;
6639 }
6640 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006641 }
6642
6643 if (subtype == VSREPLACEALL) {
6644 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006645 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006646 idx++;
6647 idx++;
6648 rmesc++;
6649 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006650 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006651 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006652 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006653
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006654 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006655 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006656 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006657 if (quotes && *loc == '\\') {
6658 STPUTC(CTLESC, expdest);
6659 len++;
6660 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006661 STPUTC(*loc, expdest);
6662 if (stackblock() != restart_detect)
6663 goto restart;
6664 len++;
6665 }
6666
6667 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006668 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006669 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006670 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006671 STPUTC(*idx, expdest);
6672 if (stackblock() != restart_detect)
6673 goto restart;
6674 len++;
6675 idx++;
6676 }
6677 break;
6678 }
6679 }
6680
6681 /* We've put the replaced text into a buffer at workloc, now
6682 * move it to the right place and adjust the stack.
6683 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006684 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006685 startp = (char *)stackblock() + startloc;
6686 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006687 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006688 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006689 STADJUST(-amount, expdest);
6690 return startp;
6691 }
6692#endif /* ENABLE_ASH_BASH_COMPAT */
6693
6694 subtype -= VSTRIMRIGHT;
6695#if DEBUG
6696 if (subtype < 0 || subtype > 7)
6697 abort();
6698#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006699 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006700 zero = subtype >> 1;
6701 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6702 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6703
6704 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6705 if (loc) {
6706 if (zero) {
6707 memmove(startp, loc, str - loc);
6708 loc = startp + (str - loc) - 1;
6709 }
6710 *loc = '\0';
6711 amount = loc - expdest;
6712 STADJUST(amount, expdest);
6713 }
6714 return loc;
6715}
6716
6717/*
6718 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006719 * name parameter (examples):
6720 * ash -c 'echo $1' name:'1='
6721 * ash -c 'echo $qwe' name:'qwe='
6722 * ash -c 'echo $$' name:'$='
6723 * ash -c 'echo ${$}' name:'$='
6724 * ash -c 'echo ${$##q}' name:'$=q'
6725 * ash -c 'echo ${#$}' name:'$='
6726 * note: examples with bad shell syntax:
6727 * ash -c 'echo ${#$1}' name:'$=1'
6728 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006729 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02006730static NOINLINE ssize_t
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006731varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int *quotedp)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006732{
Mike Frysinger98c52642009-04-02 10:02:37 +00006733 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006734 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006735 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006736 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006737 int sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006738 int quoted = *quotedp;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006739 int subtype = varflags & VSTYPE;
6740 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6741 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006742 int syntax;
6743
6744 sep = (flags & EXP_FULL) << CHAR_BIT;
6745 syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006746
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006747 switch (*name) {
6748 case '$':
6749 num = rootpid;
6750 goto numvar;
6751 case '?':
6752 num = exitstatus;
6753 goto numvar;
6754 case '#':
6755 num = shellparam.nparam;
6756 goto numvar;
6757 case '!':
6758 num = backgndpid;
6759 if (num == 0)
6760 return -1;
6761 numvar:
6762 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006763 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006764 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00006765 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006766 for (i = NOPTS - 1; i >= 0; i--) {
6767 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00006768 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006769 len++;
6770 }
6771 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006772 check_1char_name:
6773#if 0
6774 /* handles cases similar to ${#$1} */
6775 if (name[2] != '\0')
6776 raise_error_syntax("bad substitution");
6777#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006778 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006779 case '@':
6780 if (quoted && sep)
6781 goto param;
6782 /* fall through */
6783 case '*': {
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006784 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006785 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006786
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006787 if (quoted)
6788 sep = 0;
6789 sep |= ifsset() ? ifsval()[0] : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006790 param:
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006791 sepc = sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006792 *quotedp = !sepc;
6793 ap = shellparam.p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006794 if (!ap)
6795 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006796 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006797 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006798
6799 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006800 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006801 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006802 }
6803 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006804 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006805 } /* case '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006806 case '0':
6807 case '1':
6808 case '2':
6809 case '3':
6810 case '4':
6811 case '5':
6812 case '6':
6813 case '7':
6814 case '8':
6815 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02006816 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006817 if (num < 0 || num > shellparam.nparam)
6818 return -1;
6819 p = num ? shellparam.p[num - 1] : arg0;
6820 goto value;
6821 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006822 /* NB: name has form "VAR=..." */
6823
6824 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6825 * which should be considered before we check variables. */
6826 if (var_str_list) {
6827 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6828 p = NULL;
6829 do {
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00006830 char *str, *eq;
6831 str = var_str_list->text;
6832 eq = strchr(str, '=');
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006833 if (!eq) /* stop at first non-assignment */
6834 break;
6835 eq++;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00006836 if (name_len == (unsigned)(eq - str)
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006837 && strncmp(str, name, name_len) == 0
6838 ) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006839 p = eq;
6840 /* goto value; - WRONG! */
6841 /* think "A=1 A=2 B=$A" */
6842 }
6843 var_str_list = var_str_list->next;
6844 } while (var_str_list);
6845 if (p)
6846 goto value;
6847 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006848 p = lookupvar(name);
6849 value:
6850 if (!p)
6851 return -1;
6852
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006853 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006854#if ENABLE_UNICODE_SUPPORT
6855 if (subtype == VSLENGTH && len > 0) {
6856 reinit_unicode_for_ash();
6857 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00006858 STADJUST(-len, expdest);
6859 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006860 len = unicode_strlen(p);
6861 }
6862 }
6863#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006864 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006865 }
6866
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006867 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006868 STADJUST(-len, expdest);
6869 return len;
6870}
6871
6872/*
6873 * Expand a variable, and return a pointer to the next character in the
6874 * input string.
6875 */
6876static char *
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006877evalvar(char *p, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006878{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006879 char varflags;
6880 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02006881 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006882 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006883 char *var;
6884 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006885 int startloc;
6886 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006887
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006888 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006889 subtype = varflags & VSTYPE;
Denys Vlasenko88e15702016-10-26 01:55:56 +02006890
6891 if (!subtype)
6892 raise_error_syntax("bad substitution");
6893
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006894 quoted = flag & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006895 var = p;
6896 easy = (!quoted || (*var == '@' && shellparam.nparam));
6897 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02006898 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006899
6900 again:
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006901 varlen = varvalue(var, varflags, flag, var_str_list, &quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006902 if (varflags & VSNUL)
6903 varlen--;
6904
6905 if (subtype == VSPLUS) {
6906 varlen = -1 - varlen;
6907 goto vsplus;
6908 }
6909
6910 if (subtype == VSMINUS) {
6911 vsplus:
6912 if (varlen < 0) {
6913 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006914 p,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006915 flag | EXP_TILDE | EXP_WORD,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006916 var_str_list
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006917 );
6918 goto end;
6919 }
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006920 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006921 }
6922
6923 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006924 if (varlen >= 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006925 goto record;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006926
6927 subevalvar(p, var, 0, subtype, startloc, varflags,
6928 flag & ~QUOTES_ESC, var_str_list);
6929 varflags &= ~VSNUL;
6930 /*
6931 * Remove any recorded regions beyond
6932 * start of variable
6933 */
6934 removerecordregions(startloc);
6935 goto again;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006936 }
6937
6938 if (varlen < 0 && uflag)
6939 varunset(p, var, 0, 0);
6940
6941 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006942 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006943 goto record;
6944 }
6945
6946 if (subtype == VSNORMAL) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006947 record:
6948 if (!easy)
6949 goto end;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006950 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006951 goto end;
6952 }
6953
6954#if DEBUG
6955 switch (subtype) {
6956 case VSTRIMLEFT:
6957 case VSTRIMLEFTMAX:
6958 case VSTRIMRIGHT:
6959 case VSTRIMRIGHTMAX:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006960#if ENABLE_ASH_BASH_COMPAT
6961 case VSSUBSTR:
6962 case VSREPLACE:
6963 case VSREPLACEALL:
6964#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006965 break;
6966 default:
6967 abort();
6968 }
6969#endif
6970
6971 if (varlen >= 0) {
6972 /*
6973 * Terminate the string and start recording the pattern
6974 * right after it
6975 */
6976 STPUTC('\0', expdest);
6977 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006978 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006979 startloc, varflags, flag, var_str_list)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006980 int amount = expdest - (
6981 (char *)stackblock() + patloc - 1
6982 );
6983 STADJUST(-amount, expdest);
6984 }
6985 /* Remove any recorded regions beyond start of variable */
6986 removerecordregions(startloc);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006987 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006988 }
6989
6990 end:
6991 if (subtype != VSNORMAL) { /* skip to end of alternative */
6992 int nesting = 1;
6993 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006994 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006995 if (c == CTLESC)
6996 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02006997 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006998 if (varlen >= 0)
6999 argbackq = argbackq->next;
7000 } else if (c == CTLVAR) {
7001 if ((*p++ & VSTYPE) != VSNORMAL)
7002 nesting++;
7003 } else if (c == CTLENDVAR) {
7004 if (--nesting == 0)
7005 break;
7006 }
7007 }
7008 }
7009 return p;
7010}
7011
7012/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007013 * Add a file name to the list.
7014 */
7015static void
7016addfname(const char *name)
7017{
7018 struct strlist *sp;
7019
Denis Vlasenko597906c2008-02-20 16:38:54 +00007020 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02007021 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007022 *exparg.lastp = sp;
7023 exparg.lastp = &sp->next;
7024}
7025
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007026/* If we want to use glob() from libc... */
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007027#if !ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007028
7029/* Add the result of glob() to the list */
7030static void
7031addglob(const glob_t *pglob)
7032{
7033 char **p = pglob->gl_pathv;
7034
7035 do {
7036 addfname(*p);
7037 } while (*++p);
7038}
7039static void
7040expandmeta(struct strlist *str /*, int flag*/)
7041{
7042 /* TODO - EXP_REDIR */
7043
7044 while (str) {
7045 char *p;
7046 glob_t pglob;
7047 int i;
7048
7049 if (fflag)
7050 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007051
7052 /* Avoid glob() (and thus, stat() et al) for words like "echo" */
7053 p = str->text;
7054 while (*p) {
7055 if (*p == '*')
7056 goto need_glob;
7057 if (*p == '?')
7058 goto need_glob;
7059 if (*p == '[')
7060 goto need_glob;
7061 p++;
7062 }
7063 goto nometa;
7064
7065 need_glob:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007066 INT_OFF;
7067 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007068// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7069// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7070//
7071// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7072// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7073// Which means you need to unescape the string, right? Not so fast:
7074// if there _is_ a file named "file\?" (with backslash), it is returned
7075// as "file\?" too (whichever pattern you used to find it, say, "file*").
7076// You DONT KNOW by looking at the result whether you need to unescape it.
7077//
7078// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7079// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7080// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7081// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7082// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7083// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7084 i = glob(p, 0, NULL, &pglob);
7085 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007086 if (p != str->text)
7087 free(p);
7088 switch (i) {
7089 case 0:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007090#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007091 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7092 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7093 goto nometa2;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007094#endif
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007095 addglob(&pglob);
7096 globfree(&pglob);
7097 INT_ON;
7098 break;
7099 case GLOB_NOMATCH:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007100 //nometa2:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007101 globfree(&pglob);
7102 INT_ON;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007103 nometa:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007104 *exparg.lastp = str;
7105 rmescapes(str->text, 0);
7106 exparg.lastp = &str->next;
7107 break;
7108 default: /* GLOB_NOSPACE */
7109 globfree(&pglob);
7110 INT_ON;
7111 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7112 }
7113 str = str->next;
7114 }
7115}
7116
7117#else
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007118/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007119
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007120/*
7121 * Do metacharacter (i.e. *, ?, [...]) expansion.
7122 */
7123static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007124expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007125{
7126 char *p;
7127 const char *cp;
7128 char *start;
7129 char *endname;
7130 int metaflag;
7131 struct stat statb;
7132 DIR *dirp;
7133 struct dirent *dp;
7134 int atend;
7135 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007136 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007137
7138 metaflag = 0;
7139 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007140 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007141 if (*p == '*' || *p == '?')
7142 metaflag = 1;
7143 else if (*p == '[') {
7144 char *q = p + 1;
7145 if (*q == '!')
7146 q++;
7147 for (;;) {
7148 if (*q == '\\')
7149 q++;
7150 if (*q == '/' || *q == '\0')
7151 break;
7152 if (*++q == ']') {
7153 metaflag = 1;
7154 break;
7155 }
7156 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007157 } else {
7158 if (*p == '\\')
7159 esc++;
7160 if (p[esc] == '/') {
7161 if (metaflag)
7162 break;
7163 start = p + esc + 1;
7164 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007165 }
7166 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007167 if (metaflag == 0) { /* we've reached the end of the file name */
7168 if (enddir != expdir)
7169 metaflag++;
7170 p = name;
7171 do {
7172 if (*p == '\\')
7173 p++;
7174 *enddir++ = *p;
7175 } while (*p++);
7176 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7177 addfname(expdir);
7178 return;
7179 }
7180 endname = p;
7181 if (name < start) {
7182 p = name;
7183 do {
7184 if (*p == '\\')
7185 p++;
7186 *enddir++ = *p++;
7187 } while (p < start);
7188 }
7189 if (enddir == expdir) {
7190 cp = ".";
7191 } else if (enddir == expdir + 1 && *expdir == '/') {
7192 cp = "/";
7193 } else {
7194 cp = expdir;
7195 enddir[-1] = '\0';
7196 }
7197 dirp = opendir(cp);
7198 if (dirp == NULL)
7199 return;
7200 if (enddir != expdir)
7201 enddir[-1] = '/';
7202 if (*endname == 0) {
7203 atend = 1;
7204 } else {
7205 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007206 *endname = '\0';
7207 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007208 }
7209 matchdot = 0;
7210 p = start;
7211 if (*p == '\\')
7212 p++;
7213 if (*p == '.')
7214 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007215 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007216 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007217 continue;
7218 if (pmatch(start, dp->d_name)) {
7219 if (atend) {
7220 strcpy(enddir, dp->d_name);
7221 addfname(expdir);
7222 } else {
7223 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7224 continue;
7225 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007226 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007227 }
7228 }
7229 }
7230 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007231 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007232 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007233}
7234
7235static struct strlist *
7236msort(struct strlist *list, int len)
7237{
7238 struct strlist *p, *q = NULL;
7239 struct strlist **lpp;
7240 int half;
7241 int n;
7242
7243 if (len <= 1)
7244 return list;
7245 half = len >> 1;
7246 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007247 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007248 q = p;
7249 p = p->next;
7250 }
7251 q->next = NULL; /* terminate first half of list */
7252 q = msort(list, half); /* sort first half of list */
7253 p = msort(p, len - half); /* sort second half */
7254 lpp = &list;
7255 for (;;) {
7256#if ENABLE_LOCALE_SUPPORT
7257 if (strcoll(p->text, q->text) < 0)
7258#else
7259 if (strcmp(p->text, q->text) < 0)
7260#endif
7261 {
7262 *lpp = p;
7263 lpp = &p->next;
7264 p = *lpp;
7265 if (p == NULL) {
7266 *lpp = q;
7267 break;
7268 }
7269 } else {
7270 *lpp = q;
7271 lpp = &q->next;
7272 q = *lpp;
7273 if (q == NULL) {
7274 *lpp = p;
7275 break;
7276 }
7277 }
7278 }
7279 return list;
7280}
7281
7282/*
7283 * Sort the results of file name expansion. It calculates the number of
7284 * strings to sort and then calls msort (short for merge sort) to do the
7285 * work.
7286 */
7287static struct strlist *
7288expsort(struct strlist *str)
7289{
7290 int len;
7291 struct strlist *sp;
7292
7293 len = 0;
7294 for (sp = str; sp; sp = sp->next)
7295 len++;
7296 return msort(str, len);
7297}
7298
7299static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007300expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007301{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00007302 static const char metachars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007303 '*', '?', '[', 0
7304 };
7305 /* TODO - EXP_REDIR */
7306
7307 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007308 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007309 struct strlist **savelastp;
7310 struct strlist *sp;
7311 char *p;
7312
7313 if (fflag)
7314 goto nometa;
7315 if (!strpbrk(str->text, metachars))
7316 goto nometa;
7317 savelastp = exparg.lastp;
7318
7319 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007320 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007321 {
7322 int i = strlen(str->text);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007323//BUGGY estimation of how long expanded name can be
7324 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007325 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007326 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007327 free(expdir);
7328 if (p != str->text)
7329 free(p);
7330 INT_ON;
7331 if (exparg.lastp == savelastp) {
7332 /*
7333 * no matches
7334 */
7335 nometa:
7336 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007337 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007338 exparg.lastp = &str->next;
7339 } else {
7340 *exparg.lastp = NULL;
7341 *savelastp = sp = expsort(*savelastp);
7342 while (sp->next != NULL)
7343 sp = sp->next;
7344 exparg.lastp = &sp->next;
7345 }
7346 str = str->next;
7347 }
7348}
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007349#endif /* ENABLE_ASH_INTERNAL_GLOB */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007350
7351/*
7352 * Perform variable substitution and command substitution on an argument,
7353 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7354 * perform splitting and file name expansion. When arglist is NULL, perform
7355 * here document expansion.
7356 */
7357static void
7358expandarg(union node *arg, struct arglist *arglist, int flag)
7359{
7360 struct strlist *sp;
7361 char *p;
7362
7363 argbackq = arg->narg.backquote;
7364 STARTSTACKSTR(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007365 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007366 argstr(arg->narg.text, flag,
7367 /* var_str_list: */ arglist ? arglist->list : NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007368 p = _STPUTC('\0', expdest);
7369 expdest = p - 1;
7370 if (arglist == NULL) {
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007371 /* here document expanded */
7372 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007373 }
7374 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007375 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007376 exparg.lastp = &exparg.list;
7377 /*
7378 * TODO - EXP_REDIR
7379 */
7380 if (flag & EXP_FULL) {
7381 ifsbreakup(p, &exparg);
7382 *exparg.lastp = NULL;
7383 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007384 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007385 } else {
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007386 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007387 rmescapes(p, 0);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007388 TRACE(("expandarg: rmescapes:'%s'\n", p));
7389 }
Denis Vlasenko597906c2008-02-20 16:38:54 +00007390 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007391 sp->text = p;
7392 *exparg.lastp = sp;
7393 exparg.lastp = &sp->next;
7394 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007395 *exparg.lastp = NULL;
7396 if (exparg.list) {
7397 *arglist->lastp = exparg.list;
7398 arglist->lastp = exparg.lastp;
7399 }
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007400
7401 out:
7402 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007403}
7404
7405/*
7406 * Expand shell variables and backquotes inside a here document.
7407 */
7408static void
7409expandhere(union node *arg, int fd)
7410{
Ron Yorston549deab2015-05-18 09:57:51 +02007411 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007412 full_write(fd, stackblock(), expdest - (char *)stackblock());
7413}
7414
7415/*
7416 * Returns true if the pattern matches the string.
7417 */
7418static int
7419patmatch(char *pattern, const char *string)
7420{
Ron Yorston549deab2015-05-18 09:57:51 +02007421 return pmatch(preglob(pattern, 0), string);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007422}
7423
7424/*
7425 * See if a pattern matches in a case statement.
7426 */
7427static int
7428casematch(union node *pattern, char *val)
7429{
7430 struct stackmark smark;
7431 int result;
7432
7433 setstackmark(&smark);
7434 argbackq = pattern->narg.backquote;
7435 STARTSTACKSTR(expdest);
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007436 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7437 /* var_str_list: */ NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007438 STACKSTRNUL(expdest);
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007439 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007440 result = patmatch(stackblock(), val);
7441 popstackmark(&smark);
7442 return result;
7443}
7444
7445
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007446/* ============ find_command */
7447
7448struct builtincmd {
7449 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007450 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007451 /* unsigned flags; */
7452};
7453#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007454/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007455 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007456#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007457#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007458
7459struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007460 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007461 union param {
7462 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007463 /* index >= 0 for commands without path (slashes) */
7464 /* (TODO: what exactly does the value mean? PATH position?) */
7465 /* index == -1 for commands with slashes */
7466 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007467 const struct builtincmd *cmd;
7468 struct funcnode *func;
7469 } u;
7470};
7471/* values of cmdtype */
7472#define CMDUNKNOWN -1 /* no entry in table for command */
7473#define CMDNORMAL 0 /* command is an executable program */
7474#define CMDFUNCTION 1 /* command is a shell function */
7475#define CMDBUILTIN 2 /* command is a shell builtin */
7476
7477/* action to find_command() */
7478#define DO_ERR 0x01 /* prints errors */
7479#define DO_ABS 0x02 /* checks absolute paths */
7480#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7481#define DO_ALTPATH 0x08 /* using alternate path */
7482#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7483
7484static void find_command(char *, struct cmdentry *, int, const char *);
7485
7486
7487/* ============ Hashing commands */
7488
7489/*
7490 * When commands are first encountered, they are entered in a hash table.
7491 * This ensures that a full path search will not have to be done for them
7492 * on each invocation.
7493 *
7494 * We should investigate converting to a linear search, even though that
7495 * would make the command name "hash" a misnomer.
7496 */
7497
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007498struct tblentry {
7499 struct tblentry *next; /* next entry in hash chain */
7500 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007501 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007502 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007503 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007504};
7505
Denis Vlasenko01631112007-12-16 17:20:38 +00007506static struct tblentry **cmdtable;
7507#define INIT_G_cmdtable() do { \
7508 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7509} while (0)
7510
7511static int builtinloc = -1; /* index in path of %builtin, or -1 */
7512
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007513
7514static void
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007515tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007516{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007517#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007518 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007519 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007520 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007521 while (*envp)
7522 putenv(*envp++);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007523 run_applet_no_and_exit(applet_no, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007524 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007525 /* re-exec ourselves with the new arguments */
7526 execve(bb_busybox_exec_path, argv, envp);
7527 /* If they called chroot or otherwise made the binary no longer
7528 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007529 }
7530#endif
7531
7532 repeat:
7533#ifdef SYSV
7534 do {
7535 execve(cmd, argv, envp);
7536 } while (errno == EINTR);
7537#else
7538 execve(cmd, argv, envp);
7539#endif
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007540 if (cmd != (char*) bb_busybox_exec_path && errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007541 /* Run "cmd" as a shell script:
7542 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7543 * "If the execve() function fails with ENOEXEC, the shell
7544 * shall execute a command equivalent to having a shell invoked
7545 * with the command name as its first operand,
7546 * with any remaining arguments passed to the new shell"
7547 *
7548 * That is, do not use $SHELL, user's shell, or /bin/sh;
7549 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007550 *
7551 * Note that bash reads ~80 chars of the file, and if it sees
7552 * a zero byte before it sees newline, it doesn't try to
7553 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007554 * message and exit code 126. For one, this prevents attempts
7555 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007556 */
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007557 argv[0] = cmd;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007558 cmd = (char*) bb_busybox_exec_path;
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007559 /* NB: this is only possible because all callers of shellexec()
7560 * ensure that the argv[-1] slot exists!
7561 */
7562 argv--;
7563 argv[0] = (char*) "ash";
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007564 goto repeat;
7565 }
7566}
7567
7568/*
7569 * Exec a program. Never returns. If you change this routine, you may
7570 * have to change the find_command routine as well.
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007571 * argv[-1] must exist and be writable! See tryexec() for why.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007572 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007573static void shellexec(char **, const char *, int) NORETURN;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007574static void
7575shellexec(char **argv, const char *path, int idx)
7576{
7577 char *cmdname;
7578 int e;
7579 char **envp;
7580 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007581 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007582
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007583 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007584 if (strchr(argv[0], '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007585#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007586 || (applet_no = find_applet_by_name(argv[0])) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007587#endif
7588 ) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007589 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007590 if (applet_no >= 0) {
7591 /* We tried execing ourself, but it didn't work.
7592 * Maybe /proc/self/exe doesn't exist?
7593 * Try $PATH search.
7594 */
7595 goto try_PATH;
7596 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007597 e = errno;
7598 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007599 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007600 e = ENOENT;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007601 while ((cmdname = path_advance(&path, argv[0])) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007602 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007603 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007604 if (errno != ENOENT && errno != ENOTDIR)
7605 e = errno;
7606 }
7607 stunalloc(cmdname);
7608 }
7609 }
7610
7611 /* Map to POSIX errors */
7612 switch (e) {
7613 case EACCES:
7614 exerrno = 126;
7615 break;
7616 case ENOENT:
7617 exerrno = 127;
7618 break;
7619 default:
7620 exerrno = 2;
7621 break;
7622 }
7623 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007624 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7625 argv[0], e, suppress_int));
Denys Vlasenko061a0902016-10-25 17:24:25 +02007626 ash_msg_and_raise(EXEXIT, "%s: %s", argv[0], errmsg(e, "not found"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007627 /* NOTREACHED */
7628}
7629
7630static void
7631printentry(struct tblentry *cmdp)
7632{
7633 int idx;
7634 const char *path;
7635 char *name;
7636
7637 idx = cmdp->param.index;
7638 path = pathval();
7639 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007640 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007641 stunalloc(name);
7642 } while (--idx >= 0);
7643 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7644}
7645
7646/*
7647 * Clear out command entries. The argument specifies the first entry in
7648 * PATH which has changed.
7649 */
7650static void
7651clearcmdentry(int firstchange)
7652{
7653 struct tblentry **tblp;
7654 struct tblentry **pp;
7655 struct tblentry *cmdp;
7656
7657 INT_OFF;
7658 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7659 pp = tblp;
7660 while ((cmdp = *pp) != NULL) {
7661 if ((cmdp->cmdtype == CMDNORMAL &&
7662 cmdp->param.index >= firstchange)
7663 || (cmdp->cmdtype == CMDBUILTIN &&
7664 builtinloc >= firstchange)
7665 ) {
7666 *pp = cmdp->next;
7667 free(cmdp);
7668 } else {
7669 pp = &cmdp->next;
7670 }
7671 }
7672 }
7673 INT_ON;
7674}
7675
7676/*
7677 * Locate a command in the command hash table. If "add" is nonzero,
7678 * add the command to the table if it is not already present. The
7679 * variable "lastcmdentry" is set to point to the address of the link
7680 * pointing to the entry, so that delete_cmd_entry can delete the
7681 * entry.
7682 *
7683 * Interrupts must be off if called with add != 0.
7684 */
7685static struct tblentry **lastcmdentry;
7686
7687static struct tblentry *
7688cmdlookup(const char *name, int add)
7689{
7690 unsigned int hashval;
7691 const char *p;
7692 struct tblentry *cmdp;
7693 struct tblentry **pp;
7694
7695 p = name;
7696 hashval = (unsigned char)*p << 4;
7697 while (*p)
7698 hashval += (unsigned char)*p++;
7699 hashval &= 0x7FFF;
7700 pp = &cmdtable[hashval % CMDTABLESIZE];
7701 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7702 if (strcmp(cmdp->cmdname, name) == 0)
7703 break;
7704 pp = &cmdp->next;
7705 }
7706 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007707 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7708 + strlen(name)
7709 /* + 1 - already done because
7710 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007711 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007712 cmdp->cmdtype = CMDUNKNOWN;
7713 strcpy(cmdp->cmdname, name);
7714 }
7715 lastcmdentry = pp;
7716 return cmdp;
7717}
7718
7719/*
7720 * Delete the command entry returned on the last lookup.
7721 */
7722static void
7723delete_cmd_entry(void)
7724{
7725 struct tblentry *cmdp;
7726
7727 INT_OFF;
7728 cmdp = *lastcmdentry;
7729 *lastcmdentry = cmdp->next;
7730 if (cmdp->cmdtype == CMDFUNCTION)
7731 freefunc(cmdp->param.func);
7732 free(cmdp);
7733 INT_ON;
7734}
7735
7736/*
7737 * Add a new command entry, replacing any existing command entry for
7738 * the same name - except special builtins.
7739 */
7740static void
7741addcmdentry(char *name, struct cmdentry *entry)
7742{
7743 struct tblentry *cmdp;
7744
7745 cmdp = cmdlookup(name, 1);
7746 if (cmdp->cmdtype == CMDFUNCTION) {
7747 freefunc(cmdp->param.func);
7748 }
7749 cmdp->cmdtype = entry->cmdtype;
7750 cmdp->param = entry->u;
7751 cmdp->rehash = 0;
7752}
7753
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007754static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007755hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007756{
7757 struct tblentry **pp;
7758 struct tblentry *cmdp;
7759 int c;
7760 struct cmdentry entry;
7761 char *name;
7762
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007763 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007764 clearcmdentry(0);
7765 return 0;
7766 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007767
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007768 if (*argptr == NULL) {
7769 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7770 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7771 if (cmdp->cmdtype == CMDNORMAL)
7772 printentry(cmdp);
7773 }
7774 }
7775 return 0;
7776 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007777
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007778 c = 0;
7779 while ((name = *argptr) != NULL) {
7780 cmdp = cmdlookup(name, 0);
7781 if (cmdp != NULL
7782 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007783 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7784 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007785 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007786 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007787 find_command(name, &entry, DO_ERR, pathval());
7788 if (entry.cmdtype == CMDUNKNOWN)
7789 c = 1;
7790 argptr++;
7791 }
7792 return c;
7793}
7794
7795/*
7796 * Called when a cd is done. Marks all commands so the next time they
7797 * are executed they will be rehashed.
7798 */
7799static void
7800hashcd(void)
7801{
7802 struct tblentry **pp;
7803 struct tblentry *cmdp;
7804
7805 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7806 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007807 if (cmdp->cmdtype == CMDNORMAL
7808 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02007809 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007810 && builtinloc > 0)
7811 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007812 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007813 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007814 }
7815 }
7816}
7817
7818/*
7819 * Fix command hash table when PATH changed.
7820 * Called before PATH is changed. The argument is the new value of PATH;
7821 * pathval() still returns the old value at this point.
7822 * Called with interrupts off.
7823 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007824static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007825changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007826{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007827 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007828 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007829 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007830 int idx_bltin;
7831
7832 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007833 firstchange = 9999; /* assume no change */
7834 idx = 0;
7835 idx_bltin = -1;
7836 for (;;) {
7837 if (*old != *new) {
7838 firstchange = idx;
7839 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007840 || (*old == ':' && *new == '\0')
7841 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007842 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007843 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007844 old = new; /* ignore subsequent differences */
7845 }
7846 if (*new == '\0')
7847 break;
7848 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7849 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007850 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007851 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007852 new++;
7853 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007854 }
7855 if (builtinloc < 0 && idx_bltin >= 0)
7856 builtinloc = idx_bltin; /* zap builtins */
7857 if (builtinloc >= 0 && idx_bltin < 0)
7858 firstchange = 0;
7859 clearcmdentry(firstchange);
7860 builtinloc = idx_bltin;
7861}
Ron Yorston95ebcf72015-11-03 09:42:23 +00007862enum {
7863 TEOF,
7864 TNL,
7865 TREDIR,
7866 TWORD,
7867 TSEMI,
7868 TBACKGND,
7869 TAND,
7870 TOR,
7871 TPIPE,
7872 TLP,
7873 TRP,
7874 TENDCASE,
7875 TENDBQUOTE,
7876 TNOT,
7877 TCASE,
7878 TDO,
7879 TDONE,
7880 TELIF,
7881 TELSE,
7882 TESAC,
7883 TFI,
7884 TFOR,
7885#if ENABLE_ASH_BASH_COMPAT
7886 TFUNCTION,
7887#endif
7888 TIF,
7889 TIN,
7890 TTHEN,
7891 TUNTIL,
7892 TWHILE,
7893 TBEGIN,
7894 TEND
7895};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007896typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007897
Denys Vlasenko888527c2016-10-02 16:54:17 +02007898/* Nth bit indicates if token marks the end of a list */
7899enum {
7900 tokendlist = 0
7901 /* 0 */ | (1u << TEOF)
7902 /* 1 */ | (0u << TNL)
7903 /* 2 */ | (0u << TREDIR)
7904 /* 3 */ | (0u << TWORD)
7905 /* 4 */ | (0u << TSEMI)
7906 /* 5 */ | (0u << TBACKGND)
7907 /* 6 */ | (0u << TAND)
7908 /* 7 */ | (0u << TOR)
7909 /* 8 */ | (0u << TPIPE)
7910 /* 9 */ | (0u << TLP)
7911 /* 10 */ | (1u << TRP)
7912 /* 11 */ | (1u << TENDCASE)
7913 /* 12 */ | (1u << TENDBQUOTE)
7914 /* 13 */ | (0u << TNOT)
7915 /* 14 */ | (0u << TCASE)
7916 /* 15 */ | (1u << TDO)
7917 /* 16 */ | (1u << TDONE)
7918 /* 17 */ | (1u << TELIF)
7919 /* 18 */ | (1u << TELSE)
7920 /* 19 */ | (1u << TESAC)
7921 /* 20 */ | (1u << TFI)
7922 /* 21 */ | (0u << TFOR)
7923#if ENABLE_ASH_BASH_COMPAT
7924 /* 22 */ | (0u << TFUNCTION)
Denys Vlasenko80729a42016-10-02 22:33:15 +02007925#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02007926 /* 23 */ | (0u << TIF)
7927 /* 24 */ | (0u << TIN)
7928 /* 25 */ | (1u << TTHEN)
7929 /* 26 */ | (0u << TUNTIL)
7930 /* 27 */ | (0u << TWHILE)
7931 /* 28 */ | (0u << TBEGIN)
7932 /* 29 */ | (1u << TEND)
7933 , /* thus far 29 bits used */
7934};
7935
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007936static const char *const tokname_array[] = {
Denys Vlasenko888527c2016-10-02 16:54:17 +02007937 "end of file",
7938 "newline",
7939 "redirection",
7940 "word",
7941 ";",
7942 "&",
7943 "&&",
7944 "||",
7945 "|",
7946 "(",
7947 ")",
7948 ";;",
7949 "`",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007950#define KWDOFFSET 13
7951 /* the following are keywords */
Denys Vlasenko888527c2016-10-02 16:54:17 +02007952 "!",
7953 "case",
7954 "do",
7955 "done",
7956 "elif",
7957 "else",
7958 "esac",
7959 "fi",
7960 "for",
Ron Yorston95ebcf72015-11-03 09:42:23 +00007961#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko888527c2016-10-02 16:54:17 +02007962 "function",
Ron Yorston95ebcf72015-11-03 09:42:23 +00007963#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02007964 "if",
7965 "in",
7966 "then",
7967 "until",
7968 "while",
7969 "{",
7970 "}",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007971};
7972
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007973/* Wrapper around strcmp for qsort/bsearch/... */
7974static int
7975pstrcmp(const void *a, const void *b)
7976{
Denys Vlasenko888527c2016-10-02 16:54:17 +02007977 return strcmp((char*)a, *(char**)b);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007978}
7979
7980static const char *const *
7981findkwd(const char *s)
7982{
7983 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00007984 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7985 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007986}
7987
7988/*
7989 * Locate and print what a word is...
7990 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007991static int
Ron Yorston3f221112015-08-03 13:47:33 +01007992describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007993{
7994 struct cmdentry entry;
7995 struct tblentry *cmdp;
7996#if ENABLE_ASH_ALIAS
7997 const struct alias *ap;
7998#endif
Ron Yorston3f221112015-08-03 13:47:33 +01007999
8000 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008001
8002 if (describe_command_verbose) {
8003 out1str(command);
8004 }
8005
8006 /* First look at the keywords */
8007 if (findkwd(command)) {
8008 out1str(describe_command_verbose ? " is a shell keyword" : command);
8009 goto out;
8010 }
8011
8012#if ENABLE_ASH_ALIAS
8013 /* Then look at the aliases */
8014 ap = lookupalias(command, 0);
8015 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008016 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008017 out1str("alias ");
8018 printalias(ap);
8019 return 0;
8020 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00008021 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008022 goto out;
8023 }
8024#endif
8025 /* Then check if it is a tracked alias */
8026 cmdp = cmdlookup(command, 0);
8027 if (cmdp != NULL) {
8028 entry.cmdtype = cmdp->cmdtype;
8029 entry.u = cmdp->param;
8030 } else {
8031 /* Finally use brute force */
8032 find_command(command, &entry, DO_ABS, path);
8033 }
8034
8035 switch (entry.cmdtype) {
8036 case CMDNORMAL: {
8037 int j = entry.u.index;
8038 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008039 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008040 p = command;
8041 } else {
8042 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008043 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008044 stunalloc(p);
8045 } while (--j >= 0);
8046 }
8047 if (describe_command_verbose) {
8048 out1fmt(" is%s %s",
8049 (cmdp ? " a tracked alias for" : nullstr), p
8050 );
8051 } else {
8052 out1str(p);
8053 }
8054 break;
8055 }
8056
8057 case CMDFUNCTION:
8058 if (describe_command_verbose) {
8059 out1str(" is a shell function");
8060 } else {
8061 out1str(command);
8062 }
8063 break;
8064
8065 case CMDBUILTIN:
8066 if (describe_command_verbose) {
8067 out1fmt(" is a %sshell builtin",
8068 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8069 "special " : nullstr
8070 );
8071 } else {
8072 out1str(command);
8073 }
8074 break;
8075
8076 default:
8077 if (describe_command_verbose) {
8078 out1str(": not found\n");
8079 }
8080 return 127;
8081 }
8082 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008083 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008084 return 0;
8085}
8086
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008087static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008088typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008089{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008090 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008091 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008092 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008093
Denis Vlasenko46846e22007-05-20 13:08:31 +00008094 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008095 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008096 i++;
8097 verbose = 0;
8098 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008099 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008100 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008101 }
8102 return err;
8103}
8104
8105#if ENABLE_ASH_CMDCMD
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008106/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8107static char **
8108parse_command_args(char **argv, const char **path)
8109{
8110 char *cp, c;
8111
8112 for (;;) {
8113 cp = *++argv;
8114 if (!cp)
8115 return NULL;
8116 if (*cp++ != '-')
8117 break;
8118 c = *cp++;
8119 if (!c)
8120 break;
8121 if (c == '-' && !*cp) {
8122 if (!*++argv)
8123 return NULL;
8124 break;
8125 }
8126 do {
8127 switch (c) {
8128 case 'p':
8129 *path = bb_default_path;
8130 break;
8131 default:
8132 /* run 'typecmd' for other options */
8133 return NULL;
8134 }
8135 c = *cp++;
8136 } while (c);
8137 }
8138 return argv;
8139}
8140
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008141static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008142commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008143{
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008144 char *cmd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008145 int c;
8146 enum {
8147 VERIFY_BRIEF = 1,
8148 VERIFY_VERBOSE = 2,
8149 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008150 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008151
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008152 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8153 * never reaches this function.
8154 */
8155
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008156 while ((c = nextopt("pvV")) != '\0')
8157 if (c == 'V')
8158 verify |= VERIFY_VERBOSE;
8159 else if (c == 'v')
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008160 /*verify |= VERIFY_BRIEF*/;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008161#if DEBUG
8162 else if (c != 'p')
8163 abort();
8164#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008165 else
8166 path = bb_default_path;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008167
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008168 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008169 cmd = *argptr;
8170 if (/*verify && */ cmd)
8171 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008172
8173 return 0;
8174}
8175#endif
8176
8177
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008178/*static int funcblocksize; // size of structures in function */
8179/*static int funcstringsize; // size of strings in node */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008180static void *funcblock; /* block to allocate function from */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008181static char *funcstring_end; /* end of block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008182
Eric Andersencb57d552001-06-28 07:25:16 +00008183/* flags in argument to evaltree */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008184#define EV_EXIT 01 /* exit after evaluating tree */
8185#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Eric Andersencb57d552001-06-28 07:25:16 +00008186
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008187static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008188 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8189 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8190 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8191 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8192 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8193 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8194 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8195 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8196 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8197 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8198 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8199 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8200 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8201 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8202 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8203 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8204 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008205#if ENABLE_ASH_BASH_COMPAT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008206 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008207#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008208 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8209 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8210 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8211 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8212 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8213 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8214 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8215 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8216 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008217};
8218
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008219static int calcsize(int funcblocksize, union node *n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008220
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008221static int
8222sizenodelist(int funcblocksize, struct nodelist *lp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008223{
8224 while (lp) {
8225 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008226 funcblocksize = calcsize(funcblocksize, lp->n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008227 lp = lp->next;
8228 }
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008229 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008230}
8231
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008232static int
8233calcsize(int funcblocksize, union node *n)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008234{
8235 if (n == NULL)
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008236 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008237 funcblocksize += nodesize[n->type];
8238 switch (n->type) {
8239 case NCMD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008240 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8241 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8242 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008243 break;
8244 case NPIPE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008245 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008246 break;
8247 case NREDIR:
8248 case NBACKGND:
8249 case NSUBSHELL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008250 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8251 funcblocksize = calcsize(funcblocksize, n->nredir.n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008252 break;
8253 case NAND:
8254 case NOR:
8255 case NSEMI:
8256 case NWHILE:
8257 case NUNTIL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008258 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8259 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008260 break;
8261 case NIF:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008262 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8263 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8264 funcblocksize = calcsize(funcblocksize, n->nif.test);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008265 break;
8266 case NFOR:
Denys Vlasenko561639a2016-10-07 04:28:33 +02008267 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008268 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8269 funcblocksize = calcsize(funcblocksize, n->nfor.args);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008270 break;
8271 case NCASE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008272 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8273 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008274 break;
8275 case NCLIST:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008276 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8277 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8278 funcblocksize = calcsize(funcblocksize, n->nclist.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008279 break;
8280 case NDEFUN:
8281 case NARG:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008282 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
Denys Vlasenko561639a2016-10-07 04:28:33 +02008283 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008284 funcblocksize = calcsize(funcblocksize, n->narg.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008285 break;
8286 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008287#if ENABLE_ASH_BASH_COMPAT
8288 case NTO2:
8289#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008290 case NCLOBBER:
8291 case NFROM:
8292 case NFROMTO:
8293 case NAPPEND:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008294 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8295 funcblocksize = calcsize(funcblocksize, n->nfile.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008296 break;
8297 case NTOFD:
8298 case NFROMFD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008299 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8300 funcblocksize = calcsize(funcblocksize, n->ndup.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008301 break;
8302 case NHERE:
8303 case NXHERE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008304 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8305 funcblocksize = calcsize(funcblocksize, n->nhere.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008306 break;
8307 case NNOT:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008308 funcblocksize = calcsize(funcblocksize, n->nnot.com);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008309 break;
8310 };
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008311 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008312}
8313
8314static char *
8315nodeckstrdup(char *s)
8316{
Denys Vlasenko561639a2016-10-07 04:28:33 +02008317 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008318 return strcpy(funcstring_end, s);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008319}
8320
8321static union node *copynode(union node *);
8322
8323static struct nodelist *
8324copynodelist(struct nodelist *lp)
8325{
8326 struct nodelist *start;
8327 struct nodelist **lpp;
8328
8329 lpp = &start;
8330 while (lp) {
8331 *lpp = funcblock;
8332 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8333 (*lpp)->n = copynode(lp->n);
8334 lp = lp->next;
8335 lpp = &(*lpp)->next;
8336 }
8337 *lpp = NULL;
8338 return start;
8339}
8340
8341static union node *
8342copynode(union node *n)
8343{
8344 union node *new;
8345
8346 if (n == NULL)
8347 return NULL;
8348 new = funcblock;
8349 funcblock = (char *) funcblock + nodesize[n->type];
8350
8351 switch (n->type) {
8352 case NCMD:
8353 new->ncmd.redirect = copynode(n->ncmd.redirect);
8354 new->ncmd.args = copynode(n->ncmd.args);
8355 new->ncmd.assign = copynode(n->ncmd.assign);
8356 break;
8357 case NPIPE:
8358 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008359 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008360 break;
8361 case NREDIR:
8362 case NBACKGND:
8363 case NSUBSHELL:
8364 new->nredir.redirect = copynode(n->nredir.redirect);
8365 new->nredir.n = copynode(n->nredir.n);
8366 break;
8367 case NAND:
8368 case NOR:
8369 case NSEMI:
8370 case NWHILE:
8371 case NUNTIL:
8372 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8373 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8374 break;
8375 case NIF:
8376 new->nif.elsepart = copynode(n->nif.elsepart);
8377 new->nif.ifpart = copynode(n->nif.ifpart);
8378 new->nif.test = copynode(n->nif.test);
8379 break;
8380 case NFOR:
8381 new->nfor.var = nodeckstrdup(n->nfor.var);
8382 new->nfor.body = copynode(n->nfor.body);
8383 new->nfor.args = copynode(n->nfor.args);
8384 break;
8385 case NCASE:
8386 new->ncase.cases = copynode(n->ncase.cases);
8387 new->ncase.expr = copynode(n->ncase.expr);
8388 break;
8389 case NCLIST:
8390 new->nclist.body = copynode(n->nclist.body);
8391 new->nclist.pattern = copynode(n->nclist.pattern);
8392 new->nclist.next = copynode(n->nclist.next);
8393 break;
8394 case NDEFUN:
8395 case NARG:
8396 new->narg.backquote = copynodelist(n->narg.backquote);
8397 new->narg.text = nodeckstrdup(n->narg.text);
8398 new->narg.next = copynode(n->narg.next);
8399 break;
8400 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008401#if ENABLE_ASH_BASH_COMPAT
8402 case NTO2:
8403#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008404 case NCLOBBER:
8405 case NFROM:
8406 case NFROMTO:
8407 case NAPPEND:
8408 new->nfile.fname = copynode(n->nfile.fname);
8409 new->nfile.fd = n->nfile.fd;
8410 new->nfile.next = copynode(n->nfile.next);
8411 break;
8412 case NTOFD:
8413 case NFROMFD:
8414 new->ndup.vname = copynode(n->ndup.vname);
8415 new->ndup.dupfd = n->ndup.dupfd;
8416 new->ndup.fd = n->ndup.fd;
8417 new->ndup.next = copynode(n->ndup.next);
8418 break;
8419 case NHERE:
8420 case NXHERE:
8421 new->nhere.doc = copynode(n->nhere.doc);
8422 new->nhere.fd = n->nhere.fd;
8423 new->nhere.next = copynode(n->nhere.next);
8424 break;
8425 case NNOT:
8426 new->nnot.com = copynode(n->nnot.com);
8427 break;
8428 };
8429 new->type = n->type;
8430 return new;
8431}
8432
8433/*
8434 * Make a copy of a parse tree.
8435 */
8436static struct funcnode *
8437copyfunc(union node *n)
8438{
8439 struct funcnode *f;
8440 size_t blocksize;
8441
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008442 /*funcstringsize = 0;*/
8443 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8444 f = ckzalloc(blocksize /* + funcstringsize */);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008445 funcblock = (char *) f + offsetof(struct funcnode, n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008446 funcstring_end = (char *) f + blocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008447 copynode(n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008448 /* f->count = 0; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008449 return f;
8450}
8451
8452/*
8453 * Define a shell function.
8454 */
8455static void
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008456defun(union node *func)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008457{
8458 struct cmdentry entry;
8459
8460 INT_OFF;
8461 entry.cmdtype = CMDFUNCTION;
8462 entry.u.func = copyfunc(func);
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008463 addcmdentry(func->narg.text, &entry);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008464 INT_ON;
8465}
8466
Denis Vlasenko4b875702009-03-19 13:30:04 +00008467/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008468#define SKIPBREAK (1 << 0)
8469#define SKIPCONT (1 << 1)
8470#define SKIPFUNC (1 << 2)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008471static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008472static int skipcount; /* number of levels to skip */
8473static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008474static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008475
Denis Vlasenko4b875702009-03-19 13:30:04 +00008476/* Forward decl way out to parsing code - dotrap needs it */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008477static int evalstring(char *s, int flags);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008478
Denis Vlasenko4b875702009-03-19 13:30:04 +00008479/* Called to execute a trap.
8480 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008481 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008482 *
8483 * Perhaps we should avoid entering new trap handlers
8484 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008485 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008486static void
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008487dotrap(void)
8488{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008489 uint8_t *g;
8490 int sig;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008491 uint8_t last_status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008492
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008493 if (!pending_sig)
8494 return;
8495
8496 last_status = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008497 pending_sig = 0;
Denys Vlasenkode892052016-10-02 01:49:13 +02008498 barrier();
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008499
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008500 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008501 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008502 char *p;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008503
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008504 if (!*g)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008505 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008506
8507 if (evalskip) {
8508 pending_sig = sig;
8509 break;
8510 }
8511
8512 p = trap[sig];
Denis Vlasenko4b875702009-03-19 13:30:04 +00008513 /* non-trapped SIGINT is handled separately by raise_interrupt,
8514 * don't upset it by resetting gotsig[SIGINT-1] */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008515 if (sig == SIGINT && !p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008516 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008517
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008518 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008519 *g = 0;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008520 if (!p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008521 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008522 evalstring(p, 0);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008523 }
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008524 exitstatus = last_status;
8525 TRACE(("dotrap returns\n"));
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008526}
8527
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008528/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008529static int evalloop(union node *, int);
8530static int evalfor(union node *, int);
8531static int evalcase(union node *, int);
8532static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008533static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008534static int evalpipe(union node *, int);
8535static int evalcommand(union node *, int);
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008536static int evalbltin(const struct builtincmd *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008537static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008538
Eric Andersen62483552001-07-10 06:09:16 +00008539/*
Eric Andersenc470f442003-07-28 09:56:35 +00008540 * Evaluate a parse tree. The value is left in the global variable
8541 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008542 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008543static int
Eric Andersenc470f442003-07-28 09:56:35 +00008544evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008545{
Eric Andersenc470f442003-07-28 09:56:35 +00008546 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008547 int (*evalfn)(union node *, int);
8548 int status = 0;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008549
Eric Andersenc470f442003-07-28 09:56:35 +00008550 if (n == NULL) {
8551 TRACE(("evaltree(NULL) called\n"));
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02008552 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00008553 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008554 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008555
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008556 dotrap();
8557
Eric Andersenc470f442003-07-28 09:56:35 +00008558 switch (n->type) {
8559 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008560#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008561 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008562 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008563 break;
8564#endif
8565 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008566 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008567 goto setstatus;
8568 case NREDIR:
8569 expredir(n->nredir.redirect);
8570 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8571 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008572 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008573 }
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02008574 if (n->nredir.redirect)
8575 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
Eric Andersenc470f442003-07-28 09:56:35 +00008576 goto setstatus;
8577 case NCMD:
8578 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008579 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008580 if (eflag && !(flags & EV_TESTED))
8581 checkexit = ~0;
8582 goto calleval;
8583 case NFOR:
8584 evalfn = evalfor;
8585 goto calleval;
8586 case NWHILE:
8587 case NUNTIL:
8588 evalfn = evalloop;
8589 goto calleval;
8590 case NSUBSHELL:
8591 case NBACKGND:
8592 evalfn = evalsubshell;
Denys Vlasenkocf98b0c2016-10-25 18:19:39 +02008593 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00008594 case NPIPE:
8595 evalfn = evalpipe;
8596 goto checkexit;
8597 case NCASE:
8598 evalfn = evalcase;
8599 goto calleval;
8600 case NAND:
8601 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008602 case NSEMI: {
8603
Eric Andersenc470f442003-07-28 09:56:35 +00008604#if NAND + 1 != NOR
8605#error NAND + 1 != NOR
8606#endif
8607#if NOR + 1 != NSEMI
8608#error NOR + 1 != NSEMI
8609#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008610 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008611 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00008612 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008613 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008614 );
Denys Vlasenkobc1a0082016-10-02 15:31:33 +02008615 if ((!status) == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00008616 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008617 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008618 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008619 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008620 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008621 status = evalfn(n, flags);
8622 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008623 }
Eric Andersenc470f442003-07-28 09:56:35 +00008624 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008625 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008626 if (evalskip)
8627 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008628 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00008629 n = n->nif.ifpart;
8630 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008631 }
8632 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008633 n = n->nif.elsepart;
8634 goto evaln;
8635 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008636 status = 0;
8637 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00008638 case NDEFUN:
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008639 defun(n);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008640 /* Not necessary. To test it:
8641 * "false; f() { qwerty; }; echo $?" should print 0.
8642 */
8643 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008644 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00008645 exitstatus = status;
8646 break;
8647 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008648 out:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008649 /* Order of checks below is important:
8650 * signal handlers trigger before exit caused by "set -e".
8651 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008652 dotrap();
8653
8654 if (checkexit & status)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008655 raise_exception(EXEXIT);
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008656 if (flags & EV_EXIT)
8657 raise_exception(EXEXIT);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008658
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008659 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008660 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00008661}
8662
Eric Andersenc470f442003-07-28 09:56:35 +00008663#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8664static
8665#endif
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008666int evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
Eric Andersenc470f442003-07-28 09:56:35 +00008667
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02008668static int
8669skiploop(void)
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008670{
8671 int skip = evalskip;
8672
8673 switch (skip) {
8674 case 0:
8675 break;
8676 case SKIPBREAK:
8677 case SKIPCONT:
8678 if (--skipcount <= 0) {
8679 evalskip = 0;
8680 break;
8681 }
8682 skip = SKIPBREAK;
8683 break;
8684 }
8685 return skip;
8686}
8687
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008688static int
Eric Andersenc470f442003-07-28 09:56:35 +00008689evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008690{
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008691 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00008692 int status;
8693
8694 loopnest++;
8695 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008696 flags &= EV_TESTED;
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008697 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008698 int i;
8699
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008700 i = evaltree(n->nbinary.ch1, EV_TESTED);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008701 skip = skiploop();
8702 if (skip == SKIPFUNC)
8703 status = i;
8704 if (skip)
8705 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00008706 if (n->type != NWHILE)
8707 i = !i;
8708 if (i != 0)
8709 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008710 status = evaltree(n->nbinary.ch2, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008711 skip = skiploop();
8712 } while (!(skip & ~SKIPCONT));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008713 loopnest--;
8714
8715 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008716}
8717
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008718static int
Eric Andersenc470f442003-07-28 09:56:35 +00008719evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008720{
8721 struct arglist arglist;
8722 union node *argp;
8723 struct strlist *sp;
8724 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008725 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008726
8727 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008728 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008729 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008730 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02008731 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersencb57d552001-06-28 07:25:16 +00008732 }
8733 *arglist.lastp = NULL;
8734
Eric Andersencb57d552001-06-28 07:25:16 +00008735 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008736 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008737 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008738 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008739 status = evaltree(n->nfor.body, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008740 if (skiploop() & ~SKIPCONT)
Eric Andersencb57d552001-06-28 07:25:16 +00008741 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008742 }
8743 loopnest--;
Eric Andersencb57d552001-06-28 07:25:16 +00008744 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008745
8746 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008747}
8748
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008749static int
Eric Andersenc470f442003-07-28 09:56:35 +00008750evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008751{
8752 union node *cp;
8753 union node *patp;
8754 struct arglist arglist;
8755 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008756 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008757
8758 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008759 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008760 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00008761 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008762 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8763 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008764 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008765 /* Ensure body is non-empty as otherwise
8766 * EV_EXIT may prevent us from setting the
8767 * exit status.
8768 */
8769 if (evalskip == 0 && cp->nclist.body) {
8770 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008771 }
8772 goto out;
8773 }
8774 }
8775 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008776 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008777 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008778
8779 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008780}
8781
Eric Andersenc470f442003-07-28 09:56:35 +00008782/*
8783 * Kick off a subshell to evaluate a tree.
8784 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008785static int
Eric Andersenc470f442003-07-28 09:56:35 +00008786evalsubshell(union node *n, int flags)
8787{
8788 struct job *jp;
8789 int backgnd = (n->type == NBACKGND);
8790 int status;
8791
8792 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02008793 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00008794 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008795 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008796 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008797 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02008798 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008799 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008800 flags |= EV_EXIT;
8801 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02008802 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00008803 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00008804 redirect(n->nredir.redirect, 0);
8805 evaltreenr(n->nredir.n, flags);
8806 /* never returns */
8807 }
Denys Vlasenko70392332016-10-27 02:31:55 +02008808 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00008809 status = 0;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008810 if (!backgnd)
Eric Andersenc470f442003-07-28 09:56:35 +00008811 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00008812 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008813 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00008814}
8815
Eric Andersenc470f442003-07-28 09:56:35 +00008816/*
8817 * Compute the names of the files in a redirection list.
8818 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00008819static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008820static void
8821expredir(union node *n)
8822{
8823 union node *redir;
8824
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008825 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00008826 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008827
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008828 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008829 fn.lastp = &fn.list;
8830 switch (redir->type) {
8831 case NFROMTO:
8832 case NFROM:
8833 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008834#if ENABLE_ASH_BASH_COMPAT
8835 case NTO2:
8836#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008837 case NCLOBBER:
8838 case NAPPEND:
8839 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02008840 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denis Vlasenko559691a2008-10-05 18:39:31 +00008841#if ENABLE_ASH_BASH_COMPAT
8842 store_expfname:
8843#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008844#if 0
8845// By the design of stack allocator, the loop of this kind:
8846// while true; do while true; do break; done </dev/null; done
8847// will look like a memory leak: ash plans to free expfname's
8848// of "/dev/null" as soon as it finishes running the loop
8849// (in this case, never).
8850// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01008851 if (redir->nfile.expfname)
8852 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008853// It results in corrupted state of stacked allocations.
8854#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008855 redir->nfile.expfname = fn.list->text;
8856 break;
8857 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008858 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00008859 if (redir->ndup.vname) {
8860 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008861 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008862 ash_msg_and_raise_error("redir error");
Denis Vlasenko559691a2008-10-05 18:39:31 +00008863#if ENABLE_ASH_BASH_COMPAT
8864//FIXME: we used expandarg with different args!
8865 if (!isdigit_str9(fn.list->text)) {
8866 /* >&file, not >&fd */
8867 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8868 ash_msg_and_raise_error("redir error");
8869 redir->type = NTO2;
8870 goto store_expfname;
8871 }
8872#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008873 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008874 }
8875 break;
8876 }
8877 }
8878}
8879
Eric Andersencb57d552001-06-28 07:25:16 +00008880/*
Eric Andersencb57d552001-06-28 07:25:16 +00008881 * Evaluate a pipeline. All the processes in the pipeline are children
8882 * of the process creating the pipeline. (This differs from some versions
8883 * of the shell, which make the last process in a pipeline the parent
8884 * of all the rest.)
8885 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008886static int
Eric Andersenc470f442003-07-28 09:56:35 +00008887evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008888{
8889 struct job *jp;
8890 struct nodelist *lp;
8891 int pipelen;
8892 int prevfd;
8893 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008894 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008895
Eric Andersenc470f442003-07-28 09:56:35 +00008896 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00008897 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008898 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00008899 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008900 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008901 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008902 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00008903 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008904 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008905 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00008906 pip[1] = -1;
8907 if (lp->next) {
8908 if (pipe(pip) < 0) {
8909 close(prevfd);
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00008910 ash_msg_and_raise_error("pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00008911 }
8912 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008913 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02008914 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008915 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00008916 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008917 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00008918 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008919 if (prevfd > 0) {
8920 dup2(prevfd, 0);
8921 close(prevfd);
8922 }
8923 if (pip[1] > 1) {
8924 dup2(pip[1], 1);
8925 close(pip[1]);
8926 }
Eric Andersenc470f442003-07-28 09:56:35 +00008927 evaltreenr(lp->n, flags);
8928 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00008929 }
Denys Vlasenko70392332016-10-27 02:31:55 +02008930 /* parent */
Eric Andersencb57d552001-06-28 07:25:16 +00008931 if (prevfd >= 0)
8932 close(prevfd);
8933 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00008934 /* Don't want to trigger debugging */
8935 if (pip[1] != -1)
8936 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00008937 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008938 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008939 status = waitforjob(jp);
8940 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00008941 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00008942 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008943
8944 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008945}
8946
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008947/*
8948 * Controls whether the shell is interactive or not.
8949 */
8950static void
8951setinteractive(int on)
8952{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008953 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008954
8955 if (++on == is_interactive)
8956 return;
8957 is_interactive = on;
8958 setsignal(SIGINT);
8959 setsignal(SIGQUIT);
8960 setsignal(SIGTERM);
8961#if !ENABLE_FEATURE_SH_EXTRA_QUIET
8962 if (is_interactive > 1) {
8963 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008964 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008965
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008966 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008967 /* note: ash and hush share this string */
8968 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02008969 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
8970 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008971 bb_banner,
8972 "built-in shell (ash)"
8973 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008974 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008975 }
8976 }
8977#endif
8978}
8979
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008980static void
8981optschanged(void)
8982{
8983#if DEBUG
8984 opentrace();
8985#endif
8986 setinteractive(iflag);
8987 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008988#if ENABLE_FEATURE_EDITING_VI
8989 if (viflag)
8990 line_input_state->flags |= VI_MODE;
8991 else
8992 line_input_state->flags &= ~VI_MODE;
8993#else
8994 viflag = 0; /* forcibly keep the option off */
8995#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008996}
8997
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008998static struct localvar *localvars;
8999
9000/*
9001 * Called after a function returns.
9002 * Interrupts must be off.
9003 */
9004static void
9005poplocalvars(void)
9006{
9007 struct localvar *lvp;
9008 struct var *vp;
9009
9010 while ((lvp = localvars) != NULL) {
9011 localvars = lvp->next;
9012 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02009013 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009014 if (vp == NULL) { /* $- saved */
9015 memcpy(optlist, lvp->text, sizeof(optlist));
9016 free((char*)lvp->text);
9017 optschanged();
9018 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009019 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009020 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009021 if (vp->var_func)
9022 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009023 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009024 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009025 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009026 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009027 }
9028 free(lvp);
9029 }
9030}
9031
9032static int
9033evalfun(struct funcnode *func, int argc, char **argv, int flags)
9034{
9035 volatile struct shparam saveparam;
9036 struct localvar *volatile savelocalvars;
9037 struct jmploc *volatile savehandler;
9038 struct jmploc jmploc;
9039 int e;
9040
9041 saveparam = shellparam;
9042 savelocalvars = localvars;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009043 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009044 e = setjmp(jmploc.loc);
9045 if (e) {
9046 goto funcdone;
9047 }
9048 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009049 exception_handler = &jmploc;
9050 localvars = NULL;
Denis Vlasenko01631112007-12-16 17:20:38 +00009051 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009052 func->count++;
9053 funcnest++;
9054 INT_ON;
9055 shellparam.nparam = argc - 1;
9056 shellparam.p = argv + 1;
9057#if ENABLE_ASH_GETOPTS
9058 shellparam.optind = 1;
9059 shellparam.optoff = -1;
9060#endif
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009061 evaltree(func->n.narg.next, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00009062 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009063 INT_OFF;
9064 funcnest--;
9065 freefunc(func);
9066 poplocalvars();
9067 localvars = savelocalvars;
9068 freeparam(&shellparam);
9069 shellparam = saveparam;
9070 exception_handler = savehandler;
9071 INT_ON;
9072 evalskip &= ~SKIPFUNC;
9073 return e;
9074}
9075
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009076/*
9077 * Make a variable a local variable. When a variable is made local, it's
9078 * value and flags are saved in a localvar structure. The saved values
9079 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009080 * "-" as a special case: it makes changes to "set +-options" local
9081 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009082 */
9083static void
9084mklocal(char *name)
9085{
9086 struct localvar *lvp;
9087 struct var **vpp;
9088 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009089 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009090
9091 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009092 /* Cater for duplicate "local". Examples:
9093 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9094 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9095 */
9096 lvp = localvars;
9097 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009098 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009099 if (eq)
9100 setvareq(name, 0);
9101 /* else:
9102 * it's a duplicate "local VAR" declaration, do nothing
9103 */
9104 return;
9105 }
9106 lvp = lvp->next;
9107 }
9108
9109 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009110 if (LONE_DASH(name)) {
9111 char *p;
9112 p = ckmalloc(sizeof(optlist));
9113 lvp->text = memcpy(p, optlist, sizeof(optlist));
9114 vp = NULL;
9115 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009116 vpp = hashvar(name);
9117 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009118 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009119 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009120 if (eq)
9121 setvareq(name, VSTRFIXED);
9122 else
9123 setvar(name, NULL, VSTRFIXED);
9124 vp = *vpp; /* the new variable */
9125 lvp->flags = VUNSET;
9126 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009127 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009128 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009129 /* make sure neither "struct var" nor string gets freed
9130 * during (un)setting:
9131 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009132 vp->flags |= VSTRFIXED|VTEXTFIXED;
9133 if (eq)
9134 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009135 else
9136 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009137 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009138 }
9139 }
9140 lvp->vp = vp;
9141 lvp->next = localvars;
9142 localvars = lvp;
9143 INT_ON;
9144}
9145
9146/*
9147 * The "local" command.
9148 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009149static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009150localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009151{
9152 char *name;
9153
Ron Yorstonef2386b2015-10-29 16:19:14 +00009154 if (!funcnest)
9155 ash_msg_and_raise_error("not in a function");
9156
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009157 argv = argptr;
9158 while ((name = *argv++) != NULL) {
9159 mklocal(name);
9160 }
9161 return 0;
9162}
9163
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009164static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009165falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009166{
9167 return 1;
9168}
9169
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009170static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009171truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009172{
9173 return 0;
9174}
9175
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009176static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009177execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009178{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009179 if (argv[1]) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009180 iflag = 0; /* exit on error */
9181 mflag = 0;
9182 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009183 /* We should set up signals for "exec CMD"
9184 * the same way as for "CMD" without "exec".
9185 * But optschanged->setinteractive->setsignal
9186 * still thought we are a root shell. Therefore, for example,
9187 * SIGQUIT is still set to IGN. Fix it:
9188 */
9189 shlvl++;
9190 setsignal(SIGQUIT);
9191 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9192 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9193 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9194
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009195 shellexec(argv + 1, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009196 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009197 }
9198 return 0;
9199}
9200
9201/*
9202 * The return command.
9203 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009204static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009205returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009206{
9207 /*
9208 * If called outside a function, do what ksh does;
9209 * skip the rest of the file.
9210 */
Denys Vlasenko6a0710e2016-09-30 14:18:34 +02009211 evalskip = SKIPFUNC;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009212 return argv[1] ? number(argv[1]) : exitstatus;
9213}
9214
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009215/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009216static int breakcmd(int, char **) FAST_FUNC;
9217static int dotcmd(int, char **) FAST_FUNC;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009218static int evalcmd(int, char **, int) FAST_FUNC;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009219static int exitcmd(int, char **) FAST_FUNC;
9220static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009221#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009222static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009223#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009224#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009225static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009226#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009227#if MAX_HISTORY
9228static int historycmd(int, char **) FAST_FUNC;
9229#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009230#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009231static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009232#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009233static int readcmd(int, char **) FAST_FUNC;
9234static int setcmd(int, char **) FAST_FUNC;
9235static int shiftcmd(int, char **) FAST_FUNC;
9236static int timescmd(int, char **) FAST_FUNC;
9237static int trapcmd(int, char **) FAST_FUNC;
9238static int umaskcmd(int, char **) FAST_FUNC;
9239static int unsetcmd(int, char **) FAST_FUNC;
9240static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009241
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009242#define BUILTIN_NOSPEC "0"
9243#define BUILTIN_SPECIAL "1"
9244#define BUILTIN_REGULAR "2"
9245#define BUILTIN_SPEC_REG "3"
9246#define BUILTIN_ASSIGN "4"
9247#define BUILTIN_SPEC_ASSG "5"
9248#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009249#define BUILTIN_SPEC_REG_ASSG "7"
9250
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009251/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009252#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009253static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009254#endif
9255#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009256static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009257#endif
9258#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009259static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009260#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009261
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009262/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009263static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009264 { BUILTIN_SPEC_REG "." , dotcmd },
9265 { BUILTIN_SPEC_REG ":" , truecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009266#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009267 { BUILTIN_REGULAR "[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009268#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009269 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009270#endif
Denis Vlasenko80591b02008-03-25 07:49:43 +00009271#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009272#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009273 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009274#endif
9275#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009276 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009277#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009278 { BUILTIN_SPEC_REG "break" , breakcmd },
9279 { BUILTIN_REGULAR "cd" , cdcmd },
9280 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009281#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009282 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009283#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009284 { BUILTIN_SPEC_REG "continue", breakcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009285#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009286 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009287#endif
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009288 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009289 { BUILTIN_SPEC_REG "exec" , execcmd },
9290 { BUILTIN_SPEC_REG "exit" , exitcmd },
9291 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9292 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009293#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009294 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009295#endif
9296#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009297 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009298#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009299 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009300#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009301 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009302#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009303#if MAX_HISTORY
9304 { BUILTIN_NOSPEC "history" , historycmd },
9305#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009306#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009307 { BUILTIN_REGULAR "jobs" , jobscmd },
9308 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009309#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009310#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009311 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009312#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009313 { BUILTIN_ASSIGN "local" , localcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009314#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009315 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009316#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009317 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9318 { BUILTIN_REGULAR "read" , readcmd },
9319 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9320 { BUILTIN_SPEC_REG "return" , returncmd },
9321 { BUILTIN_SPEC_REG "set" , setcmd },
9322 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009323#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009324 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009325#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009326#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009327 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009328#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009329 { BUILTIN_SPEC_REG "times" , timescmd },
9330 { BUILTIN_SPEC_REG "trap" , trapcmd },
9331 { BUILTIN_REGULAR "true" , truecmd },
9332 { BUILTIN_NOSPEC "type" , typecmd },
9333 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9334 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009335#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009336 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009337#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009338 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9339 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009340};
9341
Denis Vlasenko80591b02008-03-25 07:49:43 +00009342/* Should match the above table! */
9343#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009344 /* . : */ 2 + \
9345 /* [ */ 1 * ENABLE_ASH_BUILTIN_TEST + \
9346 /* [[ */ 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9347 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9348 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9349 /* break cd cddir */ 3)
9350#define EVALCMD (COMMANDCMD + \
9351 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9352 /* continue */ 1 + \
9353 /* echo */ 1 * ENABLE_ASH_BUILTIN_ECHO + \
9354 0)
9355#define EXECCMD (EVALCMD + \
9356 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009357
9358/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009359 * Search the table of builtin commands.
9360 */
Denys Vlasenko888527c2016-10-02 16:54:17 +02009361static int
9362pstrcmp1(const void *a, const void *b)
9363{
9364 return strcmp((char*)a, *(char**)b + 1);
9365}
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009366static struct builtincmd *
9367find_builtin(const char *name)
9368{
9369 struct builtincmd *bp;
9370
9371 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009372 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denys Vlasenko888527c2016-10-02 16:54:17 +02009373 pstrcmp1
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009374 );
9375 return bp;
9376}
9377
9378/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009379 * Execute a simple command.
9380 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009381static int
9382isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009383{
9384 const char *q = endofname(p);
9385 if (p == q)
9386 return 0;
9387 return *q == '=';
9388}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009389static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009390bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009391{
9392 /* Preserve exitstatus of a previous possible redirection
9393 * as POSIX mandates */
9394 return back_exitstatus;
9395}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009396static int
Eric Andersenc470f442003-07-28 09:56:35 +00009397evalcommand(union node *cmd, int flags)
9398{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009399 static const struct builtincmd null_bltin = {
9400 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009401 };
Eric Andersenc470f442003-07-28 09:56:35 +00009402 struct stackmark smark;
9403 union node *argp;
9404 struct arglist arglist;
9405 struct arglist varlist;
9406 char **argv;
9407 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009408 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009409 struct cmdentry cmdentry;
9410 struct job *jp;
9411 char *lastarg;
9412 const char *path;
9413 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009414 int status;
9415 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00009416 struct builtincmd *bcmd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009417 smallint cmd_is_exec;
9418 smallint pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009419
9420 /* First expand the arguments. */
9421 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9422 setstackmark(&smark);
9423 back_exitstatus = 0;
9424
9425 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009426 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009427 varlist.lastp = &varlist.list;
9428 *varlist.lastp = NULL;
9429 arglist.lastp = &arglist.list;
9430 *arglist.lastp = NULL;
9431
9432 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009433 if (cmd->ncmd.args) {
Paul Foxc3850c82005-07-20 18:23:39 +00009434 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9435 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9436 }
9437
Eric Andersenc470f442003-07-28 09:56:35 +00009438 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9439 struct strlist **spp;
9440
9441 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00009442 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00009443 expandarg(argp, &arglist, EXP_VARTILDE);
9444 else
9445 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9446
Eric Andersenc470f442003-07-28 09:56:35 +00009447 for (sp = *spp; sp; sp = sp->next)
9448 argc++;
9449 }
9450
Denys Vlasenko65a8b852016-10-26 22:29:11 +02009451 /* Reserve one extra spot at the front for shellexec. */
9452 nargv = stalloc(sizeof(char *) * (argc + 2));
9453 argv = ++nargv;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009454 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009455 TRACE(("evalcommand arg: %s\n", sp->text));
9456 *nargv++ = sp->text;
9457 }
9458 *nargv = NULL;
9459
9460 lastarg = NULL;
9461 if (iflag && funcnest == 0 && argc > 0)
9462 lastarg = nargv[-1];
9463
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009464 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009465 expredir(cmd->ncmd.redirect);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009466 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009467
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009468 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009469 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9470 struct strlist **spp;
9471 char *p;
9472
9473 spp = varlist.lastp;
9474 expandarg(argp, &varlist, EXP_VARTILDE);
9475
9476 /*
9477 * Modify the command lookup path, if a PATH= assignment
9478 * is present
9479 */
9480 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009481 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009482 path = p;
9483 }
9484
9485 /* Print the command if xflag is set. */
9486 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009487 int n;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009488 const char *p = " %s" + 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009489
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009490 fdprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009491 sp = varlist.list;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009492 for (n = 0; n < 2; n++) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009493 while (sp) {
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009494 fdprintf(preverrout_fd, p, sp->text);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009495 sp = sp->next;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009496 p = " %s";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009497 }
9498 sp = arglist.list;
9499 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009500 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009501 }
9502
9503 cmd_is_exec = 0;
9504 spclbltin = -1;
9505
9506 /* Now locate the command. */
9507 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009508 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02009509#if ENABLE_ASH_CMDCMD
9510 const char *oldpath = path + 5;
9511#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009512 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009513 for (;;) {
9514 find_command(argv[0], &cmdentry, cmd_flag, path);
9515 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009516 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009517 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009518 goto bail;
9519 }
9520
9521 /* implement bltin and command here */
9522 if (cmdentry.cmdtype != CMDBUILTIN)
9523 break;
9524 if (spclbltin < 0)
9525 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9526 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009527 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009528#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009529 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009530 path = oldpath;
9531 nargv = parse_command_args(argv, &path);
9532 if (!nargv)
9533 break;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02009534 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
9535 * nargv => "PROG". path is updated if -p.
9536 */
Eric Andersenc470f442003-07-28 09:56:35 +00009537 argc -= nargv - argv;
9538 argv = nargv;
9539 cmd_flag |= DO_NOFUNC;
9540 } else
9541#endif
9542 break;
9543 }
9544 }
9545
9546 if (status) {
9547 /* We have a redirection error. */
9548 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009549 raise_exception(EXERROR);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009550 bail:
Eric Andersenc470f442003-07-28 09:56:35 +00009551 exitstatus = status;
9552 goto out;
9553 }
9554
9555 /* Execute the command. */
9556 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009557 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009558
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009559#if ENABLE_FEATURE_SH_NOFORK
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009560/* (1) BUG: if variables are set, we need to fork, or save/restore them
9561 * around run_nofork_applet() call.
9562 * (2) Should this check also be done in forkshell()?
9563 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9564 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009565 /* find_command() encodes applet_no as (-2 - applet_no) */
9566 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009567 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009568 listsetvar(varlist.list, VEXPORT|VSTACK);
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009569 /* run <applet>_main() */
Ron Yorston5ccb0e92016-10-20 12:24:02 +01009570 status = run_nofork_applet(applet_no, argv);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009571 break;
9572 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009573#endif
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009574 /* Can we avoid forking off? For example, very last command
9575 * in a script or a subshell does not need forking,
9576 * we can just exec it.
9577 */
Denys Vlasenko238bf182010-05-18 15:49:07 +02009578 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009579 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009580 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00009581 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009582 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009583 /* parent */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009584 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009585 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009586 TRACE(("forked child exited with %d\n", status));
Eric Andersenc470f442003-07-28 09:56:35 +00009587 break;
9588 }
Denys Vlasenko238bf182010-05-18 15:49:07 +02009589 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009590 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +02009591 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +00009592 }
9593 listsetvar(varlist.list, VEXPORT|VSTACK);
9594 shellexec(argv, path, cmdentry.u.index);
9595 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009596 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +00009597 case CMDBUILTIN:
9598 cmdenviron = varlist.list;
9599 if (cmdenviron) {
9600 struct strlist *list = cmdenviron;
9601 int i = VNOSET;
9602 if (spclbltin > 0 || argc == 0) {
9603 i = 0;
9604 if (cmd_is_exec && argc > 1)
9605 i = VEXPORT;
9606 }
9607 listsetvar(list, i);
9608 }
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009609 /* Tight loop with builtins only:
9610 * "while kill -0 $child; do true; done"
9611 * will never exit even if $child died, unless we do this
9612 * to reap the zombie and make kill detect that it's gone: */
9613 dowait(DOWAIT_NONBLOCK, NULL);
9614
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009615 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009616 if (exception_type == EXERROR && spclbltin <= 0) {
9617 FORCE_INT_ON;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02009618 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009619 }
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009620 raise:
9621 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009622 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009623 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009624
9625 case CMDFUNCTION:
9626 listsetvar(varlist.list, 0);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009627 /* See above for the rationale */
9628 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009629 if (evalfun(cmdentry.u.func, argc, argv, flags))
9630 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009631 readstatus:
9632 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009633 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009634 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +00009635
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009636 out:
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02009637 if (cmd->ncmd.redirect)
9638 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009639 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +00009640 /* dsl: I think this is intended to be used to support
9641 * '_' in 'vi' command mode during line editing...
9642 * However I implemented that within libedit itself.
9643 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009644 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009645 }
Eric Andersenc470f442003-07-28 09:56:35 +00009646 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009647
9648 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009649}
9650
9651static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009652evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009653{
Eric Andersenc470f442003-07-28 09:56:35 +00009654 char *volatile savecmdname;
9655 struct jmploc *volatile savehandler;
9656 struct jmploc jmploc;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009657 int status;
Eric Andersenc470f442003-07-28 09:56:35 +00009658 int i;
9659
9660 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009661 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009662 i = setjmp(jmploc.loc);
9663 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +00009664 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009665 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00009666 commandname = argv[0];
9667 argptr = argv + 1;
9668 optptr = NULL; /* initialize nextopt */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009669 if (cmd == EVALCMD)
9670 status = evalcmd(argc, argv, flags);
9671 else
9672 status = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009673 flush_stdout_stderr();
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009674 status |= ferror(stdout);
9675 exitstatus = status;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009676 cmddone:
Rob Landleyf296f0b2006-07-06 01:09:21 +00009677 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009678 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009679 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +00009680
9681 return i;
9682}
9683
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009684static int
9685goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009686{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02009687 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009688}
9689
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009690
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009691/*
9692 * Search for a command. This is called before we fork so that the
9693 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009694 * the child. The check for "goodname" is an overly conservative
9695 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009696 */
Eric Andersenc470f442003-07-28 09:56:35 +00009697static void
9698prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009699{
9700 struct cmdentry entry;
9701
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009702 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9703 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009704}
9705
Eric Andersencb57d552001-06-28 07:25:16 +00009706
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009707/* ============ Builtin commands
9708 *
9709 * Builtin commands whose functions are closely tied to evaluation
9710 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +00009711 */
9712
9713/*
Eric Andersencb57d552001-06-28 07:25:16 +00009714 * Handle break and continue commands. Break, continue, and return are
9715 * all handled by setting the evalskip flag. The evaluation routines
9716 * above all check this flag, and if it is set they start skipping
9717 * commands rather than executing them. The variable skipcount is
9718 * the number of loops to break/continue, or the number of function
9719 * levels to return. (The latter is always 1.) It should probably
9720 * be an error to break out of more loops than exist, but it isn't
9721 * in the standard shell so we don't make it one here.
9722 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009723static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009724breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009725{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009726 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009727
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00009728 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009729 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009730 if (n > loopnest)
9731 n = loopnest;
9732 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009733 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00009734 skipcount = n;
9735 }
9736 return 0;
9737}
9738
Eric Andersenc470f442003-07-28 09:56:35 +00009739
Denys Vlasenko70392332016-10-27 02:31:55 +02009740/*
Eric Andersen90898442003-08-06 11:20:52 +00009741 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00009742 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009743
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009744enum {
9745 INPUT_PUSH_FILE = 1,
9746 INPUT_NOFILE_OK = 2,
9747};
Eric Andersencb57d552001-06-28 07:25:16 +00009748
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009749static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009750/* values of checkkwd variable */
9751#define CHKALIAS 0x1
9752#define CHKKWD 0x2
9753#define CHKNL 0x4
9754
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009755/*
9756 * Push a string back onto the input at this current parsefile level.
9757 * We handle aliases this way.
9758 */
9759#if !ENABLE_ASH_ALIAS
9760#define pushstring(s, ap) pushstring(s)
9761#endif
9762static void
9763pushstring(char *s, struct alias *ap)
9764{
9765 struct strpush *sp;
9766 int len;
9767
9768 len = strlen(s);
9769 INT_OFF;
9770 if (g_parsefile->strpush) {
9771 sp = ckzalloc(sizeof(*sp));
9772 sp->prev = g_parsefile->strpush;
9773 } else {
9774 sp = &(g_parsefile->basestrpush);
9775 }
9776 g_parsefile->strpush = sp;
9777 sp->prev_string = g_parsefile->next_to_pgetc;
9778 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009779 sp->unget = g_parsefile->unget;
9780 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009781#if ENABLE_ASH_ALIAS
9782 sp->ap = ap;
9783 if (ap) {
9784 ap->flag |= ALIASINUSE;
9785 sp->string = s;
9786 }
9787#endif
9788 g_parsefile->next_to_pgetc = s;
9789 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009790 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009791 INT_ON;
9792}
9793
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009794static void
9795popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009796{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009797 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +00009798
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009799 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009800#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009801 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009802 if (g_parsefile->next_to_pgetc[-1] == ' '
9803 || g_parsefile->next_to_pgetc[-1] == '\t'
9804 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009805 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009806 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009807 if (sp->string != sp->ap->val) {
9808 free(sp->string);
9809 }
9810 sp->ap->flag &= ~ALIASINUSE;
9811 if (sp->ap->flag & ALIASDEAD) {
9812 unalias(sp->ap->name);
9813 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009814 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009815#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009816 g_parsefile->next_to_pgetc = sp->prev_string;
9817 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009818 g_parsefile->unget = sp->unget;
9819 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009820 g_parsefile->strpush = sp->prev;
9821 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009822 free(sp);
9823 INT_ON;
9824}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009825
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009826static int
9827preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009828{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009829 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00009830 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009831
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009832 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +00009833#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +00009834 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009835 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +01009836 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009837 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009838 int timeout = -1;
9839# if ENABLE_ASH_IDLE_TIMEOUT
9840 if (iflag) {
9841 const char *tmout_var = lookupvar("TMOUT");
9842 if (tmout_var) {
9843 timeout = atoi(tmout_var) * 1000;
9844 if (timeout <= 0)
9845 timeout = -1;
9846 }
9847 }
9848# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009849# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009850 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009851# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02009852 reinit_unicode_for_ash();
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009853 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009854 if (nr == 0) {
9855 /* Ctrl+C pressed */
9856 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009857 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009858 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009859 raise(SIGINT);
9860 return 1;
9861 }
Eric Andersenc470f442003-07-28 09:56:35 +00009862 goto retry;
9863 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009864 if (nr < 0) {
9865 if (errno == 0) {
9866 /* Ctrl+D pressed */
9867 nr = 0;
9868 }
9869# if ENABLE_ASH_IDLE_TIMEOUT
9870 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +02009871 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009872 exitshell();
9873 }
9874# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009875 }
Eric Andersencb57d552001-06-28 07:25:16 +00009876 }
9877#else
Ron Yorston61d6ae22015-04-19 10:50:25 +01009878 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00009879#endif
9880
Denys Vlasenko80c5b682011-05-08 21:21:10 +02009881#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +00009882 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00009883 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +00009884 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +00009885 if (flags >= 0 && (flags & O_NONBLOCK)) {
9886 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00009887 if (fcntl(0, F_SETFL, flags) >= 0) {
9888 out2str("sh: turning off NDELAY mode\n");
9889 goto retry;
9890 }
9891 }
9892 }
9893 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +00009894#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009895 return nr;
9896}
9897
9898/*
9899 * Refill the input buffer and return the next input character:
9900 *
9901 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009902 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9903 * or we are reading from a string so we can't refill the buffer,
9904 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +02009905 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +00009906 * 4) Process input up to the next newline, deleting nul characters.
9907 */
Denis Vlasenko727752d2008-11-28 03:41:47 +00009908//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9909#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009910static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009911static int
Eric Andersenc470f442003-07-28 09:56:35 +00009912preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009913{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009914 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +00009915 int more;
Eric Andersencb57d552001-06-28 07:25:16 +00009916
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009917 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +00009918#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009919 if (g_parsefile->left_in_line == -1
9920 && g_parsefile->strpush->ap
9921 && g_parsefile->next_to_pgetc[-1] != ' '
9922 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +00009923 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009924 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +00009925 return PEOA;
9926 }
Eric Andersen2870d962001-07-02 17:27:21 +00009927#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009928 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009929 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +00009930 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009931 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009932 * "pgetc" needs refilling.
9933 */
9934
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009935 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009936 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009937 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009938 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009939 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009940 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009941 /* even in failure keep left_in_line and next_to_pgetc
9942 * in lock step, for correct multi-layer pungetc.
9943 * left_in_line was decremented before preadbuffer(),
9944 * must inc next_to_pgetc: */
9945 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009946 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009947 }
Eric Andersencb57d552001-06-28 07:25:16 +00009948
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009949 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009950 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009951 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009952 again:
9953 more = preadfd();
9954 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009955 /* don't try reading again */
9956 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009957 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009958 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009959 return PEOF;
9960 }
9961 }
9962
Denis Vlasenko727752d2008-11-28 03:41:47 +00009963 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009964 * Set g_parsefile->left_in_line
9965 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009966 * NUL chars are deleted.
9967 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009968 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009969 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009970 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00009971
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009972 more--;
Eric Andersenc470f442003-07-28 09:56:35 +00009973
Denis Vlasenko727752d2008-11-28 03:41:47 +00009974 c = *q;
9975 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009976 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009977 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009978 q++;
9979 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009980 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009981 break;
9982 }
Eric Andersencb57d552001-06-28 07:25:16 +00009983 }
9984
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009985 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009986 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9987 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00009988 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009989 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009990 }
9991 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009992 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +00009993
Eric Andersencb57d552001-06-28 07:25:16 +00009994 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009995 char save = *q;
9996 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009997 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009998 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +00009999 }
10000
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010001 pgetc_debug("preadbuffer at %d:%p'%s'",
10002 g_parsefile->left_in_line,
10003 g_parsefile->next_to_pgetc,
10004 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +010010005 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010006}
10007
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010008static void
10009nlprompt(void)
10010{
10011 g_parsefile->linno++;
10012 setprompt_if(doprompt, 2);
10013}
10014static void
10015nlnoprompt(void)
10016{
10017 g_parsefile->linno++;
10018 needprompt = doprompt;
10019}
10020
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010021static int
10022pgetc(void)
10023{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010024 int c;
10025
10026 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010027 g_parsefile->left_in_line,
10028 g_parsefile->next_to_pgetc,
10029 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010030 if (g_parsefile->unget)
10031 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010032
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010033 if (--g_parsefile->left_in_line >= 0)
10034 c = (signed char)*g_parsefile->next_to_pgetc++;
10035 else
10036 c = preadbuffer();
10037
10038 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10039 g_parsefile->lastc[0] = c;
10040
10041 return c;
10042}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010043
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010044#if ENABLE_ASH_ALIAS
10045static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010046pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010047{
10048 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010049 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010050 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010051 g_parsefile->left_in_line,
10052 g_parsefile->next_to_pgetc,
10053 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010054 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010055 } while (c == PEOA);
10056 return c;
10057}
10058#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010059# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010060#endif
10061
10062/*
10063 * Read a line from the script.
10064 */
10065static char *
10066pfgets(char *line, int len)
10067{
10068 char *p = line;
10069 int nleft = len;
10070 int c;
10071
10072 while (--nleft > 0) {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010073 c = pgetc_without_PEOA();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010074 if (c == PEOF) {
10075 if (p == line)
10076 return NULL;
10077 break;
10078 }
10079 *p++ = c;
10080 if (c == '\n')
10081 break;
10082 }
10083 *p = '\0';
10084 return line;
10085}
10086
Eric Andersenc470f442003-07-28 09:56:35 +000010087/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010088 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010089 * PEOF may be pushed back.
10090 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010091static void
Eric Andersenc470f442003-07-28 09:56:35 +000010092pungetc(void)
10093{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010094 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010095}
10096
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010097/* This one eats backslash+newline */
10098static int
10099pgetc_eatbnl(void)
10100{
10101 int c;
10102
10103 while ((c = pgetc()) == '\\') {
10104 if (pgetc() != '\n') {
10105 pungetc();
10106 break;
10107 }
10108
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010109 nlprompt();
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010110 }
10111
10112 return c;
10113}
10114
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010115/*
10116 * To handle the "." command, a stack of input files is used. Pushfile
10117 * adds a new entry to the stack and popfile restores the previous level.
10118 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010119static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010120pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010121{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010122 struct parsefile *pf;
10123
Denis Vlasenko597906c2008-02-20 16:38:54 +000010124 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010125 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010126 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010127 /*pf->strpush = NULL; - ckzalloc did it */
10128 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010129 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010130 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010131}
10132
10133static void
10134popfile(void)
10135{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010136 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010137
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010010138 if (pf == &basepf)
10139 return;
10140
Denis Vlasenkob012b102007-02-19 22:43:01 +000010141 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010142 if (pf->pf_fd >= 0)
10143 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010144 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010145 while (pf->strpush)
10146 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010147 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010148 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010149 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010150}
10151
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010152/*
10153 * Return to top level.
10154 */
10155static void
10156popallfiles(void)
10157{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010158 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010159 popfile();
10160}
10161
10162/*
10163 * Close the file(s) that the shell is reading commands from. Called
10164 * after a fork is done.
10165 */
10166static void
10167closescript(void)
10168{
10169 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010170 if (g_parsefile->pf_fd > 0) {
10171 close(g_parsefile->pf_fd);
10172 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010173 }
10174}
10175
10176/*
10177 * Like setinputfile, but takes an open file descriptor. Call this with
10178 * interrupts off.
10179 */
10180static void
10181setinputfd(int fd, int push)
10182{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010183 if (push) {
10184 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010185 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010186 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010187 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010188 if (g_parsefile->buf == NULL)
10189 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010190 g_parsefile->left_in_buffer = 0;
10191 g_parsefile->left_in_line = 0;
10192 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010193}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010194
Eric Andersenc470f442003-07-28 09:56:35 +000010195/*
10196 * Set the input to take input from a file. If push is set, push the
10197 * old input onto the stack first.
10198 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010199static int
10200setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010201{
10202 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010203
Denis Vlasenkob012b102007-02-19 22:43:01 +000010204 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010205 fd = open(fname, O_RDONLY);
10206 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010207 if (flags & INPUT_NOFILE_OK)
10208 goto out;
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010209 exitstatus = 127;
Denis Vlasenko9604e1b2009-03-03 18:47:56 +000010210 ash_msg_and_raise_error("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010211 }
Denys Vlasenko64774602016-10-26 15:24:30 +020010212 if (fd < 10)
10213 fd = savefd(fd);
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020010214 else
10215 close_on_exec_on(fd);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010216 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010217 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010218 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010219 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010220}
10221
Eric Andersencb57d552001-06-28 07:25:16 +000010222/*
10223 * Like setinputfile, but takes input from a string.
10224 */
Eric Andersenc470f442003-07-28 09:56:35 +000010225static void
10226setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010227{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010228 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010229 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010230 g_parsefile->next_to_pgetc = string;
10231 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010232 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010233 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010234 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010235}
10236
10237
Denys Vlasenko70392332016-10-27 02:31:55 +020010238/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010239 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010240 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010241
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010242#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010243
Denys Vlasenko23841622015-10-09 15:52:03 +020010244/* Hash of mtimes of mailboxes */
10245static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010246/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010247static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010248
Eric Andersencb57d552001-06-28 07:25:16 +000010249/*
Eric Andersenc470f442003-07-28 09:56:35 +000010250 * Print appropriate message(s) if mail has arrived.
10251 * If mail_var_path_changed is set,
10252 * then the value of MAIL has mail_var_path_changed,
10253 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010254 */
Eric Andersenc470f442003-07-28 09:56:35 +000010255static void
10256chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010257{
Eric Andersencb57d552001-06-28 07:25:16 +000010258 const char *mpath;
10259 char *p;
10260 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010261 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010262 struct stackmark smark;
10263 struct stat statb;
10264
Eric Andersencb57d552001-06-28 07:25:16 +000010265 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010266 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010267 new_hash = 0;
10268 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010269 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010270 if (p == NULL)
10271 break;
10272 if (*p == '\0')
10273 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010274 for (q = p; *q; q++)
10275 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010276#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010277 if (q[-1] != '/')
10278 abort();
10279#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010280 q[-1] = '\0'; /* delete trailing '/' */
10281 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010282 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010283 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010284 /* Very simplistic "hash": just a sum of all mtimes */
10285 new_hash += (unsigned)statb.st_mtime;
10286 }
10287 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010288 if (mailtime_hash != 0)
10289 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010290 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010291 }
Eric Andersenc470f442003-07-28 09:56:35 +000010292 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010293 popstackmark(&smark);
10294}
Eric Andersencb57d552001-06-28 07:25:16 +000010295
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010296static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010297changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010298{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010299 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010300}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010301
Denis Vlasenko131ae172007-02-18 13:00:19 +000010302#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010303
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010304
10305/* ============ ??? */
10306
Eric Andersencb57d552001-06-28 07:25:16 +000010307/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010308 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010309 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010310static void
10311setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010312{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010313 char **newparam;
10314 char **ap;
10315 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010316
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010317 for (nparam = 0; argv[nparam]; nparam++)
10318 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010319 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10320 while (*argv) {
10321 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010322 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010323 *ap = NULL;
10324 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010325 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010326 shellparam.nparam = nparam;
10327 shellparam.p = newparam;
10328#if ENABLE_ASH_GETOPTS
10329 shellparam.optind = 1;
10330 shellparam.optoff = -1;
10331#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010332}
10333
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010334/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010335 * Process shell options. The global variable argptr contains a pointer
10336 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010337 *
10338 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10339 * For a non-interactive shell, an error condition encountered
10340 * by a special built-in ... shall cause the shell to write a diagnostic message
10341 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010342 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010343 * ...
10344 * Utility syntax error (option or operand error) Shall exit
10345 * ...
10346 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10347 * we see that bash does not do that (set "finishes" with error code 1 instead,
10348 * and shell continues), and people rely on this behavior!
10349 * Testcase:
10350 * set -o barfoo 2>/dev/null
10351 * echo $?
10352 *
10353 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010354 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010355static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010356plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010357{
10358 int i;
10359
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010360 if (name) {
10361 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010362 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010363 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010364 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010365 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010366 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010367 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010368 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010369 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010370 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010371 if (val) {
10372 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10373 } else {
10374 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10375 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010376 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010377 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010378}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010379static void
10380setoption(int flag, int val)
10381{
10382 int i;
10383
10384 for (i = 0; i < NOPTS; i++) {
10385 if (optletters(i) == flag) {
10386 optlist[i] = val;
10387 return;
10388 }
10389 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010390 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010391 /* NOTREACHED */
10392}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010393static int
Eric Andersenc470f442003-07-28 09:56:35 +000010394options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +000010395{
10396 char *p;
10397 int val;
10398 int c;
10399
10400 if (cmdline)
10401 minusc = NULL;
10402 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010403 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010404 if (c != '-' && c != '+')
10405 break;
10406 argptr++;
10407 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010408 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010409 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010410 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010411 if (!cmdline) {
10412 /* "-" means turn off -x and -v */
10413 if (p[0] == '\0')
10414 xflag = vflag = 0;
10415 /* "--" means reset params */
10416 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010417 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010418 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010419 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010420 }
Eric Andersencb57d552001-06-28 07:25:16 +000010421 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010422 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010423 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010424 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010425 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010426 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010427 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010428 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010429 /* it already printed err message */
10430 return 1; /* error */
10431 }
Eric Andersencb57d552001-06-28 07:25:16 +000010432 if (*argptr)
10433 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010434 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10435 isloginsh = 1;
10436 /* bash does not accept +-login, we also won't */
10437 } else if (cmdline && val && (c == '-')) { /* long options */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010438 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +000010439 isloginsh = 1;
10440 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010441 } else {
10442 setoption(c, val);
10443 }
10444 }
10445 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010446 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010447}
10448
Eric Andersencb57d552001-06-28 07:25:16 +000010449/*
Eric Andersencb57d552001-06-28 07:25:16 +000010450 * The shift builtin command.
10451 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010452static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010453shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010454{
10455 int n;
10456 char **ap1, **ap2;
10457
10458 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010459 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010460 n = number(argv[1]);
10461 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010462 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010463 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010464 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010465 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010466 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010467 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010468 }
10469 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010470 while ((*ap2++ = *ap1++) != NULL)
10471 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010472#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010473 shellparam.optind = 1;
10474 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010475#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010476 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010477 return 0;
10478}
10479
Eric Andersencb57d552001-06-28 07:25:16 +000010480/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010481 * POSIX requires that 'set' (but not export or readonly) output the
10482 * variables in lexicographic order - by the locale's collating order (sigh).
10483 * Maybe we could keep them in an ordered balanced binary tree
10484 * instead of hashed lists.
10485 * For now just roll 'em through qsort for printing...
10486 */
10487static int
10488showvars(const char *sep_prefix, int on, int off)
10489{
10490 const char *sep;
10491 char **ep, **epend;
10492
10493 ep = listvars(on, off, &epend);
10494 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10495
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010496 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010497
10498 for (; ep < epend; ep++) {
10499 const char *p;
10500 const char *q;
10501
10502 p = strchrnul(*ep, '=');
10503 q = nullstr;
10504 if (*p)
10505 q = single_quote(++p);
10506 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10507 }
10508 return 0;
10509}
10510
10511/*
Eric Andersencb57d552001-06-28 07:25:16 +000010512 * The set command builtin.
10513 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010514static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010515setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010516{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010517 int retval;
10518
Denis Vlasenko68404f12008-03-17 09:00:54 +000010519 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010520 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010521
Denis Vlasenkob012b102007-02-19 22:43:01 +000010522 INT_OFF;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010523 retval = options(/*cmdline:*/ 0);
10524 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010525 optschanged();
10526 if (*argptr != NULL) {
10527 setparam(argptr);
10528 }
Eric Andersencb57d552001-06-28 07:25:16 +000010529 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010530 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010531 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010532}
10533
Denis Vlasenko131ae172007-02-18 13:00:19 +000010534#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010535static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010536change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010537{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010538 uint32_t t;
10539
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010540 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010541 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010542 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010543 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010544 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010545 vrandom.flags &= ~VNOFUNC;
10546 } else {
10547 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010548 t = strtoul(value, NULL, 10);
10549 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010550 }
Eric Andersenef02f822004-03-11 13:34:24 +000010551}
Eric Andersen16767e22004-03-16 05:14:10 +000010552#endif
10553
Denis Vlasenko131ae172007-02-18 13:00:19 +000010554#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010555static int
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010556getopts(char *optstr, char *optvar, char **optfirst)
Eric Andersencb57d552001-06-28 07:25:16 +000010557{
10558 char *p, *q;
10559 char c = '?';
10560 int done = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010561 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000010562 char **optnext;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010563 int ind = shellparam.optind;
10564 int off = shellparam.optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010565
Denys Vlasenko9c541002015-10-07 15:44:36 +020010566 sbuf[1] = '\0';
10567
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010568 shellparam.optind = -1;
10569 optnext = optfirst + ind - 1;
Eric Andersena48b0a32003-10-22 10:56:47 +000010570
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010571 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
Eric Andersencb57d552001-06-28 07:25:16 +000010572 p = NULL;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010573 else
10574 p = optnext[-1] + off;
Eric Andersencb57d552001-06-28 07:25:16 +000010575 if (p == NULL || *p == '\0') {
10576 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010577 p = *optnext;
10578 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010579 atend:
Eric Andersencb57d552001-06-28 07:25:16 +000010580 p = NULL;
10581 done = 1;
10582 goto out;
10583 }
10584 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010585 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010586 goto atend;
10587 }
10588
10589 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010590 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010591 if (*q == '\0') {
10592 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010593 sbuf[0] = c;
10594 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010595 setvar0("OPTARG", sbuf);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010596 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010597 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010598 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010599 }
10600 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010601 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010602 }
10603 if (*++q == ':')
10604 q++;
10605 }
10606
10607 if (*++q == ':') {
10608 if (*p == '\0' && (p = *optnext) == NULL) {
10609 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010610 sbuf[0] = c;
10611 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010612 setvar0("OPTARG", sbuf);
Eric Andersencb57d552001-06-28 07:25:16 +000010613 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010614 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010615 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010616 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010617 c = '?';
10618 }
Eric Andersenc470f442003-07-28 09:56:35 +000010619 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010620 }
10621
10622 if (p == *optnext)
10623 optnext++;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010624 setvar0("OPTARG", p);
Eric Andersencb57d552001-06-28 07:25:16 +000010625 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010626 } else
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010627 setvar0("OPTARG", nullstr);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010628 out:
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010629 ind = optnext - optfirst + 1;
10630 setvar("OPTIND", itoa(ind), VNOFUNC);
Denys Vlasenko9c541002015-10-07 15:44:36 +020010631 sbuf[0] = c;
10632 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010633 setvar0(optvar, sbuf);
10634
10635 shellparam.optoff = p ? p - *(optnext - 1) : -1;
10636 shellparam.optind = ind;
10637
Eric Andersencb57d552001-06-28 07:25:16 +000010638 return done;
10639}
Eric Andersenc470f442003-07-28 09:56:35 +000010640
10641/*
10642 * The getopts builtin. Shellparam.optnext points to the next argument
10643 * to be processed. Shellparam.optptr points to the next character to
10644 * be processed in the current argument. If shellparam.optnext is NULL,
10645 * then it's the first time getopts has been called.
10646 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010647static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000010648getoptscmd(int argc, char **argv)
10649{
10650 char **optbase;
10651
10652 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010653 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010654 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000010655 optbase = shellparam.p;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010656 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
Eric Andersenc470f442003-07-28 09:56:35 +000010657 shellparam.optind = 1;
10658 shellparam.optoff = -1;
10659 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010660 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010661 optbase = &argv[3];
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010662 if ((unsigned)shellparam.optind > argc - 2) {
Eric Andersenc470f442003-07-28 09:56:35 +000010663 shellparam.optind = 1;
10664 shellparam.optoff = -1;
10665 }
10666 }
10667
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010668 return getopts(argv[1], argv[2], optbase);
Eric Andersenc470f442003-07-28 09:56:35 +000010669}
Denis Vlasenko131ae172007-02-18 13:00:19 +000010670#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000010671
Eric Andersencb57d552001-06-28 07:25:16 +000010672
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010673/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000010674
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010675struct heredoc {
10676 struct heredoc *next; /* next here document in list */
10677 union node *here; /* redirection node */
10678 char *eofmark; /* string indicating end of input */
10679 smallint striptabs; /* if set, strip leading tabs */
10680};
10681
10682static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010683static smallint quoteflag; /* set if (part of) last token was quoted */
10684static token_id_t lasttoken; /* last token read (integer id Txxx) */
10685static struct heredoc *heredoclist; /* list of here documents to read */
10686static char *wordtext; /* text of last word returned by readtoken */
10687static struct nodelist *backquotelist;
10688static union node *redirnode;
10689static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010690
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010691static const char *
10692tokname(char *buf, int tok)
10693{
10694 if (tok < TSEMI)
Denys Vlasenko888527c2016-10-02 16:54:17 +020010695 return tokname_array[tok];
10696 sprintf(buf, "\"%s\"", tokname_array[tok]);
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010697 return buf;
10698}
10699
10700/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010701 * Called when an unexpected token is read during the parse. The argument
10702 * is the token that is expected, or -1 if more than one type of token can
10703 * occur at this point.
10704 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010705static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010706static void
10707raise_error_unexpected_syntax(int token)
10708{
10709 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010710 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010711 int l;
10712
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010713 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010714 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010715 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010716 raise_error_syntax(msg);
10717 /* NOTREACHED */
10718}
Eric Andersencb57d552001-06-28 07:25:16 +000010719
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010720#define EOFMARKLEN 79
Eric Andersencb57d552001-06-28 07:25:16 +000010721
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010722/* parsing is heavily cross-recursive, need these forward decls */
10723static union node *andor(void);
10724static union node *pipeline(void);
10725static union node *parse_command(void);
10726static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000010727static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010728static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000010729
Eric Andersenc470f442003-07-28 09:56:35 +000010730static union node *
10731list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000010732{
10733 union node *n1, *n2, *n3;
10734 int tok;
10735
Eric Andersencb57d552001-06-28 07:25:16 +000010736 n1 = NULL;
10737 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010738 switch (peektoken()) {
10739 case TNL:
10740 if (!(nlflag & 1))
10741 break;
10742 parseheredoc();
10743 return n1;
10744
10745 case TEOF:
10746 if (!n1 && (nlflag & 1))
10747 n1 = NODE_EOF;
10748 parseheredoc();
10749 return n1;
10750 }
10751
10752 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko888527c2016-10-02 16:54:17 +020010753 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
Ron Yorstonc0e00762015-10-29 11:30:55 +000010754 return n1;
10755 nlflag |= 2;
10756
Eric Andersencb57d552001-06-28 07:25:16 +000010757 n2 = andor();
10758 tok = readtoken();
10759 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000010760 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010761 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010762 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010763 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010764 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000010765 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010766 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010767 n2 = n3;
10768 }
10769 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000010770 }
10771 }
10772 if (n1 == NULL) {
10773 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010774 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010775 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010776 n3->type = NSEMI;
10777 n3->nbinary.ch1 = n1;
10778 n3->nbinary.ch2 = n2;
10779 n1 = n3;
10780 }
10781 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010782 case TNL:
10783 case TEOF:
10784 tokpushback = 1;
10785 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000010786 case TBACKGND:
10787 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000010788 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010789 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000010790 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010791 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010792 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010793 return n1;
10794 }
10795 }
10796}
10797
Eric Andersenc470f442003-07-28 09:56:35 +000010798static union node *
10799andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010800{
Eric Andersencb57d552001-06-28 07:25:16 +000010801 union node *n1, *n2, *n3;
10802 int t;
10803
Eric Andersencb57d552001-06-28 07:25:16 +000010804 n1 = pipeline();
10805 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010806 t = readtoken();
10807 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000010808 t = NAND;
10809 } else if (t == TOR) {
10810 t = NOR;
10811 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010812 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010813 return n1;
10814 }
Eric Andersenc470f442003-07-28 09:56:35 +000010815 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010816 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010817 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010818 n3->type = t;
10819 n3->nbinary.ch1 = n1;
10820 n3->nbinary.ch2 = n2;
10821 n1 = n3;
10822 }
10823}
10824
Eric Andersenc470f442003-07-28 09:56:35 +000010825static union node *
10826pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010827{
Eric Andersencb57d552001-06-28 07:25:16 +000010828 union node *n1, *n2, *pipenode;
10829 struct nodelist *lp, *prev;
10830 int negate;
10831
10832 negate = 0;
10833 TRACE(("pipeline: entered\n"));
10834 if (readtoken() == TNOT) {
10835 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000010836 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010837 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010838 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010839 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010840 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010841 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000010842 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010843 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010844 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000010845 pipenode->npipe.cmdlist = lp;
10846 lp->n = n1;
10847 do {
10848 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010849 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000010850 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010851 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010852 prev->next = lp;
10853 } while (readtoken() == TPIPE);
10854 lp->next = NULL;
10855 n1 = pipenode;
10856 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010857 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010858 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010859 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000010860 n2->type = NNOT;
10861 n2->nnot.com = n1;
10862 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010863 }
10864 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000010865}
10866
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010867static union node *
10868makename(void)
10869{
10870 union node *n;
10871
Denis Vlasenko597906c2008-02-20 16:38:54 +000010872 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010873 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010874 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010875 n->narg.text = wordtext;
10876 n->narg.backquote = backquotelist;
10877 return n;
10878}
10879
10880static void
10881fixredir(union node *n, const char *text, int err)
10882{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010883 int fd;
10884
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010885 TRACE(("Fix redir %s %d\n", text, err));
10886 if (!err)
10887 n->ndup.vname = NULL;
10888
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010889 fd = bb_strtou(text, NULL, 10);
10890 if (!errno && fd >= 0)
10891 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010892 else if (LONE_DASH(text))
10893 n->ndup.dupfd = -1;
10894 else {
10895 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010896 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010897 n->ndup.vname = makename();
10898 }
10899}
10900
10901/*
10902 * Returns true if the text contains nothing to expand (no dollar signs
10903 * or backquotes).
10904 */
10905static int
Denis Vlasenko68819d12008-12-15 11:26:36 +000010906noexpand(const char *text)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010907{
Denys Vlasenkocd716832009-11-28 22:14:02 +010010908 unsigned char c;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010909
Denys Vlasenkocd716832009-11-28 22:14:02 +010010910 while ((c = *text++) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010911 if (c == CTLQUOTEMARK)
10912 continue;
10913 if (c == CTLESC)
Denys Vlasenkocd716832009-11-28 22:14:02 +010010914 text++;
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010010915 else if (SIT(c, BASESYNTAX) == CCTL)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010916 return 0;
10917 }
10918 return 1;
10919}
10920
10921static void
10922parsefname(void)
10923{
10924 union node *n = redirnode;
10925
10926 if (readtoken() != TWORD)
10927 raise_error_unexpected_syntax(-1);
10928 if (n->type == NHERE) {
10929 struct heredoc *here = heredoc;
10930 struct heredoc *p;
10931 int i;
10932
10933 if (quoteflag == 0)
10934 n->type = NXHERE;
10935 TRACE(("Here document %d\n", n->type));
10936 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010937 raise_error_syntax("illegal eof marker for << redirection");
Denys Vlasenkob6c84342009-08-29 20:23:20 +020010938 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010939 here->eofmark = wordtext;
10940 here->next = NULL;
10941 if (heredoclist == NULL)
10942 heredoclist = here;
10943 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010944 for (p = heredoclist; p->next; p = p->next)
10945 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010946 p->next = here;
10947 }
10948 } else if (n->type == NTOFD || n->type == NFROMFD) {
10949 fixredir(n, wordtext, 0);
10950 } else {
10951 n->nfile.fname = makename();
10952 }
10953}
Eric Andersencb57d552001-06-28 07:25:16 +000010954
Eric Andersenc470f442003-07-28 09:56:35 +000010955static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010956simplecmd(void)
10957{
10958 union node *args, **app;
10959 union node *n = NULL;
10960 union node *vars, **vpp;
10961 union node **rpp, *redir;
10962 int savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010963#if ENABLE_ASH_BASH_COMPAT
10964 smallint double_brackets_flag = 0;
Ron Yorston95ebcf72015-11-03 09:42:23 +000010965 smallint function_flag = 0;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010966#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010967
10968 args = NULL;
10969 app = &args;
10970 vars = NULL;
10971 vpp = &vars;
10972 redir = NULL;
10973 rpp = &redir;
10974
10975 savecheckkwd = CHKALIAS;
10976 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000010977 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010978 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010979 t = readtoken();
10980 switch (t) {
10981#if ENABLE_ASH_BASH_COMPAT
Ron Yorston95ebcf72015-11-03 09:42:23 +000010982 case TFUNCTION:
10983 if (peektoken() != TWORD)
10984 raise_error_unexpected_syntax(TWORD);
10985 function_flag = 1;
10986 break;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010987 case TAND: /* "&&" */
10988 case TOR: /* "||" */
10989 if (!double_brackets_flag) {
10990 tokpushback = 1;
10991 goto out;
10992 }
10993 wordtext = (char *) (t == TAND ? "-a" : "-o");
10994#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010995 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000010996 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010997 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010998 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010999 n->narg.text = wordtext;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011000#if ENABLE_ASH_BASH_COMPAT
11001 if (strcmp("[[", wordtext) == 0)
11002 double_brackets_flag = 1;
11003 else if (strcmp("]]", wordtext) == 0)
11004 double_brackets_flag = 0;
11005#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011006 n->narg.backquote = backquotelist;
11007 if (savecheckkwd && isassignment(wordtext)) {
11008 *vpp = n;
11009 vpp = &n->narg.next;
11010 } else {
11011 *app = n;
11012 app = &n->narg.next;
11013 savecheckkwd = 0;
11014 }
Ron Yorston95ebcf72015-11-03 09:42:23 +000011015#if ENABLE_ASH_BASH_COMPAT
11016 if (function_flag) {
11017 checkkwd = CHKNL | CHKKWD;
11018 switch (peektoken()) {
11019 case TBEGIN:
11020 case TIF:
11021 case TCASE:
11022 case TUNTIL:
11023 case TWHILE:
11024 case TFOR:
11025 goto do_func;
11026 case TLP:
11027 function_flag = 0;
11028 break;
11029 case TWORD:
11030 if (strcmp("[[", wordtext) == 0)
11031 goto do_func;
11032 /* fall through */
11033 default:
11034 raise_error_unexpected_syntax(-1);
11035 }
11036 }
11037#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011038 break;
11039 case TREDIR:
11040 *rpp = n = redirnode;
11041 rpp = &n->nfile.next;
11042 parsefname(); /* read name of redirection file */
11043 break;
11044 case TLP:
Ron Yorston95ebcf72015-11-03 09:42:23 +000011045 IF_ASH_BASH_COMPAT(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011046 if (args && app == &args->narg.next
11047 && !vars && !redir
11048 ) {
11049 struct builtincmd *bcmd;
11050 const char *name;
11051
11052 /* We have a function */
Ron Yorston95ebcf72015-11-03 09:42:23 +000011053 if (IF_ASH_BASH_COMPAT(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011054 raise_error_unexpected_syntax(TRP);
11055 name = n->narg.text;
11056 if (!goodname(name)
11057 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11058 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011059 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011060 }
11061 n->type = NDEFUN;
11062 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11063 n->narg.next = parse_command();
11064 return n;
11065 }
Ron Yorston95ebcf72015-11-03 09:42:23 +000011066 IF_ASH_BASH_COMPAT(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011067 /* fall through */
11068 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011069 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011070 goto out;
11071 }
11072 }
11073 out:
11074 *app = NULL;
11075 *vpp = NULL;
11076 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011077 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011078 n->type = NCMD;
11079 n->ncmd.args = args;
11080 n->ncmd.assign = vars;
11081 n->ncmd.redirect = redir;
11082 return n;
11083}
11084
11085static union node *
11086parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011087{
Eric Andersencb57d552001-06-28 07:25:16 +000011088 union node *n1, *n2;
11089 union node *ap, **app;
11090 union node *cp, **cpp;
11091 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011092 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011093 int t;
11094
11095 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011096 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011097
Eric Andersencb57d552001-06-28 07:25:16 +000011098 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011099 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011100 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011101 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011102 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011103 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011104 n1->type = NIF;
11105 n1->nif.test = list(0);
11106 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011107 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011108 n1->nif.ifpart = list(0);
11109 n2 = n1;
11110 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011111 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011112 n2 = n2->nif.elsepart;
11113 n2->type = NIF;
11114 n2->nif.test = list(0);
11115 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011116 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011117 n2->nif.ifpart = list(0);
11118 }
11119 if (lasttoken == TELSE)
11120 n2->nif.elsepart = list(0);
11121 else {
11122 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011123 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011124 }
Eric Andersenc470f442003-07-28 09:56:35 +000011125 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011126 break;
11127 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011128 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011129 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011130 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011131 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011132 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011133 got = readtoken();
11134 if (got != TDO) {
Denys Vlasenko888527c2016-10-02 16:54:17 +020011135 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
Denis Vlasenko131ae172007-02-18 13:00:19 +000011136 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011137 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011138 }
11139 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011140 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011141 break;
11142 }
11143 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011144 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011145 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011146 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011147 n1->type = NFOR;
11148 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011149 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011150 if (readtoken() == TIN) {
11151 app = &ap;
11152 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011153 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011154 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011155 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011156 n2->narg.text = wordtext;
11157 n2->narg.backquote = backquotelist;
11158 *app = n2;
11159 app = &n2->narg.next;
11160 }
11161 *app = NULL;
11162 n1->nfor.args = ap;
11163 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011164 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011165 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011166 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011167 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011168 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011169 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011170 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011171 n1->nfor.args = n2;
11172 /*
11173 * Newline or semicolon here is optional (but note
11174 * that the original Bourne shell only allowed NL).
11175 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011176 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011177 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011178 }
Eric Andersenc470f442003-07-28 09:56:35 +000011179 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011180 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011181 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011182 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011183 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011184 break;
11185 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011186 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011187 n1->type = NCASE;
11188 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011189 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011190 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011191 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011192 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011193 n2->narg.text = wordtext;
11194 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011195 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11196 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011197 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011198 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011199 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011200 checkkwd = CHKNL | CHKKWD;
11201 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011202 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011203 if (lasttoken == TLP)
11204 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011205 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011206 cp->type = NCLIST;
11207 app = &cp->nclist.pattern;
11208 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011209 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011210 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011211 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011212 ap->narg.text = wordtext;
11213 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011214 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011215 break;
11216 app = &ap->narg.next;
11217 readtoken();
11218 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011219 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011220 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011221 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011222 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011223
Eric Andersenc470f442003-07-28 09:56:35 +000011224 cpp = &cp->nclist.next;
11225
11226 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011227 t = readtoken();
11228 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011229 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011230 raise_error_unexpected_syntax(TENDCASE);
11231 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011232 }
Eric Andersenc470f442003-07-28 09:56:35 +000011233 }
Eric Andersencb57d552001-06-28 07:25:16 +000011234 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011235 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011236 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011237 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011238 n1->type = NSUBSHELL;
11239 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011240 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011241 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011242 break;
11243 case TBEGIN:
11244 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011245 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011246 break;
Ron Yorston95ebcf72015-11-03 09:42:23 +000011247 IF_ASH_BASH_COMPAT(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011248 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011249 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011250 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011251 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011252 }
11253
Eric Andersenc470f442003-07-28 09:56:35 +000011254 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011255 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011256
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011257 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011258 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011259 checkkwd = CHKKWD | CHKALIAS;
11260 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011261 while (readtoken() == TREDIR) {
11262 *rpp = n2 = redirnode;
11263 rpp = &n2->nfile.next;
11264 parsefname();
11265 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011266 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011267 *rpp = NULL;
11268 if (redir) {
11269 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011270 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011271 n2->type = NREDIR;
11272 n2->nredir.n = n1;
11273 n1 = n2;
11274 }
11275 n1->nredir.redirect = redir;
11276 }
Eric Andersencb57d552001-06-28 07:25:16 +000011277 return n1;
11278}
11279
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011280#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko37dc08b2016-10-02 04:38:07 +020011281static int
11282decode_dollar_squote(void)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011283{
11284 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11285 int c, cnt;
11286 char *p;
11287 char buf[4];
11288
11289 c = pgetc();
11290 p = strchr(C_escapes, c);
11291 if (p) {
11292 buf[0] = c;
11293 p = buf;
11294 cnt = 3;
11295 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11296 do {
11297 c = pgetc();
11298 *++p = c;
11299 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11300 pungetc();
11301 } else if (c == 'x') { /* \xHH */
11302 do {
11303 c = pgetc();
11304 *++p = c;
11305 } while (isxdigit(c) && --cnt);
11306 pungetc();
11307 if (cnt == 3) { /* \x but next char is "bad" */
11308 c = 'x';
11309 goto unrecognized;
11310 }
11311 } else { /* simple seq like \\ or \t */
11312 p++;
11313 }
11314 *p = '\0';
11315 p = buf;
11316 c = bb_process_escape_sequence((void*)&p);
11317 } else { /* unrecognized "\z": print both chars unless ' or " */
11318 if (c != '\'' && c != '"') {
11319 unrecognized:
11320 c |= 0x100; /* "please encode \, then me" */
11321 }
11322 }
11323 return c;
11324}
11325#endif
11326
Eric Andersencb57d552001-06-28 07:25:16 +000011327/*
11328 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11329 * is not NULL, read a here document. In the latter case, eofmark is the
11330 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011331 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011332 * is the first character of the input token or document.
11333 *
11334 * Because C does not have internal subroutines, I have simulated them
11335 * using goto's to implement the subroutine linkage. The following macros
11336 * will run code that appears at the end of readtoken1.
11337 */
Eric Andersen2870d962001-07-02 17:27:21 +000011338#define CHECKEND() {goto checkend; checkend_return:;}
11339#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11340#define PARSESUB() {goto parsesub; parsesub_return:;}
11341#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11342#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11343#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011344static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011345readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011346{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011347 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011348 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011349 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020011350 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +000011351 char line[EOFMARKLEN + 1];
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011352 struct nodelist *bqlist;
11353 smallint quotef;
11354 smallint dblquote;
11355 smallint oldstyle;
11356 smallint prevsyntax; /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011357#if ENABLE_ASH_EXPAND_PRMT
11358 smallint pssyntax; /* we are expanding a prompt string */
11359#endif
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011360 int varnest; /* levels of variables expansion */
11361 int arinest; /* levels of arithmetic expansion */
11362 int parenlevel; /* levels of parens in arithmetic */
11363 int dqvarnest; /* levels of variables expansion within double quotes */
11364
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011365 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011366
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011367 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011368 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011369 quotef = 0;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011370 prevsyntax = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000011371#if ENABLE_ASH_EXPAND_PRMT
11372 pssyntax = (syntax == PSSYNTAX);
11373 if (pssyntax)
11374 syntax = DQSYNTAX;
11375#endif
11376 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011377 varnest = 0;
11378 arinest = 0;
11379 parenlevel = 0;
11380 dqvarnest = 0;
11381
11382 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011383 loop:
11384 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011385 CHECKEND(); /* set c to PEOF if at end of here document */
11386 for (;;) { /* until end of line or end of word */
11387 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11388 switch (SIT(c, syntax)) {
11389 case CNL: /* '\n' */
11390 if (syntax == BASESYNTAX)
11391 goto endword; /* exit outer loop */
11392 USTPUTC(c, out);
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011393 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011394 c = pgetc();
11395 goto loop; /* continue outer loop */
11396 case CWORD:
11397 USTPUTC(c, out);
11398 break;
11399 case CCTL:
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011400#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011401 if (c == '\\' && bash_dollar_squote) {
11402 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020011403 if (c == '\0') {
11404 /* skip $'\000', $'\x00' (like bash) */
11405 break;
11406 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011407 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020011408 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011409 c = (unsigned char)c;
Denys Vlasenko13f20912016-09-25 20:54:25 +020011410 if (eofmark == NULL || dblquote)
11411 USTPUTC(CTLESC, out);
11412 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011413 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011414 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011415#endif
Denys Vlasenko13f20912016-09-25 20:54:25 +020011416 if (eofmark == NULL || dblquote)
11417 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011418 USTPUTC(c, out);
11419 break;
11420 case CBACK: /* backslash */
11421 c = pgetc_without_PEOA();
11422 if (c == PEOF) {
11423 USTPUTC(CTLESC, out);
11424 USTPUTC('\\', out);
11425 pungetc();
11426 } else if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011427 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011428 } else {
11429#if ENABLE_ASH_EXPAND_PRMT
11430 if (c == '$' && pssyntax) {
Eric Andersenc470f442003-07-28 09:56:35 +000011431 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011432 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011433 }
Denis Vlasenko46a53062007-09-24 18:30:02 +000011434#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011435 /* Backslash is retained if we are in "str" and next char isn't special */
11436 if (dblquote
11437 && c != '\\'
11438 && c != '`'
11439 && c != '$'
11440 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011441 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011442 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011443 }
Ron Yorston549deab2015-05-18 09:57:51 +020011444 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011445 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011446 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011447 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011448 break;
11449 case CSQUOTE:
11450 syntax = SQSYNTAX;
11451 quotemark:
11452 if (eofmark == NULL) {
11453 USTPUTC(CTLQUOTEMARK, out);
11454 }
11455 break;
11456 case CDQUOTE:
11457 syntax = DQSYNTAX;
11458 dblquote = 1;
11459 goto quotemark;
11460 case CENDQUOTE:
11461 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020011462 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011463 USTPUTC(c, out);
11464 } else {
11465 if (dqvarnest == 0) {
11466 syntax = BASESYNTAX;
11467 dblquote = 0;
11468 }
11469 quotef = 1;
11470 goto quotemark;
11471 }
11472 break;
11473 case CVAR: /* '$' */
11474 PARSESUB(); /* parse substitution */
11475 break;
11476 case CENDVAR: /* '}' */
11477 if (varnest > 0) {
11478 varnest--;
11479 if (dqvarnest > 0) {
11480 dqvarnest--;
11481 }
11482 c = CTLENDVAR;
11483 }
11484 USTPUTC(c, out);
11485 break;
11486#if ENABLE_SH_MATH_SUPPORT
11487 case CLP: /* '(' in arithmetic */
11488 parenlevel++;
11489 USTPUTC(c, out);
11490 break;
11491 case CRP: /* ')' in arithmetic */
11492 if (parenlevel > 0) {
11493 parenlevel--;
11494 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011495 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020011496 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011497 if (--arinest == 0) {
11498 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011499 }
11500 } else {
11501 /*
11502 * unbalanced parens
11503 * (don't 2nd guess - no error)
11504 */
11505 pungetc();
11506 }
11507 }
11508 USTPUTC(c, out);
11509 break;
11510#endif
11511 case CBQUOTE: /* '`' */
11512 PARSEBACKQOLD();
11513 break;
11514 case CENDFILE:
11515 goto endword; /* exit outer loop */
11516 case CIGN:
11517 break;
11518 default:
11519 if (varnest == 0) {
11520#if ENABLE_ASH_BASH_COMPAT
11521 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011522//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020011523 if (pgetc() == '>')
11524 c = 0x100 + '>'; /* flag &> */
11525 pungetc();
11526 }
11527#endif
11528 goto endword; /* exit outer loop */
11529 }
11530 IF_ASH_ALIAS(if (c != PEOA))
11531 USTPUTC(c, out);
11532 }
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020011533 c = pgetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011534 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011535 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011536
Mike Frysinger98c52642009-04-02 10:02:37 +000011537#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011538 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011539 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011540#endif
Ron Yorston0e056f72015-07-01 16:45:40 +010011541 if (syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011542 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011543 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011544 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011545 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011546 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011547 }
11548 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011549 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011550 out = stackblock();
11551 if (eofmark == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011552 if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011553 && quotef == 0
11554 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011555 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011556 PARSEREDIR(); /* passed as params: out, c */
11557 lasttoken = TREDIR;
11558 return lasttoken;
11559 }
11560 /* else: non-number X seen, interpret it
11561 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011562 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011563 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011564 }
11565 quoteflag = quotef;
11566 backquotelist = bqlist;
11567 grabstackblock(len);
11568 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011569 lasttoken = TWORD;
11570 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011571/* end of readtoken routine */
11572
Eric Andersencb57d552001-06-28 07:25:16 +000011573/*
11574 * Check to see whether we are at the end of the here document. When this
11575 * is called, c is set to the first character of the next input line. If
11576 * we are at the end of the here document, this routine sets the c to PEOF.
11577 */
Eric Andersenc470f442003-07-28 09:56:35 +000011578checkend: {
11579 if (eofmark) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000011580#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011581 if (c == PEOA)
11582 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011583#endif
11584 if (striptabs) {
11585 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011586 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011587 }
Eric Andersenc470f442003-07-28 09:56:35 +000011588 }
11589 if (c == *eofmark) {
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011590 if (pfgets(line, sizeof(line)) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000011591 char *p, *q;
Denys Vlasenko350e6862016-10-26 16:26:45 +020011592 int cc;
Eric Andersencb57d552001-06-28 07:25:16 +000011593
Eric Andersenc470f442003-07-28 09:56:35 +000011594 p = line;
Denys Vlasenko350e6862016-10-26 16:26:45 +020011595 for (q = eofmark + 1;; p++, q++) {
11596 cc = *p;
11597 if (cc == '\n')
11598 cc = 0;
11599 if (!*q || cc != *q)
11600 break;
11601 }
11602 if (cc == *q) {
Eric Andersenc470f442003-07-28 09:56:35 +000011603 c = PEOF;
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011604 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011605 } else {
11606 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011607 }
11608 }
11609 }
11610 }
Eric Andersenc470f442003-07-28 09:56:35 +000011611 goto checkend_return;
11612}
Eric Andersencb57d552001-06-28 07:25:16 +000011613
Eric Andersencb57d552001-06-28 07:25:16 +000011614/*
11615 * Parse a redirection operator. The variable "out" points to a string
11616 * specifying the fd to be redirected. The variable "c" contains the
11617 * first character of the redirection operator.
11618 */
Eric Andersenc470f442003-07-28 09:56:35 +000011619parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011620 /* out is already checked to be a valid number or "" */
11621 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000011622 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000011623
Denis Vlasenko597906c2008-02-20 16:38:54 +000011624 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000011625 if (c == '>') {
11626 np->nfile.fd = 1;
11627 c = pgetc();
11628 if (c == '>')
11629 np->type = NAPPEND;
11630 else if (c == '|')
11631 np->type = NCLOBBER;
11632 else if (c == '&')
11633 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011634 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000011635 else {
11636 np->type = NTO;
11637 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011638 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000011639 }
11640#if ENABLE_ASH_BASH_COMPAT
11641 else if (c == 0x100 + '>') { /* this flags &> redirection */
11642 np->nfile.fd = 1;
11643 pgetc(); /* this is '>', no need to check */
11644 np->type = NTO2;
11645 }
11646#endif
11647 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000011648 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011649 c = pgetc();
11650 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000011651 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011652 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011653 np = stzalloc(sizeof(struct nhere));
11654 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011655 }
11656 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011657 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000011658 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011659 c = pgetc();
11660 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000011661 heredoc->striptabs = 1;
11662 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011663 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011664 pungetc();
11665 }
11666 break;
11667
11668 case '&':
11669 np->type = NFROMFD;
11670 break;
11671
11672 case '>':
11673 np->type = NFROMTO;
11674 break;
11675
11676 default:
11677 np->type = NFROM;
11678 pungetc();
11679 break;
11680 }
Eric Andersencb57d552001-06-28 07:25:16 +000011681 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011682 if (fd >= 0)
11683 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011684 redirnode = np;
11685 goto parseredir_return;
11686}
Eric Andersencb57d552001-06-28 07:25:16 +000011687
Eric Andersencb57d552001-06-28 07:25:16 +000011688/*
11689 * Parse a substitution. At this point, we have read the dollar sign
11690 * and nothing else.
11691 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000011692
11693/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11694 * (assuming ascii char codes, as the original implementation did) */
11695#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011696 (((unsigned)(c) - 33 < 32) \
11697 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000011698parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010011699 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011700 int typeloc;
Eric Andersencb57d552001-06-28 07:25:16 +000011701
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011702 c = pgetc_eatbnl();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011703 if (c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011704 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000011705 ) {
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011706#if ENABLE_ASH_BASH_COMPAT
Ron Yorston84ba50c2016-04-03 22:43:14 +010011707 if (syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011708 bash_dollar_squote = 1;
11709 else
11710#endif
11711 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011712 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011713 } else if (c == '(') {
11714 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011715 if (pgetc_eatbnl() == '(') {
Mike Frysinger98c52642009-04-02 10:02:37 +000011716#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000011717 PARSEARITH();
11718#else
Mike Frysinger98a6f562008-06-09 09:38:45 +000011719 raise_error_syntax("you disabled math support for $((arith)) syntax");
Eric Andersenc470f442003-07-28 09:56:35 +000011720#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011721 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011722 pungetc();
11723 PARSEBACKQNEW();
11724 }
11725 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011726 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000011727 USTPUTC(CTLVAR, out);
11728 typeloc = out - (char *)stackblock();
Denys Vlasenko3df14102016-10-26 16:41:13 +020011729 STADJUST(1, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011730 subtype = VSNORMAL;
11731 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011732 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011733 subtype = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011734 }
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011735 varname:
Denys Vlasenko3df14102016-10-26 16:41:13 +020011736 if (is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011737 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011738 do {
11739 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011740 c = pgetc_eatbnl();
Denys Vlasenko3df14102016-10-26 16:41:13 +020011741 } while (is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011742 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011743 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011744 do {
11745 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011746 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011747 } while (isdigit(c));
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011748 } else if (is_special(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011749 /* $[{[#]]<specialchar>[}] */
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011750 int cc = c;
11751
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011752 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011753 if (!subtype && cc == '#') {
11754 subtype = VSLENGTH;
11755 if (c == '_' || isalnum(c))
11756 goto varname;
11757 cc = c;
11758 c = pgetc_eatbnl();
11759 if (cc == '}' || c != '}') {
11760 pungetc();
11761 subtype = 0;
11762 c = cc;
11763 cc = '#';
11764 }
11765 }
11766 USTPUTC(cc, out);
Denis Vlasenko559691a2008-10-05 18:39:31 +000011767 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020011768 goto badsub;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011769 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011770 if (c != '}' && subtype == VSLENGTH) {
11771 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020011772 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011773 }
Eric Andersencb57d552001-06-28 07:25:16 +000011774
Eric Andersenc470f442003-07-28 09:56:35 +000011775 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011776 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011777 /* ${VAR...} but not $VAR or ${#VAR} */
11778 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000011779 switch (c) {
11780 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011781 c = pgetc_eatbnl();
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011782#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011783 /* This check is only needed to not misinterpret
11784 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
11785 * constructs.
11786 */
11787 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011788 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011789 pungetc();
Denys Vlasenko88e15702016-10-26 01:55:56 +020011790 break; /* "goto badsub" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011791 }
11792#endif
Denys Vlasenko3df14102016-10-26 16:41:13 +020011793 subtype = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000011794 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011795 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011796 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000011797 if (p == NULL)
Denys Vlasenko88e15702016-10-26 01:55:56 +020011798 break;
Denys Vlasenko3df14102016-10-26 16:41:13 +020011799 subtype |= p - types + VSNORMAL;
Eric Andersenc470f442003-07-28 09:56:35 +000011800 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011801 }
Eric Andersenc470f442003-07-28 09:56:35 +000011802 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011803 case '#': {
11804 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011805 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011806 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011807 if (c != cc)
Denys Vlasenko88e15702016-10-26 01:55:56 +020011808 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011809 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011810 break;
11811 }
11812#if ENABLE_ASH_BASH_COMPAT
11813 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011814 /* ${v/[/]pattern/repl} */
11815//TODO: encode pattern and repl separately.
11816// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011817 subtype = VSREPLACE;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011818 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011819 if (c != '/')
Denys Vlasenko88e15702016-10-26 01:55:56 +020011820 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011821 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011822 break;
11823#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011824 }
Eric Andersenc470f442003-07-28 09:56:35 +000011825 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020011826 badsub:
Eric Andersenc470f442003-07-28 09:56:35 +000011827 pungetc();
11828 }
Denys Vlasenko3df14102016-10-26 16:41:13 +020011829 ((unsigned char *)stackblock())[typeloc] = subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011830 if (subtype != VSNORMAL) {
11831 varnest++;
Denys Vlasenko3df14102016-10-26 16:41:13 +020011832 if (dblquote)
Eric Andersenc470f442003-07-28 09:56:35 +000011833 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000011834 }
Denys Vlasenko88e15702016-10-26 01:55:56 +020011835 STPUTC('=', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011836 }
Eric Andersenc470f442003-07-28 09:56:35 +000011837 goto parsesub_return;
11838}
Eric Andersencb57d552001-06-28 07:25:16 +000011839
Eric Andersencb57d552001-06-28 07:25:16 +000011840/*
11841 * Called to parse command substitutions. Newstyle is set if the command
11842 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11843 * list of commands (passed by reference), and savelen is the number of
11844 * characters on the top of the stack which must be preserved.
11845 */
Eric Andersenc470f442003-07-28 09:56:35 +000011846parsebackq: {
11847 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011848 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010011849 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000011850 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011851 smallint saveprompt = 0;
11852
Eric Andersenc470f442003-07-28 09:56:35 +000011853 str = NULL;
11854 savelen = out - (char *)stackblock();
11855 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011856 /*
11857 * FIXME: this can allocate very large block on stack and SEGV.
11858 * Example:
11859 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020011860 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011861 * a hundred command substitutions stack overflows.
11862 * With larger prepended string, SEGV happens sooner.
11863 */
Ron Yorston072fc602015-07-01 16:46:18 +010011864 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000011865 memcpy(str, stackblock(), savelen);
11866 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011867
Eric Andersenc470f442003-07-28 09:56:35 +000011868 if (oldstyle) {
11869 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010011870 * treatment to some slashes, and then push the string and
11871 * reread it as input, interpreting it normally.
11872 */
Eric Andersenc470f442003-07-28 09:56:35 +000011873 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000011874 size_t psavelen;
11875 char *pstr;
11876
Eric Andersenc470f442003-07-28 09:56:35 +000011877 STARTSTACKSTR(pout);
11878 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011879 int pc;
11880
11881 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011882 pc = pgetc();
11883 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000011884 case '`':
11885 goto done;
11886
11887 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011888 pc = pgetc();
11889 if (pc == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011890 nlprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011891 /*
11892 * If eating a newline, avoid putting
11893 * the newline into the new character
11894 * stream (via the STPUTC after the
11895 * switch).
11896 */
11897 continue;
11898 }
11899 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011900 && (!dblquote || pc != '"')
11901 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000011902 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011903 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011904 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000011905 break;
11906 }
11907 /* fall through */
11908
11909 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011910 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011911 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011912 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000011913
11914 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011915 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011916 break;
11917
11918 default:
11919 break;
11920 }
11921 STPUTC(pc, pout);
11922 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011923 done:
Eric Andersenc470f442003-07-28 09:56:35 +000011924 STPUTC('\0', pout);
11925 psavelen = pout - (char *)stackblock();
11926 if (psavelen > 0) {
11927 pstr = grabstackstr(pout);
11928 setinputstring(pstr);
11929 }
11930 }
11931 nlpp = &bqlist;
11932 while (*nlpp)
11933 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011934 *nlpp = stzalloc(sizeof(**nlpp));
11935 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011936
11937 if (oldstyle) {
11938 saveprompt = doprompt;
11939 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011940 }
11941
Eric Andersenc470f442003-07-28 09:56:35 +000011942 n = list(2);
11943
11944 if (oldstyle)
11945 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011946 else if (readtoken() != TRP)
11947 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011948
11949 (*nlpp)->n = n;
11950 if (oldstyle) {
11951 /*
11952 * Start reading from old file again, ignoring any pushed back
11953 * tokens left from the backquote parsing
11954 */
11955 popfile();
11956 tokpushback = 0;
11957 }
11958 while (stackblocksize() <= savelen)
11959 growstackblock();
11960 STARTSTACKSTR(out);
11961 if (str) {
11962 memcpy(out, str, savelen);
11963 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011964 }
Ron Yorston549deab2015-05-18 09:57:51 +020011965 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011966 if (oldstyle)
11967 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011968 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000011969}
11970
Mike Frysinger98c52642009-04-02 10:02:37 +000011971#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011972/*
11973 * Parse an arithmetic expansion (indicate start of one and set state)
11974 */
Eric Andersenc470f442003-07-28 09:56:35 +000011975parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000011976 if (++arinest == 1) {
11977 prevsyntax = syntax;
11978 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000011979 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020011980 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011981 goto parsearith_return;
11982}
11983#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011984} /* end of readtoken */
11985
Eric Andersencb57d552001-06-28 07:25:16 +000011986/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011987 * Read the next input token.
11988 * If the token is a word, we set backquotelist to the list of cmds in
11989 * backquotes. We set quoteflag to true if any part of the word was
11990 * quoted.
11991 * If the token is TREDIR, then we set redirnode to a structure containing
11992 * the redirection.
11993 * In all cases, the variable startlinno is set to the number of the line
11994 * on which the token starts.
11995 *
11996 * [Change comment: here documents and internal procedures]
11997 * [Readtoken shouldn't have any arguments. Perhaps we should make the
11998 * word parsing code into a separate routine. In this case, readtoken
11999 * doesn't need to have any internal procedures, but parseword does.
12000 * We could also make parseoperator in essence the main routine, and
12001 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000012002 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012003#define NEW_xxreadtoken
12004#ifdef NEW_xxreadtoken
12005/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012006static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000012007 '\n', '(', ')', /* singles */
12008 '&', '|', ';', /* doubles */
12009 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012010};
Eric Andersencb57d552001-06-28 07:25:16 +000012011
Denis Vlasenko834dee72008-10-07 09:18:30 +000012012#define xxreadtoken_singles 3
12013#define xxreadtoken_doubles 3
12014
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012015static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012016 TNL, TLP, TRP, /* only single occurrence allowed */
12017 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12018 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012019 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012020};
12021
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012022static int
12023xxreadtoken(void)
12024{
12025 int c;
12026
12027 if (tokpushback) {
12028 tokpushback = 0;
12029 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012030 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012031 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012032 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012033 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012034 c = pgetc();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000012035 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012036 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012037
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012038 if (c == '#') {
12039 while ((c = pgetc()) != '\n' && c != PEOF)
12040 continue;
12041 pungetc();
12042 } else if (c == '\\') {
12043 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012044 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012045 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012046 }
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012047 nlprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012048 } else {
12049 const char *p;
12050
12051 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12052 if (c != PEOF) {
12053 if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012054 nlnoprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012055 }
12056
12057 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000012058 if (p == NULL)
12059 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012060
Denis Vlasenko834dee72008-10-07 09:18:30 +000012061 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12062 int cc = pgetc();
12063 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012064 p += xxreadtoken_doubles + 1;
12065 } else {
12066 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012067#if ENABLE_ASH_BASH_COMPAT
12068 if (c == '&' && cc == '>') /* &> */
12069 break; /* return readtoken1(...) */
12070#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012071 }
12072 }
12073 }
12074 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12075 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012076 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012077 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012078
12079 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012080}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012081#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012082#define RETURN(token) return lasttoken = token
12083static int
12084xxreadtoken(void)
12085{
12086 int c;
12087
12088 if (tokpushback) {
12089 tokpushback = 0;
12090 return lasttoken;
12091 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012092 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012093 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012094 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012095 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012096 switch (c) {
12097 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012098 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012099 continue;
12100 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012101 while ((c = pgetc()) != '\n' && c != PEOF)
12102 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012103 pungetc();
12104 continue;
12105 case '\\':
12106 if (pgetc() == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012107 nlprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012108 continue;
12109 }
12110 pungetc();
12111 goto breakloop;
12112 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012113 nlnoprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012114 RETURN(TNL);
12115 case PEOF:
12116 RETURN(TEOF);
12117 case '&':
12118 if (pgetc() == '&')
12119 RETURN(TAND);
12120 pungetc();
12121 RETURN(TBACKGND);
12122 case '|':
12123 if (pgetc() == '|')
12124 RETURN(TOR);
12125 pungetc();
12126 RETURN(TPIPE);
12127 case ';':
12128 if (pgetc() == ';')
12129 RETURN(TENDCASE);
12130 pungetc();
12131 RETURN(TSEMI);
12132 case '(':
12133 RETURN(TLP);
12134 case ')':
12135 RETURN(TRP);
12136 default:
12137 goto breakloop;
12138 }
12139 }
12140 breakloop:
12141 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12142#undef RETURN
12143}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012144#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012145
12146static int
12147readtoken(void)
12148{
12149 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012150 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012151#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012152 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012153#endif
12154
12155#if ENABLE_ASH_ALIAS
12156 top:
12157#endif
12158
12159 t = xxreadtoken();
12160
12161 /*
12162 * eat newlines
12163 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012164 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012165 while (t == TNL) {
12166 parseheredoc();
12167 t = xxreadtoken();
12168 }
12169 }
12170
12171 if (t != TWORD || quoteflag) {
12172 goto out;
12173 }
12174
12175 /*
12176 * check for keywords
12177 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012178 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012179 const char *const *pp;
12180
12181 pp = findkwd(wordtext);
12182 if (pp) {
12183 lasttoken = t = pp - tokname_array;
Denys Vlasenko888527c2016-10-02 16:54:17 +020012184 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012185 goto out;
12186 }
12187 }
12188
12189 if (checkkwd & CHKALIAS) {
12190#if ENABLE_ASH_ALIAS
12191 struct alias *ap;
12192 ap = lookupalias(wordtext, 1);
12193 if (ap != NULL) {
12194 if (*ap->val) {
12195 pushstring(ap->val, ap);
12196 }
12197 goto top;
12198 }
12199#endif
12200 }
12201 out:
12202 checkkwd = 0;
12203#if DEBUG
12204 if (!alreadyseen)
Denys Vlasenko888527c2016-10-02 16:54:17 +020012205 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012206 else
Denys Vlasenko888527c2016-10-02 16:54:17 +020012207 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012208#endif
12209 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012210}
12211
Ron Yorstonc0e00762015-10-29 11:30:55 +000012212static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012213peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012214{
12215 int t;
12216
12217 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012218 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012219 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012220}
Eric Andersencb57d552001-06-28 07:25:16 +000012221
12222/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012223 * Read and parse a command. Returns NODE_EOF on end of file.
12224 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012225 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012226static union node *
12227parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012228{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012229 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012230 checkkwd = 0;
12231 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012232 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012233 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012234 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012235 return list(1);
12236}
12237
12238/*
12239 * Input any here documents.
12240 */
12241static void
12242parseheredoc(void)
12243{
12244 struct heredoc *here;
12245 union node *n;
12246
12247 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012248 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012249
12250 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012251 setprompt_if(needprompt, 2);
12252 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012253 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012254 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012255 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012256 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012257 n->narg.text = wordtext;
12258 n->narg.backquote = backquotelist;
12259 here->here->nhere.doc = n;
12260 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012261 }
Eric Andersencb57d552001-06-28 07:25:16 +000012262}
12263
12264
12265/*
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012266 * called by editline -- any expansions to the prompt should be added here.
Eric Andersencb57d552001-06-28 07:25:16 +000012267 */
Denis Vlasenko131ae172007-02-18 13:00:19 +000012268#if ENABLE_ASH_EXPAND_PRMT
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012269static const char *
12270expandstr(const char *ps)
12271{
12272 union node n;
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012273 int saveprompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012274
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000012275 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12276 * and token processing _can_ alter it (delete NULs etc). */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012277 setinputstring((char *)ps);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012278
12279 saveprompt = doprompt;
12280 doprompt = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000012281 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012282 doprompt = saveprompt;
12283
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012284 popfile();
12285
12286 n.narg.type = NARG;
12287 n.narg.next = NULL;
12288 n.narg.text = wordtext;
12289 n.narg.backquote = backquotelist;
12290
Ron Yorston549deab2015-05-18 09:57:51 +020012291 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012292 return stackblock();
12293}
12294#endif
12295
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012296/*
12297 * Execute a command or commands contained in a string.
12298 */
12299static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012300evalstring(char *s, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000012301{
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012302 struct jmploc *volatile savehandler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012303 struct jmploc jmploc;
12304 int ex;
12305
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012306 union node *n;
12307 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012308 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012309
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012310 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012311 setinputstring(s);
12312 setstackmark(&smark);
12313
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012314 status = 0;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012315 /* On exception inside execution loop, we must popfile().
12316 * Try interactively:
12317 * readonly a=a
12318 * command eval "a=b" # throws "is read only" error
12319 * "command BLTIN" is not supposed to abort (even in non-interactive use).
12320 * But if we skip popfile(), we hit EOF in eval's string, and exit.
12321 */
12322 savehandler = exception_handler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012323 ex = setjmp(jmploc.loc);
12324 if (ex)
12325 goto out;
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012326 exception_handler = &jmploc;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012327
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012328 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012329 int i;
12330
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012331 i = evaltree(n, flags);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012332 if (n)
12333 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012334 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012335 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012336 break;
12337 }
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012338 out:
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012339 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012340 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012341 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012342
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012343 exception_handler = savehandler;
12344 if (ex)
12345 longjmp(exception_handler->loc, ex);
12346
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012347 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000012348}
12349
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012350/*
12351 * The eval command.
12352 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012353static int FAST_FUNC
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012354evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012355{
12356 char *p;
12357 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012358
Denis Vlasenko68404f12008-03-17 09:00:54 +000012359 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012360 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012361 argv += 2;
12362 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012363 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012364 for (;;) {
12365 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012366 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012367 if (p == NULL)
12368 break;
12369 STPUTC(' ', concat);
12370 }
12371 STPUTC('\0', concat);
12372 p = grabstackstr(concat);
12373 }
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012374 return evalstring(p, flags & EV_TESTED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012375 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012376 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012377}
12378
12379/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012380 * Read and execute commands.
12381 * "Top" is nonzero for the top level command loop;
12382 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012383 */
12384static int
12385cmdloop(int top)
12386{
12387 union node *n;
12388 struct stackmark smark;
12389 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012390 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012391 int numeof = 0;
12392
12393 TRACE(("cmdloop(%d) called\n", top));
12394 for (;;) {
12395 int skip;
12396
12397 setstackmark(&smark);
12398#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012399 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020012400 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012401#endif
12402 inter = 0;
12403 if (iflag && top) {
12404 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012405 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012406 }
12407 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012408#if DEBUG
12409 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012410 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012411#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012412 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012413 if (!top || numeof >= 50)
12414 break;
12415 if (!stoppedjobs()) {
12416 if (!Iflag)
12417 break;
12418 out2str("\nUse \"exit\" to leave shell.\n");
12419 }
12420 numeof++;
12421 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012422 int i;
12423
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012424 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12425 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012426 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012427 i = evaltree(n, 0);
12428 if (n)
12429 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012430 }
12431 popstackmark(&smark);
12432 skip = evalskip;
12433
12434 if (skip) {
Denys Vlasenko6a0710e2016-09-30 14:18:34 +020012435 evalskip &= ~SKIPFUNC;
Denys Vlasenko0840c912016-10-01 15:27:44 +020012436 break;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012437 }
12438 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012439 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012440}
12441
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012442/*
12443 * Take commands from a file. To be compatible we should do a path
12444 * search for the file, which is necessary to find sub-commands.
12445 */
12446static char *
12447find_dot_file(char *name)
12448{
12449 char *fullname;
12450 const char *path = pathval();
12451 struct stat statb;
12452
12453 /* don't try this for absolute or relative paths */
12454 if (strchr(name, '/'))
12455 return name;
12456
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012457 /* IIRC standards do not say whether . is to be searched.
12458 * And it is even smaller this way, making it unconditional for now:
12459 */
12460 if (1) { /* ENABLE_ASH_BASH_COMPAT */
12461 fullname = name;
12462 goto try_cur_dir;
12463 }
12464
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012465 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012466 try_cur_dir:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012467 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12468 /*
12469 * Don't bother freeing here, since it will
12470 * be freed by the caller.
12471 */
12472 return fullname;
12473 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012474 if (fullname != name)
12475 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012476 }
12477
12478 /* not found in the PATH */
12479 ash_msg_and_raise_error("%s: not found", name);
12480 /* NOTREACHED */
12481}
12482
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012483static int FAST_FUNC
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012484dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012485{
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012486 /* "false; . empty_file; echo $?" should print 0, not 1: */
12487 int status = 0;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012488 char *fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012489 char **argv;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012490 struct strlist *sp;
12491 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012492
12493 for (sp = cmdenviron; sp; sp = sp->next)
Denis Vlasenko4222ae42007-02-25 02:37:49 +000012494 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012495
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012496 nextopt(nullstr); /* handle possible "--" */
12497 argv = argptr;
12498
12499 if (!argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012500 /* bash says: "bash: .: filename argument required" */
12501 return 2; /* bash compat */
12502 }
12503
Denys Vlasenko091f8312013-03-17 14:25:22 +010012504 /* This aborts if file isn't found, which is POSIXly correct.
12505 * bash returns exitcode 1 instead.
12506 */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012507 fullname = find_dot_file(argv[0]);
12508 argv++;
12509 if (argv[0]) { /* . FILE ARGS, ARGS exist */
12510 int argc;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012511 saveparam = shellparam;
12512 shellparam.malloced = 0;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012513 argc = 1;
12514 while (argv[argc])
12515 argc++;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012516 shellparam.nparam = argc;
12517 shellparam.p = argv;
12518 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012519
Denys Vlasenko091f8312013-03-17 14:25:22 +010012520 /* This aborts if file can't be opened, which is POSIXly correct.
12521 * bash returns exitcode 1 instead.
12522 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012523 setinputfile(fullname, INPUT_PUSH_FILE);
12524 commandname = fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012525 status = cmdloop(0);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012526 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012527
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012528 if (argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012529 freeparam(&shellparam);
12530 shellparam = saveparam;
12531 };
12532
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012533 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012534}
12535
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012536static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012537exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012538{
12539 if (stoppedjobs())
12540 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012541 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012542 exitstatus = number(argv[1]);
12543 raise_exception(EXEXIT);
12544 /* NOTREACHED */
12545}
12546
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012547/*
12548 * Read a file containing shell functions.
12549 */
12550static void
12551readcmdfile(char *name)
12552{
12553 setinputfile(name, INPUT_PUSH_FILE);
12554 cmdloop(0);
12555 popfile();
12556}
12557
12558
Denis Vlasenkocc571512007-02-23 21:10:35 +000012559/* ============ find_command inplementation */
12560
12561/*
12562 * Resolve a command name. If you change this routine, you may have to
12563 * change the shellexec routine as well.
12564 */
12565static void
12566find_command(char *name, struct cmdentry *entry, int act, const char *path)
12567{
12568 struct tblentry *cmdp;
12569 int idx;
12570 int prev;
12571 char *fullname;
12572 struct stat statb;
12573 int e;
12574 int updatetbl;
12575 struct builtincmd *bcmd;
12576
12577 /* If name contains a slash, don't use PATH or hash table */
12578 if (strchr(name, '/') != NULL) {
12579 entry->u.index = -1;
12580 if (act & DO_ABS) {
12581 while (stat(name, &statb) < 0) {
12582#ifdef SYSV
12583 if (errno == EINTR)
12584 continue;
12585#endif
12586 entry->cmdtype = CMDUNKNOWN;
12587 return;
12588 }
12589 }
12590 entry->cmdtype = CMDNORMAL;
12591 return;
12592 }
12593
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012594/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012595
12596 updatetbl = (path == pathval());
12597 if (!updatetbl) {
12598 act |= DO_ALTPATH;
12599 if (strstr(path, "%builtin") != NULL)
12600 act |= DO_ALTBLTIN;
12601 }
12602
12603 /* If name is in the table, check answer will be ok */
12604 cmdp = cmdlookup(name, 0);
12605 if (cmdp != NULL) {
12606 int bit;
12607
12608 switch (cmdp->cmdtype) {
12609 default:
12610#if DEBUG
12611 abort();
12612#endif
12613 case CMDNORMAL:
12614 bit = DO_ALTPATH;
12615 break;
12616 case CMDFUNCTION:
12617 bit = DO_NOFUNC;
12618 break;
12619 case CMDBUILTIN:
12620 bit = DO_ALTBLTIN;
12621 break;
12622 }
12623 if (act & bit) {
12624 updatetbl = 0;
12625 cmdp = NULL;
12626 } else if (cmdp->rehash == 0)
12627 /* if not invalidated by cd, we're done */
12628 goto success;
12629 }
12630
12631 /* If %builtin not in path, check for builtin next */
12632 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012633 if (bcmd) {
12634 if (IS_BUILTIN_REGULAR(bcmd))
12635 goto builtin_success;
12636 if (act & DO_ALTPATH) {
12637 if (!(act & DO_ALTBLTIN))
12638 goto builtin_success;
12639 } else if (builtinloc <= 0) {
12640 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000012641 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012642 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000012643
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012644#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000012645 {
12646 int applet_no = find_applet_by_name(name);
12647 if (applet_no >= 0) {
12648 entry->cmdtype = CMDNORMAL;
12649 entry->u.index = -2 - applet_no;
12650 return;
12651 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012652 }
12653#endif
12654
Denis Vlasenkocc571512007-02-23 21:10:35 +000012655 /* We have to search path. */
12656 prev = -1; /* where to start */
12657 if (cmdp && cmdp->rehash) { /* doing a rehash */
12658 if (cmdp->cmdtype == CMDBUILTIN)
12659 prev = builtinloc;
12660 else
12661 prev = cmdp->param.index;
12662 }
12663
12664 e = ENOENT;
12665 idx = -1;
12666 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012667 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000012668 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012669 /* NB: code below will still use fullname
12670 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012671 idx++;
12672 if (pathopt) {
12673 if (prefix(pathopt, "builtin")) {
12674 if (bcmd)
12675 goto builtin_success;
12676 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000012677 }
12678 if ((act & DO_NOFUNC)
12679 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020012680 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012681 continue;
12682 }
12683 }
12684 /* if rehash, don't redo absolute path names */
12685 if (fullname[0] == '/' && idx <= prev) {
12686 if (idx < prev)
12687 continue;
12688 TRACE(("searchexec \"%s\": no change\n", name));
12689 goto success;
12690 }
12691 while (stat(fullname, &statb) < 0) {
12692#ifdef SYSV
12693 if (errno == EINTR)
12694 continue;
12695#endif
12696 if (errno != ENOENT && errno != ENOTDIR)
12697 e = errno;
12698 goto loop;
12699 }
12700 e = EACCES; /* if we fail, this will be the error */
12701 if (!S_ISREG(statb.st_mode))
12702 continue;
12703 if (pathopt) { /* this is a %func directory */
12704 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012705 /* NB: stalloc will return space pointed by fullname
12706 * (because we don't have any intervening allocations
12707 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012708 readcmdfile(fullname);
12709 cmdp = cmdlookup(name, 0);
12710 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12711 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12712 stunalloc(fullname);
12713 goto success;
12714 }
12715 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12716 if (!updatetbl) {
12717 entry->cmdtype = CMDNORMAL;
12718 entry->u.index = idx;
12719 return;
12720 }
12721 INT_OFF;
12722 cmdp = cmdlookup(name, 1);
12723 cmdp->cmdtype = CMDNORMAL;
12724 cmdp->param.index = idx;
12725 INT_ON;
12726 goto success;
12727 }
12728
12729 /* We failed. If there was an entry for this command, delete it */
12730 if (cmdp && updatetbl)
12731 delete_cmd_entry();
12732 if (act & DO_ERR)
12733 ash_msg("%s: %s", name, errmsg(e, "not found"));
12734 entry->cmdtype = CMDUNKNOWN;
12735 return;
12736
12737 builtin_success:
12738 if (!updatetbl) {
12739 entry->cmdtype = CMDBUILTIN;
12740 entry->u.cmd = bcmd;
12741 return;
12742 }
12743 INT_OFF;
12744 cmdp = cmdlookup(name, 1);
12745 cmdp->cmdtype = CMDBUILTIN;
12746 cmdp->param.cmd = bcmd;
12747 INT_ON;
12748 success:
12749 cmdp->rehash = 0;
12750 entry->cmdtype = cmdp->cmdtype;
12751 entry->u = cmdp->param;
12752}
12753
12754
Eric Andersencb57d552001-06-28 07:25:16 +000012755/*
Eric Andersencb57d552001-06-28 07:25:16 +000012756 * The trap builtin.
12757 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012758static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012759trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012760{
12761 char *action;
12762 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012763 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012764
Eric Andersenc470f442003-07-28 09:56:35 +000012765 nextopt(nullstr);
12766 ap = argptr;
12767 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012768 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012769 char *tr = trap_ptr[signo];
12770 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012771 /* note: bash adds "SIG", but only if invoked
12772 * as "bash". If called as "sh", or if set -o posix,
12773 * then it prints short signal names.
12774 * We are printing short names: */
12775 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012776 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012777 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012778 /* trap_ptr != trap only if we are in special-cased `trap` code.
12779 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012780 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012781 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000012782 }
12783 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012784 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012785 if (trap_ptr != trap) {
12786 free(trap_ptr);
12787 trap_ptr = trap;
12788 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012789 */
Eric Andersencb57d552001-06-28 07:25:16 +000012790 return 0;
12791 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012792
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012793 action = NULL;
12794 if (ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000012795 action = *ap++;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012796 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012797 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012798 signo = get_signum(*ap);
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012799 if (signo < 0) {
12800 /* Mimic bash message exactly */
12801 ash_msg("%s: invalid signal specification", *ap);
12802 exitcode = 1;
12803 goto next;
12804 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000012805 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000012806 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000012807 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000012808 action = NULL;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020012809 else {
12810 if (action[0]) /* not NULL and not "" and not "-" */
12811 may_have_traps = 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012812 action = ckstrdup(action);
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020012813 }
Eric Andersencb57d552001-06-28 07:25:16 +000012814 }
Denis Vlasenko60818682007-09-28 22:07:23 +000012815 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000012816 trap[signo] = action;
12817 if (signo != 0)
12818 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012819 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012820 next:
Eric Andersencb57d552001-06-28 07:25:16 +000012821 ap++;
12822 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012823 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012824}
12825
Eric Andersenc470f442003-07-28 09:56:35 +000012826
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012827/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000012828
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012829#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012830static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012831helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012832{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000012833 unsigned col;
12834 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000012835
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020012836 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000012837 "Built-in commands:\n"
12838 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000012839 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012840 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000012841 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000012842 if (col > 60) {
12843 out1fmt("\n");
12844 col = 0;
12845 }
12846 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012847# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000012848 {
12849 const char *a = applet_names;
12850 while (*a) {
12851 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12852 if (col > 60) {
12853 out1fmt("\n");
12854 col = 0;
12855 }
Ron Yorston2b919582016-04-08 11:57:20 +010012856 while (*a++ != '\0')
12857 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000012858 }
12859 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012860# endif
Denys Vlasenkoebedb942016-10-02 18:45:09 +020012861 newline_and_flush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000012862 return EXIT_SUCCESS;
12863}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012864#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012865
Flemming Madsend96ffda2013-04-07 18:47:24 +020012866#if MAX_HISTORY
12867static int FAST_FUNC
12868historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12869{
12870 show_history(line_input_state);
12871 return EXIT_SUCCESS;
12872}
12873#endif
12874
Eric Andersencb57d552001-06-28 07:25:16 +000012875/*
Eric Andersencb57d552001-06-28 07:25:16 +000012876 * The export and readonly commands.
12877 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012878static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012879exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012880{
12881 struct var *vp;
12882 char *name;
12883 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012884 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020012885 char opt;
12886 int flag;
12887 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000012888
Denys Vlasenkod5275882012-10-01 13:41:17 +020012889 /* "readonly" in bash accepts, but ignores -n.
12890 * We do the same: it saves a conditional in nextopt's param.
12891 */
12892 flag_off = 0;
12893 while ((opt = nextopt("np")) != '\0') {
12894 if (opt == 'n')
12895 flag_off = VEXPORT;
12896 }
12897 flag = VEXPORT;
12898 if (argv[0][0] == 'r') {
12899 flag = VREADONLY;
12900 flag_off = 0; /* readonly ignores -n */
12901 }
12902 flag_off = ~flag_off;
12903
12904 /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */
12905 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012906 aptr = argptr;
12907 name = *aptr;
12908 if (name) {
12909 do {
12910 p = strchr(name, '=');
12911 if (p != NULL) {
12912 p++;
12913 } else {
12914 vp = *findvar(hashvar(name), name);
12915 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020012916 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012917 continue;
12918 }
Eric Andersencb57d552001-06-28 07:25:16 +000012919 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012920 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012921 } while ((name = *++aptr) != NULL);
12922 return 0;
12923 }
Eric Andersencb57d552001-06-28 07:25:16 +000012924 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012925
12926 /* No arguments. Show the list of exported or readonly vars.
12927 * -n is ignored.
12928 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012929 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012930 return 0;
12931}
12932
Eric Andersencb57d552001-06-28 07:25:16 +000012933/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012934 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000012935 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000012936static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012937unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012938{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012939 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000012940
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012941 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012942 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012943 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000012944}
12945
Eric Andersencb57d552001-06-28 07:25:16 +000012946/*
Eric Andersencb57d552001-06-28 07:25:16 +000012947 * The unset builtin command. We unset the function before we unset the
12948 * variable to allow a function to be unset when there is a readonly variable
12949 * with the same name.
12950 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012951static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012952unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012953{
12954 char **ap;
12955 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012956 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012957 int ret = 0;
12958
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012959 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000012960 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012961 }
Eric Andersencb57d552001-06-28 07:25:16 +000012962
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012963 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012964 if (flag != 'f') {
12965 i = unsetvar(*ap);
12966 ret |= i;
12967 if (!(i & 2))
12968 continue;
12969 }
12970 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012971 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012972 }
Eric Andersenc470f442003-07-28 09:56:35 +000012973 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012974}
12975
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012976static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012977 ' ', offsetof(struct tms, tms_utime),
12978 '\n', offsetof(struct tms, tms_stime),
12979 ' ', offsetof(struct tms, tms_cutime),
12980 '\n', offsetof(struct tms, tms_cstime),
12981 0
12982};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012983static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012984timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012985{
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012986 unsigned long clk_tck, s, t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012987 const unsigned char *p;
12988 struct tms buf;
12989
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020012990 clk_tck = bb_clk_tck();
Eric Andersencb57d552001-06-28 07:25:16 +000012991 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012992
12993 p = timescmd_str;
12994 do {
12995 t = *(clock_t *)(((char *) &buf) + p[1]);
12996 s = t / clk_tck;
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012997 t = t % clk_tck;
12998 out1fmt("%lum%lu.%03lus%c",
12999 s / 60, s % 60,
13000 (t * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013001 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013002 p += 2;
13003 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013004
Eric Andersencb57d552001-06-28 07:25:16 +000013005 return 0;
13006}
13007
Mike Frysinger98c52642009-04-02 10:02:37 +000013008#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000013009/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013010 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013011 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000013012 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013013 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000013014 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013015static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013016letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013017{
Denis Vlasenko68404f12008-03-17 09:00:54 +000013018 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000013019
Denis Vlasenko68404f12008-03-17 09:00:54 +000013020 argv++;
13021 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000013022 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000013023 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013024 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013025 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013026
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000013027 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000013028}
Eric Andersenc470f442003-07-28 09:56:35 +000013029#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013030
Eric Andersenc470f442003-07-28 09:56:35 +000013031/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013032 * The read builtin. Options:
13033 * -r Do not interpret '\' specially
13034 * -s Turn off echo (tty only)
13035 * -n NCHARS Read NCHARS max
13036 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13037 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13038 * -u FD Read from given FD instead of fd 0
Eric Andersenc470f442003-07-28 09:56:35 +000013039 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013040 * TODO: bash also has:
13041 * -a ARRAY Read into array[0],[1],etc
13042 * -d DELIM End on DELIM char, not newline
13043 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000013044 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013045static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013046readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013047{
Denys Vlasenko73067272010-01-12 22:11:24 +010013048 char *opt_n = NULL;
13049 char *opt_p = NULL;
13050 char *opt_t = NULL;
13051 char *opt_u = NULL;
13052 int read_flags = 0;
13053 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000013054 int i;
13055
Denys Vlasenko73067272010-01-12 22:11:24 +010013056 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000013057 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000013058 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010013059 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013060 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013061 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010013062 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013063 break;
13064 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010013065 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000013066 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013067 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010013068 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013069 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013070 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010013071 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000013072 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013073 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010013074 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013075 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013076 default:
13077 break;
13078 }
Eric Andersenc470f442003-07-28 09:56:35 +000013079 }
Paul Fox02eb9342005-09-07 16:56:02 +000013080
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013081 /* "read -s" needs to save/restore termios, can't allow ^C
13082 * to jump out of it.
13083 */
13084 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013085 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010013086 argptr,
13087 bltinlookup("IFS"), /* can be NULL */
13088 read_flags,
13089 opt_n,
13090 opt_p,
13091 opt_t,
13092 opt_u
13093 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013094 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000013095
Denys Vlasenko73067272010-01-12 22:11:24 +010013096 if ((uintptr_t)r > 1)
13097 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000013098
Denys Vlasenko73067272010-01-12 22:11:24 +010013099 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000013100}
13101
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013102static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020013103umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013104{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013105 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000013106
Eric Andersenc470f442003-07-28 09:56:35 +000013107 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000013108 int symbolic_mode = 0;
13109
13110 while (nextopt("S") != '\0') {
13111 symbolic_mode = 1;
13112 }
13113
Denis Vlasenkob012b102007-02-19 22:43:01 +000013114 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013115 mask = umask(0);
13116 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013117 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013118
Denys Vlasenko6283f982015-10-07 16:56:20 +020013119 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013120 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013121 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013122 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013123 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013124
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013125 i = 2;
13126 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013127 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013128 *p++ = permuser[i];
13129 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013130 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013131 if (!(mask & 0400)) *p++ = 'r';
13132 if (!(mask & 0200)) *p++ = 'w';
13133 if (!(mask & 0100)) *p++ = 'x';
13134 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013135 if (--i < 0)
13136 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013137 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013138 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013139 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013140 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013141 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013142 }
13143 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013144 char *modestr = *argptr;
13145 /* numeric umasks are taken as-is */
13146 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
13147 if (!isdigit(modestr[0]))
13148 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013149 mask = bb_parse_mode(modestr, mask);
13150 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013151 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013152 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013153 if (!isdigit(modestr[0]))
13154 mask ^= 0777;
13155 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013156 }
13157 return 0;
13158}
13159
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013160static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013161ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013162{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013163 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013164}
13165
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013166/* ============ main() and helpers */
13167
13168/*
13169 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013170 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013171static void
13172exitshell(void)
13173{
13174 struct jmploc loc;
13175 char *p;
13176 int status;
13177
Denys Vlasenkobede2152011-09-04 16:12:33 +020013178#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13179 save_history(line_input_state);
13180#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013181 status = exitstatus;
13182 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13183 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013184 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013185 status = exitstatus;
13186 goto out;
13187 }
13188 exception_handler = &loc;
13189 p = trap[0];
13190 if (p) {
13191 trap[0] = NULL;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013192 evalskip = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013193 evalstring(p, 0);
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013194 /*free(p); - we'll exit soon */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013195 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013196 out:
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013197 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13198 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13199 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013200 setjobctl(0);
Denys Vlasenkocaee80c2016-10-25 20:49:53 +020013201 flush_stdout_stderr();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013202 _exit(status);
13203 /* NOTREACHED */
13204}
13205
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013206static void
13207init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013208{
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013209 /* we will never free this */
13210 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013211
Denys Vlasenko458c1f22016-10-27 23:51:19 +020013212 sigmode[SIGCHLD - 1] = S_DFL;
13213 setsignal(SIGCHLD);
13214
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013215 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13216 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13217 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013218 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013219
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013220 {
13221 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013222 const char *p;
13223 struct stat st1, st2;
13224
13225 initvar();
13226 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenkob6838b52016-09-30 11:33:47 +020013227 p = endofname(*envp);
13228 if (p != *envp && *p == '=') {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013229 setvareq(*envp, VEXPORT|VTEXTFIXED);
13230 }
13231 }
13232
Denys Vlasenkoe627ac92016-09-30 14:36:59 +020013233 setvareq((char*)defoptindvar, VTEXTFIXED);
13234
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013235 setvar0("PPID", utoa(getppid()));
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013236#if ENABLE_ASH_BASH_COMPAT
13237 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013238 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013239 if (!lookupvar("HOSTNAME")) {
13240 struct utsname uts;
13241 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013242 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013243 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013244#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013245 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013246 if (p) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013247 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013248 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13249 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013250 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013251 }
13252 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013253 setpwd(p, 0);
13254 }
13255}
13256
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013257
13258//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013259//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013260//usage:#define ash_full_usage "\n\n"
13261//usage: "Unix shell interpreter"
13262
13263//usage:#if ENABLE_FEATURE_SH_IS_ASH
13264//usage:# define sh_trivial_usage ash_trivial_usage
13265//usage:# define sh_full_usage ash_full_usage
13266//usage:#endif
13267//usage:#if ENABLE_FEATURE_BASH_IS_ASH
13268//usage:# define bash_trivial_usage ash_trivial_usage
13269//usage:# define bash_full_usage ash_full_usage
13270//usage:#endif
13271
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013272/*
13273 * Process the shell command line arguments.
13274 */
13275static void
Denis Vlasenko68404f12008-03-17 09:00:54 +000013276procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013277{
13278 int i;
13279 const char *xminusc;
13280 char **xargv;
13281
13282 xargv = argv;
13283 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013284 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013285 xargv++;
13286 for (i = 0; i < NOPTS; i++)
13287 optlist[i] = 2;
13288 argptr = xargv;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013289 if (options(/*cmdline:*/ 1)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013290 /* it already printed err message */
13291 raise_exception(EXERROR);
13292 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013293 xargv = argptr;
13294 xminusc = minusc;
13295 if (*xargv == NULL) {
13296 if (xminusc)
13297 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13298 sflag = 1;
13299 }
13300 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13301 iflag = 1;
13302 if (mflag == 2)
13303 mflag = iflag;
13304 for (i = 0; i < NOPTS; i++)
13305 if (optlist[i] == 2)
13306 optlist[i] = 0;
13307#if DEBUG == 2
13308 debug = 1;
13309#endif
13310 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13311 if (xminusc) {
13312 minusc = *xargv++;
13313 if (*xargv)
13314 goto setarg0;
13315 } else if (!sflag) {
13316 setinputfile(*xargv, 0);
13317 setarg0:
13318 arg0 = *xargv++;
13319 commandname = arg0;
13320 }
13321
13322 shellparam.p = xargv;
13323#if ENABLE_ASH_GETOPTS
13324 shellparam.optind = 1;
13325 shellparam.optoff = -1;
13326#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013327 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013328 while (*xargv) {
13329 shellparam.nparam++;
13330 xargv++;
13331 }
13332 optschanged();
13333}
13334
13335/*
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013336 * Read /etc/profile, ~/.profile, $ENV.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013337 */
13338static void
13339read_profile(const char *name)
13340{
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013341 name = expandstr(name);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013342 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13343 return;
Denys Vlasenko0840c912016-10-01 15:27:44 +020013344 cmdloop(0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013345 popfile();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013346}
13347
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013348/*
13349 * This routine is called when an error or an interrupt occurs in an
13350 * interactive shell and control is returned to the main command loop.
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013351 * (In dash, this function is auto-generated by build machinery).
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013352 */
13353static void
13354reset(void)
13355{
13356 /* from eval.c: */
13357 evalskip = 0;
13358 loopnest = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013359
13360 /* from expand.c: */
13361 ifsfree();
13362
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013363 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013364 g_parsefile->left_in_buffer = 0;
13365 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013366 popallfiles();
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013367
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013368 /* from redir.c: */
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020013369 while (redirlist)
13370 popredir(/*drop:*/ 0, /*restore:*/ 0);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013371}
13372
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013373#if PROFILE
13374static short profile_buf[16384];
13375extern int etext();
13376#endif
13377
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013378/*
13379 * Main routine. We initialize things, parse the arguments, execute
13380 * profiles if we're a login shell, and then call cmdloop to execute
13381 * commands. The setjmp call sets up the location to jump to when an
13382 * exception occurs. When an exception occurs the variable "state"
13383 * is used to figure out how far we had gotten.
13384 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013385int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013386int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013387{
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013388 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013389 struct jmploc jmploc;
13390 struct stackmark smark;
13391
Denis Vlasenko01631112007-12-16 17:20:38 +000013392 /* Initialize global data */
13393 INIT_G_misc();
13394 INIT_G_memstack();
13395 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013396#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013397 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013398#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013399 INIT_G_cmdtable();
13400
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013401#if PROFILE
13402 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13403#endif
13404
13405#if ENABLE_FEATURE_EDITING
13406 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13407#endif
13408 state = 0;
13409 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013410 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013411 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013412
13413 reset();
13414
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013415 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013416 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013417 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013418 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013419 }
13420 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020013421 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013422 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013423
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013424 popstackmark(&smark);
13425 FORCE_INT_ON; /* enable interrupts */
13426 if (s == 1)
13427 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013428 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013429 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013430 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013431 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013432 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013433 }
13434 exception_handler = &jmploc;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013435 rootpid = getpid();
13436
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013437 init();
13438 setstackmark(&smark);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013439 procargs(argv);
Denys Vlasenko474ed062016-10-30 18:30:29 +010013440#if DEBUG
13441 TRACE(("Shell args: "));
13442 trace_puts_args(argv);
13443#endif
Denis Vlasenko68404f12008-03-17 09:00:54 +000013444
Denys Vlasenko6088e132010-12-25 23:58:42 +010013445 if (argv[0] && argv[0][0] == '-')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013446 isloginsh = 1;
13447 if (isloginsh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013448 const char *hp;
13449
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013450 state = 1;
13451 read_profile("/etc/profile");
13452 state1:
13453 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013454 hp = lookupvar("HOME");
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013455 if (hp)
13456 read_profile("$HOME/.profile");
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013457 }
13458 state2:
13459 state = 3;
13460 if (
13461#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013462 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013463#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013464 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013465 ) {
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013466 const char *shinit = lookupvar("ENV");
13467 if (shinit != NULL && *shinit != '\0')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013468 read_profile(shinit);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013469 }
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013470 popstackmark(&smark);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013471 state3:
13472 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013473 if (minusc) {
13474 /* evalstring pushes parsefile stack.
13475 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013476 * is one of stacked source fds.
13477 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013478 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013479 // ^^ not necessary since now we special-case fd 0
13480 // in is_hidden_fd() to not be considered "hidden fd"
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013481 evalstring(minusc, 0);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013482 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013483
13484 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020013485#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013486 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013487 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013488 if (!hp) {
13489 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013490 if (hp) {
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013491 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013492 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013493 free((char*)hp);
13494 hp = lookupvar("HISTFILE");
13495 }
13496 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013497 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013498 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013499# if ENABLE_FEATURE_SH_HISTFILESIZE
13500 hp = lookupvar("HISTFILESIZE");
13501 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13502# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013503 }
13504#endif
13505 state4: /* XXX ??? - why isn't this before the "if" statement */
13506 cmdloop(1);
13507 }
13508#if PROFILE
13509 monitor(0);
13510#endif
13511#ifdef GPROF
13512 {
13513 extern void _mcleanup(void);
13514 _mcleanup();
13515 }
13516#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013517 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013518 exitshell();
13519 /* NOTREACHED */
13520}
13521
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013522
Eric Andersendf82f612001-06-28 07:46:40 +000013523/*-
13524 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013525 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013526 *
13527 * This code is derived from software contributed to Berkeley by
13528 * Kenneth Almquist.
13529 *
13530 * Redistribution and use in source and binary forms, with or without
13531 * modification, are permitted provided that the following conditions
13532 * are met:
13533 * 1. Redistributions of source code must retain the above copyright
13534 * notice, this list of conditions and the following disclaimer.
13535 * 2. Redistributions in binary form must reproduce the above copyright
13536 * notice, this list of conditions and the following disclaimer in the
13537 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013538 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013539 * may be used to endorse or promote products derived from this software
13540 * without specific prior written permission.
13541 *
13542 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13543 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13544 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13545 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13546 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13547 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13548 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13549 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13550 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13551 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13552 * SUCH DAMAGE.
13553 */