blob: 0c84805879488dd27cd1f9b08e6090d65aebb1f5 [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;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000847 if (DEBUG_TIME)
848 fprintf(tracefile, "%u ", (int) time(NULL));
849 if (DEBUG_PID)
850 fprintf(tracefile, "[%u] ", (int) getpid());
851 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200852 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000853 vfprintf(tracefile, fmt, va);
854}
855
856static void
857trace_puts(const char *s)
858{
859 if (debug != 1)
860 return;
861 fputs(s, tracefile);
862}
863
864static void
865trace_puts_quoted(char *s)
866{
867 char *p;
868 char c;
869
870 if (debug != 1)
871 return;
872 putc('"', tracefile);
873 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100874 switch ((unsigned char)*p) {
875 case '\n': c = 'n'; goto backslash;
876 case '\t': c = 't'; goto backslash;
877 case '\r': c = 'r'; goto backslash;
878 case '\"': c = '\"'; goto backslash;
879 case '\\': c = '\\'; goto backslash;
880 case CTLESC: c = 'e'; goto backslash;
881 case CTLVAR: c = 'v'; goto backslash;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100882 case CTLBACKQ: c = 'q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000883 backslash:
884 putc('\\', tracefile);
885 putc(c, tracefile);
886 break;
887 default:
888 if (*p >= ' ' && *p <= '~')
889 putc(*p, tracefile);
890 else {
891 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +0100892 putc((*p >> 6) & 03, tracefile);
893 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000894 putc(*p & 07, tracefile);
895 }
896 break;
897 }
898 }
899 putc('"', tracefile);
900}
901
902static void
903trace_puts_args(char **ap)
904{
905 if (debug != 1)
906 return;
907 if (!*ap)
908 return;
909 while (1) {
910 trace_puts_quoted(*ap);
911 if (!*++ap) {
912 putc('\n', tracefile);
913 break;
914 }
915 putc(' ', tracefile);
916 }
917}
918
919static void
920opentrace(void)
921{
922 char s[100];
923#ifdef O_APPEND
924 int flags;
925#endif
926
927 if (debug != 1) {
928 if (tracefile)
929 fflush(tracefile);
930 /* leave open because libedit might be using it */
931 return;
932 }
933 strcpy(s, "./trace");
934 if (tracefile) {
935 if (!freopen(s, "a", tracefile)) {
936 fprintf(stderr, "Can't re-open %s\n", s);
937 debug = 0;
938 return;
939 }
940 } else {
941 tracefile = fopen(s, "a");
942 if (tracefile == NULL) {
943 fprintf(stderr, "Can't open %s\n", s);
944 debug = 0;
945 return;
946 }
947 }
948#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000949 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000950 if (flags >= 0)
951 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
952#endif
953 setlinebuf(tracefile);
954 fputs("\nTracing started.\n", tracefile);
955}
956
957static void
958indent(int amount, char *pfx, FILE *fp)
959{
960 int i;
961
962 for (i = 0; i < amount; i++) {
963 if (pfx && i == amount - 1)
964 fputs(pfx, fp);
965 putc('\t', fp);
966 }
967}
968
969/* little circular references here... */
970static void shtree(union node *n, int ind, char *pfx, FILE *fp);
971
972static void
973sharg(union node *arg, FILE *fp)
974{
975 char *p;
976 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100977 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000978
979 if (arg->type != NARG) {
980 out1fmt("<node type %d>\n", arg->type);
981 abort();
982 }
983 bqlist = arg->narg.backquote;
984 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100985 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000986 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -0700987 p++;
988 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000989 break;
990 case CTLVAR:
991 putc('$', fp);
992 putc('{', fp);
993 subtype = *++p;
994 if (subtype == VSLENGTH)
995 putc('#', fp);
996
Dan Fandrich77d48722010-09-07 23:38:28 -0700997 while (*p != '=') {
998 putc(*p, fp);
999 p++;
1000 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001001
1002 if (subtype & VSNUL)
1003 putc(':', fp);
1004
1005 switch (subtype & VSTYPE) {
1006 case VSNORMAL:
1007 putc('}', fp);
1008 break;
1009 case VSMINUS:
1010 putc('-', fp);
1011 break;
1012 case VSPLUS:
1013 putc('+', fp);
1014 break;
1015 case VSQUESTION:
1016 putc('?', fp);
1017 break;
1018 case VSASSIGN:
1019 putc('=', fp);
1020 break;
1021 case VSTRIMLEFT:
1022 putc('#', fp);
1023 break;
1024 case VSTRIMLEFTMAX:
1025 putc('#', fp);
1026 putc('#', fp);
1027 break;
1028 case VSTRIMRIGHT:
1029 putc('%', fp);
1030 break;
1031 case VSTRIMRIGHTMAX:
1032 putc('%', fp);
1033 putc('%', fp);
1034 break;
1035 case VSLENGTH:
1036 break;
1037 default:
1038 out1fmt("<subtype %d>", subtype);
1039 }
1040 break;
1041 case CTLENDVAR:
1042 putc('}', fp);
1043 break;
1044 case CTLBACKQ:
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001045 putc('$', fp);
1046 putc('(', fp);
1047 shtree(bqlist->n, -1, NULL, fp);
1048 putc(')', fp);
1049 break;
1050 default:
1051 putc(*p, fp);
1052 break;
1053 }
1054 }
1055}
1056
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001057static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001058shcmd(union node *cmd, FILE *fp)
1059{
1060 union node *np;
1061 int first;
1062 const char *s;
1063 int dftfd;
1064
1065 first = 1;
1066 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001067 if (!first)
1068 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001069 sharg(np, fp);
1070 first = 0;
1071 }
1072 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001073 if (!first)
1074 putc(' ', fp);
1075 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001076 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001077 case NTO: s = ">>"+1; dftfd = 1; break;
1078 case NCLOBBER: s = ">|"; dftfd = 1; break;
1079 case NAPPEND: s = ">>"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001080#if ENABLE_ASH_BASH_COMPAT
1081 case NTO2:
1082#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001083 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001084 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001085 case NFROMFD: s = "<&"; break;
1086 case NFROMTO: s = "<>"; break;
1087 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001088 }
1089 if (np->nfile.fd != dftfd)
1090 fprintf(fp, "%d", np->nfile.fd);
1091 fputs(s, fp);
1092 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1093 fprintf(fp, "%d", np->ndup.dupfd);
1094 } else {
1095 sharg(np->nfile.fname, fp);
1096 }
1097 first = 0;
1098 }
1099}
1100
1101static void
1102shtree(union node *n, int ind, char *pfx, FILE *fp)
1103{
1104 struct nodelist *lp;
1105 const char *s;
1106
1107 if (n == NULL)
1108 return;
1109
1110 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001111
1112 if (n == NODE_EOF) {
1113 fputs("<EOF>", fp);
1114 return;
1115 }
1116
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001117 switch (n->type) {
1118 case NSEMI:
1119 s = "; ";
1120 goto binop;
1121 case NAND:
1122 s = " && ";
1123 goto binop;
1124 case NOR:
1125 s = " || ";
1126 binop:
1127 shtree(n->nbinary.ch1, ind, NULL, fp);
1128 /* if (ind < 0) */
1129 fputs(s, fp);
1130 shtree(n->nbinary.ch2, ind, NULL, fp);
1131 break;
1132 case NCMD:
1133 shcmd(n, fp);
1134 if (ind >= 0)
1135 putc('\n', fp);
1136 break;
1137 case NPIPE:
1138 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001139 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001140 if (lp->next)
1141 fputs(" | ", fp);
1142 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001143 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001144 fputs(" &", fp);
1145 if (ind >= 0)
1146 putc('\n', fp);
1147 break;
1148 default:
1149 fprintf(fp, "<node type %d>", n->type);
1150 if (ind >= 0)
1151 putc('\n', fp);
1152 break;
1153 }
1154}
1155
1156static void
1157showtree(union node *n)
1158{
1159 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001160 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001161}
1162
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001163#endif /* DEBUG */
1164
1165
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001166/* ============ Parser data */
1167
1168/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001169 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1170 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001171struct strlist {
1172 struct strlist *next;
1173 char *text;
1174};
1175
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001176struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001177
Denis Vlasenkob012b102007-02-19 22:43:01 +00001178struct strpush {
1179 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001180 char *prev_string;
1181 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001182#if ENABLE_ASH_ALIAS
1183 struct alias *ap; /* if push was associated with an alias */
1184#endif
1185 char *string; /* remember the string since it may change */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001186
1187 /* Remember last two characters for pungetc. */
1188 int lastc[2];
1189
1190 /* Number of outstanding calls to pungetc. */
1191 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001192};
1193
1194struct parsefile {
1195 struct parsefile *prev; /* preceding file on stack */
1196 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001197 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001198 int left_in_line; /* number of chars left in this line */
1199 int left_in_buffer; /* number of chars left in this buffer past the line */
1200 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001201 char *buf; /* input buffer */
1202 struct strpush *strpush; /* for pushing strings at this level */
1203 struct strpush basestrpush; /* so pushing one is fast */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001204
1205 /* Remember last two characters for pungetc. */
1206 int lastc[2];
1207
1208 /* Number of outstanding calls to pungetc. */
1209 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001210};
1211
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001212static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001213static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001214static int startlinno; /* line # where last token started */
1215static char *commandname; /* currently executing command */
1216static struct strlist *cmdenviron; /* environment for builtin command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001217
1218
1219/* ============ Message printing */
1220
1221static void
1222ash_vmsg(const char *msg, va_list ap)
1223{
1224 fprintf(stderr, "%s: ", arg0);
1225 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001226 if (strcmp(arg0, commandname))
1227 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001228 if (!iflag || g_parsefile->pf_fd > 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001229 fprintf(stderr, "line %d: ", startlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001230 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001231 vfprintf(stderr, msg, ap);
Denys Vlasenko9c541002015-10-07 15:44:36 +02001232 newline_and_flush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001233}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001234
1235/*
1236 * Exverror is called to raise the error exception. If the second argument
1237 * is not NULL then error prints an error message using printf style
1238 * formatting. It then raises the error exception.
1239 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001240static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001241static void
1242ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001243{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001244#if DEBUG
1245 if (msg) {
1246 TRACE(("ash_vmsg_and_raise(%d, \"", cond));
1247 TRACEV((msg, ap));
1248 TRACE(("\") pid=%d\n", getpid()));
1249 } else
1250 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
1251 if (msg)
1252#endif
1253 ash_vmsg(msg, ap);
1254
1255 flush_stdout_stderr();
1256 raise_exception(cond);
1257 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001258}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001259
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001260static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001261static void
1262ash_msg_and_raise_error(const char *msg, ...)
1263{
1264 va_list ap;
1265
1266 va_start(ap, msg);
1267 ash_vmsg_and_raise(EXERROR, msg, ap);
1268 /* NOTREACHED */
1269 va_end(ap);
1270}
1271
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001272static void raise_error_syntax(const char *) NORETURN;
1273static void
1274raise_error_syntax(const char *msg)
1275{
1276 ash_msg_and_raise_error("syntax error: %s", msg);
1277 /* NOTREACHED */
1278}
1279
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001280static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001281static void
1282ash_msg_and_raise(int cond, const char *msg, ...)
1283{
1284 va_list ap;
1285
1286 va_start(ap, msg);
1287 ash_vmsg_and_raise(cond, msg, ap);
1288 /* NOTREACHED */
1289 va_end(ap);
1290}
1291
1292/*
1293 * error/warning routines for external builtins
1294 */
1295static void
1296ash_msg(const char *fmt, ...)
1297{
1298 va_list ap;
1299
1300 va_start(ap, fmt);
1301 ash_vmsg(fmt, ap);
1302 va_end(ap);
1303}
1304
1305/*
1306 * Return a string describing an error. The returned string may be a
1307 * pointer to a static buffer that will be overwritten on the next call.
1308 * Action describes the operation that got the error.
1309 */
1310static const char *
1311errmsg(int e, const char *em)
1312{
1313 if (e == ENOENT || e == ENOTDIR) {
1314 return em;
1315 }
1316 return strerror(e);
1317}
1318
1319
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001320/* ============ Memory allocation */
1321
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001322#if 0
1323/* I consider these wrappers nearly useless:
1324 * ok, they return you to nearest exception handler, but
1325 * how much memory do you leak in the process, making
1326 * memory starvation worse?
1327 */
1328static void *
1329ckrealloc(void * p, size_t nbytes)
1330{
1331 p = realloc(p, nbytes);
1332 if (!p)
1333 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1334 return p;
1335}
1336
1337static void *
1338ckmalloc(size_t nbytes)
1339{
1340 return ckrealloc(NULL, nbytes);
1341}
1342
1343static void *
1344ckzalloc(size_t nbytes)
1345{
1346 return memset(ckmalloc(nbytes), 0, nbytes);
1347}
1348
1349static char *
1350ckstrdup(const char *s)
1351{
1352 char *p = strdup(s);
1353 if (!p)
1354 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1355 return p;
1356}
1357#else
1358/* Using bbox equivalents. They exit if out of memory */
1359# define ckrealloc xrealloc
1360# define ckmalloc xmalloc
1361# define ckzalloc xzalloc
1362# define ckstrdup xstrdup
1363#endif
1364
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001365/*
1366 * It appears that grabstackstr() will barf with such alignments
1367 * because stalloc() will return a string allocated in a new stackblock.
1368 */
1369#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1370enum {
1371 /* Most machines require the value returned from malloc to be aligned
1372 * in some way. The following macro will get this right
1373 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001374 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001375 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001376 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001377};
1378
1379struct stack_block {
1380 struct stack_block *prev;
1381 char space[MINSIZE];
1382};
1383
1384struct stackmark {
1385 struct stack_block *stackp;
1386 char *stacknxt;
1387 size_t stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001388};
1389
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001390
Denis Vlasenko01631112007-12-16 17:20:38 +00001391struct globals_memstack {
1392 struct stack_block *g_stackp; // = &stackbase;
Denis Vlasenko01631112007-12-16 17:20:38 +00001393 char *g_stacknxt; // = stackbase.space;
1394 char *sstrend; // = stackbase.space + MINSIZE;
1395 size_t g_stacknleft; // = MINSIZE;
Denis Vlasenko01631112007-12-16 17:20:38 +00001396 struct stack_block stackbase;
1397};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001398extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1399#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001400#define g_stackp (G_memstack.g_stackp )
Denis Vlasenko01631112007-12-16 17:20:38 +00001401#define g_stacknxt (G_memstack.g_stacknxt )
1402#define sstrend (G_memstack.sstrend )
1403#define g_stacknleft (G_memstack.g_stacknleft)
Denis Vlasenko01631112007-12-16 17:20:38 +00001404#define stackbase (G_memstack.stackbase )
1405#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001406 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1407 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001408 g_stackp = &stackbase; \
1409 g_stacknxt = stackbase.space; \
1410 g_stacknleft = MINSIZE; \
1411 sstrend = stackbase.space + MINSIZE; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001412} while (0)
1413
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001414
Denis Vlasenko01631112007-12-16 17:20:38 +00001415#define stackblock() ((void *)g_stacknxt)
1416#define stackblocksize() g_stacknleft
1417
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001418/*
1419 * Parse trees for commands are allocated in lifo order, so we use a stack
1420 * to make this more efficient, and also to avoid all sorts of exception
1421 * handling code to handle interrupts in the middle of a parse.
1422 *
1423 * The size 504 was chosen because the Ultrix malloc handles that size
1424 * well.
1425 */
1426static void *
1427stalloc(size_t nbytes)
1428{
1429 char *p;
1430 size_t aligned;
1431
1432 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001433 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001434 size_t len;
1435 size_t blocksize;
1436 struct stack_block *sp;
1437
1438 blocksize = aligned;
1439 if (blocksize < MINSIZE)
1440 blocksize = MINSIZE;
1441 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1442 if (len < blocksize)
1443 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1444 INT_OFF;
1445 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001446 sp->prev = g_stackp;
1447 g_stacknxt = sp->space;
1448 g_stacknleft = blocksize;
1449 sstrend = g_stacknxt + blocksize;
1450 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001451 INT_ON;
1452 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001453 p = g_stacknxt;
1454 g_stacknxt += aligned;
1455 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001456 return p;
1457}
1458
Denis Vlasenko597906c2008-02-20 16:38:54 +00001459static void *
1460stzalloc(size_t nbytes)
1461{
1462 return memset(stalloc(nbytes), 0, nbytes);
1463}
1464
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001465static void
1466stunalloc(void *p)
1467{
1468#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001469 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001470 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001471 abort();
1472 }
1473#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001474 g_stacknleft += g_stacknxt - (char *)p;
1475 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001476}
1477
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001478/*
1479 * Like strdup but works with the ash stack.
1480 */
1481static char *
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02001482sstrdup(const char *p)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001483{
1484 size_t len = strlen(p) + 1;
1485 return memcpy(stalloc(len), p, len);
1486}
1487
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001488static inline void
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001489grabstackblock(size_t len)
1490{
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001491 stalloc(len);
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001492}
1493
1494static void
1495pushstackmark(struct stackmark *mark, size_t len)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001496{
Denis Vlasenko01631112007-12-16 17:20:38 +00001497 mark->stackp = g_stackp;
1498 mark->stacknxt = g_stacknxt;
1499 mark->stacknleft = g_stacknleft;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001500 grabstackblock(len);
1501}
1502
1503static void
1504setstackmark(struct stackmark *mark)
1505{
1506 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001507}
1508
1509static void
1510popstackmark(struct stackmark *mark)
1511{
1512 struct stack_block *sp;
1513
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001514 if (!mark->stackp)
1515 return;
1516
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001517 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001518 while (g_stackp != mark->stackp) {
1519 sp = g_stackp;
1520 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001521 free(sp);
1522 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001523 g_stacknxt = mark->stacknxt;
1524 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001525 sstrend = mark->stacknxt + mark->stacknleft;
1526 INT_ON;
1527}
1528
1529/*
1530 * When the parser reads in a string, it wants to stick the string on the
1531 * stack and only adjust the stack pointer when it knows how big the
1532 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1533 * of space on top of the stack and stackblocklen returns the length of
1534 * this block. Growstackblock will grow this space by at least one byte,
1535 * possibly moving it (like realloc). Grabstackblock actually allocates the
1536 * part of the block that has been used.
1537 */
1538static void
1539growstackblock(void)
1540{
1541 size_t newlen;
1542
Denis Vlasenko01631112007-12-16 17:20:38 +00001543 newlen = g_stacknleft * 2;
1544 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001545 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1546 if (newlen < 128)
1547 newlen += 128;
1548
Denis Vlasenko01631112007-12-16 17:20:38 +00001549 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001550 struct stack_block *sp;
1551 struct stack_block *prevstackp;
1552 size_t grosslen;
1553
1554 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001555 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001556 prevstackp = sp->prev;
1557 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1558 sp = ckrealloc(sp, grosslen);
1559 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001560 g_stackp = sp;
1561 g_stacknxt = sp->space;
1562 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001563 sstrend = sp->space + newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001564 INT_ON;
1565 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001566 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001567 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001568 char *p = stalloc(newlen);
1569
1570 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001571 g_stacknxt = memcpy(p, oldspace, oldlen);
1572 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001573 }
1574}
1575
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001576/*
1577 * The following routines are somewhat easier to use than the above.
1578 * The user declares a variable of type STACKSTR, which may be declared
1579 * to be a register. The macro STARTSTACKSTR initializes things. Then
1580 * the user uses the macro STPUTC to add characters to the string. In
1581 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1582 * grown as necessary. When the user is done, she can just leave the
1583 * string there and refer to it using stackblock(). Or she can allocate
1584 * the space for it using grabstackstr(). If it is necessary to allow
1585 * someone else to use the stack temporarily and then continue to grow
1586 * the string, the user should use grabstack to allocate the space, and
1587 * then call ungrabstr(p) to return to the previous mode of operation.
1588 *
1589 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1590 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1591 * is space for at least one character.
1592 */
1593static void *
1594growstackstr(void)
1595{
1596 size_t len = stackblocksize();
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001597 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001598 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001599}
1600
1601/*
1602 * Called from CHECKSTRSPACE.
1603 */
1604static char *
1605makestrspace(size_t newlen, char *p)
1606{
Denis Vlasenko01631112007-12-16 17:20:38 +00001607 size_t len = p - g_stacknxt;
Denys Vlasenko53d6e032016-09-30 11:24:12 +02001608 size_t size;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001609
1610 for (;;) {
1611 size_t nleft;
1612
1613 size = stackblocksize();
1614 nleft = size - len;
1615 if (nleft >= newlen)
1616 break;
1617 growstackblock();
1618 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001619 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001620}
1621
1622static char *
1623stack_nputstr(const char *s, size_t n, char *p)
1624{
1625 p = makestrspace(n, p);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001626 p = (char *)memcpy(p, s, n) + n;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001627 return p;
1628}
1629
1630static char *
1631stack_putstr(const char *s, char *p)
1632{
1633 return stack_nputstr(s, strlen(s), p);
1634}
1635
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001636static char *
1637_STPUTC(int c, char *p)
1638{
1639 if (p == sstrend)
1640 p = growstackstr();
1641 *p++ = c;
1642 return p;
1643}
1644
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001645#define STARTSTACKSTR(p) ((p) = stackblock())
1646#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001647#define CHECKSTRSPACE(n, p) do { \
1648 char *q = (p); \
1649 size_t l = (n); \
1650 size_t m = sstrend - q; \
1651 if (l > m) \
1652 (p) = makestrspace(l, q); \
1653} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001654#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001655#define STACKSTRNUL(p) do { \
1656 if ((p) == sstrend) \
1657 (p) = growstackstr(); \
1658 *(p) = '\0'; \
1659} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001660#define STUNPUTC(p) (--(p))
1661#define STTOPC(p) ((p)[-1])
1662#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001663
1664#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001665#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001666#define stackstrend() ((void *)sstrend)
1667
1668
1669/* ============ String helpers */
1670
1671/*
1672 * prefix -- see if pfx is a prefix of string.
1673 */
1674static char *
1675prefix(const char *string, const char *pfx)
1676{
1677 while (*pfx) {
1678 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001679 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001680 }
1681 return (char *) string;
1682}
1683
1684/*
1685 * Check for a valid number. This should be elsewhere.
1686 */
1687static int
1688is_number(const char *p)
1689{
1690 do {
1691 if (!isdigit(*p))
1692 return 0;
1693 } while (*++p != '\0');
1694 return 1;
1695}
1696
1697/*
1698 * Convert a string of digits to an integer, printing an error message on
1699 * failure.
1700 */
1701static int
1702number(const char *s)
1703{
1704 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001705 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001706 return atoi(s);
1707}
1708
1709/*
1710 * Produce a possibly single quoted string suitable as input to the shell.
1711 * The return string is allocated on the stack.
1712 */
1713static char *
1714single_quote(const char *s)
1715{
1716 char *p;
1717
1718 STARTSTACKSTR(p);
1719
1720 do {
1721 char *q;
1722 size_t len;
1723
1724 len = strchrnul(s, '\'') - s;
1725
1726 q = p = makestrspace(len + 3, p);
1727
1728 *q++ = '\'';
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001729 q = (char *)memcpy(q, s, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001730 *q++ = '\'';
1731 s += len;
1732
1733 STADJUST(q - p, p);
1734
Denys Vlasenkocd716832009-11-28 22:14:02 +01001735 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001736 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001737 len = 0;
1738 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001739
1740 q = p = makestrspace(len + 3, p);
1741
1742 *q++ = '"';
Denys Vlasenkocd716832009-11-28 22:14:02 +01001743 q = (char *)memcpy(q, s - len, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001744 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001745
1746 STADJUST(q - p, p);
1747 } while (*s);
1748
Denys Vlasenkocd716832009-11-28 22:14:02 +01001749 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001750
1751 return stackblock();
1752}
1753
1754
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001755/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001756
1757static char **argptr; /* argument list for builtin commands */
1758static char *optionarg; /* set by nextopt (like getopt) */
1759static char *optptr; /* used by nextopt */
1760
1761/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001762 * XXX - should get rid of. Have all builtins use getopt(3).
1763 * The library getopt must have the BSD extension static variable
1764 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001765 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001766 * Standard option processing (a la getopt) for builtin routines.
1767 * The only argument that is passed to nextopt is the option string;
1768 * the other arguments are unnecessary. It returns the character,
1769 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001770 */
1771static int
1772nextopt(const char *optstring)
1773{
1774 char *p;
1775 const char *q;
1776 char c;
1777
1778 p = optptr;
1779 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001780 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001781 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001782 if (p == NULL)
1783 return '\0';
1784 if (*p != '-')
1785 return '\0';
1786 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001787 return '\0';
1788 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001789 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001790 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001791 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001792 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001793 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001794 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001795 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001796 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001797 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001798 if (*++q == ':')
1799 q++;
1800 }
1801 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001802 if (*p == '\0') {
1803 p = *argptr++;
1804 if (p == NULL)
1805 ash_msg_and_raise_error("no arg for -%c option", c);
1806 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001807 optionarg = p;
1808 p = NULL;
1809 }
1810 optptr = p;
1811 return c;
1812}
1813
1814
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001815/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001816
Denis Vlasenko01631112007-12-16 17:20:38 +00001817/*
1818 * The parsefile structure pointed to by the global variable parsefile
1819 * contains information about the current file being read.
1820 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001821struct shparam {
1822 int nparam; /* # of positional parameters (without $0) */
1823#if ENABLE_ASH_GETOPTS
1824 int optind; /* next parameter to be processed by getopts */
1825 int optoff; /* used by getopts */
1826#endif
1827 unsigned char malloced; /* if parameter list dynamically allocated */
1828 char **p; /* parameter list */
1829};
1830
1831/*
1832 * Free the list of positional parameters.
1833 */
1834static void
1835freeparam(volatile struct shparam *param)
1836{
Denis Vlasenko01631112007-12-16 17:20:38 +00001837 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001838 char **ap, **ap1;
1839 ap = ap1 = param->p;
1840 while (*ap)
1841 free(*ap++);
1842 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001843 }
1844}
1845
1846#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001847static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001848#endif
1849
1850struct var {
1851 struct var *next; /* next entry in hash list */
1852 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001853 const char *var_text; /* name=value */
1854 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001855 /* the variable gets set/unset */
1856};
1857
1858struct localvar {
1859 struct localvar *next; /* next local variable in list */
1860 struct var *vp; /* the variable that was made local */
1861 int flags; /* saved flags */
1862 const char *text; /* saved text */
1863};
1864
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001865/* flags */
1866#define VEXPORT 0x01 /* variable is exported */
1867#define VREADONLY 0x02 /* variable cannot be modified */
1868#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1869#define VTEXTFIXED 0x08 /* text is statically allocated */
1870#define VSTACK 0x10 /* text is allocated on the stack */
1871#define VUNSET 0x20 /* the variable is not set */
1872#define VNOFUNC 0x40 /* don't call the callback function */
1873#define VNOSET 0x80 /* do not set variable - just readonly test */
1874#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001875#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001876# define VDYNAMIC 0x200 /* dynamic variable */
1877#else
1878# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001879#endif
1880
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001881
Denis Vlasenko01631112007-12-16 17:20:38 +00001882/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001883#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001884static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001885change_lc_all(const char *value)
1886{
1887 if (value && *value != '\0')
1888 setlocale(LC_ALL, value);
1889}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001890static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001891change_lc_ctype(const char *value)
1892{
1893 if (value && *value != '\0')
1894 setlocale(LC_CTYPE, value);
1895}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001896#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001897#if ENABLE_ASH_MAIL
1898static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01001899static void changemail(const char *var_value) FAST_FUNC;
1900#else
1901# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001902#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001903static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001904#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001905static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001906#endif
1907
Denis Vlasenko01631112007-12-16 17:20:38 +00001908static const struct {
1909 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001910 const char *var_text;
1911 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00001912} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02001913 /*
1914 * Note: VEXPORT would not work correctly here for NOFORK applets:
1915 * some environment strings may be constant.
1916 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001917 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001918#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001919 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
1920 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001921#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001922 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1923 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1924 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1925 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001926#if ENABLE_ASH_GETOPTS
Denys Vlasenkoe627ac92016-09-30 14:36:59 +02001927 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001928#endif
1929#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001930 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001931#endif
1932#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001933 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
1934 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001935#endif
1936#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001937 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001938#endif
1939};
1940
Denis Vlasenko0b769642008-07-24 07:54:57 +00001941struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00001942
1943struct globals_var {
1944 struct shparam shellparam; /* $@ current positional parameters */
1945 struct redirtab *redirlist;
Denis Vlasenko01631112007-12-16 17:20:38 +00001946 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1947 struct var *vartab[VTABSIZE];
1948 struct var varinit[ARRAY_SIZE(varinit_data)];
1949};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001950extern struct globals_var *const ash_ptr_to_globals_var;
1951#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00001952#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00001953//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00001954#define preverrout_fd (G_var.preverrout_fd)
1955#define vartab (G_var.vartab )
1956#define varinit (G_var.varinit )
1957#define INIT_G_var() do { \
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00001958 unsigned i; \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001959 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1960 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001961 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001962 varinit[i].flags = varinit_data[i].flags; \
1963 varinit[i].var_text = varinit_data[i].var_text; \
1964 varinit[i].var_func = varinit_data[i].var_func; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001965 } \
1966} while (0)
1967
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001968#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001969#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001970# define vmail (&vifs)[1]
1971# define vmpath (&vmail)[1]
1972# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001973#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001974# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001975#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001976#define vps1 (&vpath)[1]
1977#define vps2 (&vps1)[1]
1978#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001979#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001980# define voptind (&vps4)[1]
1981# if ENABLE_ASH_RANDOM_SUPPORT
1982# define vrandom (&voptind)[1]
1983# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001984#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001985# if ENABLE_ASH_RANDOM_SUPPORT
1986# define vrandom (&vps4)[1]
1987# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001988#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001989
1990/*
1991 * The following macros access the values of the above variables.
1992 * They have to skip over the name. They return the null string
1993 * for unset variables.
1994 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001995#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001996#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001997#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001998# define mailval() (vmail.var_text + 5)
1999# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002000# define mpathset() ((vmpath.flags & VUNSET) == 0)
2001#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002002#define pathval() (vpath.var_text + 5)
2003#define ps1val() (vps1.var_text + 4)
2004#define ps2val() (vps2.var_text + 4)
2005#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002006#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002007# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002008#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002009
Denis Vlasenko01631112007-12-16 17:20:38 +00002010#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002011static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002012getoptsreset(const char *value)
2013{
Denys Vlasenkoa513bf32016-10-26 02:03:37 +02002014 shellparam.optind = number(value) ?: 1;
Denis Vlasenko01631112007-12-16 17:20:38 +00002015 shellparam.optoff = -1;
2016}
2017#endif
2018
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002019/*
2020 * Compares two strings up to the first = or '\0'. The first
2021 * string must be terminated by '='; the second may be terminated by
2022 * either '=' or '\0'.
2023 */
2024static int
2025varcmp(const char *p, const char *q)
2026{
2027 int c, d;
2028
2029 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002030 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002031 goto out;
2032 p++;
2033 q++;
2034 }
2035 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002036 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002037 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002038 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002039 out:
2040 return c - d;
2041}
2042
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002043/*
2044 * Find the appropriate entry in the hash table from the name.
2045 */
2046static struct var **
2047hashvar(const char *p)
2048{
2049 unsigned hashval;
2050
2051 hashval = ((unsigned char) *p) << 4;
2052 while (*p && *p != '=')
2053 hashval += (unsigned char) *p++;
2054 return &vartab[hashval % VTABSIZE];
2055}
2056
2057static int
2058vpcmp(const void *a, const void *b)
2059{
2060 return varcmp(*(const char **)a, *(const char **)b);
2061}
2062
2063/*
2064 * This routine initializes the builtin variables.
2065 */
2066static void
2067initvar(void)
2068{
2069 struct var *vp;
2070 struct var *end;
2071 struct var **vpp;
2072
2073 /*
2074 * PS1 depends on uid
2075 */
2076#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002077 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002078#else
2079 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002080 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002081#endif
2082 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002083 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002084 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002085 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002086 vp->next = *vpp;
2087 *vpp = vp;
2088 } while (++vp < end);
2089}
2090
2091static struct var **
2092findvar(struct var **vpp, const char *name)
2093{
2094 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002095 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002096 break;
2097 }
2098 }
2099 return vpp;
2100}
2101
2102/*
2103 * Find the value of a variable. Returns NULL if not set.
2104 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002105static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002106lookupvar(const char *name)
2107{
2108 struct var *v;
2109
2110 v = *findvar(hashvar(name), name);
2111 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002112#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002113 /*
2114 * Dynamic variables are implemented roughly the same way they are
2115 * in bash. Namely, they're "special" so long as they aren't unset.
2116 * As soon as they're unset, they're no longer dynamic, and dynamic
2117 * lookup will no longer happen at that point. -- PFM.
2118 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002119 if (v->flags & VDYNAMIC)
2120 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002121#endif
2122 if (!(v->flags & VUNSET))
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002123 return var_end(v->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002124 }
2125 return NULL;
2126}
2127
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02002128static void
2129reinit_unicode_for_ash(void)
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002130{
2131 /* Unicode support should be activated even if LANG is set
2132 * _during_ shell execution, not only if it was set when
2133 * shell was started. Therefore, re-check LANG every time:
2134 */
2135 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2136 || ENABLE_UNICODE_USING_LOCALE
2137 ) {
2138 const char *s = lookupvar("LC_ALL");
2139 if (!s) s = lookupvar("LC_CTYPE");
2140 if (!s) s = lookupvar("LANG");
2141 reinit_unicode(s);
2142 }
2143}
2144
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002145/*
2146 * Search the environment of a builtin command.
2147 */
Mike Frysinger98c52642009-04-02 10:02:37 +00002148static const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002149bltinlookup(const char *name)
2150{
2151 struct strlist *sp;
2152
2153 for (sp = cmdenviron; sp; sp = sp->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002154 if (varcmp(sp->text, name) == 0)
2155 return var_end(sp->text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002156 }
2157 return lookupvar(name);
2158}
2159
2160/*
2161 * Same as setvar except that the variable and value are passed in
2162 * the first argument as name=value. Since the first argument will
2163 * be actually stored in the table, it should not be a string that
2164 * will go away.
2165 * Called with interrupts off.
2166 */
2167static void
2168setvareq(char *s, int flags)
2169{
2170 struct var *vp, **vpp;
2171
2172 vpp = hashvar(s);
2173 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2174 vp = *findvar(vpp, s);
2175 if (vp) {
2176 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2177 const char *n;
2178
2179 if (flags & VNOSAVE)
2180 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002181 n = vp->var_text;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02002182 exitstatus = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002183 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2184 }
2185
2186 if (flags & VNOSET)
2187 return;
2188
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002189 if (vp->var_func && !(flags & VNOFUNC))
2190 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002191
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002192 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2193 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002194
2195 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2196 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002197 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002198 if (flags & VNOSET)
2199 return;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002200 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002201 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002202 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002203 *vpp = vp;
2204 }
2205 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2206 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002207 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002208 vp->flags = flags;
2209}
2210
2211/*
2212 * Set the value of a variable. The flags argument is ored with the
2213 * flags of the variable. If val is NULL, the variable is unset.
2214 */
2215static void
2216setvar(const char *name, const char *val, int flags)
2217{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002218 const char *q;
2219 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002220 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002221 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002222 size_t vallen;
2223
2224 q = endofname(name);
2225 p = strchrnul(q, '=');
2226 namelen = p - name;
2227 if (!namelen || p != q)
2228 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2229 vallen = 0;
2230 if (val == NULL) {
2231 flags |= VUNSET;
2232 } else {
2233 vallen = strlen(val);
2234 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002235
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002236 INT_OFF;
2237 nameeq = ckmalloc(namelen + vallen + 2);
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002238 p = memcpy(nameeq, name, namelen) + namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002239 if (val) {
2240 *p++ = '=';
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002241 p = memcpy(p, val, vallen) + vallen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002242 }
2243 *p = '\0';
2244 setvareq(nameeq, flags | VNOSAVE);
2245 INT_ON;
2246}
2247
Denys Vlasenko03dad222010-01-12 23:29:57 +01002248static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002249setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002250{
2251 setvar(name, val, 0);
2252}
2253
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002254/*
2255 * Unset the specified variable.
2256 */
2257static int
2258unsetvar(const char *s)
2259{
2260 struct var **vpp;
2261 struct var *vp;
2262 int retval;
2263
2264 vpp = findvar(hashvar(s), s);
2265 vp = *vpp;
2266 retval = 2;
2267 if (vp) {
2268 int flags = vp->flags;
2269
2270 retval = 1;
2271 if (flags & VREADONLY)
2272 goto out;
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002273#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002274 vp->flags &= ~VDYNAMIC;
2275#endif
2276 if (flags & VUNSET)
2277 goto ok;
2278 if ((flags & VSTRFIXED) == 0) {
2279 INT_OFF;
2280 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002281 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002282 *vpp = vp->next;
2283 free(vp);
2284 INT_ON;
2285 } else {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002286 setvar0(s, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002287 vp->flags &= ~VEXPORT;
2288 }
2289 ok:
2290 retval = 0;
2291 }
2292 out:
2293 return retval;
2294}
2295
2296/*
2297 * Process a linked list of variable assignments.
2298 */
2299static void
2300listsetvar(struct strlist *list_set_var, int flags)
2301{
2302 struct strlist *lp = list_set_var;
2303
2304 if (!lp)
2305 return;
2306 INT_OFF;
2307 do {
2308 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002309 lp = lp->next;
2310 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002311 INT_ON;
2312}
2313
2314/*
2315 * Generate a list of variables satisfying the given conditions.
2316 */
2317static char **
2318listvars(int on, int off, char ***end)
2319{
2320 struct var **vpp;
2321 struct var *vp;
2322 char **ep;
2323 int mask;
2324
2325 STARTSTACKSTR(ep);
2326 vpp = vartab;
2327 mask = on | off;
2328 do {
2329 for (vp = *vpp; vp; vp = vp->next) {
2330 if ((vp->flags & mask) == on) {
2331 if (ep == stackstrend())
2332 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002333 *ep++ = (char*)vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002334 }
2335 }
2336 } while (++vpp < vartab + VTABSIZE);
2337 if (ep == stackstrend())
2338 ep = growstackstr();
2339 if (end)
2340 *end = ep;
2341 *ep++ = NULL;
2342 return grabstackstr(ep);
2343}
2344
2345
2346/* ============ Path search helper
2347 *
2348 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002349 * of the path before the first call; path_advance will update
2350 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002351 * the possible path expansions in sequence. If an option (indicated by
2352 * a percent sign) appears in the path entry then the global variable
2353 * pathopt will be set to point to it; otherwise pathopt will be set to
2354 * NULL.
2355 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002356static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002357
2358static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002359path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002360{
2361 const char *p;
2362 char *q;
2363 const char *start;
2364 size_t len;
2365
2366 if (*path == NULL)
2367 return NULL;
2368 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002369 for (p = start; *p && *p != ':' && *p != '%'; p++)
2370 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002371 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2372 while (stackblocksize() < len)
2373 growstackblock();
2374 q = stackblock();
2375 if (p != start) {
2376 memcpy(q, start, p - start);
2377 q += p - start;
2378 *q++ = '/';
2379 }
2380 strcpy(q, name);
2381 pathopt = NULL;
2382 if (*p == '%') {
2383 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002384 while (*p && *p != ':')
2385 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002386 }
2387 if (*p == ':')
2388 *path = p + 1;
2389 else
2390 *path = NULL;
2391 return stalloc(len);
2392}
2393
2394
2395/* ============ Prompt */
2396
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002397static smallint doprompt; /* if set, prompt the user */
2398static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002399
2400#if ENABLE_FEATURE_EDITING
2401static line_input_t *line_input_state;
2402static const char *cmdedit_prompt;
2403static void
2404putprompt(const char *s)
2405{
2406 if (ENABLE_ASH_EXPAND_PRMT) {
2407 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002408 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002409 return;
2410 }
2411 cmdedit_prompt = s;
2412}
2413#else
2414static void
2415putprompt(const char *s)
2416{
2417 out2str(s);
2418}
2419#endif
2420
2421#if ENABLE_ASH_EXPAND_PRMT
2422/* expandstr() needs parsing machinery, so it is far away ahead... */
2423static const char *expandstr(const char *ps);
2424#else
2425#define expandstr(s) s
2426#endif
2427
2428static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002429setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002430{
2431 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002432 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2433
2434 if (!do_set)
2435 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002436
2437 needprompt = 0;
2438
2439 switch (whichprompt) {
2440 case 1:
2441 prompt = ps1val();
2442 break;
2443 case 2:
2444 prompt = ps2val();
2445 break;
2446 default: /* 0 */
2447 prompt = nullstr;
2448 }
2449#if ENABLE_ASH_EXPAND_PRMT
Denys Vlasenko60ca8342016-09-30 11:21:21 +02002450 pushstackmark(&smark, stackblocksize());
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002451#endif
2452 putprompt(expandstr(prompt));
2453#if ENABLE_ASH_EXPAND_PRMT
2454 popstackmark(&smark);
2455#endif
2456}
2457
2458
2459/* ============ The cd and pwd commands */
2460
2461#define CD_PHYSICAL 1
2462#define CD_PRINT 2
2463
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002464static int
2465cdopt(void)
2466{
2467 int flags = 0;
2468 int i, j;
2469
2470 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002471 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002472 if (i != j) {
2473 flags ^= CD_PHYSICAL;
2474 j = i;
2475 }
2476 }
2477
2478 return flags;
2479}
2480
2481/*
2482 * Update curdir (the name of the current directory) in response to a
2483 * cd command.
2484 */
2485static const char *
2486updatepwd(const char *dir)
2487{
2488 char *new;
2489 char *p;
2490 char *cdcomppath;
2491 const char *lim;
2492
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02002493 cdcomppath = sstrdup(dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002494 STARTSTACKSTR(new);
2495 if (*dir != '/') {
2496 if (curdir == nullstr)
2497 return 0;
2498 new = stack_putstr(curdir, new);
2499 }
2500 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002501 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002502 if (*dir != '/') {
2503 if (new[-1] != '/')
2504 USTPUTC('/', new);
2505 if (new > lim && *lim == '/')
2506 lim++;
2507 } else {
2508 USTPUTC('/', new);
2509 cdcomppath++;
2510 if (dir[1] == '/' && dir[2] != '/') {
2511 USTPUTC('/', new);
2512 cdcomppath++;
2513 lim++;
2514 }
2515 }
2516 p = strtok(cdcomppath, "/");
2517 while (p) {
2518 switch (*p) {
2519 case '.':
2520 if (p[1] == '.' && p[2] == '\0') {
2521 while (new > lim) {
2522 STUNPUTC(new);
2523 if (new[-1] == '/')
2524 break;
2525 }
2526 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002527 }
2528 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002529 break;
2530 /* fall through */
2531 default:
2532 new = stack_putstr(p, new);
2533 USTPUTC('/', new);
2534 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002535 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002536 }
2537 if (new > lim)
2538 STUNPUTC(new);
2539 *new = 0;
2540 return stackblock();
2541}
2542
2543/*
2544 * Find out what the current directory is. If we already know the current
2545 * directory, this routine returns immediately.
2546 */
2547static char *
2548getpwd(void)
2549{
Denis Vlasenko01631112007-12-16 17:20:38 +00002550 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002551 return dir ? dir : nullstr;
2552}
2553
2554static void
2555setpwd(const char *val, int setold)
2556{
2557 char *oldcur, *dir;
2558
2559 oldcur = dir = curdir;
2560
2561 if (setold) {
2562 setvar("OLDPWD", oldcur, VEXPORT);
2563 }
2564 INT_OFF;
2565 if (physdir != nullstr) {
2566 if (physdir != oldcur)
2567 free(physdir);
2568 physdir = nullstr;
2569 }
2570 if (oldcur == val || !val) {
2571 char *s = getpwd();
2572 physdir = s;
2573 if (!val)
2574 dir = s;
2575 } else
2576 dir = ckstrdup(val);
2577 if (oldcur != dir && oldcur != nullstr) {
2578 free(oldcur);
2579 }
2580 curdir = dir;
2581 INT_ON;
2582 setvar("PWD", dir, VEXPORT);
2583}
2584
2585static void hashcd(void);
2586
2587/*
Denys Vlasenko70392332016-10-27 02:31:55 +02002588 * Actually do the chdir. We also call hashcd to let other routines
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002589 * know that the current directory has changed.
2590 */
2591static int
2592docd(const char *dest, int flags)
2593{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002594 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002595 int err;
2596
2597 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2598
2599 INT_OFF;
2600 if (!(flags & CD_PHYSICAL)) {
2601 dir = updatepwd(dest);
2602 if (dir)
2603 dest = dir;
2604 }
2605 err = chdir(dest);
2606 if (err)
2607 goto out;
2608 setpwd(dir, 1);
2609 hashcd();
2610 out:
2611 INT_ON;
2612 return err;
2613}
2614
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002615static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002616cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002617{
2618 const char *dest;
2619 const char *path;
2620 const char *p;
2621 char c;
2622 struct stat statb;
2623 int flags;
2624
2625 flags = cdopt();
2626 dest = *argptr;
2627 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002628 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002629 else if (LONE_DASH(dest)) {
2630 dest = bltinlookup("OLDPWD");
2631 flags |= CD_PRINT;
2632 }
2633 if (!dest)
2634 dest = nullstr;
2635 if (*dest == '/')
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002636 goto step6;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002637 if (*dest == '.') {
2638 c = dest[1];
2639 dotdot:
2640 switch (c) {
2641 case '\0':
2642 case '/':
2643 goto step6;
2644 case '.':
2645 c = dest[2];
2646 if (c != '.')
2647 goto dotdot;
2648 }
2649 }
2650 if (!*dest)
2651 dest = ".";
2652 path = bltinlookup("CDPATH");
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002653 while (path) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002654 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002655 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002656 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2657 if (c && c != ':')
2658 flags |= CD_PRINT;
2659 docd:
2660 if (!docd(p, flags))
2661 goto out;
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002662 goto err;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002663 }
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002664 }
2665
2666 step6:
2667 p = dest;
2668 goto docd;
2669
2670 err:
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002671 ash_msg_and_raise_error("can't cd to %s", dest);
2672 /* NOTREACHED */
2673 out:
2674 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002675 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002676 return 0;
2677}
2678
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002679static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002680pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002681{
2682 int flags;
2683 const char *dir = curdir;
2684
2685 flags = cdopt();
2686 if (flags) {
2687 if (physdir == nullstr)
2688 setpwd(dir, 0);
2689 dir = physdir;
2690 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002691 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002692 return 0;
2693}
2694
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002695
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002696/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002697
Denis Vlasenko834dee72008-10-07 09:18:30 +00002698
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002699#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002700
Eric Andersenc470f442003-07-28 09:56:35 +00002701/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002702#define CWORD 0 /* character is nothing special */
2703#define CNL 1 /* newline character */
2704#define CBACK 2 /* a backslash character */
2705#define CSQUOTE 3 /* single quote */
2706#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002707#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002708#define CBQUOTE 6 /* backwards single quote */
2709#define CVAR 7 /* a dollar sign */
2710#define CENDVAR 8 /* a '}' character */
2711#define CLP 9 /* a left paren in arithmetic */
2712#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002713#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002714#define CCTL 12 /* like CWORD, except it must be escaped */
2715#define CSPCL 13 /* these terminate a word */
2716#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002717
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002718#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002719#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002720# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002721#endif
2722
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002723#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002724
Mike Frysinger98c52642009-04-02 10:02:37 +00002725#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002726# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002727#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002728# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002729#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002730static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002731#if ENABLE_ASH_ALIAS
2732 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2733#endif
2734 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2735 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2736 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2737 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2738 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2739 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2740 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2741 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2742 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2743 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2744 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002745#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002746 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2747 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2748 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2749#endif
2750#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002751};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002752/* Constants below must match table above */
2753enum {
2754#if ENABLE_ASH_ALIAS
2755 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2756#endif
2757 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2758 CNL_CNL_CNL_CNL , /* 2 */
2759 CWORD_CCTL_CCTL_CWORD , /* 3 */
2760 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2761 CVAR_CVAR_CWORD_CVAR , /* 5 */
2762 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2763 CSPCL_CWORD_CWORD_CLP , /* 7 */
2764 CSPCL_CWORD_CWORD_CRP , /* 8 */
2765 CBACK_CBACK_CCTL_CBACK , /* 9 */
2766 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2767 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2768 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2769 CWORD_CWORD_CWORD_CWORD , /* 13 */
2770 CCTL_CCTL_CCTL_CCTL , /* 14 */
2771};
Eric Andersen2870d962001-07-02 17:27:21 +00002772
Denys Vlasenkocd716832009-11-28 22:14:02 +01002773/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2774 * caller must ensure proper cast on it if c is *char_ptr!
2775 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002776/* Values for syntax param */
2777#define BASESYNTAX 0 /* not in quotes */
2778#define DQSYNTAX 1 /* in double quotes */
2779#define SQSYNTAX 2 /* in single quotes */
2780#define ARISYNTAX 3 /* in arithmetic */
2781#define PSSYNTAX 4 /* prompt. never passed to SIT() */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002782
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002783#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002784
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002785static int
2786SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002787{
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002788 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2789 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2790 /*
2791 * This causes '/' to be prepended with CTLESC in dquoted string,
2792 * making "./file"* treated incorrectly because we feed
2793 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2794 * The "homegrown" glob implementation is okay with that,
2795 * but glibc one isn't. With '/' always treated as CWORD,
2796 * both work fine.
2797 */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002798# if ENABLE_ASH_ALIAS
2799 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002800 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002801 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002802 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2803 11, 3 /* "}~" */
2804 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002805# else
2806 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002807 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002808 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002809 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2810 10, 2 /* "}~" */
2811 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002812# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002813 const char *s;
2814 int indx;
2815
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002816 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002817 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002818# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002819 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002820 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002821 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002822# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002823 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002824 /* Cast is purely for paranoia here,
2825 * just in case someone passed signed char to us */
2826 if ((unsigned char)c >= CTL_FIRST
2827 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002828 ) {
2829 return CCTL;
2830 }
2831 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002832 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002833 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002834 indx = syntax_index_table[s - spec_symbls];
2835 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002836 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002837}
2838
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002839#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002840
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002841static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002842 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002843 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2844 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2845 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2846 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2847 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2848 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2849 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2850 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2851 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2852 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2853 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2854 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2855 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2856 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2857 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2858 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2859 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2860 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2861 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2862 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2867 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2872 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2876 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2877 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2878 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2879 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2880 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2881 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2882 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2883 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2884 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2885 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2886 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2887 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2888 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2889 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002890/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
2891 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkocd716832009-11-28 22:14:02 +01002892 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2893 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2894 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2895 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2896 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2897 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2898 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2899 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2900 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2901 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2902 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2903 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2904 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2905 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2906 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2907 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2908 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2909 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2910 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2911 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2912 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2913 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2914 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2915 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2916 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2917 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2918 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2919 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2920 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2921 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2922 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2923 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2924 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2925 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2926 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2927 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2928 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2929 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2936 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2937 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2938 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2941 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
2969 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2970 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
2971 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
2972 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2973 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2974 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2975 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2976 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2977 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2978 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2979 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2980 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2981 /* 137 */ CWORD_CWORD_CWORD_CWORD,
2982 /* 138 */ CWORD_CWORD_CWORD_CWORD,
2983 /* 139 */ CWORD_CWORD_CWORD_CWORD,
2984 /* 140 */ CWORD_CWORD_CWORD_CWORD,
2985 /* 141 */ CWORD_CWORD_CWORD_CWORD,
2986 /* 142 */ CWORD_CWORD_CWORD_CWORD,
2987 /* 143 */ CWORD_CWORD_CWORD_CWORD,
2988 /* 144 */ CWORD_CWORD_CWORD_CWORD,
2989 /* 145 */ CWORD_CWORD_CWORD_CWORD,
2990 /* 146 */ CWORD_CWORD_CWORD_CWORD,
2991 /* 147 */ CWORD_CWORD_CWORD_CWORD,
2992 /* 148 */ CWORD_CWORD_CWORD_CWORD,
2993 /* 149 */ CWORD_CWORD_CWORD_CWORD,
2994 /* 150 */ CWORD_CWORD_CWORD_CWORD,
2995 /* 151 */ CWORD_CWORD_CWORD_CWORD,
2996 /* 152 */ CWORD_CWORD_CWORD_CWORD,
2997 /* 153 */ CWORD_CWORD_CWORD_CWORD,
2998 /* 154 */ CWORD_CWORD_CWORD_CWORD,
2999 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3000 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3001 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3002 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3003 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3004 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3005 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3006 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3007 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3008 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3009 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3010 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3011 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3012 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3013 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3014 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3015 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3016 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3017 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3018 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3019 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3020 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3021 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3029 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3042 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3047 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003100 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003101# if ENABLE_ASH_ALIAS
3102 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3103# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003104};
3105
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003106# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003107
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003108#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003109
Eric Andersen2870d962001-07-02 17:27:21 +00003110
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003111/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003112
Denis Vlasenko131ae172007-02-18 13:00:19 +00003113#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003114
3115#define ALIASINUSE 1
3116#define ALIASDEAD 2
3117
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003118struct alias {
3119 struct alias *next;
3120 char *name;
3121 char *val;
3122 int flag;
3123};
3124
Denis Vlasenko01631112007-12-16 17:20:38 +00003125
3126static struct alias **atab; // [ATABSIZE];
3127#define INIT_G_alias() do { \
3128 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3129} while (0)
3130
Eric Andersen2870d962001-07-02 17:27:21 +00003131
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003132static struct alias **
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02003133__lookupalias(const char *name)
3134{
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003135 unsigned int hashval;
3136 struct alias **app;
3137 const char *p;
3138 unsigned int ch;
3139
3140 p = name;
3141
3142 ch = (unsigned char)*p;
3143 hashval = ch << 4;
3144 while (ch) {
3145 hashval += ch;
3146 ch = (unsigned char)*++p;
3147 }
3148 app = &atab[hashval % ATABSIZE];
3149
3150 for (; *app; app = &(*app)->next) {
3151 if (strcmp(name, (*app)->name) == 0) {
3152 break;
3153 }
3154 }
3155
3156 return app;
3157}
3158
3159static struct alias *
3160lookupalias(const char *name, int check)
3161{
3162 struct alias *ap = *__lookupalias(name);
3163
3164 if (check && ap && (ap->flag & ALIASINUSE))
3165 return NULL;
3166 return ap;
3167}
3168
3169static struct alias *
3170freealias(struct alias *ap)
3171{
3172 struct alias *next;
3173
3174 if (ap->flag & ALIASINUSE) {
3175 ap->flag |= ALIASDEAD;
3176 return ap;
3177 }
3178
3179 next = ap->next;
3180 free(ap->name);
3181 free(ap->val);
3182 free(ap);
3183 return next;
3184}
Eric Andersencb57d552001-06-28 07:25:16 +00003185
Eric Andersenc470f442003-07-28 09:56:35 +00003186static void
3187setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003188{
3189 struct alias *ap, **app;
3190
3191 app = __lookupalias(name);
3192 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003193 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003194 if (ap) {
3195 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003196 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003197 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003198 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003199 ap->flag &= ~ALIASDEAD;
3200 } else {
3201 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003202 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003203 ap->name = ckstrdup(name);
3204 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003205 /*ap->flag = 0; - ckzalloc did it */
3206 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003207 *app = ap;
3208 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003209 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003210}
3211
Eric Andersenc470f442003-07-28 09:56:35 +00003212static int
3213unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003214{
Eric Andersencb57d552001-06-28 07:25:16 +00003215 struct alias **app;
3216
3217 app = __lookupalias(name);
3218
3219 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003220 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003221 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003222 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003223 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003224 }
3225
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003226 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003227}
3228
Eric Andersenc470f442003-07-28 09:56:35 +00003229static void
3230rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003231{
Eric Andersencb57d552001-06-28 07:25:16 +00003232 struct alias *ap, **app;
3233 int i;
3234
Denis Vlasenkob012b102007-02-19 22:43:01 +00003235 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003236 for (i = 0; i < ATABSIZE; i++) {
3237 app = &atab[i];
3238 for (ap = *app; ap; ap = *app) {
3239 *app = freealias(*app);
3240 if (ap == *app) {
3241 app = &ap->next;
3242 }
3243 }
3244 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003245 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003246}
3247
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003248static void
3249printalias(const struct alias *ap)
3250{
3251 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3252}
3253
Eric Andersencb57d552001-06-28 07:25:16 +00003254/*
3255 * TODO - sort output
3256 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003257static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003258aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003259{
3260 char *n, *v;
3261 int ret = 0;
3262 struct alias *ap;
3263
Denis Vlasenko68404f12008-03-17 09:00:54 +00003264 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003265 int i;
3266
Denis Vlasenko68404f12008-03-17 09:00:54 +00003267 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003268 for (ap = atab[i]; ap; ap = ap->next) {
3269 printalias(ap);
3270 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003271 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003272 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003273 }
3274 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003275 v = strchr(n+1, '=');
3276 if (v == NULL) { /* n+1: funny ksh stuff */
3277 ap = *__lookupalias(n);
3278 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003279 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003280 ret = 1;
3281 } else
3282 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003283 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003284 *v++ = '\0';
3285 setalias(n, v);
3286 }
3287 }
3288
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003289 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003290}
3291
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003292static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003293unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003294{
3295 int i;
3296
3297 while ((i = nextopt("a")) != '\0') {
3298 if (i == 'a') {
3299 rmaliases();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003300 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003301 }
3302 }
3303 for (i = 0; *argptr; argptr++) {
3304 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003305 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003306 i = 1;
3307 }
3308 }
3309
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003310 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003311}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003312
Denis Vlasenko131ae172007-02-18 13:00:19 +00003313#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003314
Eric Andersenc470f442003-07-28 09:56:35 +00003315
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003316/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003317#define FORK_FG 0
3318#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003319#define FORK_NOJOB 2
3320
3321/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003322#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3323#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3324#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003325#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003326
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003327/*
3328 * A job structure contains information about a job. A job is either a
3329 * single process or a set of processes contained in a pipeline. In the
3330 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3331 * array of pids.
3332 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003333struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003334 pid_t ps_pid; /* process id */
3335 int ps_status; /* last process status from wait() */
3336 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003337};
3338
3339struct job {
3340 struct procstat ps0; /* status of process */
3341 struct procstat *ps; /* status or processes when more than one */
3342#if JOBS
3343 int stopstatus; /* status of a stopped job */
3344#endif
3345 uint32_t
3346 nprocs: 16, /* number of processes */
3347 state: 8,
3348#define JOBRUNNING 0 /* at least one proc running */
3349#define JOBSTOPPED 1 /* all procs are stopped */
3350#define JOBDONE 2 /* all procs are completed */
3351#if JOBS
3352 sigint: 1, /* job was killed by SIGINT */
3353 jobctl: 1, /* job running under job control */
3354#endif
3355 waited: 1, /* true if this entry has been waited for */
3356 used: 1, /* true if this entry is in used */
3357 changed: 1; /* true if status has changed */
3358 struct job *prev_job; /* previous job */
3359};
3360
Denis Vlasenko68404f12008-03-17 09:00:54 +00003361static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003362static int forkshell(struct job *, union node *, int);
3363static int waitforjob(struct job *);
3364
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003365#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003366enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003367#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003368#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003369static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003370static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003371#endif
3372
3373/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003374 * Ignore a signal.
3375 */
3376static void
3377ignoresig(int signo)
3378{
3379 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3380 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3381 /* No, need to do it */
3382 signal(signo, SIG_IGN);
3383 }
3384 sigmode[signo - 1] = S_HARD_IGN;
3385}
3386
3387/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003388 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003389 */
3390static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003391signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003392{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003393 if (signo == SIGCHLD) {
3394 got_sigchld = 1;
3395 if (!trap[SIGCHLD])
3396 return;
3397 }
3398
Denis Vlasenko4b875702009-03-19 13:30:04 +00003399 gotsig[signo - 1] = 1;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003400 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003401
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003402 if (signo == SIGINT && !trap[SIGINT]) {
3403 if (!suppress_int) {
3404 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003405 raise_interrupt(); /* does not return */
3406 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003407 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003408 }
3409}
3410
3411/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003412 * Set the signal handler for the specified signal. The routine figures
3413 * out what it should be set to.
3414 */
3415static void
3416setsignal(int signo)
3417{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003418 char *t;
3419 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003420 struct sigaction act;
3421
3422 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003423 new_act = S_DFL;
3424 if (t != NULL) { /* trap for this sig is set */
3425 new_act = S_CATCH;
3426 if (t[0] == '\0') /* trap is "": ignore this sig */
3427 new_act = S_IGN;
3428 }
3429
3430 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003431 switch (signo) {
3432 case SIGINT:
3433 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003434 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003435 break;
3436 case SIGQUIT:
3437#if DEBUG
3438 if (debug)
3439 break;
3440#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003441 /* man bash:
3442 * "In all cases, bash ignores SIGQUIT. Non-builtin
3443 * commands run by bash have signal handlers
3444 * set to the values inherited by the shell
3445 * from its parent". */
3446 new_act = S_IGN;
3447 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003448 case SIGTERM:
3449 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003450 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003451 break;
3452#if JOBS
3453 case SIGTSTP:
3454 case SIGTTOU:
3455 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003456 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003457 break;
3458#endif
3459 }
3460 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003461//TODO: if !rootshell, we reset SIGQUIT to DFL,
3462//whereas we have to restore it to what shell got on entry
3463//from the parent. See comment above
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003464
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003465 if (signo == SIGCHLD)
3466 new_act = S_CATCH;
3467
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003468 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003469 cur_act = *t;
3470 if (cur_act == 0) {
3471 /* current setting is not yet known */
3472 if (sigaction(signo, NULL, &act)) {
3473 /* pretend it worked; maybe we should give a warning,
3474 * but other shells don't. We don't alter sigmode,
3475 * so we retry every time.
3476 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003477 return;
3478 }
3479 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003480 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003481 if (mflag
3482 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3483 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003484 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003485 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003486 }
3487 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003488 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003489 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003490
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003491 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003492 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003493 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003494 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003495 break;
3496 case S_IGN:
3497 act.sa_handler = SIG_IGN;
3498 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003499 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003500
3501 /* flags and mask matter only if !DFL and !IGN, but we do it
3502 * for all cases for more deterministic behavior:
3503 */
3504 act.sa_flags = 0;
3505 sigfillset(&act.sa_mask);
3506
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003507 sigaction_set(signo, &act);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003508
3509 *t = new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003510}
3511
3512/* mode flags for set_curjob */
3513#define CUR_DELETE 2
3514#define CUR_RUNNING 1
3515#define CUR_STOPPED 0
3516
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003517#if JOBS
3518/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003519static int initialpgrp; //references:2
3520static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003521#endif
3522/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003523static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003524/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003525static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003526/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003527static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003528/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003529static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003530
3531static void
3532set_curjob(struct job *jp, unsigned mode)
3533{
3534 struct job *jp1;
3535 struct job **jpp, **curp;
3536
3537 /* first remove from list */
3538 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003539 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003540 jp1 = *jpp;
3541 if (jp1 == jp)
3542 break;
3543 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003544 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003545 *jpp = jp1->prev_job;
3546
3547 /* Then re-insert in correct position */
3548 jpp = curp;
3549 switch (mode) {
3550 default:
3551#if DEBUG
3552 abort();
3553#endif
3554 case CUR_DELETE:
3555 /* job being deleted */
3556 break;
3557 case CUR_RUNNING:
3558 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003559 * put after all stopped jobs.
3560 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003561 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003562 jp1 = *jpp;
3563#if JOBS
3564 if (!jp1 || jp1->state != JOBSTOPPED)
3565#endif
3566 break;
3567 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003568 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003569 /* FALLTHROUGH */
3570#if JOBS
3571 case CUR_STOPPED:
3572#endif
3573 /* newly stopped job - becomes curjob */
3574 jp->prev_job = *jpp;
3575 *jpp = jp;
3576 break;
3577 }
3578}
3579
3580#if JOBS || DEBUG
3581static int
3582jobno(const struct job *jp)
3583{
3584 return jp - jobtab + 1;
3585}
3586#endif
3587
3588/*
3589 * Convert a job name to a job structure.
3590 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003591#if !JOBS
3592#define getjob(name, getctl) getjob(name)
3593#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003594static struct job *
3595getjob(const char *name, int getctl)
3596{
3597 struct job *jp;
3598 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003599 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003600 unsigned num;
3601 int c;
3602 const char *p;
3603 char *(*match)(const char *, const char *);
3604
3605 jp = curjob;
3606 p = name;
3607 if (!p)
3608 goto currentjob;
3609
3610 if (*p != '%')
3611 goto err;
3612
3613 c = *++p;
3614 if (!c)
3615 goto currentjob;
3616
3617 if (!p[1]) {
3618 if (c == '+' || c == '%') {
3619 currentjob:
3620 err_msg = "No current job";
3621 goto check;
3622 }
3623 if (c == '-') {
3624 if (jp)
3625 jp = jp->prev_job;
3626 err_msg = "No previous job";
3627 check:
3628 if (!jp)
3629 goto err;
3630 goto gotit;
3631 }
3632 }
3633
3634 if (is_number(p)) {
3635 num = atoi(p);
Denys Vlasenko46a45ce2016-09-29 01:10:08 +02003636 if (num > 0 && num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003637 jp = jobtab + num - 1;
3638 if (jp->used)
3639 goto gotit;
3640 goto err;
3641 }
3642 }
3643
3644 match = prefix;
3645 if (*p == '?') {
3646 match = strstr;
3647 p++;
3648 }
3649
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003650 found = NULL;
3651 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003652 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003653 if (found)
3654 goto err;
3655 found = jp;
3656 err_msg = "%s: ambiguous";
3657 }
3658 jp = jp->prev_job;
3659 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003660 if (!found)
3661 goto err;
3662 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003663
3664 gotit:
3665#if JOBS
3666 err_msg = "job %s not created under job control";
3667 if (getctl && jp->jobctl == 0)
3668 goto err;
3669#endif
3670 return jp;
3671 err:
3672 ash_msg_and_raise_error(err_msg, name);
3673}
3674
3675/*
3676 * Mark a job structure as unused.
3677 */
3678static void
3679freejob(struct job *jp)
3680{
3681 struct procstat *ps;
3682 int i;
3683
3684 INT_OFF;
3685 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003686 if (ps->ps_cmd != nullstr)
3687 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003688 }
3689 if (jp->ps != &jp->ps0)
3690 free(jp->ps);
3691 jp->used = 0;
3692 set_curjob(jp, CUR_DELETE);
3693 INT_ON;
3694}
3695
3696#if JOBS
3697static void
3698xtcsetpgrp(int fd, pid_t pgrp)
3699{
3700 if (tcsetpgrp(fd, pgrp))
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003701 ash_msg_and_raise_error("can't set tty process group (%m)");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003702}
3703
3704/*
3705 * Turn job control on and off.
3706 *
3707 * Note: This code assumes that the third arg to ioctl is a character
3708 * pointer, which is true on Berkeley systems but not System V. Since
3709 * System V doesn't have job control yet, this isn't a problem now.
3710 *
3711 * Called with interrupts off.
3712 */
3713static void
3714setjobctl(int on)
3715{
3716 int fd;
3717 int pgrp;
3718
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003719 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003720 return;
3721 if (on) {
3722 int ofd;
3723 ofd = fd = open(_PATH_TTY, O_RDWR);
3724 if (fd < 0) {
3725 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3726 * That sometimes helps to acquire controlling tty.
3727 * Obviously, a workaround for bugs when someone
3728 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003729 fd = 2;
3730 while (!isatty(fd))
3731 if (--fd < 0)
3732 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003733 }
Denys Vlasenko64774602016-10-26 15:24:30 +02003734 /* fd is a tty at this point */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003735 fd = fcntl(fd, F_DUPFD, 10);
Denys Vlasenko64774602016-10-26 15:24:30 +02003736 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, dont */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003737 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003738 if (fd < 0)
Denys Vlasenko64774602016-10-26 15:24:30 +02003739 goto out; /* F_DUPFD failed */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003740 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003741 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003742 pgrp = tcgetpgrp(fd);
3743 if (pgrp < 0) {
3744 out:
3745 ash_msg("can't access tty; job control turned off");
3746 mflag = on = 0;
3747 goto close;
3748 }
3749 if (pgrp == getpgrp())
3750 break;
3751 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003752 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003753 initialpgrp = pgrp;
3754
3755 setsignal(SIGTSTP);
3756 setsignal(SIGTTOU);
3757 setsignal(SIGTTIN);
3758 pgrp = rootpid;
3759 setpgid(0, pgrp);
3760 xtcsetpgrp(fd, pgrp);
3761 } else {
3762 /* turning job control off */
3763 fd = ttyfd;
3764 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003765 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003766 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003767 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003768 setpgid(0, pgrp);
3769 setsignal(SIGTSTP);
3770 setsignal(SIGTTOU);
3771 setsignal(SIGTTIN);
3772 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003773 if (fd >= 0)
3774 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003775 fd = -1;
3776 }
3777 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003778 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003779}
3780
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003781static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003782killcmd(int argc, char **argv)
3783{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003784 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003785 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003786 do {
3787 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003788 /*
3789 * "kill %N" - job kill
3790 * Converting to pgrp / pid kill
3791 */
3792 struct job *jp;
3793 char *dst;
3794 int j, n;
3795
3796 jp = getjob(argv[i], 0);
3797 /*
3798 * In jobs started under job control, we signal
3799 * entire process group by kill -PGRP_ID.
3800 * This happens, f.e., in interactive shell.
3801 *
3802 * Otherwise, we signal each child via
3803 * kill PID1 PID2 PID3.
3804 * Testcases:
3805 * sh -c 'sleep 1|sleep 1 & kill %1'
3806 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3807 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3808 */
3809 n = jp->nprocs; /* can't be 0 (I hope) */
3810 if (jp->jobctl)
3811 n = 1;
3812 dst = alloca(n * sizeof(int)*4);
3813 argv[i] = dst;
3814 for (j = 0; j < n; j++) {
3815 struct procstat *ps = &jp->ps[j];
3816 /* Skip non-running and not-stopped members
3817 * (i.e. dead members) of the job
3818 */
3819 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3820 continue;
3821 /*
3822 * kill_main has matching code to expect
3823 * leading space. Needed to not confuse
3824 * negative pids with "kill -SIGNAL_NO" syntax
3825 */
3826 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3827 }
3828 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003829 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003830 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003831 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003832 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003833}
3834
3835static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01003836showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003837{
Denys Vlasenko285ad152009-12-04 23:02:27 +01003838 struct procstat *ps;
3839 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003840
Denys Vlasenko285ad152009-12-04 23:02:27 +01003841 psend = jp->ps + jp->nprocs;
3842 for (ps = jp->ps + 1; ps < psend; ps++)
3843 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003844 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003845 flush_stdout_stderr();
3846}
3847
3848
3849static int
3850restartjob(struct job *jp, int mode)
3851{
3852 struct procstat *ps;
3853 int i;
3854 int status;
3855 pid_t pgid;
3856
3857 INT_OFF;
3858 if (jp->state == JOBDONE)
3859 goto out;
3860 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003861 pgid = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003862 if (mode == FORK_FG)
3863 xtcsetpgrp(ttyfd, pgid);
3864 killpg(pgid, SIGCONT);
3865 ps = jp->ps;
3866 i = jp->nprocs;
3867 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003868 if (WIFSTOPPED(ps->ps_status)) {
3869 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003870 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003871 ps++;
3872 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003873 out:
3874 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3875 INT_ON;
3876 return status;
3877}
3878
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003879static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003880fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003881{
3882 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003883 int mode;
3884 int retval;
3885
3886 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3887 nextopt(nullstr);
3888 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003889 do {
3890 jp = getjob(*argv, 1);
3891 if (mode == FORK_BG) {
3892 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01003893 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003894 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003895 out1str(jp->ps[0].ps_cmd);
3896 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003897 retval = restartjob(jp, mode);
3898 } while (*argv && *++argv);
3899 return retval;
3900}
3901#endif
3902
3903static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02003904sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003905{
3906 int col;
3907 int st;
3908
3909 col = 0;
3910 if (!WIFEXITED(status)) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003911 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003912 st = WSTOPSIG(status);
3913 else
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003914 st = WTERMSIG(status);
3915 if (sigonly) {
3916 if (st == SIGINT || st == SIGPIPE)
3917 goto out;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003918 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003919 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003920 }
3921 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01003922//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003923 col = fmtstr(s, 32, strsignal(st));
3924 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02003925 strcpy(s + col, " (core dumped)");
3926 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003927 }
3928 } else if (!sigonly) {
3929 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003930 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003931 }
3932 out:
3933 return col;
3934}
3935
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003936static int
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003937wait_block_or_sig(int *status)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003938{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003939 int pid;
3940
3941 do {
3942 /* Poll all children for changes in their state */
3943 got_sigchld = 0;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003944 /* if job control is active, accept stopped processes too */
3945 pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003946 if (pid != 0)
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003947 break; /* Error (e.g. EINTR, ECHILD) or pid */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003948
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003949 /* Children exist, but none are ready. Sleep until interesting signal */
3950#if 0 /* dash does this */
3951 sigset_t mask;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003952 sigfillset(&mask);
3953 sigprocmask(SIG_SETMASK, &mask, &mask);
3954 while (!got_sigchld && !pending_sig)
3955 sigsuspend(&mask);
3956 sigprocmask(SIG_SETMASK, &mask, NULL);
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003957#else
3958 while (!got_sigchld && !pending_sig)
3959 pause();
3960#endif
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003961
3962 /* If it was SIGCHLD, poll children again */
3963 } while (got_sigchld);
3964
3965 return pid;
3966}
3967
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003968#define DOWAIT_NONBLOCK 0
3969#define DOWAIT_BLOCK 1
3970#define DOWAIT_BLOCK_OR_SIG 2
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003971
3972static int
Denys Vlasenkob543bda2016-10-27 20:08:28 +02003973dowait(int block, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003974{
3975 int pid;
3976 int status;
3977 struct job *jp;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003978 struct job *thisjob = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003979
Denys Vlasenkob543bda2016-10-27 20:08:28 +02003980 TRACE(("dowait(0x%x) called\n", block));
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00003981
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003982 /* It's wrong to call waitpid() outside of INT_OFF region:
3983 * signal can arrive just after syscall return and handler can
3984 * longjmp away, losing stop/exit notification processing.
3985 * Thus, for "jobs" builtin, and for waiting for a fg job,
3986 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
3987 *
3988 * However, for "wait" builtin it is wrong to simply call waitpid()
3989 * in INT_OFF region: "wait" needs to wait for any running job
3990 * to change state, but should exit on any trap too.
3991 * In INT_OFF region, a signal just before syscall entry can set
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003992 * pending_sig variables, but we can't check them, and we would
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003993 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003994 *
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003995 * Because of this, we run inside INT_OFF, but use a special routine
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003996 * which combines waitpid() and pause().
3997 * This is the reason why we need to have a handler for SIGCHLD:
3998 * SIG_DFL handler does not wake pause().
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003999 */
4000 INT_OFF;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004001 if (block == DOWAIT_BLOCK_OR_SIG) {
4002 pid = wait_block_or_sig(&status);
4003 } else {
4004 int wait_flags = 0;
4005 if (block == DOWAIT_NONBLOCK)
4006 wait_flags = WNOHANG;
4007 /* if job control is active, accept stopped processes too */
4008 if (doing_jobctl)
4009 wait_flags |= WUNTRACED;
4010 /* NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004011 pid = waitpid(-1, &status, wait_flags);
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004012 }
Denis Vlasenkob21f3792009-03-19 23:09:58 +00004013 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4014 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004015 if (pid <= 0)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004016 goto out;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004017
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004018 thisjob = NULL;
4019 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004020 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004021 struct procstat *ps;
4022 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004023 if (jp->state == JOBDONE)
4024 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004025 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004026 ps = jp->ps;
4027 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004028 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004029 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004030 TRACE(("Job %d: changing status of proc %d "
4031 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01004032 jobno(jp), pid, ps->ps_status, status));
4033 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004034 thisjob = jp;
4035 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004036 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004037 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004038#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004039 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004040 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004041 if (WIFSTOPPED(ps->ps_status)) {
4042 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004043 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004044 }
4045#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004046 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004047 if (!thisjob)
4048 continue;
4049
4050 /* Found the job where one of its processes changed its state.
4051 * Is there at least one live and running process in this job? */
4052 if (jobstate != JOBRUNNING) {
4053 /* No. All live processes in the job are stopped
4054 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4055 */
4056 thisjob->changed = 1;
4057 if (thisjob->state != jobstate) {
4058 TRACE(("Job %d: changing state from %d to %d\n",
4059 jobno(thisjob), thisjob->state, jobstate));
4060 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004061#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004062 if (jobstate == JOBSTOPPED)
4063 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004064#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004065 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004066 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004067 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004068 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004069 /* The process wasn't found in job list */
4070 if (JOBS && !WIFSTOPPED(status))
4071 jobless--;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004072 out:
4073 INT_ON;
4074
4075 if (thisjob && thisjob == job) {
4076 char s[48 + 1];
4077 int len;
4078
Denys Vlasenko9c541002015-10-07 15:44:36 +02004079 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004080 if (len) {
4081 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004082 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004083 out2str(s);
4084 }
4085 }
4086 return pid;
4087}
4088
4089#if JOBS
4090static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004091showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004092{
4093 struct procstat *ps;
4094 struct procstat *psend;
4095 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004096 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004097 char s[16 + 16 + 48];
4098 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004099
4100 ps = jp->ps;
4101
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004102 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004103 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004104 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004105 return;
4106 }
4107
4108 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004109 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004110
4111 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004112 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004113 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004114 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004115
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004116 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004117 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004118
4119 psend = ps + jp->nprocs;
4120
4121 if (jp->state == JOBRUNNING) {
4122 strcpy(s + col, "Running");
4123 col += sizeof("Running") - 1;
4124 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004125 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004126 if (jp->state == JOBSTOPPED)
4127 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004128 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004129 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004130 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004131
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004132 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4133 * or prints several "PID | <cmdN>" lines,
4134 * depending on SHOW_PIDS bit.
4135 * We do not print status of individual processes
4136 * between PID and <cmdN>. bash does it, but not very well:
4137 * first line shows overall job status, not process status,
4138 * making it impossible to know 1st process status.
4139 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004140 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004141 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004142 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004143 s[0] = '\0';
4144 col = 33;
4145 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004146 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004147 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004148 fprintf(out, "%s%*c%s%s",
4149 s,
4150 33 - col >= 0 ? 33 - col : 0, ' ',
4151 ps == jp->ps ? "" : "| ",
4152 ps->ps_cmd
4153 );
4154 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004155 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004156
4157 jp->changed = 0;
4158
4159 if (jp->state == JOBDONE) {
4160 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4161 freejob(jp);
4162 }
4163}
4164
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004165/*
4166 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4167 * statuses have changed since the last call to showjobs.
4168 */
4169static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004170showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004171{
4172 struct job *jp;
4173
Denys Vlasenko883cea42009-07-11 15:31:59 +02004174 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004175
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004176 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004177 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004178 continue;
4179
4180 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004181 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004182 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004183 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004184 }
4185}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004186
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004187static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004188jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004189{
4190 int mode, m;
4191
4192 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004193 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004194 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004195 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004196 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004197 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004198 }
4199
4200 argv = argptr;
4201 if (*argv) {
4202 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004203 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004204 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004205 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004206 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004207 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004208
4209 return 0;
4210}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004211#endif /* JOBS */
4212
Michael Abbott359da5e2009-12-04 23:03:29 +01004213/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004214static int
4215getstatus(struct job *job)
4216{
4217 int status;
4218 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004219 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004220
Michael Abbott359da5e2009-12-04 23:03:29 +01004221 /* Fetch last member's status */
4222 ps = job->ps + job->nprocs - 1;
4223 status = ps->ps_status;
4224 if (pipefail) {
4225 /* "set -o pipefail" mode: use last _nonzero_ status */
4226 while (status == 0 && --ps >= job->ps)
4227 status = ps->ps_status;
4228 }
4229
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004230 retval = WEXITSTATUS(status);
4231 if (!WIFEXITED(status)) {
4232#if JOBS
4233 retval = WSTOPSIG(status);
4234 if (!WIFSTOPPED(status))
4235#endif
4236 {
4237 /* XXX: limits number of signals */
4238 retval = WTERMSIG(status);
4239#if JOBS
4240 if (retval == SIGINT)
4241 job->sigint = 1;
4242#endif
4243 }
4244 retval += 128;
4245 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004246 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004247 jobno(job), job->nprocs, status, retval));
4248 return retval;
4249}
4250
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004251static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004252waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004253{
4254 struct job *job;
4255 int retval;
4256 struct job *jp;
4257
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004258 nextopt(nullstr);
4259 retval = 0;
4260
4261 argv = argptr;
4262 if (!*argv) {
4263 /* wait for all jobs */
4264 for (;;) {
4265 jp = curjob;
4266 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004267 if (!jp) /* no running procs */
4268 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004269 if (jp->state == JOBRUNNING)
4270 break;
4271 jp->waited = 1;
4272 jp = jp->prev_job;
4273 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004274 /* man bash:
4275 * "When bash is waiting for an asynchronous command via
4276 * the wait builtin, the reception of a signal for which a trap
4277 * has been set will cause the wait builtin to return immediately
4278 * with an exit status greater than 128, immediately after which
4279 * the trap is executed."
Denys Vlasenko69188112016-10-27 20:18:18 +02004280 */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004281 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004282 /* if child sends us a signal *and immediately exits*,
4283 * dowait() returns pid > 0. Check this case,
4284 * not "if (dowait() < 0)"!
4285 */
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004286 if (pending_sig)
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004287 goto sigout;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004288 }
4289 }
4290
4291 retval = 127;
4292 do {
4293 if (**argv != '%') {
4294 pid_t pid = number(*argv);
4295 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004296 while (1) {
4297 if (!job)
4298 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004299 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004300 break;
4301 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004302 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004303 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004304 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004305 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004306 /* loop until process terminated or stopped */
Denys Vlasenko69188112016-10-27 20:18:18 +02004307 while (job->state == JOBRUNNING) {
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004308 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004309 if (pending_sig)
4310 goto sigout;
Denys Vlasenko69188112016-10-27 20:18:18 +02004311 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004312 job->waited = 1;
4313 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004314 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004315 } while (*++argv);
4316
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004317 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004318 return retval;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004319 sigout:
4320 retval = 128 + pending_sig;
4321 return retval;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004322}
4323
4324static struct job *
4325growjobtab(void)
4326{
4327 size_t len;
4328 ptrdiff_t offset;
4329 struct job *jp, *jq;
4330
4331 len = njobs * sizeof(*jp);
4332 jq = jobtab;
4333 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4334
4335 offset = (char *)jp - (char *)jq;
4336 if (offset) {
4337 /* Relocate pointers */
4338 size_t l = len;
4339
4340 jq = (struct job *)((char *)jq + l);
4341 while (l) {
4342 l -= sizeof(*jp);
4343 jq--;
4344#define joff(p) ((struct job *)((char *)(p) + l))
4345#define jmove(p) (p) = (void *)((char *)(p) + offset)
4346 if (joff(jp)->ps == &jq->ps0)
4347 jmove(joff(jp)->ps);
4348 if (joff(jp)->prev_job)
4349 jmove(joff(jp)->prev_job);
4350 }
4351 if (curjob)
4352 jmove(curjob);
4353#undef joff
4354#undef jmove
4355 }
4356
4357 njobs += 4;
4358 jobtab = jp;
4359 jp = (struct job *)((char *)jp + len);
4360 jq = jp + 3;
4361 do {
4362 jq->used = 0;
4363 } while (--jq >= jp);
4364 return jp;
4365}
4366
4367/*
4368 * Return a new job structure.
4369 * Called with interrupts off.
4370 */
4371static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004372makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004373{
4374 int i;
4375 struct job *jp;
4376
4377 for (i = njobs, jp = jobtab; ; jp++) {
4378 if (--i < 0) {
4379 jp = growjobtab();
4380 break;
4381 }
4382 if (jp->used == 0)
4383 break;
4384 if (jp->state != JOBDONE || !jp->waited)
4385 continue;
4386#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004387 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004388 continue;
4389#endif
4390 freejob(jp);
4391 break;
4392 }
4393 memset(jp, 0, sizeof(*jp));
4394#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004395 /* jp->jobctl is a bitfield.
4396 * "jp->jobctl |= jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004397 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004398 jp->jobctl = 1;
4399#endif
4400 jp->prev_job = curjob;
4401 curjob = jp;
4402 jp->used = 1;
4403 jp->ps = &jp->ps0;
4404 if (nprocs > 1) {
4405 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4406 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004407 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004408 jobno(jp)));
4409 return jp;
4410}
4411
4412#if JOBS
4413/*
4414 * Return a string identifying a command (to be printed by the
4415 * jobs command).
4416 */
4417static char *cmdnextc;
4418
4419static void
4420cmdputs(const char *s)
4421{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004422 static const char vstype[VSTYPE + 1][3] = {
4423 "", "}", "-", "+", "?", "=",
4424 "%", "%%", "#", "##"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00004425 IF_ASH_BASH_COMPAT(, ":", "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004426 };
4427
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004428 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004429 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004430 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004431 unsigned char c;
4432 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004433 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004434
Denys Vlasenko46a14772009-12-10 21:27:13 +01004435 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004436 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4437 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004438 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004439 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004440 switch (c) {
4441 case CTLESC:
4442 c = *p++;
4443 break;
4444 case CTLVAR:
4445 subtype = *p++;
4446 if ((subtype & VSTYPE) == VSLENGTH)
4447 str = "${#";
4448 else
4449 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004450 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004451 case CTLENDVAR:
4452 str = "\"}" + !(quoted & 1);
4453 quoted >>= 1;
4454 subtype = 0;
4455 goto dostr;
4456 case CTLBACKQ:
4457 str = "$(...)";
4458 goto dostr;
Mike Frysinger98c52642009-04-02 10:02:37 +00004459#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004460 case CTLARI:
4461 str = "$((";
4462 goto dostr;
4463 case CTLENDARI:
4464 str = "))";
4465 goto dostr;
4466#endif
4467 case CTLQUOTEMARK:
4468 quoted ^= 1;
4469 c = '"';
4470 break;
4471 case '=':
4472 if (subtype == 0)
4473 break;
4474 if ((subtype & VSTYPE) != VSNORMAL)
4475 quoted <<= 1;
4476 str = vstype[subtype & VSTYPE];
4477 if (subtype & VSNUL)
4478 c = ':';
4479 else
4480 goto checkstr;
4481 break;
4482 case '\'':
4483 case '\\':
4484 case '"':
4485 case '$':
4486 /* These can only happen inside quotes */
4487 cc[0] = c;
4488 str = cc;
4489 c = '\\';
4490 break;
4491 default:
4492 break;
4493 }
4494 USTPUTC(c, nextc);
4495 checkstr:
4496 if (!str)
4497 continue;
4498 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004499 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004500 USTPUTC(c, nextc);
4501 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004502 } /* while *p++ not NUL */
4503
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004504 if (quoted & 1) {
4505 USTPUTC('"', nextc);
4506 }
4507 *nextc = 0;
4508 cmdnextc = nextc;
4509}
4510
4511/* cmdtxt() and cmdlist() call each other */
4512static void cmdtxt(union node *n);
4513
4514static void
4515cmdlist(union node *np, int sep)
4516{
4517 for (; np; np = np->narg.next) {
4518 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004519 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004520 cmdtxt(np);
4521 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004522 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004523 }
4524}
4525
4526static void
4527cmdtxt(union node *n)
4528{
4529 union node *np;
4530 struct nodelist *lp;
4531 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004532
4533 if (!n)
4534 return;
4535 switch (n->type) {
4536 default:
4537#if DEBUG
4538 abort();
4539#endif
4540 case NPIPE:
4541 lp = n->npipe.cmdlist;
4542 for (;;) {
4543 cmdtxt(lp->n);
4544 lp = lp->next;
4545 if (!lp)
4546 break;
4547 cmdputs(" | ");
4548 }
4549 break;
4550 case NSEMI:
4551 p = "; ";
4552 goto binop;
4553 case NAND:
4554 p = " && ";
4555 goto binop;
4556 case NOR:
4557 p = " || ";
4558 binop:
4559 cmdtxt(n->nbinary.ch1);
4560 cmdputs(p);
4561 n = n->nbinary.ch2;
4562 goto donode;
4563 case NREDIR:
4564 case NBACKGND:
4565 n = n->nredir.n;
4566 goto donode;
4567 case NNOT:
4568 cmdputs("!");
4569 n = n->nnot.com;
4570 donode:
4571 cmdtxt(n);
4572 break;
4573 case NIF:
4574 cmdputs("if ");
4575 cmdtxt(n->nif.test);
4576 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004577 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004578 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004579 cmdputs("; else ");
4580 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004581 } else {
4582 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004583 }
4584 p = "; fi";
4585 goto dotail;
4586 case NSUBSHELL:
4587 cmdputs("(");
4588 n = n->nredir.n;
4589 p = ")";
4590 goto dotail;
4591 case NWHILE:
4592 p = "while ";
4593 goto until;
4594 case NUNTIL:
4595 p = "until ";
4596 until:
4597 cmdputs(p);
4598 cmdtxt(n->nbinary.ch1);
4599 n = n->nbinary.ch2;
4600 p = "; done";
4601 dodo:
4602 cmdputs("; do ");
4603 dotail:
4604 cmdtxt(n);
4605 goto dotail2;
4606 case NFOR:
4607 cmdputs("for ");
4608 cmdputs(n->nfor.var);
4609 cmdputs(" in ");
4610 cmdlist(n->nfor.args, 1);
4611 n = n->nfor.body;
4612 p = "; done";
4613 goto dodo;
4614 case NDEFUN:
4615 cmdputs(n->narg.text);
4616 p = "() { ... }";
4617 goto dotail2;
4618 case NCMD:
4619 cmdlist(n->ncmd.args, 1);
4620 cmdlist(n->ncmd.redirect, 0);
4621 break;
4622 case NARG:
4623 p = n->narg.text;
4624 dotail2:
4625 cmdputs(p);
4626 break;
4627 case NHERE:
4628 case NXHERE:
4629 p = "<<...";
4630 goto dotail2;
4631 case NCASE:
4632 cmdputs("case ");
4633 cmdputs(n->ncase.expr->narg.text);
4634 cmdputs(" in ");
4635 for (np = n->ncase.cases; np; np = np->nclist.next) {
4636 cmdtxt(np->nclist.pattern);
4637 cmdputs(") ");
4638 cmdtxt(np->nclist.body);
4639 cmdputs(";; ");
4640 }
4641 p = "esac";
4642 goto dotail2;
4643 case NTO:
4644 p = ">";
4645 goto redir;
4646 case NCLOBBER:
4647 p = ">|";
4648 goto redir;
4649 case NAPPEND:
4650 p = ">>";
4651 goto redir;
Denis Vlasenko559691a2008-10-05 18:39:31 +00004652#if ENABLE_ASH_BASH_COMPAT
4653 case NTO2:
4654#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004655 case NTOFD:
4656 p = ">&";
4657 goto redir;
4658 case NFROM:
4659 p = "<";
4660 goto redir;
4661 case NFROMFD:
4662 p = "<&";
4663 goto redir;
4664 case NFROMTO:
4665 p = "<>";
4666 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004667 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004668 cmdputs(p);
4669 if (n->type == NTOFD || n->type == NFROMFD) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004670 cmdputs(utoa(n->ndup.dupfd));
4671 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004672 }
4673 n = n->nfile.fname;
4674 goto donode;
4675 }
4676}
4677
4678static char *
4679commandtext(union node *n)
4680{
4681 char *name;
4682
4683 STARTSTACKSTR(cmdnextc);
4684 cmdtxt(n);
4685 name = stackblock();
Denys Vlasenko6a94cee2016-10-25 17:40:25 +02004686 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004687 return ckstrdup(name);
4688}
4689#endif /* JOBS */
4690
4691/*
4692 * Fork off a subshell. If we are doing job control, give the subshell its
4693 * own process group. Jp is a job structure that the job is to be added to.
4694 * N is the command that will be evaluated by the child. Both jp and n may
4695 * be NULL. The mode parameter can be one of the following:
4696 * FORK_FG - Fork off a foreground process.
4697 * FORK_BG - Fork off a background process.
4698 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4699 * process group even if job control is on.
4700 *
4701 * When job control is turned off, background processes have their standard
4702 * input redirected to /dev/null (except for the second and later processes
4703 * in a pipeline).
4704 *
4705 * Called with interrupts off.
4706 */
4707/*
4708 * Clear traps on a fork.
4709 */
4710static void
4711clear_traps(void)
4712{
4713 char **tp;
4714
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004715 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004716 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004717 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004718 if (trap_ptr == trap)
4719 free(*tp);
4720 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004721 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004722 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004723 setsignal(tp - trap);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004724 }
4725 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004726 may_have_traps = 0;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004727 INT_ON;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004728}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004729
4730/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004731static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004732
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004733/* Called after fork(), in child */
Denys Vlasenko70392332016-10-27 02:31:55 +02004734/* jp and n are NULL when called by openhere() for heredoc support */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004735static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004736forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004737{
4738 int oldlvl;
4739
4740 TRACE(("Child shell %d\n", getpid()));
4741 oldlvl = shlvl;
4742 shlvl++;
4743
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004744 /* man bash: "Non-builtin commands run by bash have signal handlers
4745 * set to the values inherited by the shell from its parent".
4746 * Do we do it correctly? */
4747
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004748 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004749
4750 if (mode == FORK_NOJOB /* is it `xxx` ? */
4751 && n && n->type == NCMD /* is it single cmd? */
4752 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004753 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004754 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4755 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4756 ) {
4757 TRACE(("Trap hack\n"));
4758 /* Awful hack for `trap` or $(trap).
4759 *
4760 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4761 * contains an example where "trap" is executed in a subshell:
4762 *
4763 * save_traps=$(trap)
4764 * ...
4765 * eval "$save_traps"
4766 *
4767 * Standard does not say that "trap" in subshell shall print
4768 * parent shell's traps. It only says that its output
4769 * must have suitable form, but then, in the above example
4770 * (which is not supposed to be normative), it implies that.
4771 *
4772 * bash (and probably other shell) does implement it
4773 * (traps are reset to defaults, but "trap" still shows them),
4774 * but as a result, "trap" logic is hopelessly messed up:
4775 *
4776 * # trap
4777 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4778 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4779 * # true | trap <--- trap is in subshell - no output (ditto)
4780 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4781 * trap -- 'echo Ho' SIGWINCH
4782 * # echo `(trap)` <--- in subshell in subshell - output
4783 * trap -- 'echo Ho' SIGWINCH
4784 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4785 * trap -- 'echo Ho' SIGWINCH
4786 *
4787 * The rules when to forget and when to not forget traps
4788 * get really complex and nonsensical.
4789 *
4790 * Our solution: ONLY bare $(trap) or `trap` is special.
4791 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004792 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02004793 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004794 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004795 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004796 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004797#if JOBS
4798 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004799 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004800 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004801 pid_t pgrp;
4802
4803 if (jp->nprocs == 0)
4804 pgrp = getpid();
4805 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004806 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004807 /* this can fail because we are doing it in the parent also */
4808 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004809 if (mode == FORK_FG)
4810 xtcsetpgrp(ttyfd, pgrp);
4811 setsignal(SIGTSTP);
4812 setsignal(SIGTTOU);
4813 } else
4814#endif
4815 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004816 /* man bash: "When job control is not in effect,
4817 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004818 ignoresig(SIGINT);
4819 ignoresig(SIGQUIT);
4820 if (jp->nprocs == 0) {
4821 close(0);
4822 if (open(bb_dev_null, O_RDONLY) != 0)
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00004823 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004824 }
4825 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004826 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004827 if (iflag) { /* why if iflag only? */
4828 setsignal(SIGINT);
4829 setsignal(SIGTERM);
4830 }
4831 /* man bash:
4832 * "In all cases, bash ignores SIGQUIT. Non-builtin
4833 * commands run by bash have signal handlers
4834 * set to the values inherited by the shell
4835 * from its parent".
4836 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004837 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004838 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004839#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02004840 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01004841 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004842 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004843 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02004844 /* "jobs": we do not want to clear job list for it,
4845 * instead we remove only _its_ own_ job from job list.
4846 * This makes "jobs .... | cat" more useful.
4847 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004848 freejob(curjob);
4849 return;
4850 }
4851#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004852 for (jp = curjob; jp; jp = jp->prev_job)
4853 freejob(jp);
4854 jobless = 0;
4855}
4856
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004857/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00004858#if !JOBS
4859#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4860#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004861static void
4862forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4863{
4864 TRACE(("In parent shell: child = %d\n", pid));
4865 if (!jp) {
Denys Vlasenko70392332016-10-27 02:31:55 +02004866 /* jp is NULL when called by openhere() for heredoc support */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004867 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4868 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004869 jobless++;
4870 return;
4871 }
4872#if JOBS
4873 if (mode != FORK_NOJOB && jp->jobctl) {
4874 int pgrp;
4875
4876 if (jp->nprocs == 0)
4877 pgrp = pid;
4878 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004879 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004880 /* This can fail because we are doing it in the child also */
4881 setpgid(pid, pgrp);
4882 }
4883#endif
4884 if (mode == FORK_BG) {
4885 backgndpid = pid; /* set $! */
4886 set_curjob(jp, CUR_RUNNING);
4887 }
4888 if (jp) {
4889 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01004890 ps->ps_pid = pid;
4891 ps->ps_status = -1;
4892 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004893#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004894 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004895 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004896#endif
4897 }
4898}
4899
Denys Vlasenko70392332016-10-27 02:31:55 +02004900/* jp and n are NULL when called by openhere() for heredoc support */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004901static int
4902forkshell(struct job *jp, union node *n, int mode)
4903{
4904 int pid;
4905
4906 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4907 pid = fork();
4908 if (pid < 0) {
4909 TRACE(("Fork failed, errno=%d", errno));
4910 if (jp)
4911 freejob(jp);
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +00004912 ash_msg_and_raise_error("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004913 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02004914 if (pid == 0) {
4915 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004916 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004917 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004918 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004919 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004920 return pid;
4921}
4922
4923/*
4924 * Wait for job to finish.
4925 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004926 * Under job control we have the problem that while a child process
4927 * is running interrupts generated by the user are sent to the child
4928 * but not to the shell. This means that an infinite loop started by
4929 * an interactive user may be hard to kill. With job control turned off,
4930 * an interactive user may place an interactive program inside a loop.
4931 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004932 * these interrupts to also abort the loop. The approach we take here
4933 * is to have the shell ignore interrupt signals while waiting for a
4934 * foreground process to terminate, and then send itself an interrupt
4935 * signal if the child process was terminated by an interrupt signal.
4936 * Unfortunately, some programs want to do a bit of cleanup and then
4937 * exit on interrupt; unless these processes terminate themselves by
4938 * sending a signal to themselves (instead of calling exit) they will
4939 * confuse this approach.
4940 *
4941 * Called with interrupts off.
4942 */
4943static int
4944waitforjob(struct job *jp)
4945{
4946 int st;
4947
4948 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004949
4950 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004951 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004952 /* In non-interactive shells, we _can_ get
4953 * a keyboard signal here and be EINTRed,
4954 * but we just loop back, waiting for command to complete.
4955 *
4956 * man bash:
4957 * "If bash is waiting for a command to complete and receives
4958 * a signal for which a trap has been set, the trap
4959 * will not be executed until the command completes."
4960 *
4961 * Reality is that even if trap is not set, bash
4962 * will not act on the signal until command completes.
4963 * Try this. sleep5intoff.c:
4964 * #include <signal.h>
4965 * #include <unistd.h>
4966 * int main() {
4967 * sigset_t set;
4968 * sigemptyset(&set);
4969 * sigaddset(&set, SIGINT);
4970 * sigaddset(&set, SIGQUIT);
4971 * sigprocmask(SIG_BLOCK, &set, NULL);
4972 * sleep(5);
4973 * return 0;
4974 * }
4975 * $ bash -c './sleep5intoff; echo hi'
4976 * ^C^C^C^C <--- pressing ^C once a second
4977 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004978 * $ bash -c './sleep5intoff; echo hi'
4979 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
4980 * $ _
4981 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004982 dowait(DOWAIT_BLOCK, jp);
4983 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004984 INT_ON;
4985
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004986 st = getstatus(jp);
4987#if JOBS
4988 if (jp->jobctl) {
4989 xtcsetpgrp(ttyfd, rootpid);
4990 /*
4991 * This is truly gross.
4992 * If we're doing job control, then we did a TIOCSPGRP which
4993 * caused us (the shell) to no longer be in the controlling
4994 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4995 * intuit from the subprocess exit status whether a SIGINT
4996 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4997 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004998 if (jp->sigint) /* TODO: do the same with all signals */
4999 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005000 }
5001 if (jp->state == JOBDONE)
5002#endif
5003 freejob(jp);
5004 return st;
5005}
5006
5007/*
5008 * return 1 if there are stopped jobs, otherwise 0
5009 */
5010static int
5011stoppedjobs(void)
5012{
5013 struct job *jp;
5014 int retval;
5015
5016 retval = 0;
5017 if (job_warning)
5018 goto out;
5019 jp = curjob;
5020 if (jp && jp->state == JOBSTOPPED) {
5021 out2str("You have stopped jobs.\n");
5022 job_warning = 2;
5023 retval++;
5024 }
5025 out:
5026 return retval;
5027}
5028
5029
Denys Vlasenko70392332016-10-27 02:31:55 +02005030/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005031 * Code for dealing with input/output redirection.
5032 */
5033
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005034#undef EMPTY
5035#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005036#define EMPTY -2 /* marks an unused slot in redirtab */
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005037#define CLOSED -3 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005038
5039/*
5040 * Open a file in noclobber mode.
5041 * The code was copied from bash.
5042 */
5043static int
5044noclobberopen(const char *fname)
5045{
5046 int r, fd;
5047 struct stat finfo, finfo2;
5048
5049 /*
5050 * If the file exists and is a regular file, return an error
5051 * immediately.
5052 */
5053 r = stat(fname, &finfo);
5054 if (r == 0 && S_ISREG(finfo.st_mode)) {
5055 errno = EEXIST;
5056 return -1;
5057 }
5058
5059 /*
5060 * If the file was not present (r != 0), make sure we open it
5061 * exclusively so that if it is created before we open it, our open
5062 * will fail. Make sure that we do not truncate an existing file.
5063 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5064 * file was not a regular file, we leave O_EXCL off.
5065 */
5066 if (r != 0)
5067 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5068 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5069
5070 /* If the open failed, return the file descriptor right away. */
5071 if (fd < 0)
5072 return fd;
5073
5074 /*
5075 * OK, the open succeeded, but the file may have been changed from a
5076 * non-regular file to a regular file between the stat and the open.
5077 * We are assuming that the O_EXCL open handles the case where FILENAME
5078 * did not exist and is symlinked to an existing file between the stat
5079 * and open.
5080 */
5081
5082 /*
5083 * If we can open it and fstat the file descriptor, and neither check
5084 * revealed that it was a regular file, and the file has not been
5085 * replaced, return the file descriptor.
5086 */
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005087 if (fstat(fd, &finfo2) == 0
5088 && !S_ISREG(finfo2.st_mode)
5089 && finfo.st_dev == finfo2.st_dev
5090 && finfo.st_ino == finfo2.st_ino
5091 ) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005092 return fd;
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005093 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005094
5095 /* The file has been replaced. badness. */
5096 close(fd);
5097 errno = EEXIST;
5098 return -1;
5099}
5100
5101/*
5102 * Handle here documents. Normally we fork off a process to write the
5103 * data to a pipe. If the document is short, we can stuff the data in
5104 * the pipe without forking.
5105 */
5106/* openhere needs this forward reference */
5107static void expandhere(union node *arg, int fd);
5108static int
5109openhere(union node *redir)
5110{
5111 int pip[2];
5112 size_t len = 0;
5113
5114 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005115 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005116 if (redir->type == NHERE) {
5117 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005118 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005119 full_write(pip[1], redir->nhere.doc->narg.text, len);
5120 goto out;
5121 }
5122 }
5123 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005124 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005125 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005126 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5127 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5128 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5129 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005130 signal(SIGPIPE, SIG_DFL);
5131 if (redir->type == NHERE)
5132 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005133 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005134 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005135 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005136 }
5137 out:
5138 close(pip[1]);
5139 return pip[0];
5140}
5141
5142static int
5143openredirect(union node *redir)
5144{
5145 char *fname;
5146 int f;
5147
5148 switch (redir->nfile.type) {
Denys Vlasenko557482c2016-09-25 21:24:04 +02005149/* Can't happen, our single caller does this itself */
5150// case NTOFD:
5151// case NFROMFD:
5152// return -1;
5153 case NHERE:
5154 case NXHERE:
5155 return openhere(redir);
5156 }
5157
5158 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5159 * allocated space. Do it only when we know it is safe.
5160 */
5161 fname = redir->nfile.expfname;
5162
5163 switch (redir->nfile.type) {
5164 default:
5165#if DEBUG
5166 abort();
5167#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005168 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005169 f = open(fname, O_RDONLY);
5170 if (f < 0)
5171 goto eopen;
5172 break;
5173 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005174 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005175 if (f < 0)
5176 goto ecreate;
5177 break;
5178 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00005179#if ENABLE_ASH_BASH_COMPAT
5180 case NTO2:
5181#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005182 /* Take care of noclobber mode. */
5183 if (Cflag) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005184 f = noclobberopen(fname);
5185 if (f < 0)
5186 goto ecreate;
5187 break;
5188 }
5189 /* FALLTHROUGH */
5190 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005191 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5192 if (f < 0)
5193 goto ecreate;
5194 break;
5195 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005196 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5197 if (f < 0)
5198 goto ecreate;
5199 break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005200 }
5201
5202 return f;
5203 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005204 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005205 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005206 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005207}
5208
5209/*
Denys Vlasenko64774602016-10-26 15:24:30 +02005210 * Copy a file descriptor to be >= 10. Throws exception on error.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005211 */
5212static int
Denys Vlasenko64774602016-10-26 15:24:30 +02005213savefd(int from)
5214{
5215 int newfd;
5216 int err;
5217
5218 newfd = fcntl(from, F_DUPFD, 10);
5219 err = newfd < 0 ? errno : 0;
5220 if (err != EBADF) {
5221 if (err)
5222 ash_msg_and_raise_error("%d: %m", from);
5223 close(from);
5224 fcntl(newfd, F_SETFD, FD_CLOEXEC);
5225 }
5226
5227 return newfd;
5228}
5229static int
5230dup2_or_raise(int from, int to)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005231{
5232 int newfd;
5233
Denys Vlasenko64774602016-10-26 15:24:30 +02005234 newfd = (from != to) ? dup2(from, to) : to;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005235 if (newfd < 0) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005236 /* Happens when source fd is not open: try "echo >&99" */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005237 ash_msg_and_raise_error("%d: %m", from);
5238 }
5239 return newfd;
5240}
5241
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005242/* Struct def and variable are moved down to the first usage site */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005243struct two_fd_t {
5244 int orig, copy;
5245};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005246struct redirtab {
5247 struct redirtab *next;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005248 int pair_count;
Denys Vlasenko606291b2009-09-23 23:15:43 +02005249 struct two_fd_t two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005250};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005251#define redirlist (G_var.redirlist)
Denys Vlasenko64774602016-10-26 15:24:30 +02005252enum {
5253 COPYFD_RESTORE = (int)~(INT_MAX),
5254};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005255
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005256static int
5257need_to_remember(struct redirtab *rp, int fd)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005258{
5259 int i;
5260
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005261 if (!rp) /* remembering was not requested */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005262 return 0;
5263
5264 for (i = 0; i < rp->pair_count; i++) {
5265 if (rp->two_fd[i].orig == fd) {
5266 /* already remembered */
5267 return 0;
5268 }
5269 }
5270 return 1;
5271}
5272
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005273/* "hidden" fd is a fd used to read scripts, or a copy of such */
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005274static int
5275is_hidden_fd(struct redirtab *rp, int fd)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005276{
5277 int i;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005278 struct parsefile *pf;
5279
5280 if (fd == -1)
5281 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005282 /* Check open scripts' fds */
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005283 pf = g_parsefile;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005284 while (pf) {
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005285 /* We skip pf_fd == 0 case because of the following case:
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005286 * $ ash # running ash interactively
5287 * $ . ./script.sh
5288 * and in script.sh: "exec 9>&0".
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005289 * Even though top-level pf_fd _is_ 0,
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005290 * it's still ok to use it: "read" builtin uses it,
5291 * why should we cripple "exec" builtin?
5292 */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005293 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005294 return 1;
5295 }
5296 pf = pf->prev;
5297 }
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005298
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005299 if (!rp)
5300 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005301 /* Check saved fds of redirects */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005302 fd |= COPYFD_RESTORE;
5303 for (i = 0; i < rp->pair_count; i++) {
5304 if (rp->two_fd[i].copy == fd) {
5305 return 1;
5306 }
5307 }
5308 return 0;
5309}
5310
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005311/*
5312 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5313 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005314 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005315 */
5316/* flags passed to redirect */
5317#define REDIR_PUSH 01 /* save previous values of file descriptors */
5318#define REDIR_SAVEFD2 03 /* set preverrout */
5319static void
5320redirect(union node *redir, int flags)
5321{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005322 struct redirtab *sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005323 int sv_pos;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005324 int i;
5325 int fd;
5326 int newfd;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005327 int copied_fd2 = -1;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005328
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005329 if (!redir) {
5330 return;
5331 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005332
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005333 sv = NULL;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005334 sv_pos = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005335 INT_OFF;
5336 if (flags & REDIR_PUSH) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005337 union node *tmp = redir;
5338 do {
5339 sv_pos++;
Denis Vlasenko559691a2008-10-05 18:39:31 +00005340#if ENABLE_ASH_BASH_COMPAT
Chris Metcalfc3c1fb62010-01-08 13:18:06 +01005341 if (tmp->nfile.type == NTO2)
Denis Vlasenko559691a2008-10-05 18:39:31 +00005342 sv_pos++;
5343#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005344 tmp = tmp->nfile.next;
5345 } while (tmp);
5346 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005347 sv->next = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005348 sv->pair_count = sv_pos;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005349 redirlist = sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005350 while (sv_pos > 0) {
5351 sv_pos--;
5352 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5353 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005354 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005355
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005356 do {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005357 int right_fd = -1;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005358 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005359 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005360 right_fd = redir->ndup.dupfd;
5361 //bb_error_msg("doing %d > %d", fd, right_fd);
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005362 /* redirect from/to same file descriptor? */
5363 if (right_fd == fd)
5364 continue;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005365 /* "echo >&10" and 10 is a fd opened to a sh script? */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005366 if (is_hidden_fd(sv, right_fd)) {
5367 errno = EBADF; /* as if it is closed */
5368 ash_msg_and_raise_error("%d: %m", right_fd);
5369 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005370 newfd = -1;
5371 } else {
5372 newfd = openredirect(redir); /* always >= 0 */
5373 if (fd == newfd) {
5374 /* Descriptor wasn't open before redirect.
5375 * Mark it for close in the future */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005376 if (need_to_remember(sv, fd)) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005377 goto remember_to_close;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005378 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005379 continue;
5380 }
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005381 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005382#if ENABLE_ASH_BASH_COMPAT
5383 redirect_more:
5384#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005385 if (need_to_remember(sv, fd)) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005386 /* Copy old descriptor */
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005387 /* Careful to not accidentally "save"
5388 * to the same fd as right side fd in N>&M */
5389 int minfd = right_fd < 10 ? 10 : right_fd + 1;
5390 i = fcntl(fd, F_DUPFD, minfd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005391/* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5392 * are closed in popredir() in the child, preventing them from leaking
5393 * into child. (popredir() also cleans up the mess in case of failures)
5394 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005395 if (i == -1) {
5396 i = errno;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005397 if (i != EBADF) {
5398 /* Strange error (e.g. "too many files" EMFILE?) */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005399 if (newfd >= 0)
5400 close(newfd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005401 errno = i;
5402 ash_msg_and_raise_error("%d: %m", fd);
5403 /* NOTREACHED */
5404 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005405 /* EBADF: it is not open - good, remember to close it */
5406 remember_to_close:
5407 i = CLOSED;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005408 } else { /* fd is open, save its copy */
5409 /* "exec fd>&-" should not close fds
5410 * which point to script file(s).
5411 * Force them to be restored afterwards */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005412 if (is_hidden_fd(sv, fd))
5413 i |= COPYFD_RESTORE;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005414 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005415 if (fd == 2)
5416 copied_fd2 = i;
5417 sv->two_fd[sv_pos].orig = fd;
5418 sv->two_fd[sv_pos].copy = i;
5419 sv_pos++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005420 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005421 if (newfd < 0) {
5422 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005423 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005424 /* Don't want to trigger debugging */
5425 if (fd != -1)
5426 close(fd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005427 } else {
Denys Vlasenko64774602016-10-26 15:24:30 +02005428 dup2_or_raise(redir->ndup.dupfd, fd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005429 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005430 } else if (fd != newfd) { /* move newfd to fd */
Denys Vlasenko64774602016-10-26 15:24:30 +02005431 dup2_or_raise(newfd, fd);
Denis Vlasenko559691a2008-10-05 18:39:31 +00005432#if ENABLE_ASH_BASH_COMPAT
5433 if (!(redir->nfile.type == NTO2 && fd == 2))
5434#endif
5435 close(newfd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005436 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005437#if ENABLE_ASH_BASH_COMPAT
5438 if (redir->nfile.type == NTO2 && fd == 1) {
5439 /* We already redirected it to fd 1, now copy it to 2 */
5440 newfd = 1;
5441 fd = 2;
5442 goto redirect_more;
5443 }
5444#endif
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005445 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005446
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005447 INT_ON;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005448 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5449 preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005450}
5451
5452/*
5453 * Undo the effects of the last redirection.
5454 */
5455static void
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005456popredir(int drop, int restore)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005457{
5458 struct redirtab *rp;
5459 int i;
5460
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02005461 if (redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005462 return;
5463 INT_OFF;
5464 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005465 for (i = 0; i < rp->pair_count; i++) {
5466 int fd = rp->two_fd[i].orig;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005467 int copy = rp->two_fd[i].copy;
5468 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005469 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005470 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005471 continue;
5472 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005473 if (copy != EMPTY) {
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005474 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
Denis Vlasenko22f74142008-07-24 22:34:43 +00005475 copy &= ~COPYFD_RESTORE;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005476 /*close(fd);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02005477 dup2_or_raise(copy, fd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005478 }
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005479 close(copy & ~COPYFD_RESTORE);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005480 }
5481 }
5482 redirlist = rp->next;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005483 free(rp);
5484 INT_ON;
5485}
5486
5487/*
5488 * Undo all redirections. Called on error or interrupt.
5489 */
5490
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005491static int
5492redirectsafe(union node *redir, int flags)
5493{
5494 int err;
5495 volatile int saveint;
5496 struct jmploc *volatile savehandler = exception_handler;
5497 struct jmploc jmploc;
5498
5499 SAVE_INT(saveint);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005500 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5501 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005502 if (!err) {
5503 exception_handler = &jmploc;
5504 redirect(redir, flags);
5505 }
5506 exception_handler = savehandler;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00005507 if (err && exception_type != EXERROR)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005508 longjmp(exception_handler->loc, 1);
5509 RESTORE_INT(saveint);
5510 return err;
5511}
5512
5513
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005514/* ============ Routines to expand arguments to commands
5515 *
5516 * We have to deal with backquotes, shell variables, and file metacharacters.
5517 */
5518
Mike Frysinger98c52642009-04-02 10:02:37 +00005519#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005520static arith_t
5521ash_arith(const char *s)
5522{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005523 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005524 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005525
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005526 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005527 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005528 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005529
5530 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005531 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005532 if (math_state.errmsg)
5533 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005534 INT_ON;
5535
5536 return result;
5537}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005538#endif
5539
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005540/*
5541 * expandarg flags
5542 */
5543#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5544#define EXP_TILDE 0x2 /* do normal tilde expansion */
5545#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5546#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
Denys Vlasenkodb74c6c2016-10-24 21:12:33 +02005547/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5548 * POSIX says for this case:
5549 * Pathname expansion shall not be performed on the word by a
5550 * non-interactive shell; an interactive shell may perform it, but shall
5551 * do so only when the expansion would result in one word.
5552 * Currently, our code complies to the above rule by never globbing
5553 * redirection filenames.
5554 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5555 * (this means that on a typical Linux distro, bash almost always
5556 * performs globbing, and thus diverges from what we do).
5557 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005558#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Ron Yorston549deab2015-05-18 09:57:51 +02005559#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005560#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5561#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005562#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005563/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005564 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005565 */
5566#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5567#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005568#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5569#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Ron Yorston417622c2015-05-18 09:59:14 +02005570#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005571
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005572/* Add CTLESC when necessary. */
Ron Yorston549deab2015-05-18 09:57:51 +02005573#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005574/* Do not skip NUL characters. */
5575#define QUOTES_KEEPNUL EXP_TILDE
5576
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005577/*
5578 * Structure specifying which parts of the string should be searched
5579 * for IFS characters.
5580 */
5581struct ifsregion {
5582 struct ifsregion *next; /* next region in list */
5583 int begoff; /* offset of start of region */
5584 int endoff; /* offset of end of region */
5585 int nulonly; /* search for nul bytes only */
5586};
5587
5588struct arglist {
5589 struct strlist *list;
5590 struct strlist **lastp;
5591};
5592
5593/* output of current string */
5594static char *expdest;
5595/* list of back quote expressions */
5596static struct nodelist *argbackq;
5597/* first struct in list of ifs regions */
5598static struct ifsregion ifsfirst;
5599/* last struct in list */
5600static struct ifsregion *ifslastp;
5601/* holds expanded arg list */
5602static struct arglist exparg;
5603
5604/*
5605 * Our own itoa().
5606 */
Denys Vlasenko26777aa2010-11-22 23:49:10 +01005607#if !ENABLE_SH_MATH_SUPPORT
5608/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5609typedef long arith_t;
5610# define ARITH_FMT "%ld"
5611#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005612static int
5613cvtnum(arith_t num)
5614{
5615 int len;
5616
Denys Vlasenko9c541002015-10-07 15:44:36 +02005617 expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest);
5618 len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005619 STADJUST(len, expdest);
5620 return len;
5621}
5622
Denys Vlasenko455e4222016-10-27 14:45:13 +02005623/*
5624 * Break the argument string into pieces based upon IFS and add the
5625 * strings to the argument list. The regions of the string to be
5626 * searched for IFS characters have been stored by recordregion.
5627 */
5628static void
5629ifsbreakup(char *string, struct arglist *arglist)
5630{
5631 struct ifsregion *ifsp;
5632 struct strlist *sp;
5633 char *start;
5634 char *p;
5635 char *q;
5636 const char *ifs, *realifs;
5637 int ifsspc;
5638 int nulonly;
5639
5640 start = string;
5641 if (ifslastp != NULL) {
5642 ifsspc = 0;
5643 nulonly = 0;
5644 realifs = ifsset() ? ifsval() : defifs;
5645 ifsp = &ifsfirst;
5646 do {
5647 p = string + ifsp->begoff;
5648 nulonly = ifsp->nulonly;
5649 ifs = nulonly ? nullstr : realifs;
5650 ifsspc = 0;
5651 while (p < string + ifsp->endoff) {
5652 q = p;
5653 if ((unsigned char)*p == CTLESC)
5654 p++;
5655 if (!strchr(ifs, *p)) {
5656 p++;
5657 continue;
5658 }
5659 if (!nulonly)
5660 ifsspc = (strchr(defifs, *p) != NULL);
5661 /* Ignore IFS whitespace at start */
5662 if (q == start && ifsspc) {
5663 p++;
5664 start = p;
5665 continue;
5666 }
5667 *q = '\0';
5668 sp = stzalloc(sizeof(*sp));
5669 sp->text = start;
5670 *arglist->lastp = sp;
5671 arglist->lastp = &sp->next;
5672 p++;
5673 if (!nulonly) {
5674 for (;;) {
5675 if (p >= string + ifsp->endoff) {
5676 break;
5677 }
5678 q = p;
5679 if ((unsigned char)*p == CTLESC)
5680 p++;
5681 if (strchr(ifs, *p) == NULL) {
5682 p = q;
5683 break;
5684 }
5685 if (strchr(defifs, *p) == NULL) {
5686 if (ifsspc) {
5687 p++;
5688 ifsspc = 0;
5689 } else {
5690 p = q;
5691 break;
5692 }
5693 } else
5694 p++;
5695 }
5696 }
5697 start = p;
5698 } /* while */
5699 ifsp = ifsp->next;
5700 } while (ifsp != NULL);
5701 if (nulonly)
5702 goto add;
5703 }
5704
5705 if (!*start)
5706 return;
5707
5708 add:
5709 sp = stzalloc(sizeof(*sp));
5710 sp->text = start;
5711 *arglist->lastp = sp;
5712 arglist->lastp = &sp->next;
5713}
5714
5715static void
5716ifsfree(void)
5717{
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005718 struct ifsregion *p = ifsfirst.next;
5719
5720 if (!p)
5721 goto out;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005722
5723 INT_OFF;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005724 do {
5725 struct ifsregion *ifsp;
5726 ifsp = p->next;
5727 free(p);
5728 p = ifsp;
5729 } while (p);
Denys Vlasenko455e4222016-10-27 14:45:13 +02005730 ifsfirst.next = NULL;
5731 INT_ON;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005732 out:
5733 ifslastp = NULL;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005734}
5735
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005736static size_t
5737esclen(const char *start, const char *p)
5738{
5739 size_t esc = 0;
5740
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005741 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005742 esc++;
5743 }
5744 return esc;
5745}
5746
5747/*
5748 * Remove any CTLESC characters from a string.
5749 */
5750static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005751rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005752{
Ron Yorston417622c2015-05-18 09:59:14 +02005753 static const char qchars[] ALIGN1 = {
5754 IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005755
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005756 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005757 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005758 unsigned protect_against_glob;
5759 unsigned globbing;
Ron Yorston417622c2015-05-18 09:59:14 +02005760 IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005761
Ron Yorston417622c2015-05-18 09:59:14 +02005762 p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005763 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005764 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005765
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005766 q = p;
5767 r = str;
5768 if (flag & RMESCAPE_ALLOC) {
5769 size_t len = p - str;
5770 size_t fulllen = len + strlen(p) + 1;
5771
5772 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005773 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005774 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005775 /* p and str may be invalidated by makestrspace */
5776 str = (char *)stackblock() + strloc;
5777 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005778 } else if (flag & RMESCAPE_HEAP) {
5779 r = ckmalloc(fulllen);
5780 } else {
5781 r = stalloc(fulllen);
5782 }
5783 q = r;
5784 if (len > 0) {
Denis Vlasenko29eb3592008-05-18 14:06:08 +00005785 q = (char *)memcpy(q, str, len) + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005786 }
5787 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005788
Ron Yorston549deab2015-05-18 09:57:51 +02005789 inquotes = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005790 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005791 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005792 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005793 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005794// Note: both inquotes and protect_against_glob only affect whether
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005795 inquotes = ~inquotes;
5796 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005797 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005798 continue;
5799 }
Ron Yorston549deab2015-05-18 09:57:51 +02005800 if ((unsigned char)*p == CTLESC) {
5801 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02005802#if DEBUG
5803 if (*p == '\0')
5804 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
5805#endif
Ron Yorston549deab2015-05-18 09:57:51 +02005806 if (protect_against_glob) {
5807 *q++ = '\\';
5808 }
5809 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005810 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005811 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005812 goto copy;
5813 }
Ron Yorston417622c2015-05-18 09:59:14 +02005814#if ENABLE_ASH_BASH_COMPAT
5815 else if (*p == '/' && slash) {
5816 /* stop handling globbing and mark location of slash */
5817 globbing = slash = 0;
5818 *p = CTLESC;
5819 }
5820#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005821 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005822 copy:
5823 *q++ = *p++;
5824 }
5825 *q = '\0';
5826 if (flag & RMESCAPE_GROW) {
5827 expdest = r;
5828 STADJUST(q - r + 1, expdest);
5829 }
5830 return r;
5831}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005832#define pmatch(a, b) !fnmatch((a), (b), 0)
5833
5834/*
5835 * Prepare a pattern for a expmeta (internal glob(3)) call.
5836 *
5837 * Returns an stalloced string.
5838 */
5839static char *
Ron Yorston549deab2015-05-18 09:57:51 +02005840preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005841{
Ron Yorston549deab2015-05-18 09:57:51 +02005842 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005843}
5844
5845/*
5846 * Put a string on the stack.
5847 */
5848static void
5849memtodest(const char *p, size_t len, int syntax, int quotes)
5850{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005851 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005852
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005853 if (!len)
5854 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005855
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005856 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
5857
5858 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005859 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005860 if (c) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005861 int n = SIT(c, syntax);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02005862 if ((quotes & QUOTES_ESC)
5863 && ((n == CCTL)
5864 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
5865 && n == CBACK)
5866 )
5867 ) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005868 USTPUTC(CTLESC, q);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02005869 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005870 } else if (!(quotes & QUOTES_KEEPNUL))
5871 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005872 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005873 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005874
5875 expdest = q;
5876}
5877
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005878static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005879strtodest(const char *p, int syntax, int quotes)
5880{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005881 size_t len = strlen(p);
5882 memtodest(p, len, syntax, quotes);
5883 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005884}
5885
5886/*
5887 * Record the fact that we have to scan this region of the
5888 * string for IFS characters.
5889 */
5890static void
5891recordregion(int start, int end, int nulonly)
5892{
5893 struct ifsregion *ifsp;
5894
5895 if (ifslastp == NULL) {
5896 ifsp = &ifsfirst;
5897 } else {
5898 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00005899 ifsp = ckzalloc(sizeof(*ifsp));
5900 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005901 ifslastp->next = ifsp;
5902 INT_ON;
5903 }
5904 ifslastp = ifsp;
5905 ifslastp->begoff = start;
5906 ifslastp->endoff = end;
5907 ifslastp->nulonly = nulonly;
5908}
5909
5910static void
5911removerecordregions(int endoff)
5912{
5913 if (ifslastp == NULL)
5914 return;
5915
5916 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005917 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005918 struct ifsregion *ifsp;
5919 INT_OFF;
5920 ifsp = ifsfirst.next->next;
5921 free(ifsfirst.next);
5922 ifsfirst.next = ifsp;
5923 INT_ON;
5924 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005925 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005926 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005927 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005928 ifslastp = &ifsfirst;
5929 ifsfirst.endoff = endoff;
5930 }
5931 return;
5932 }
5933
5934 ifslastp = &ifsfirst;
5935 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005936 ifslastp = ifslastp->next;
5937 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005938 struct ifsregion *ifsp;
5939 INT_OFF;
5940 ifsp = ifslastp->next->next;
5941 free(ifslastp->next);
5942 ifslastp->next = ifsp;
5943 INT_ON;
5944 }
5945 if (ifslastp->endoff > endoff)
5946 ifslastp->endoff = endoff;
5947}
5948
5949static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005950exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005951{
Denys Vlasenkocd716832009-11-28 22:14:02 +01005952 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005953 char *name;
5954 struct passwd *pw;
5955 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005956 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005957
5958 name = p + 1;
5959
5960 while ((c = *++p) != '\0') {
5961 switch (c) {
5962 case CTLESC:
5963 return startp;
5964 case CTLQUOTEMARK:
5965 return startp;
5966 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005967 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005968 goto done;
5969 break;
5970 case '/':
5971 case CTLENDVAR:
5972 goto done;
5973 }
5974 }
5975 done:
5976 *p = '\0';
5977 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02005978 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005979 } else {
5980 pw = getpwnam(name);
5981 if (pw == NULL)
5982 goto lose;
5983 home = pw->pw_dir;
5984 }
5985 if (!home || !*home)
5986 goto lose;
5987 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005988 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005989 return p;
5990 lose:
5991 *p = c;
5992 return startp;
5993}
5994
5995/*
5996 * Execute a command inside back quotes. If it's a builtin command, we
5997 * want to save its output in a block obtained from malloc. Otherwise
5998 * we fork off a subprocess and get the output of the command via a pipe.
5999 * Should be called with interrupts off.
6000 */
6001struct backcmd { /* result of evalbackcmd */
6002 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006003 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00006004 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006005 struct job *jp; /* job structure for command */
6006};
6007
6008/* These forward decls are needed to use "eval" code for backticks handling: */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006009#define EV_EXIT 01 /* exit after evaluating tree */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02006010static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006011
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02006012static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006013evalbackcmd(union node *n, struct backcmd *result)
6014{
Denys Vlasenko579ad102016-10-25 21:10:20 +02006015 int pip[2];
6016 struct job *jp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006017
6018 result->fd = -1;
6019 result->buf = NULL;
6020 result->nleft = 0;
6021 result->jp = NULL;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006022 if (n == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006023 goto out;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006024 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006025
Denys Vlasenko579ad102016-10-25 21:10:20 +02006026 if (pipe(pip) < 0)
6027 ash_msg_and_raise_error("pipe call failed");
6028 jp = makejob(/*n,*/ 1);
6029 if (forkshell(jp, n, FORK_NOJOB) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02006030 /* child */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006031 FORCE_INT_ON;
6032 close(pip[0]);
6033 if (pip[1] != 1) {
6034 /*close(1);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02006035 dup2_or_raise(pip[1], 1);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006036 close(pip[1]);
6037 }
Denys Vlasenko960ca382016-10-25 18:12:15 +02006038/* TODO: eflag clearing makes the following not abort:
6039 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6040 * which is what bash does (unless it is in POSIX mode).
6041 * dash deleted "eflag = 0" line in the commit
6042 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6043 * [EVAL] Don't clear eflag in evalbackcmd
6044 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6045 */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006046 eflag = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006047 ifsfree();
Denys Vlasenko579ad102016-10-25 21:10:20 +02006048 evaltree(n, EV_EXIT); /* actually evaltreenr... */
6049 /* NOTREACHED */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006050 }
Denys Vlasenko70392332016-10-27 02:31:55 +02006051 /* parent */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006052 close(pip[1]);
6053 result->fd = pip[0];
6054 result->jp = jp;
6055
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006056 out:
6057 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6058 result->fd, result->buf, result->nleft, result->jp));
6059}
6060
6061/*
6062 * Expand stuff in backwards quotes.
6063 */
6064static void
Ron Yorston549deab2015-05-18 09:57:51 +02006065expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006066{
6067 struct backcmd in;
6068 int i;
6069 char buf[128];
6070 char *p;
6071 char *dest;
6072 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02006073 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006074 struct stackmark smark;
6075
6076 INT_OFF;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02006077 startloc = expdest - (char *)stackblock();
6078 pushstackmark(&smark, startloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006079 evalbackcmd(cmd, &in);
6080 popstackmark(&smark);
6081
6082 p = in.buf;
6083 i = in.nleft;
6084 if (i == 0)
6085 goto read;
6086 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02006087 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006088 read:
6089 if (in.fd < 0)
6090 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01006091 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006092 TRACE(("expbackq: read returns %d\n", i));
6093 if (i <= 0)
6094 break;
6095 p = buf;
6096 }
6097
Denis Vlasenko60818682007-09-28 22:07:23 +00006098 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006099 if (in.fd >= 0) {
6100 close(in.fd);
6101 back_exitstatus = waitforjob(in.jp);
6102 }
6103 INT_ON;
6104
6105 /* Eat all trailing newlines */
6106 dest = expdest;
6107 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6108 STUNPUTC(dest);
6109 expdest = dest;
6110
Ron Yorston549deab2015-05-18 09:57:51 +02006111 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006112 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006113 TRACE(("evalbackq: size:%d:'%.*s'\n",
6114 (int)((dest - (char *)stackblock()) - startloc),
6115 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006116 stackblock() + startloc));
6117}
6118
Mike Frysinger98c52642009-04-02 10:02:37 +00006119#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006120/*
6121 * Expand arithmetic expression. Backup to start of expression,
6122 * evaluate, place result in (backed up) result, adjust string position.
6123 */
6124static void
Ron Yorston549deab2015-05-18 09:57:51 +02006125expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006126{
6127 char *p, *start;
6128 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006129 int len;
6130
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006131 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006132
6133 /*
6134 * This routine is slightly over-complicated for
6135 * efficiency. Next we scan backwards looking for the
6136 * start of arithmetic.
6137 */
6138 start = stackblock();
6139 p = expdest - 1;
6140 *p = '\0';
6141 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006142 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006143 int esc;
6144
Denys Vlasenkocd716832009-11-28 22:14:02 +01006145 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006146 p--;
6147#if DEBUG
6148 if (p < start) {
6149 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6150 }
6151#endif
6152 }
6153
6154 esc = esclen(start, p);
6155 if (!(esc % 2)) {
6156 break;
6157 }
6158
6159 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006160 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006161
6162 begoff = p - start;
6163
6164 removerecordregions(begoff);
6165
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006166 expdest = p;
6167
Ron Yorston549deab2015-05-18 09:57:51 +02006168 if (flag & QUOTES_ESC)
6169 rmescapes(p + 1, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006170
Ron Yorston549deab2015-05-18 09:57:51 +02006171 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006172
Ron Yorston549deab2015-05-18 09:57:51 +02006173 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006174 recordregion(begoff, begoff + len, 0);
6175}
6176#endif
6177
6178/* argstr needs it */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006179static char *evalvar(char *p, int flags, struct strlist *var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006180
6181/*
6182 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6183 * characters to allow for further processing. Otherwise treat
6184 * $@ like $* since no splitting will be performed.
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006185 *
6186 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
6187 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
6188 * for correct expansion of "B=$A" word.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006189 */
6190static void
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006191argstr(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006192{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006193 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006194 '=',
6195 ':',
6196 CTLQUOTEMARK,
6197 CTLENDVAR,
6198 CTLESC,
6199 CTLVAR,
6200 CTLBACKQ,
Mike Frysinger98c52642009-04-02 10:02:37 +00006201#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006202 CTLENDARI,
6203#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006204 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006205 };
6206 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006207 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006208 int inquotes;
6209 size_t length;
6210 int startloc;
6211
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006212 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006213 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006214 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006215 reject++;
6216 }
6217 inquotes = 0;
6218 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006219 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006220 char *q;
6221
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006222 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006223 tilde:
6224 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006225 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006226 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006227 }
6228 start:
6229 startloc = expdest - (char *)stackblock();
6230 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006231 unsigned char c;
6232
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006233 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006234 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006235 if (c) {
6236 if (!(c & 0x80)
Denys Vlasenko958581a2010-09-12 15:04:27 +02006237 IF_SH_MATH_SUPPORT(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006238 ) {
6239 /* c == '=' || c == ':' || c == CTLENDARI */
6240 length++;
6241 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006242 }
6243 if (length > 0) {
6244 int newloc;
6245 expdest = stack_nputstr(p, length, expdest);
6246 newloc = expdest - (char *)stackblock();
6247 if (breakall && !inquotes && newloc > startloc) {
6248 recordregion(startloc, newloc, 0);
6249 }
6250 startloc = newloc;
6251 }
6252 p += length + 1;
6253 length = 0;
6254
6255 switch (c) {
6256 case '\0':
6257 goto breakloop;
6258 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006259 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006260 p--;
6261 continue;
6262 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006263 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006264 reject++;
6265 /* fall through */
6266 case ':':
6267 /*
6268 * sort of a hack - expand tildes in variable
6269 * assignments (after the first '=' and after ':'s).
6270 */
6271 if (*--p == '~') {
6272 goto tilde;
6273 }
6274 continue;
6275 }
6276
6277 switch (c) {
6278 case CTLENDVAR: /* ??? */
6279 goto breakloop;
6280 case CTLQUOTEMARK:
Ron Yorston549deab2015-05-18 09:57:51 +02006281 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006282 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006283 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6284 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006285 goto start;
6286 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006287 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006288 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006289 p--;
6290 length++;
6291 startloc++;
6292 }
6293 break;
6294 case CTLESC:
6295 startloc++;
6296 length++;
Ron Yorston549deab2015-05-18 09:57:51 +02006297
6298 /*
6299 * Quoted parameter expansion pattern: remove quote
6300 * unless inside inner quotes or we have a literal
6301 * backslash.
6302 */
6303 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6304 EXP_QPAT && *p != '\\')
6305 break;
6306
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006307 goto addquote;
6308 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006309 TRACE(("argstr: evalvar('%s')\n", p));
Ron Yorston549deab2015-05-18 09:57:51 +02006310 p = evalvar(p, flags | inquotes, var_str_list);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006311 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006312 goto start;
6313 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006314 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006315 argbackq = argbackq->next;
6316 goto start;
Mike Frysinger98c52642009-04-02 10:02:37 +00006317#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006318 case CTLENDARI:
6319 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006320 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006321 goto start;
6322#endif
6323 }
6324 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006325 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006326}
6327
6328static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006329scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6330 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006331{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006332 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006333 char c;
6334
6335 loc = startp;
6336 loc2 = rmesc;
6337 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006338 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006339 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006340
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006341 c = *loc2;
6342 if (zero) {
6343 *loc2 = '\0';
6344 s = rmesc;
6345 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006346 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006347
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006348 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006349 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006350 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006351 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006352 loc++;
6353 loc++;
6354 loc2++;
6355 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006356 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006357}
6358
6359static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006360scanright(char *startp, char *rmesc, char *rmescend,
6361 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006362{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006363#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6364 int try2optimize = match_at_start;
6365#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006366 int esc = 0;
6367 char *loc;
6368 char *loc2;
6369
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006370 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6371 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6372 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6373 * Logic:
6374 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6375 * and on each iteration they go back two/one char until they reach the beginning.
6376 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6377 */
6378 /* TODO: document in what other circumstances we are called. */
6379
6380 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006381 int match;
6382 char c = *loc2;
6383 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006384 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006385 *loc2 = '\0';
6386 s = rmesc;
6387 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006388 match = pmatch(pattern, s);
6389 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006390 *loc2 = c;
6391 if (match)
6392 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006393#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6394 if (try2optimize) {
6395 /* Maybe we can optimize this:
6396 * if pattern ends with unescaped *, we can avoid checking
6397 * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6398 * it wont match truncated "raw_value_of_" strings too.
6399 */
6400 unsigned plen = strlen(pattern);
6401 /* Does it end with "*"? */
6402 if (plen != 0 && pattern[--plen] == '*') {
6403 /* "xxxx*" is not escaped */
6404 /* "xxx\*" is escaped */
6405 /* "xx\\*" is not escaped */
6406 /* "x\\\*" is escaped */
6407 int slashes = 0;
6408 while (plen != 0 && pattern[--plen] == '\\')
6409 slashes++;
6410 if (!(slashes & 1))
6411 break; /* ends with unescaped "*" */
6412 }
6413 try2optimize = 0;
6414 }
6415#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006416 loc--;
6417 if (quotes) {
6418 if (--esc < 0) {
6419 esc = esclen(startp, loc);
6420 }
6421 if (esc % 2) {
6422 esc--;
6423 loc--;
6424 }
6425 }
6426 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006427 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006428}
6429
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006430static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006431static void
6432varunset(const char *end, const char *var, const char *umsg, int varflags)
6433{
6434 const char *msg;
6435 const char *tail;
6436
6437 tail = nullstr;
6438 msg = "parameter not set";
6439 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006440 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006441 if (varflags & VSNUL)
6442 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006443 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006444 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006445 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006446 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006447 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006448}
6449
6450static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006451subevalvar(char *p, char *varname, int strloc, int subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006452 int startloc, int varflags, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006453{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006454 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006455 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006456 char *startp;
6457 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006458 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006459 char *str;
Ron Yorston417622c2015-05-18 09:59:14 +02006460 IF_ASH_BASH_COMPAT(char *repl = NULL;)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006461 IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006462 int amount, resetloc;
6463 IF_ASH_BASH_COMPAT(int workloc;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006464 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006465 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006466
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006467 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6468 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006469
Ron Yorstoneb6b48b2015-05-18 09:51:35 +02006470 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
Ron Yorston549deab2015-05-18 09:57:51 +02006471 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6472 var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006473 STPUTC('\0', expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006474 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006475 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006476
6477 switch (subtype) {
6478 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006479 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006480 amount = startp - expdest;
6481 STADJUST(amount, expdest);
6482 return startp;
6483
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006484 case VSQUESTION:
6485 varunset(p, varname, startp, varflags);
6486 /* NOTREACHED */
6487
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006488#if ENABLE_ASH_BASH_COMPAT
6489 case VSSUBSTR:
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +02006490//TODO: support more general format ${v:EXPR:EXPR},
6491// where EXPR follows $(()) rules
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006492 loc = str = stackblock() + strloc;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006493 /* Read POS in ${var:POS:LEN} */
6494 pos = atoi(loc); /* number(loc) errors out on "1:4" */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006495 len = str - startp - 1;
6496
6497 /* *loc != '\0', guaranteed by parser */
6498 if (quotes) {
6499 char *ptr;
6500
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006501 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006502 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006503 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006504 len--;
6505 ptr++;
6506 }
6507 }
6508 }
6509 orig_len = len;
6510
6511 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006512 /* ${var::LEN} */
6513 len = number(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006514 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006515 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006516 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006517 while (*loc && *loc != ':') {
6518 /* TODO?
6519 * bash complains on: var=qwe; echo ${var:1a:123}
6520 if (!isdigit(*loc))
6521 ash_msg_and_raise_error(msg_illnum, str);
6522 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006523 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006524 }
6525 if (*loc++ == ':') {
6526 len = number(loc);
6527 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006528 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006529 if (pos < 0) {
6530 /* ${VAR:$((-n)):l} starts n chars from the end */
6531 pos = orig_len + pos;
6532 }
6533 if ((unsigned)pos >= orig_len) {
6534 /* apart from obvious ${VAR:999999:l},
6535 * covers ${VAR:$((-9999999)):l} - result is ""
6536 * (bash-compat)
6537 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006538 pos = 0;
6539 len = 0;
6540 }
6541 if (len > (orig_len - pos))
6542 len = orig_len - pos;
6543
6544 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006545 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006546 str++;
6547 }
6548 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006549 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006550 *loc++ = *str++;
6551 *loc++ = *str++;
6552 }
6553 *loc = '\0';
6554 amount = loc - expdest;
6555 STADJUST(amount, expdest);
6556 return loc;
6557#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006558 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006559
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006560 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006561
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006562 /* We'll comeback here if we grow the stack while handling
6563 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6564 * stack will need rebasing, and we'll need to remove our work
6565 * areas each time
6566 */
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006567 IF_ASH_BASH_COMPAT(restart:)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006568
6569 amount = expdest - ((char *)stackblock() + resetloc);
6570 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006571 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006572
6573 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006574 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006575 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006576 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006577 if (rmesc != startp) {
6578 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006579 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006580 }
6581 }
6582 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006583 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02006584 /*
6585 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6586 * The result is a_\_z_c (not a\_\_z_c)!
6587 *
6588 * The search pattern and replace string treat backslashes differently!
6589 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6590 * and string. It's only used on the first call.
6591 */
6592 preglob(str, IF_ASH_BASH_COMPAT(
6593 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
6594 RMESCAPE_SLASH :) 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006595
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006596#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006597 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006598 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006599 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006600
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006601 if (!repl) {
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006602 repl = strchr(str, CTLESC);
6603 if (repl)
Ron Yorston417622c2015-05-18 09:59:14 +02006604 *repl++ = '\0';
6605 else
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006606 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006607 }
Ron Yorston417622c2015-05-18 09:59:14 +02006608 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006609
6610 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006611 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006612 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006613
6614 len = 0;
6615 idx = startp;
6616 end = str - 1;
6617 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006618 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006619 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006620 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006621 if (!loc) {
6622 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006623 char *restart_detect = stackblock();
6624 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006625 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006626 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006627 idx++;
6628 len++;
6629 STPUTC(*idx, expdest);
6630 }
6631 if (stackblock() != restart_detect)
6632 goto restart;
6633 idx++;
6634 len++;
6635 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006636 /* continue; - prone to quadratic behavior, smarter code: */
6637 if (idx >= end)
6638 break;
6639 if (str[0] == '*') {
6640 /* Pattern is "*foo". If "*foo" does not match "long_string",
6641 * it would never match "ong_string" etc, no point in trying.
6642 */
6643 goto skip_matching;
6644 }
6645 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006646 }
6647
6648 if (subtype == VSREPLACEALL) {
6649 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006650 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006651 idx++;
6652 idx++;
6653 rmesc++;
6654 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006655 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006656 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006657 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006658
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006659 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006660 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006661 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006662 if (quotes && *loc == '\\') {
6663 STPUTC(CTLESC, expdest);
6664 len++;
6665 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006666 STPUTC(*loc, expdest);
6667 if (stackblock() != restart_detect)
6668 goto restart;
6669 len++;
6670 }
6671
6672 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006673 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006674 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006675 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006676 STPUTC(*idx, expdest);
6677 if (stackblock() != restart_detect)
6678 goto restart;
6679 len++;
6680 idx++;
6681 }
6682 break;
6683 }
6684 }
6685
6686 /* We've put the replaced text into a buffer at workloc, now
6687 * move it to the right place and adjust the stack.
6688 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006689 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006690 startp = (char *)stackblock() + startloc;
6691 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006692 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006693 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006694 STADJUST(-amount, expdest);
6695 return startp;
6696 }
6697#endif /* ENABLE_ASH_BASH_COMPAT */
6698
6699 subtype -= VSTRIMRIGHT;
6700#if DEBUG
6701 if (subtype < 0 || subtype > 7)
6702 abort();
6703#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006704 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006705 zero = subtype >> 1;
6706 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6707 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6708
6709 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6710 if (loc) {
6711 if (zero) {
6712 memmove(startp, loc, str - loc);
6713 loc = startp + (str - loc) - 1;
6714 }
6715 *loc = '\0';
6716 amount = loc - expdest;
6717 STADJUST(amount, expdest);
6718 }
6719 return loc;
6720}
6721
6722/*
6723 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006724 * name parameter (examples):
6725 * ash -c 'echo $1' name:'1='
6726 * ash -c 'echo $qwe' name:'qwe='
6727 * ash -c 'echo $$' name:'$='
6728 * ash -c 'echo ${$}' name:'$='
6729 * ash -c 'echo ${$##q}' name:'$=q'
6730 * ash -c 'echo ${#$}' name:'$='
6731 * note: examples with bad shell syntax:
6732 * ash -c 'echo ${#$1}' name:'$=1'
6733 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006734 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02006735static NOINLINE ssize_t
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006736varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int *quotedp)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006737{
Mike Frysinger98c52642009-04-02 10:02:37 +00006738 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006739 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006740 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006741 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006742 int sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006743 int quoted = *quotedp;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006744 int subtype = varflags & VSTYPE;
6745 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6746 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006747 int syntax;
6748
6749 sep = (flags & EXP_FULL) << CHAR_BIT;
6750 syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006751
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006752 switch (*name) {
6753 case '$':
6754 num = rootpid;
6755 goto numvar;
6756 case '?':
6757 num = exitstatus;
6758 goto numvar;
6759 case '#':
6760 num = shellparam.nparam;
6761 goto numvar;
6762 case '!':
6763 num = backgndpid;
6764 if (num == 0)
6765 return -1;
6766 numvar:
6767 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006768 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006769 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00006770 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006771 for (i = NOPTS - 1; i >= 0; i--) {
6772 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00006773 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006774 len++;
6775 }
6776 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006777 check_1char_name:
6778#if 0
6779 /* handles cases similar to ${#$1} */
6780 if (name[2] != '\0')
6781 raise_error_syntax("bad substitution");
6782#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006783 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006784 case '@':
6785 if (quoted && sep)
6786 goto param;
6787 /* fall through */
6788 case '*': {
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006789 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006790 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006791
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006792 if (quoted)
6793 sep = 0;
6794 sep |= ifsset() ? ifsval()[0] : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006795 param:
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006796 sepc = sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006797 *quotedp = !sepc;
6798 ap = shellparam.p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006799 if (!ap)
6800 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006801 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006802 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006803
6804 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006805 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006806 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006807 }
6808 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006809 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006810 } /* case '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006811 case '0':
6812 case '1':
6813 case '2':
6814 case '3':
6815 case '4':
6816 case '5':
6817 case '6':
6818 case '7':
6819 case '8':
6820 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02006821 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006822 if (num < 0 || num > shellparam.nparam)
6823 return -1;
6824 p = num ? shellparam.p[num - 1] : arg0;
6825 goto value;
6826 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006827 /* NB: name has form "VAR=..." */
6828
6829 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6830 * which should be considered before we check variables. */
6831 if (var_str_list) {
6832 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6833 p = NULL;
6834 do {
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00006835 char *str, *eq;
6836 str = var_str_list->text;
6837 eq = strchr(str, '=');
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006838 if (!eq) /* stop at first non-assignment */
6839 break;
6840 eq++;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00006841 if (name_len == (unsigned)(eq - str)
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006842 && strncmp(str, name, name_len) == 0
6843 ) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006844 p = eq;
6845 /* goto value; - WRONG! */
6846 /* think "A=1 A=2 B=$A" */
6847 }
6848 var_str_list = var_str_list->next;
6849 } while (var_str_list);
6850 if (p)
6851 goto value;
6852 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006853 p = lookupvar(name);
6854 value:
6855 if (!p)
6856 return -1;
6857
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006858 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006859#if ENABLE_UNICODE_SUPPORT
6860 if (subtype == VSLENGTH && len > 0) {
6861 reinit_unicode_for_ash();
6862 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00006863 STADJUST(-len, expdest);
6864 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006865 len = unicode_strlen(p);
6866 }
6867 }
6868#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006869 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006870 }
6871
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006872 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006873 STADJUST(-len, expdest);
6874 return len;
6875}
6876
6877/*
6878 * Expand a variable, and return a pointer to the next character in the
6879 * input string.
6880 */
6881static char *
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006882evalvar(char *p, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006883{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006884 char varflags;
6885 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02006886 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006887 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006888 char *var;
6889 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006890 int startloc;
6891 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006892
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006893 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006894 subtype = varflags & VSTYPE;
Denys Vlasenko88e15702016-10-26 01:55:56 +02006895
6896 if (!subtype)
6897 raise_error_syntax("bad substitution");
6898
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006899 quoted = flag & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006900 var = p;
6901 easy = (!quoted || (*var == '@' && shellparam.nparam));
6902 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02006903 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006904
6905 again:
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006906 varlen = varvalue(var, varflags, flag, var_str_list, &quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006907 if (varflags & VSNUL)
6908 varlen--;
6909
6910 if (subtype == VSPLUS) {
6911 varlen = -1 - varlen;
6912 goto vsplus;
6913 }
6914
6915 if (subtype == VSMINUS) {
6916 vsplus:
6917 if (varlen < 0) {
6918 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006919 p,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006920 flag | EXP_TILDE | EXP_WORD,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006921 var_str_list
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006922 );
6923 goto end;
6924 }
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006925 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006926 }
6927
6928 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006929 if (varlen >= 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006930 goto record;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006931
6932 subevalvar(p, var, 0, subtype, startloc, varflags,
6933 flag & ~QUOTES_ESC, var_str_list);
6934 varflags &= ~VSNUL;
6935 /*
6936 * Remove any recorded regions beyond
6937 * start of variable
6938 */
6939 removerecordregions(startloc);
6940 goto again;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006941 }
6942
6943 if (varlen < 0 && uflag)
6944 varunset(p, var, 0, 0);
6945
6946 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006947 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006948 goto record;
6949 }
6950
6951 if (subtype == VSNORMAL) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006952 record:
6953 if (!easy)
6954 goto end;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006955 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006956 goto end;
6957 }
6958
6959#if DEBUG
6960 switch (subtype) {
6961 case VSTRIMLEFT:
6962 case VSTRIMLEFTMAX:
6963 case VSTRIMRIGHT:
6964 case VSTRIMRIGHTMAX:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006965#if ENABLE_ASH_BASH_COMPAT
6966 case VSSUBSTR:
6967 case VSREPLACE:
6968 case VSREPLACEALL:
6969#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006970 break;
6971 default:
6972 abort();
6973 }
6974#endif
6975
6976 if (varlen >= 0) {
6977 /*
6978 * Terminate the string and start recording the pattern
6979 * right after it
6980 */
6981 STPUTC('\0', expdest);
6982 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006983 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006984 startloc, varflags, flag, var_str_list)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006985 int amount = expdest - (
6986 (char *)stackblock() + patloc - 1
6987 );
6988 STADJUST(-amount, expdest);
6989 }
6990 /* Remove any recorded regions beyond start of variable */
6991 removerecordregions(startloc);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006992 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006993 }
6994
6995 end:
6996 if (subtype != VSNORMAL) { /* skip to end of alternative */
6997 int nesting = 1;
6998 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006999 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007000 if (c == CTLESC)
7001 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02007002 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007003 if (varlen >= 0)
7004 argbackq = argbackq->next;
7005 } else if (c == CTLVAR) {
7006 if ((*p++ & VSTYPE) != VSNORMAL)
7007 nesting++;
7008 } else if (c == CTLENDVAR) {
7009 if (--nesting == 0)
7010 break;
7011 }
7012 }
7013 }
7014 return p;
7015}
7016
7017/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007018 * Add a file name to the list.
7019 */
7020static void
7021addfname(const char *name)
7022{
7023 struct strlist *sp;
7024
Denis Vlasenko597906c2008-02-20 16:38:54 +00007025 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02007026 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007027 *exparg.lastp = sp;
7028 exparg.lastp = &sp->next;
7029}
7030
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007031/* If we want to use glob() from libc... */
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007032#if !ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007033
7034/* Add the result of glob() to the list */
7035static void
7036addglob(const glob_t *pglob)
7037{
7038 char **p = pglob->gl_pathv;
7039
7040 do {
7041 addfname(*p);
7042 } while (*++p);
7043}
7044static void
7045expandmeta(struct strlist *str /*, int flag*/)
7046{
7047 /* TODO - EXP_REDIR */
7048
7049 while (str) {
7050 char *p;
7051 glob_t pglob;
7052 int i;
7053
7054 if (fflag)
7055 goto nometa;
7056 INT_OFF;
7057 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007058// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7059// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7060//
7061// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7062// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7063// Which means you need to unescape the string, right? Not so fast:
7064// if there _is_ a file named "file\?" (with backslash), it is returned
7065// as "file\?" too (whichever pattern you used to find it, say, "file*").
7066// You DONT KNOW by looking at the result whether you need to unescape it.
7067//
7068// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7069// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7070// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7071// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7072// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7073// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7074 i = glob(p, 0, NULL, &pglob);
7075 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007076 if (p != str->text)
7077 free(p);
7078 switch (i) {
7079 case 0:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007080#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007081 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7082 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7083 goto nometa2;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007084#endif
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007085 addglob(&pglob);
7086 globfree(&pglob);
7087 INT_ON;
7088 break;
7089 case GLOB_NOMATCH:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007090 //nometa2:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007091 globfree(&pglob);
7092 INT_ON;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007093 nometa:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007094 *exparg.lastp = str;
7095 rmescapes(str->text, 0);
7096 exparg.lastp = &str->next;
7097 break;
7098 default: /* GLOB_NOSPACE */
7099 globfree(&pglob);
7100 INT_ON;
7101 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7102 }
7103 str = str->next;
7104 }
7105}
7106
7107#else
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007108/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007109
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007110/*
7111 * Do metacharacter (i.e. *, ?, [...]) expansion.
7112 */
7113static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007114expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007115{
7116 char *p;
7117 const char *cp;
7118 char *start;
7119 char *endname;
7120 int metaflag;
7121 struct stat statb;
7122 DIR *dirp;
7123 struct dirent *dp;
7124 int atend;
7125 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007126 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007127
7128 metaflag = 0;
7129 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007130 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007131 if (*p == '*' || *p == '?')
7132 metaflag = 1;
7133 else if (*p == '[') {
7134 char *q = p + 1;
7135 if (*q == '!')
7136 q++;
7137 for (;;) {
7138 if (*q == '\\')
7139 q++;
7140 if (*q == '/' || *q == '\0')
7141 break;
7142 if (*++q == ']') {
7143 metaflag = 1;
7144 break;
7145 }
7146 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007147 } else {
7148 if (*p == '\\')
7149 esc++;
7150 if (p[esc] == '/') {
7151 if (metaflag)
7152 break;
7153 start = p + esc + 1;
7154 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007155 }
7156 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007157 if (metaflag == 0) { /* we've reached the end of the file name */
7158 if (enddir != expdir)
7159 metaflag++;
7160 p = name;
7161 do {
7162 if (*p == '\\')
7163 p++;
7164 *enddir++ = *p;
7165 } while (*p++);
7166 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7167 addfname(expdir);
7168 return;
7169 }
7170 endname = p;
7171 if (name < start) {
7172 p = name;
7173 do {
7174 if (*p == '\\')
7175 p++;
7176 *enddir++ = *p++;
7177 } while (p < start);
7178 }
7179 if (enddir == expdir) {
7180 cp = ".";
7181 } else if (enddir == expdir + 1 && *expdir == '/') {
7182 cp = "/";
7183 } else {
7184 cp = expdir;
7185 enddir[-1] = '\0';
7186 }
7187 dirp = opendir(cp);
7188 if (dirp == NULL)
7189 return;
7190 if (enddir != expdir)
7191 enddir[-1] = '/';
7192 if (*endname == 0) {
7193 atend = 1;
7194 } else {
7195 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007196 *endname = '\0';
7197 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007198 }
7199 matchdot = 0;
7200 p = start;
7201 if (*p == '\\')
7202 p++;
7203 if (*p == '.')
7204 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007205 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007206 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007207 continue;
7208 if (pmatch(start, dp->d_name)) {
7209 if (atend) {
7210 strcpy(enddir, dp->d_name);
7211 addfname(expdir);
7212 } else {
7213 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7214 continue;
7215 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007216 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007217 }
7218 }
7219 }
7220 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007221 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007222 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007223}
7224
7225static struct strlist *
7226msort(struct strlist *list, int len)
7227{
7228 struct strlist *p, *q = NULL;
7229 struct strlist **lpp;
7230 int half;
7231 int n;
7232
7233 if (len <= 1)
7234 return list;
7235 half = len >> 1;
7236 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007237 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007238 q = p;
7239 p = p->next;
7240 }
7241 q->next = NULL; /* terminate first half of list */
7242 q = msort(list, half); /* sort first half of list */
7243 p = msort(p, len - half); /* sort second half */
7244 lpp = &list;
7245 for (;;) {
7246#if ENABLE_LOCALE_SUPPORT
7247 if (strcoll(p->text, q->text) < 0)
7248#else
7249 if (strcmp(p->text, q->text) < 0)
7250#endif
7251 {
7252 *lpp = p;
7253 lpp = &p->next;
7254 p = *lpp;
7255 if (p == NULL) {
7256 *lpp = q;
7257 break;
7258 }
7259 } else {
7260 *lpp = q;
7261 lpp = &q->next;
7262 q = *lpp;
7263 if (q == NULL) {
7264 *lpp = p;
7265 break;
7266 }
7267 }
7268 }
7269 return list;
7270}
7271
7272/*
7273 * Sort the results of file name expansion. It calculates the number of
7274 * strings to sort and then calls msort (short for merge sort) to do the
7275 * work.
7276 */
7277static struct strlist *
7278expsort(struct strlist *str)
7279{
7280 int len;
7281 struct strlist *sp;
7282
7283 len = 0;
7284 for (sp = str; sp; sp = sp->next)
7285 len++;
7286 return msort(str, len);
7287}
7288
7289static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007290expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007291{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00007292 static const char metachars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007293 '*', '?', '[', 0
7294 };
7295 /* TODO - EXP_REDIR */
7296
7297 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007298 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007299 struct strlist **savelastp;
7300 struct strlist *sp;
7301 char *p;
7302
7303 if (fflag)
7304 goto nometa;
7305 if (!strpbrk(str->text, metachars))
7306 goto nometa;
7307 savelastp = exparg.lastp;
7308
7309 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007310 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007311 {
7312 int i = strlen(str->text);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007313//BUGGY estimation of how long expanded name can be
7314 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007315 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007316 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007317 free(expdir);
7318 if (p != str->text)
7319 free(p);
7320 INT_ON;
7321 if (exparg.lastp == savelastp) {
7322 /*
7323 * no matches
7324 */
7325 nometa:
7326 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007327 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007328 exparg.lastp = &str->next;
7329 } else {
7330 *exparg.lastp = NULL;
7331 *savelastp = sp = expsort(*savelastp);
7332 while (sp->next != NULL)
7333 sp = sp->next;
7334 exparg.lastp = &sp->next;
7335 }
7336 str = str->next;
7337 }
7338}
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007339#endif /* ENABLE_ASH_INTERNAL_GLOB */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007340
7341/*
7342 * Perform variable substitution and command substitution on an argument,
7343 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7344 * perform splitting and file name expansion. When arglist is NULL, perform
7345 * here document expansion.
7346 */
7347static void
7348expandarg(union node *arg, struct arglist *arglist, int flag)
7349{
7350 struct strlist *sp;
7351 char *p;
7352
7353 argbackq = arg->narg.backquote;
7354 STARTSTACKSTR(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007355 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007356 argstr(arg->narg.text, flag,
7357 /* var_str_list: */ arglist ? arglist->list : NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007358 p = _STPUTC('\0', expdest);
7359 expdest = p - 1;
7360 if (arglist == NULL) {
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007361 /* here document expanded */
7362 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007363 }
7364 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007365 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007366 exparg.lastp = &exparg.list;
7367 /*
7368 * TODO - EXP_REDIR
7369 */
7370 if (flag & EXP_FULL) {
7371 ifsbreakup(p, &exparg);
7372 *exparg.lastp = NULL;
7373 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007374 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007375 } else {
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007376 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007377 rmescapes(p, 0);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007378 TRACE(("expandarg: rmescapes:'%s'\n", p));
7379 }
Denis Vlasenko597906c2008-02-20 16:38:54 +00007380 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007381 sp->text = p;
7382 *exparg.lastp = sp;
7383 exparg.lastp = &sp->next;
7384 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007385 *exparg.lastp = NULL;
7386 if (exparg.list) {
7387 *arglist->lastp = exparg.list;
7388 arglist->lastp = exparg.lastp;
7389 }
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007390
7391 out:
7392 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007393}
7394
7395/*
7396 * Expand shell variables and backquotes inside a here document.
7397 */
7398static void
7399expandhere(union node *arg, int fd)
7400{
Ron Yorston549deab2015-05-18 09:57:51 +02007401 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007402 full_write(fd, stackblock(), expdest - (char *)stackblock());
7403}
7404
7405/*
7406 * Returns true if the pattern matches the string.
7407 */
7408static int
7409patmatch(char *pattern, const char *string)
7410{
Ron Yorston549deab2015-05-18 09:57:51 +02007411 return pmatch(preglob(pattern, 0), string);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007412}
7413
7414/*
7415 * See if a pattern matches in a case statement.
7416 */
7417static int
7418casematch(union node *pattern, char *val)
7419{
7420 struct stackmark smark;
7421 int result;
7422
7423 setstackmark(&smark);
7424 argbackq = pattern->narg.backquote;
7425 STARTSTACKSTR(expdest);
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007426 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7427 /* var_str_list: */ NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007428 STACKSTRNUL(expdest);
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007429 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007430 result = patmatch(stackblock(), val);
7431 popstackmark(&smark);
7432 return result;
7433}
7434
7435
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007436/* ============ find_command */
7437
7438struct builtincmd {
7439 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007440 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007441 /* unsigned flags; */
7442};
7443#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007444/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007445 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007446#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007447#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007448
7449struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007450 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007451 union param {
7452 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007453 /* index >= 0 for commands without path (slashes) */
7454 /* (TODO: what exactly does the value mean? PATH position?) */
7455 /* index == -1 for commands with slashes */
7456 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007457 const struct builtincmd *cmd;
7458 struct funcnode *func;
7459 } u;
7460};
7461/* values of cmdtype */
7462#define CMDUNKNOWN -1 /* no entry in table for command */
7463#define CMDNORMAL 0 /* command is an executable program */
7464#define CMDFUNCTION 1 /* command is a shell function */
7465#define CMDBUILTIN 2 /* command is a shell builtin */
7466
7467/* action to find_command() */
7468#define DO_ERR 0x01 /* prints errors */
7469#define DO_ABS 0x02 /* checks absolute paths */
7470#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7471#define DO_ALTPATH 0x08 /* using alternate path */
7472#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7473
7474static void find_command(char *, struct cmdentry *, int, const char *);
7475
7476
7477/* ============ Hashing commands */
7478
7479/*
7480 * When commands are first encountered, they are entered in a hash table.
7481 * This ensures that a full path search will not have to be done for them
7482 * on each invocation.
7483 *
7484 * We should investigate converting to a linear search, even though that
7485 * would make the command name "hash" a misnomer.
7486 */
7487
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007488struct tblentry {
7489 struct tblentry *next; /* next entry in hash chain */
7490 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007491 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007492 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007493 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007494};
7495
Denis Vlasenko01631112007-12-16 17:20:38 +00007496static struct tblentry **cmdtable;
7497#define INIT_G_cmdtable() do { \
7498 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7499} while (0)
7500
7501static int builtinloc = -1; /* index in path of %builtin, or -1 */
7502
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007503
7504static void
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007505tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007506{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007507#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007508 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007509 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007510 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007511 while (*envp)
7512 putenv(*envp++);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007513 run_applet_no_and_exit(applet_no, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007514 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007515 /* re-exec ourselves with the new arguments */
7516 execve(bb_busybox_exec_path, argv, envp);
7517 /* If they called chroot or otherwise made the binary no longer
7518 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007519 }
7520#endif
7521
7522 repeat:
7523#ifdef SYSV
7524 do {
7525 execve(cmd, argv, envp);
7526 } while (errno == EINTR);
7527#else
7528 execve(cmd, argv, envp);
7529#endif
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007530 if (cmd != (char*) bb_busybox_exec_path && errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007531 /* Run "cmd" as a shell script:
7532 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7533 * "If the execve() function fails with ENOEXEC, the shell
7534 * shall execute a command equivalent to having a shell invoked
7535 * with the command name as its first operand,
7536 * with any remaining arguments passed to the new shell"
7537 *
7538 * That is, do not use $SHELL, user's shell, or /bin/sh;
7539 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007540 *
7541 * Note that bash reads ~80 chars of the file, and if it sees
7542 * a zero byte before it sees newline, it doesn't try to
7543 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007544 * message and exit code 126. For one, this prevents attempts
7545 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007546 */
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007547 argv[0] = cmd;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007548 cmd = (char*) bb_busybox_exec_path;
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007549 /* NB: this is only possible because all callers of shellexec()
7550 * ensure that the argv[-1] slot exists!
7551 */
7552 argv--;
7553 argv[0] = (char*) "ash";
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007554 goto repeat;
7555 }
7556}
7557
7558/*
7559 * Exec a program. Never returns. If you change this routine, you may
7560 * have to change the find_command routine as well.
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007561 * argv[-1] must exist and be writable! See tryexec() for why.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007562 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007563static void shellexec(char **, const char *, int) NORETURN;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007564static void
7565shellexec(char **argv, const char *path, int idx)
7566{
7567 char *cmdname;
7568 int e;
7569 char **envp;
7570 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007571 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007572
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007573 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007574 if (strchr(argv[0], '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007575#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007576 || (applet_no = find_applet_by_name(argv[0])) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007577#endif
7578 ) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007579 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007580 if (applet_no >= 0) {
7581 /* We tried execing ourself, but it didn't work.
7582 * Maybe /proc/self/exe doesn't exist?
7583 * Try $PATH search.
7584 */
7585 goto try_PATH;
7586 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007587 e = errno;
7588 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007589 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007590 e = ENOENT;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007591 while ((cmdname = path_advance(&path, argv[0])) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007592 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007593 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007594 if (errno != ENOENT && errno != ENOTDIR)
7595 e = errno;
7596 }
7597 stunalloc(cmdname);
7598 }
7599 }
7600
7601 /* Map to POSIX errors */
7602 switch (e) {
7603 case EACCES:
7604 exerrno = 126;
7605 break;
7606 case ENOENT:
7607 exerrno = 127;
7608 break;
7609 default:
7610 exerrno = 2;
7611 break;
7612 }
7613 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007614 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7615 argv[0], e, suppress_int));
Denys Vlasenko061a0902016-10-25 17:24:25 +02007616 ash_msg_and_raise(EXEXIT, "%s: %s", argv[0], errmsg(e, "not found"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007617 /* NOTREACHED */
7618}
7619
7620static void
7621printentry(struct tblentry *cmdp)
7622{
7623 int idx;
7624 const char *path;
7625 char *name;
7626
7627 idx = cmdp->param.index;
7628 path = pathval();
7629 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007630 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007631 stunalloc(name);
7632 } while (--idx >= 0);
7633 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7634}
7635
7636/*
7637 * Clear out command entries. The argument specifies the first entry in
7638 * PATH which has changed.
7639 */
7640static void
7641clearcmdentry(int firstchange)
7642{
7643 struct tblentry **tblp;
7644 struct tblentry **pp;
7645 struct tblentry *cmdp;
7646
7647 INT_OFF;
7648 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7649 pp = tblp;
7650 while ((cmdp = *pp) != NULL) {
7651 if ((cmdp->cmdtype == CMDNORMAL &&
7652 cmdp->param.index >= firstchange)
7653 || (cmdp->cmdtype == CMDBUILTIN &&
7654 builtinloc >= firstchange)
7655 ) {
7656 *pp = cmdp->next;
7657 free(cmdp);
7658 } else {
7659 pp = &cmdp->next;
7660 }
7661 }
7662 }
7663 INT_ON;
7664}
7665
7666/*
7667 * Locate a command in the command hash table. If "add" is nonzero,
7668 * add the command to the table if it is not already present. The
7669 * variable "lastcmdentry" is set to point to the address of the link
7670 * pointing to the entry, so that delete_cmd_entry can delete the
7671 * entry.
7672 *
7673 * Interrupts must be off if called with add != 0.
7674 */
7675static struct tblentry **lastcmdentry;
7676
7677static struct tblentry *
7678cmdlookup(const char *name, int add)
7679{
7680 unsigned int hashval;
7681 const char *p;
7682 struct tblentry *cmdp;
7683 struct tblentry **pp;
7684
7685 p = name;
7686 hashval = (unsigned char)*p << 4;
7687 while (*p)
7688 hashval += (unsigned char)*p++;
7689 hashval &= 0x7FFF;
7690 pp = &cmdtable[hashval % CMDTABLESIZE];
7691 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7692 if (strcmp(cmdp->cmdname, name) == 0)
7693 break;
7694 pp = &cmdp->next;
7695 }
7696 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007697 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7698 + strlen(name)
7699 /* + 1 - already done because
7700 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007701 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007702 cmdp->cmdtype = CMDUNKNOWN;
7703 strcpy(cmdp->cmdname, name);
7704 }
7705 lastcmdentry = pp;
7706 return cmdp;
7707}
7708
7709/*
7710 * Delete the command entry returned on the last lookup.
7711 */
7712static void
7713delete_cmd_entry(void)
7714{
7715 struct tblentry *cmdp;
7716
7717 INT_OFF;
7718 cmdp = *lastcmdentry;
7719 *lastcmdentry = cmdp->next;
7720 if (cmdp->cmdtype == CMDFUNCTION)
7721 freefunc(cmdp->param.func);
7722 free(cmdp);
7723 INT_ON;
7724}
7725
7726/*
7727 * Add a new command entry, replacing any existing command entry for
7728 * the same name - except special builtins.
7729 */
7730static void
7731addcmdentry(char *name, struct cmdentry *entry)
7732{
7733 struct tblentry *cmdp;
7734
7735 cmdp = cmdlookup(name, 1);
7736 if (cmdp->cmdtype == CMDFUNCTION) {
7737 freefunc(cmdp->param.func);
7738 }
7739 cmdp->cmdtype = entry->cmdtype;
7740 cmdp->param = entry->u;
7741 cmdp->rehash = 0;
7742}
7743
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007744static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007745hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007746{
7747 struct tblentry **pp;
7748 struct tblentry *cmdp;
7749 int c;
7750 struct cmdentry entry;
7751 char *name;
7752
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007753 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007754 clearcmdentry(0);
7755 return 0;
7756 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007757
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007758 if (*argptr == NULL) {
7759 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7760 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7761 if (cmdp->cmdtype == CMDNORMAL)
7762 printentry(cmdp);
7763 }
7764 }
7765 return 0;
7766 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007767
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007768 c = 0;
7769 while ((name = *argptr) != NULL) {
7770 cmdp = cmdlookup(name, 0);
7771 if (cmdp != NULL
7772 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007773 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7774 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007775 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007776 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007777 find_command(name, &entry, DO_ERR, pathval());
7778 if (entry.cmdtype == CMDUNKNOWN)
7779 c = 1;
7780 argptr++;
7781 }
7782 return c;
7783}
7784
7785/*
7786 * Called when a cd is done. Marks all commands so the next time they
7787 * are executed they will be rehashed.
7788 */
7789static void
7790hashcd(void)
7791{
7792 struct tblentry **pp;
7793 struct tblentry *cmdp;
7794
7795 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7796 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007797 if (cmdp->cmdtype == CMDNORMAL
7798 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02007799 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007800 && builtinloc > 0)
7801 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007802 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007803 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007804 }
7805 }
7806}
7807
7808/*
7809 * Fix command hash table when PATH changed.
7810 * Called before PATH is changed. The argument is the new value of PATH;
7811 * pathval() still returns the old value at this point.
7812 * Called with interrupts off.
7813 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007814static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007815changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007816{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007817 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007818 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007819 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007820 int idx_bltin;
7821
7822 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007823 firstchange = 9999; /* assume no change */
7824 idx = 0;
7825 idx_bltin = -1;
7826 for (;;) {
7827 if (*old != *new) {
7828 firstchange = idx;
7829 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007830 || (*old == ':' && *new == '\0')
7831 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007832 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007833 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007834 old = new; /* ignore subsequent differences */
7835 }
7836 if (*new == '\0')
7837 break;
7838 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7839 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007840 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007841 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007842 new++;
7843 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007844 }
7845 if (builtinloc < 0 && idx_bltin >= 0)
7846 builtinloc = idx_bltin; /* zap builtins */
7847 if (builtinloc >= 0 && idx_bltin < 0)
7848 firstchange = 0;
7849 clearcmdentry(firstchange);
7850 builtinloc = idx_bltin;
7851}
Ron Yorston95ebcf72015-11-03 09:42:23 +00007852enum {
7853 TEOF,
7854 TNL,
7855 TREDIR,
7856 TWORD,
7857 TSEMI,
7858 TBACKGND,
7859 TAND,
7860 TOR,
7861 TPIPE,
7862 TLP,
7863 TRP,
7864 TENDCASE,
7865 TENDBQUOTE,
7866 TNOT,
7867 TCASE,
7868 TDO,
7869 TDONE,
7870 TELIF,
7871 TELSE,
7872 TESAC,
7873 TFI,
7874 TFOR,
7875#if ENABLE_ASH_BASH_COMPAT
7876 TFUNCTION,
7877#endif
7878 TIF,
7879 TIN,
7880 TTHEN,
7881 TUNTIL,
7882 TWHILE,
7883 TBEGIN,
7884 TEND
7885};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007886typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007887
Denys Vlasenko888527c2016-10-02 16:54:17 +02007888/* Nth bit indicates if token marks the end of a list */
7889enum {
7890 tokendlist = 0
7891 /* 0 */ | (1u << TEOF)
7892 /* 1 */ | (0u << TNL)
7893 /* 2 */ | (0u << TREDIR)
7894 /* 3 */ | (0u << TWORD)
7895 /* 4 */ | (0u << TSEMI)
7896 /* 5 */ | (0u << TBACKGND)
7897 /* 6 */ | (0u << TAND)
7898 /* 7 */ | (0u << TOR)
7899 /* 8 */ | (0u << TPIPE)
7900 /* 9 */ | (0u << TLP)
7901 /* 10 */ | (1u << TRP)
7902 /* 11 */ | (1u << TENDCASE)
7903 /* 12 */ | (1u << TENDBQUOTE)
7904 /* 13 */ | (0u << TNOT)
7905 /* 14 */ | (0u << TCASE)
7906 /* 15 */ | (1u << TDO)
7907 /* 16 */ | (1u << TDONE)
7908 /* 17 */ | (1u << TELIF)
7909 /* 18 */ | (1u << TELSE)
7910 /* 19 */ | (1u << TESAC)
7911 /* 20 */ | (1u << TFI)
7912 /* 21 */ | (0u << TFOR)
7913#if ENABLE_ASH_BASH_COMPAT
7914 /* 22 */ | (0u << TFUNCTION)
Denys Vlasenko80729a42016-10-02 22:33:15 +02007915#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02007916 /* 23 */ | (0u << TIF)
7917 /* 24 */ | (0u << TIN)
7918 /* 25 */ | (1u << TTHEN)
7919 /* 26 */ | (0u << TUNTIL)
7920 /* 27 */ | (0u << TWHILE)
7921 /* 28 */ | (0u << TBEGIN)
7922 /* 29 */ | (1u << TEND)
7923 , /* thus far 29 bits used */
7924};
7925
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007926static const char *const tokname_array[] = {
Denys Vlasenko888527c2016-10-02 16:54:17 +02007927 "end of file",
7928 "newline",
7929 "redirection",
7930 "word",
7931 ";",
7932 "&",
7933 "&&",
7934 "||",
7935 "|",
7936 "(",
7937 ")",
7938 ";;",
7939 "`",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007940#define KWDOFFSET 13
7941 /* the following are keywords */
Denys Vlasenko888527c2016-10-02 16:54:17 +02007942 "!",
7943 "case",
7944 "do",
7945 "done",
7946 "elif",
7947 "else",
7948 "esac",
7949 "fi",
7950 "for",
Ron Yorston95ebcf72015-11-03 09:42:23 +00007951#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko888527c2016-10-02 16:54:17 +02007952 "function",
Ron Yorston95ebcf72015-11-03 09:42:23 +00007953#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02007954 "if",
7955 "in",
7956 "then",
7957 "until",
7958 "while",
7959 "{",
7960 "}",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007961};
7962
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007963/* Wrapper around strcmp for qsort/bsearch/... */
7964static int
7965pstrcmp(const void *a, const void *b)
7966{
Denys Vlasenko888527c2016-10-02 16:54:17 +02007967 return strcmp((char*)a, *(char**)b);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007968}
7969
7970static const char *const *
7971findkwd(const char *s)
7972{
7973 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00007974 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7975 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007976}
7977
7978/*
7979 * Locate and print what a word is...
7980 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007981static int
Ron Yorston3f221112015-08-03 13:47:33 +01007982describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007983{
7984 struct cmdentry entry;
7985 struct tblentry *cmdp;
7986#if ENABLE_ASH_ALIAS
7987 const struct alias *ap;
7988#endif
Ron Yorston3f221112015-08-03 13:47:33 +01007989
7990 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007991
7992 if (describe_command_verbose) {
7993 out1str(command);
7994 }
7995
7996 /* First look at the keywords */
7997 if (findkwd(command)) {
7998 out1str(describe_command_verbose ? " is a shell keyword" : command);
7999 goto out;
8000 }
8001
8002#if ENABLE_ASH_ALIAS
8003 /* Then look at the aliases */
8004 ap = lookupalias(command, 0);
8005 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008006 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008007 out1str("alias ");
8008 printalias(ap);
8009 return 0;
8010 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00008011 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008012 goto out;
8013 }
8014#endif
8015 /* Then check if it is a tracked alias */
8016 cmdp = cmdlookup(command, 0);
8017 if (cmdp != NULL) {
8018 entry.cmdtype = cmdp->cmdtype;
8019 entry.u = cmdp->param;
8020 } else {
8021 /* Finally use brute force */
8022 find_command(command, &entry, DO_ABS, path);
8023 }
8024
8025 switch (entry.cmdtype) {
8026 case CMDNORMAL: {
8027 int j = entry.u.index;
8028 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008029 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008030 p = command;
8031 } else {
8032 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008033 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008034 stunalloc(p);
8035 } while (--j >= 0);
8036 }
8037 if (describe_command_verbose) {
8038 out1fmt(" is%s %s",
8039 (cmdp ? " a tracked alias for" : nullstr), p
8040 );
8041 } else {
8042 out1str(p);
8043 }
8044 break;
8045 }
8046
8047 case CMDFUNCTION:
8048 if (describe_command_verbose) {
8049 out1str(" is a shell function");
8050 } else {
8051 out1str(command);
8052 }
8053 break;
8054
8055 case CMDBUILTIN:
8056 if (describe_command_verbose) {
8057 out1fmt(" is a %sshell builtin",
8058 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8059 "special " : nullstr
8060 );
8061 } else {
8062 out1str(command);
8063 }
8064 break;
8065
8066 default:
8067 if (describe_command_verbose) {
8068 out1str(": not found\n");
8069 }
8070 return 127;
8071 }
8072 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008073 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008074 return 0;
8075}
8076
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008077static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008078typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008079{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008080 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008081 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008082 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008083
Denis Vlasenko46846e22007-05-20 13:08:31 +00008084 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008085 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008086 i++;
8087 verbose = 0;
8088 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008089 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008090 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008091 }
8092 return err;
8093}
8094
8095#if ENABLE_ASH_CMDCMD
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008096/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8097static char **
8098parse_command_args(char **argv, const char **path)
8099{
8100 char *cp, c;
8101
8102 for (;;) {
8103 cp = *++argv;
8104 if (!cp)
8105 return NULL;
8106 if (*cp++ != '-')
8107 break;
8108 c = *cp++;
8109 if (!c)
8110 break;
8111 if (c == '-' && !*cp) {
8112 if (!*++argv)
8113 return NULL;
8114 break;
8115 }
8116 do {
8117 switch (c) {
8118 case 'p':
8119 *path = bb_default_path;
8120 break;
8121 default:
8122 /* run 'typecmd' for other options */
8123 return NULL;
8124 }
8125 c = *cp++;
8126 } while (c);
8127 }
8128 return argv;
8129}
8130
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008131static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008132commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008133{
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008134 char *cmd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008135 int c;
8136 enum {
8137 VERIFY_BRIEF = 1,
8138 VERIFY_VERBOSE = 2,
8139 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008140 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008141
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008142 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8143 * never reaches this function.
8144 */
8145
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008146 while ((c = nextopt("pvV")) != '\0')
8147 if (c == 'V')
8148 verify |= VERIFY_VERBOSE;
8149 else if (c == 'v')
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008150 /*verify |= VERIFY_BRIEF*/;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008151#if DEBUG
8152 else if (c != 'p')
8153 abort();
8154#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008155 else
8156 path = bb_default_path;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008157
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008158 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008159 cmd = *argptr;
8160 if (/*verify && */ cmd)
8161 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008162
8163 return 0;
8164}
8165#endif
8166
8167
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008168/*static int funcblocksize; // size of structures in function */
8169/*static int funcstringsize; // size of strings in node */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008170static void *funcblock; /* block to allocate function from */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008171static char *funcstring_end; /* end of block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008172
Eric Andersencb57d552001-06-28 07:25:16 +00008173/* flags in argument to evaltree */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008174#define EV_EXIT 01 /* exit after evaluating tree */
8175#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Eric Andersencb57d552001-06-28 07:25:16 +00008176
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008177static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008178 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8179 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8180 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8181 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8182 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8183 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8184 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8185 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8186 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8187 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8188 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8189 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8190 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8191 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8192 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8193 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8194 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008195#if ENABLE_ASH_BASH_COMPAT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008196 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008197#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008198 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8199 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8200 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8201 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8202 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8203 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8204 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8205 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8206 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008207};
8208
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008209static int calcsize(int funcblocksize, union node *n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008210
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008211static int
8212sizenodelist(int funcblocksize, struct nodelist *lp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008213{
8214 while (lp) {
8215 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008216 funcblocksize = calcsize(funcblocksize, lp->n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008217 lp = lp->next;
8218 }
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008219 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008220}
8221
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008222static int
8223calcsize(int funcblocksize, union node *n)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008224{
8225 if (n == NULL)
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008226 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008227 funcblocksize += nodesize[n->type];
8228 switch (n->type) {
8229 case NCMD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008230 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8231 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8232 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008233 break;
8234 case NPIPE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008235 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008236 break;
8237 case NREDIR:
8238 case NBACKGND:
8239 case NSUBSHELL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008240 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8241 funcblocksize = calcsize(funcblocksize, n->nredir.n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008242 break;
8243 case NAND:
8244 case NOR:
8245 case NSEMI:
8246 case NWHILE:
8247 case NUNTIL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008248 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8249 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008250 break;
8251 case NIF:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008252 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8253 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8254 funcblocksize = calcsize(funcblocksize, n->nif.test);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008255 break;
8256 case NFOR:
Denys Vlasenko561639a2016-10-07 04:28:33 +02008257 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008258 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8259 funcblocksize = calcsize(funcblocksize, n->nfor.args);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008260 break;
8261 case NCASE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008262 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8263 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008264 break;
8265 case NCLIST:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008266 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8267 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8268 funcblocksize = calcsize(funcblocksize, n->nclist.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008269 break;
8270 case NDEFUN:
8271 case NARG:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008272 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
Denys Vlasenko561639a2016-10-07 04:28:33 +02008273 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008274 funcblocksize = calcsize(funcblocksize, n->narg.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008275 break;
8276 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008277#if ENABLE_ASH_BASH_COMPAT
8278 case NTO2:
8279#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008280 case NCLOBBER:
8281 case NFROM:
8282 case NFROMTO:
8283 case NAPPEND:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008284 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8285 funcblocksize = calcsize(funcblocksize, n->nfile.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008286 break;
8287 case NTOFD:
8288 case NFROMFD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008289 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8290 funcblocksize = calcsize(funcblocksize, n->ndup.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008291 break;
8292 case NHERE:
8293 case NXHERE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008294 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8295 funcblocksize = calcsize(funcblocksize, n->nhere.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008296 break;
8297 case NNOT:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008298 funcblocksize = calcsize(funcblocksize, n->nnot.com);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008299 break;
8300 };
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008301 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008302}
8303
8304static char *
8305nodeckstrdup(char *s)
8306{
Denys Vlasenko561639a2016-10-07 04:28:33 +02008307 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008308 return strcpy(funcstring_end, s);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008309}
8310
8311static union node *copynode(union node *);
8312
8313static struct nodelist *
8314copynodelist(struct nodelist *lp)
8315{
8316 struct nodelist *start;
8317 struct nodelist **lpp;
8318
8319 lpp = &start;
8320 while (lp) {
8321 *lpp = funcblock;
8322 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8323 (*lpp)->n = copynode(lp->n);
8324 lp = lp->next;
8325 lpp = &(*lpp)->next;
8326 }
8327 *lpp = NULL;
8328 return start;
8329}
8330
8331static union node *
8332copynode(union node *n)
8333{
8334 union node *new;
8335
8336 if (n == NULL)
8337 return NULL;
8338 new = funcblock;
8339 funcblock = (char *) funcblock + nodesize[n->type];
8340
8341 switch (n->type) {
8342 case NCMD:
8343 new->ncmd.redirect = copynode(n->ncmd.redirect);
8344 new->ncmd.args = copynode(n->ncmd.args);
8345 new->ncmd.assign = copynode(n->ncmd.assign);
8346 break;
8347 case NPIPE:
8348 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008349 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008350 break;
8351 case NREDIR:
8352 case NBACKGND:
8353 case NSUBSHELL:
8354 new->nredir.redirect = copynode(n->nredir.redirect);
8355 new->nredir.n = copynode(n->nredir.n);
8356 break;
8357 case NAND:
8358 case NOR:
8359 case NSEMI:
8360 case NWHILE:
8361 case NUNTIL:
8362 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8363 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8364 break;
8365 case NIF:
8366 new->nif.elsepart = copynode(n->nif.elsepart);
8367 new->nif.ifpart = copynode(n->nif.ifpart);
8368 new->nif.test = copynode(n->nif.test);
8369 break;
8370 case NFOR:
8371 new->nfor.var = nodeckstrdup(n->nfor.var);
8372 new->nfor.body = copynode(n->nfor.body);
8373 new->nfor.args = copynode(n->nfor.args);
8374 break;
8375 case NCASE:
8376 new->ncase.cases = copynode(n->ncase.cases);
8377 new->ncase.expr = copynode(n->ncase.expr);
8378 break;
8379 case NCLIST:
8380 new->nclist.body = copynode(n->nclist.body);
8381 new->nclist.pattern = copynode(n->nclist.pattern);
8382 new->nclist.next = copynode(n->nclist.next);
8383 break;
8384 case NDEFUN:
8385 case NARG:
8386 new->narg.backquote = copynodelist(n->narg.backquote);
8387 new->narg.text = nodeckstrdup(n->narg.text);
8388 new->narg.next = copynode(n->narg.next);
8389 break;
8390 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008391#if ENABLE_ASH_BASH_COMPAT
8392 case NTO2:
8393#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008394 case NCLOBBER:
8395 case NFROM:
8396 case NFROMTO:
8397 case NAPPEND:
8398 new->nfile.fname = copynode(n->nfile.fname);
8399 new->nfile.fd = n->nfile.fd;
8400 new->nfile.next = copynode(n->nfile.next);
8401 break;
8402 case NTOFD:
8403 case NFROMFD:
8404 new->ndup.vname = copynode(n->ndup.vname);
8405 new->ndup.dupfd = n->ndup.dupfd;
8406 new->ndup.fd = n->ndup.fd;
8407 new->ndup.next = copynode(n->ndup.next);
8408 break;
8409 case NHERE:
8410 case NXHERE:
8411 new->nhere.doc = copynode(n->nhere.doc);
8412 new->nhere.fd = n->nhere.fd;
8413 new->nhere.next = copynode(n->nhere.next);
8414 break;
8415 case NNOT:
8416 new->nnot.com = copynode(n->nnot.com);
8417 break;
8418 };
8419 new->type = n->type;
8420 return new;
8421}
8422
8423/*
8424 * Make a copy of a parse tree.
8425 */
8426static struct funcnode *
8427copyfunc(union node *n)
8428{
8429 struct funcnode *f;
8430 size_t blocksize;
8431
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008432 /*funcstringsize = 0;*/
8433 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8434 f = ckzalloc(blocksize /* + funcstringsize */);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008435 funcblock = (char *) f + offsetof(struct funcnode, n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008436 funcstring_end = (char *) f + blocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008437 copynode(n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008438 /* f->count = 0; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008439 return f;
8440}
8441
8442/*
8443 * Define a shell function.
8444 */
8445static void
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008446defun(union node *func)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008447{
8448 struct cmdentry entry;
8449
8450 INT_OFF;
8451 entry.cmdtype = CMDFUNCTION;
8452 entry.u.func = copyfunc(func);
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008453 addcmdentry(func->narg.text, &entry);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008454 INT_ON;
8455}
8456
Denis Vlasenko4b875702009-03-19 13:30:04 +00008457/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008458#define SKIPBREAK (1 << 0)
8459#define SKIPCONT (1 << 1)
8460#define SKIPFUNC (1 << 2)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008461static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008462static int skipcount; /* number of levels to skip */
8463static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008464static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008465
Denis Vlasenko4b875702009-03-19 13:30:04 +00008466/* Forward decl way out to parsing code - dotrap needs it */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008467static int evalstring(char *s, int flags);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008468
Denis Vlasenko4b875702009-03-19 13:30:04 +00008469/* Called to execute a trap.
8470 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008471 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008472 *
8473 * Perhaps we should avoid entering new trap handlers
8474 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008475 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008476static void
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008477dotrap(void)
8478{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008479 uint8_t *g;
8480 int sig;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008481 uint8_t last_status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008482
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008483 if (!pending_sig)
8484 return;
8485
8486 last_status = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008487 pending_sig = 0;
Denys Vlasenkode892052016-10-02 01:49:13 +02008488 barrier();
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008489
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008490 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008491 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008492 char *p;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008493
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008494 if (!*g)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008495 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008496
8497 if (evalskip) {
8498 pending_sig = sig;
8499 break;
8500 }
8501
8502 p = trap[sig];
Denis Vlasenko4b875702009-03-19 13:30:04 +00008503 /* non-trapped SIGINT is handled separately by raise_interrupt,
8504 * don't upset it by resetting gotsig[SIGINT-1] */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008505 if (sig == SIGINT && !p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008506 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008507
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008508 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008509 *g = 0;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008510 if (!p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008511 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008512 evalstring(p, 0);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008513 }
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008514 exitstatus = last_status;
8515 TRACE(("dotrap returns\n"));
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008516}
8517
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008518/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008519static int evalloop(union node *, int);
8520static int evalfor(union node *, int);
8521static int evalcase(union node *, int);
8522static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008523static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008524static int evalpipe(union node *, int);
8525static int evalcommand(union node *, int);
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008526static int evalbltin(const struct builtincmd *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008527static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008528
Eric Andersen62483552001-07-10 06:09:16 +00008529/*
Eric Andersenc470f442003-07-28 09:56:35 +00008530 * Evaluate a parse tree. The value is left in the global variable
8531 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008532 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008533static int
Eric Andersenc470f442003-07-28 09:56:35 +00008534evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008535{
Eric Andersenc470f442003-07-28 09:56:35 +00008536 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008537 int (*evalfn)(union node *, int);
8538 int status = 0;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008539
Eric Andersenc470f442003-07-28 09:56:35 +00008540 if (n == NULL) {
8541 TRACE(("evaltree(NULL) called\n"));
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02008542 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00008543 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008544 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008545
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008546 dotrap();
8547
Eric Andersenc470f442003-07-28 09:56:35 +00008548 switch (n->type) {
8549 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008550#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008551 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008552 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008553 break;
8554#endif
8555 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008556 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008557 goto setstatus;
8558 case NREDIR:
8559 expredir(n->nredir.redirect);
8560 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8561 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008562 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008563 }
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02008564 if (n->nredir.redirect)
8565 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
Eric Andersenc470f442003-07-28 09:56:35 +00008566 goto setstatus;
8567 case NCMD:
8568 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008569 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008570 if (eflag && !(flags & EV_TESTED))
8571 checkexit = ~0;
8572 goto calleval;
8573 case NFOR:
8574 evalfn = evalfor;
8575 goto calleval;
8576 case NWHILE:
8577 case NUNTIL:
8578 evalfn = evalloop;
8579 goto calleval;
8580 case NSUBSHELL:
8581 case NBACKGND:
8582 evalfn = evalsubshell;
Denys Vlasenkocf98b0c2016-10-25 18:19:39 +02008583 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00008584 case NPIPE:
8585 evalfn = evalpipe;
8586 goto checkexit;
8587 case NCASE:
8588 evalfn = evalcase;
8589 goto calleval;
8590 case NAND:
8591 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008592 case NSEMI: {
8593
Eric Andersenc470f442003-07-28 09:56:35 +00008594#if NAND + 1 != NOR
8595#error NAND + 1 != NOR
8596#endif
8597#if NOR + 1 != NSEMI
8598#error NOR + 1 != NSEMI
8599#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008600 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008601 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00008602 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008603 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008604 );
Denys Vlasenkobc1a0082016-10-02 15:31:33 +02008605 if ((!status) == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00008606 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008607 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008608 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008609 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008610 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008611 status = evalfn(n, flags);
8612 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008613 }
Eric Andersenc470f442003-07-28 09:56:35 +00008614 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008615 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008616 if (evalskip)
8617 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008618 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00008619 n = n->nif.ifpart;
8620 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008621 }
8622 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008623 n = n->nif.elsepart;
8624 goto evaln;
8625 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008626 status = 0;
8627 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00008628 case NDEFUN:
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008629 defun(n);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008630 /* Not necessary. To test it:
8631 * "false; f() { qwerty; }; echo $?" should print 0.
8632 */
8633 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008634 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00008635 exitstatus = status;
8636 break;
8637 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008638 out:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008639 /* Order of checks below is important:
8640 * signal handlers trigger before exit caused by "set -e".
8641 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008642 dotrap();
8643
8644 if (checkexit & status)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008645 raise_exception(EXEXIT);
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008646 if (flags & EV_EXIT)
8647 raise_exception(EXEXIT);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008648
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008649 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008650 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00008651}
8652
Eric Andersenc470f442003-07-28 09:56:35 +00008653#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8654static
8655#endif
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008656int evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
Eric Andersenc470f442003-07-28 09:56:35 +00008657
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02008658static int
8659skiploop(void)
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008660{
8661 int skip = evalskip;
8662
8663 switch (skip) {
8664 case 0:
8665 break;
8666 case SKIPBREAK:
8667 case SKIPCONT:
8668 if (--skipcount <= 0) {
8669 evalskip = 0;
8670 break;
8671 }
8672 skip = SKIPBREAK;
8673 break;
8674 }
8675 return skip;
8676}
8677
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008678static int
Eric Andersenc470f442003-07-28 09:56:35 +00008679evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008680{
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008681 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00008682 int status;
8683
8684 loopnest++;
8685 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008686 flags &= EV_TESTED;
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008687 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008688 int i;
8689
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008690 i = evaltree(n->nbinary.ch1, EV_TESTED);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008691 skip = skiploop();
8692 if (skip == SKIPFUNC)
8693 status = i;
8694 if (skip)
8695 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00008696 if (n->type != NWHILE)
8697 i = !i;
8698 if (i != 0)
8699 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008700 status = evaltree(n->nbinary.ch2, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008701 skip = skiploop();
8702 } while (!(skip & ~SKIPCONT));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008703 loopnest--;
8704
8705 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008706}
8707
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008708static int
Eric Andersenc470f442003-07-28 09:56:35 +00008709evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008710{
8711 struct arglist arglist;
8712 union node *argp;
8713 struct strlist *sp;
8714 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008715 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008716
8717 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008718 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008719 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008720 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02008721 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersencb57d552001-06-28 07:25:16 +00008722 }
8723 *arglist.lastp = NULL;
8724
Eric Andersencb57d552001-06-28 07:25:16 +00008725 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008726 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008727 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008728 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008729 status = evaltree(n->nfor.body, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008730 if (skiploop() & ~SKIPCONT)
Eric Andersencb57d552001-06-28 07:25:16 +00008731 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008732 }
8733 loopnest--;
Eric Andersencb57d552001-06-28 07:25:16 +00008734 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008735
8736 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008737}
8738
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008739static int
Eric Andersenc470f442003-07-28 09:56:35 +00008740evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008741{
8742 union node *cp;
8743 union node *patp;
8744 struct arglist arglist;
8745 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008746 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008747
8748 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008749 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008750 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00008751 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008752 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8753 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008754 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008755 /* Ensure body is non-empty as otherwise
8756 * EV_EXIT may prevent us from setting the
8757 * exit status.
8758 */
8759 if (evalskip == 0 && cp->nclist.body) {
8760 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008761 }
8762 goto out;
8763 }
8764 }
8765 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008766 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008767 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008768
8769 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008770}
8771
Eric Andersenc470f442003-07-28 09:56:35 +00008772/*
8773 * Kick off a subshell to evaluate a tree.
8774 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008775static int
Eric Andersenc470f442003-07-28 09:56:35 +00008776evalsubshell(union node *n, int flags)
8777{
8778 struct job *jp;
8779 int backgnd = (n->type == NBACKGND);
8780 int status;
8781
8782 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02008783 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00008784 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008785 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008786 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008787 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02008788 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008789 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008790 flags |= EV_EXIT;
8791 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02008792 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00008793 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00008794 redirect(n->nredir.redirect, 0);
8795 evaltreenr(n->nredir.n, flags);
8796 /* never returns */
8797 }
Denys Vlasenko70392332016-10-27 02:31:55 +02008798 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00008799 status = 0;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008800 if (!backgnd)
Eric Andersenc470f442003-07-28 09:56:35 +00008801 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00008802 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008803 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00008804}
8805
Eric Andersenc470f442003-07-28 09:56:35 +00008806/*
8807 * Compute the names of the files in a redirection list.
8808 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00008809static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008810static void
8811expredir(union node *n)
8812{
8813 union node *redir;
8814
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008815 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00008816 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008817
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008818 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008819 fn.lastp = &fn.list;
8820 switch (redir->type) {
8821 case NFROMTO:
8822 case NFROM:
8823 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008824#if ENABLE_ASH_BASH_COMPAT
8825 case NTO2:
8826#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008827 case NCLOBBER:
8828 case NAPPEND:
8829 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02008830 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denis Vlasenko559691a2008-10-05 18:39:31 +00008831#if ENABLE_ASH_BASH_COMPAT
8832 store_expfname:
8833#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008834#if 0
8835// By the design of stack allocator, the loop of this kind:
8836// while true; do while true; do break; done </dev/null; done
8837// will look like a memory leak: ash plans to free expfname's
8838// of "/dev/null" as soon as it finishes running the loop
8839// (in this case, never).
8840// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01008841 if (redir->nfile.expfname)
8842 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008843// It results in corrupted state of stacked allocations.
8844#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008845 redir->nfile.expfname = fn.list->text;
8846 break;
8847 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008848 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00008849 if (redir->ndup.vname) {
8850 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008851 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008852 ash_msg_and_raise_error("redir error");
Denis Vlasenko559691a2008-10-05 18:39:31 +00008853#if ENABLE_ASH_BASH_COMPAT
8854//FIXME: we used expandarg with different args!
8855 if (!isdigit_str9(fn.list->text)) {
8856 /* >&file, not >&fd */
8857 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8858 ash_msg_and_raise_error("redir error");
8859 redir->type = NTO2;
8860 goto store_expfname;
8861 }
8862#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008863 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008864 }
8865 break;
8866 }
8867 }
8868}
8869
Eric Andersencb57d552001-06-28 07:25:16 +00008870/*
Eric Andersencb57d552001-06-28 07:25:16 +00008871 * Evaluate a pipeline. All the processes in the pipeline are children
8872 * of the process creating the pipeline. (This differs from some versions
8873 * of the shell, which make the last process in a pipeline the parent
8874 * of all the rest.)
8875 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008876static int
Eric Andersenc470f442003-07-28 09:56:35 +00008877evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008878{
8879 struct job *jp;
8880 struct nodelist *lp;
8881 int pipelen;
8882 int prevfd;
8883 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008884 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008885
Eric Andersenc470f442003-07-28 09:56:35 +00008886 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00008887 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008888 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00008889 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008890 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008891 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008892 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00008893 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008894 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008895 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00008896 pip[1] = -1;
8897 if (lp->next) {
8898 if (pipe(pip) < 0) {
8899 close(prevfd);
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00008900 ash_msg_and_raise_error("pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00008901 }
8902 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008903 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02008904 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008905 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00008906 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008907 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00008908 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008909 if (prevfd > 0) {
8910 dup2(prevfd, 0);
8911 close(prevfd);
8912 }
8913 if (pip[1] > 1) {
8914 dup2(pip[1], 1);
8915 close(pip[1]);
8916 }
Eric Andersenc470f442003-07-28 09:56:35 +00008917 evaltreenr(lp->n, flags);
8918 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00008919 }
Denys Vlasenko70392332016-10-27 02:31:55 +02008920 /* parent */
Eric Andersencb57d552001-06-28 07:25:16 +00008921 if (prevfd >= 0)
8922 close(prevfd);
8923 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00008924 /* Don't want to trigger debugging */
8925 if (pip[1] != -1)
8926 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00008927 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008928 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008929 status = waitforjob(jp);
8930 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00008931 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00008932 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008933
8934 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008935}
8936
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008937/*
8938 * Controls whether the shell is interactive or not.
8939 */
8940static void
8941setinteractive(int on)
8942{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008943 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008944
8945 if (++on == is_interactive)
8946 return;
8947 is_interactive = on;
8948 setsignal(SIGINT);
8949 setsignal(SIGQUIT);
8950 setsignal(SIGTERM);
8951#if !ENABLE_FEATURE_SH_EXTRA_QUIET
8952 if (is_interactive > 1) {
8953 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008954 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008955
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008956 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008957 /* note: ash and hush share this string */
8958 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02008959 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
8960 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008961 bb_banner,
8962 "built-in shell (ash)"
8963 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008964 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008965 }
8966 }
8967#endif
8968}
8969
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008970static void
8971optschanged(void)
8972{
8973#if DEBUG
8974 opentrace();
8975#endif
8976 setinteractive(iflag);
8977 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008978#if ENABLE_FEATURE_EDITING_VI
8979 if (viflag)
8980 line_input_state->flags |= VI_MODE;
8981 else
8982 line_input_state->flags &= ~VI_MODE;
8983#else
8984 viflag = 0; /* forcibly keep the option off */
8985#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008986}
8987
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008988static struct localvar *localvars;
8989
8990/*
8991 * Called after a function returns.
8992 * Interrupts must be off.
8993 */
8994static void
8995poplocalvars(void)
8996{
8997 struct localvar *lvp;
8998 struct var *vp;
8999
9000 while ((lvp = localvars) != NULL) {
9001 localvars = lvp->next;
9002 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02009003 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009004 if (vp == NULL) { /* $- saved */
9005 memcpy(optlist, lvp->text, sizeof(optlist));
9006 free((char*)lvp->text);
9007 optschanged();
9008 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009009 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009010 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009011 if (vp->var_func)
9012 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009013 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009014 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009015 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009016 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009017 }
9018 free(lvp);
9019 }
9020}
9021
9022static int
9023evalfun(struct funcnode *func, int argc, char **argv, int flags)
9024{
9025 volatile struct shparam saveparam;
9026 struct localvar *volatile savelocalvars;
9027 struct jmploc *volatile savehandler;
9028 struct jmploc jmploc;
9029 int e;
9030
9031 saveparam = shellparam;
9032 savelocalvars = localvars;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009033 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009034 e = setjmp(jmploc.loc);
9035 if (e) {
9036 goto funcdone;
9037 }
9038 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009039 exception_handler = &jmploc;
9040 localvars = NULL;
Denis Vlasenko01631112007-12-16 17:20:38 +00009041 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009042 func->count++;
9043 funcnest++;
9044 INT_ON;
9045 shellparam.nparam = argc - 1;
9046 shellparam.p = argv + 1;
9047#if ENABLE_ASH_GETOPTS
9048 shellparam.optind = 1;
9049 shellparam.optoff = -1;
9050#endif
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009051 evaltree(func->n.narg.next, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00009052 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009053 INT_OFF;
9054 funcnest--;
9055 freefunc(func);
9056 poplocalvars();
9057 localvars = savelocalvars;
9058 freeparam(&shellparam);
9059 shellparam = saveparam;
9060 exception_handler = savehandler;
9061 INT_ON;
9062 evalskip &= ~SKIPFUNC;
9063 return e;
9064}
9065
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009066/*
9067 * Make a variable a local variable. When a variable is made local, it's
9068 * value and flags are saved in a localvar structure. The saved values
9069 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009070 * "-" as a special case: it makes changes to "set +-options" local
9071 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009072 */
9073static void
9074mklocal(char *name)
9075{
9076 struct localvar *lvp;
9077 struct var **vpp;
9078 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009079 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009080
9081 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009082 /* Cater for duplicate "local". Examples:
9083 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9084 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9085 */
9086 lvp = localvars;
9087 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009088 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009089 if (eq)
9090 setvareq(name, 0);
9091 /* else:
9092 * it's a duplicate "local VAR" declaration, do nothing
9093 */
9094 return;
9095 }
9096 lvp = lvp->next;
9097 }
9098
9099 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009100 if (LONE_DASH(name)) {
9101 char *p;
9102 p = ckmalloc(sizeof(optlist));
9103 lvp->text = memcpy(p, optlist, sizeof(optlist));
9104 vp = NULL;
9105 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009106 vpp = hashvar(name);
9107 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009108 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009109 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009110 if (eq)
9111 setvareq(name, VSTRFIXED);
9112 else
9113 setvar(name, NULL, VSTRFIXED);
9114 vp = *vpp; /* the new variable */
9115 lvp->flags = VUNSET;
9116 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009117 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009118 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009119 /* make sure neither "struct var" nor string gets freed
9120 * during (un)setting:
9121 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009122 vp->flags |= VSTRFIXED|VTEXTFIXED;
9123 if (eq)
9124 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009125 else
9126 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009127 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009128 }
9129 }
9130 lvp->vp = vp;
9131 lvp->next = localvars;
9132 localvars = lvp;
9133 INT_ON;
9134}
9135
9136/*
9137 * The "local" command.
9138 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009139static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009140localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009141{
9142 char *name;
9143
Ron Yorstonef2386b2015-10-29 16:19:14 +00009144 if (!funcnest)
9145 ash_msg_and_raise_error("not in a function");
9146
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009147 argv = argptr;
9148 while ((name = *argv++) != NULL) {
9149 mklocal(name);
9150 }
9151 return 0;
9152}
9153
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009154static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009155falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009156{
9157 return 1;
9158}
9159
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009160static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009161truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009162{
9163 return 0;
9164}
9165
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009166static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009167execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009168{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009169 if (argv[1]) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009170 iflag = 0; /* exit on error */
9171 mflag = 0;
9172 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009173 /* We should set up signals for "exec CMD"
9174 * the same way as for "CMD" without "exec".
9175 * But optschanged->setinteractive->setsignal
9176 * still thought we are a root shell. Therefore, for example,
9177 * SIGQUIT is still set to IGN. Fix it:
9178 */
9179 shlvl++;
9180 setsignal(SIGQUIT);
9181 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9182 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9183 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9184
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009185 shellexec(argv + 1, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009186 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009187 }
9188 return 0;
9189}
9190
9191/*
9192 * The return command.
9193 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009194static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009195returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009196{
9197 /*
9198 * If called outside a function, do what ksh does;
9199 * skip the rest of the file.
9200 */
Denys Vlasenko6a0710e2016-09-30 14:18:34 +02009201 evalskip = SKIPFUNC;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009202 return argv[1] ? number(argv[1]) : exitstatus;
9203}
9204
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009205/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009206static int breakcmd(int, char **) FAST_FUNC;
9207static int dotcmd(int, char **) FAST_FUNC;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009208static int evalcmd(int, char **, int) FAST_FUNC;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009209static int exitcmd(int, char **) FAST_FUNC;
9210static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009211#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009212static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009213#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009214#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009215static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009216#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009217#if MAX_HISTORY
9218static int historycmd(int, char **) FAST_FUNC;
9219#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009220#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009221static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009222#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009223static int readcmd(int, char **) FAST_FUNC;
9224static int setcmd(int, char **) FAST_FUNC;
9225static int shiftcmd(int, char **) FAST_FUNC;
9226static int timescmd(int, char **) FAST_FUNC;
9227static int trapcmd(int, char **) FAST_FUNC;
9228static int umaskcmd(int, char **) FAST_FUNC;
9229static int unsetcmd(int, char **) FAST_FUNC;
9230static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009231
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009232#define BUILTIN_NOSPEC "0"
9233#define BUILTIN_SPECIAL "1"
9234#define BUILTIN_REGULAR "2"
9235#define BUILTIN_SPEC_REG "3"
9236#define BUILTIN_ASSIGN "4"
9237#define BUILTIN_SPEC_ASSG "5"
9238#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009239#define BUILTIN_SPEC_REG_ASSG "7"
9240
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009241/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009242#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009243static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009244#endif
9245#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009246static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009247#endif
9248#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009249static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009250#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009251
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009252/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009253static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009254 { BUILTIN_SPEC_REG "." , dotcmd },
9255 { BUILTIN_SPEC_REG ":" , truecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009256#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009257 { BUILTIN_REGULAR "[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009258#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009259 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009260#endif
Denis Vlasenko80591b02008-03-25 07:49:43 +00009261#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009262#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009263 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009264#endif
9265#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009266 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009267#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009268 { BUILTIN_SPEC_REG "break" , breakcmd },
9269 { BUILTIN_REGULAR "cd" , cdcmd },
9270 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009271#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009272 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009273#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009274 { BUILTIN_SPEC_REG "continue", breakcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009275#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009276 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009277#endif
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009278 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009279 { BUILTIN_SPEC_REG "exec" , execcmd },
9280 { BUILTIN_SPEC_REG "exit" , exitcmd },
9281 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9282 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009283#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009284 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009285#endif
9286#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009287 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009288#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009289 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009290#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009291 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009292#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009293#if MAX_HISTORY
9294 { BUILTIN_NOSPEC "history" , historycmd },
9295#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009296#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009297 { BUILTIN_REGULAR "jobs" , jobscmd },
9298 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009299#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009300#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009301 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009302#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009303 { BUILTIN_ASSIGN "local" , localcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009304#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009305 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009306#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009307 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9308 { BUILTIN_REGULAR "read" , readcmd },
9309 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9310 { BUILTIN_SPEC_REG "return" , returncmd },
9311 { BUILTIN_SPEC_REG "set" , setcmd },
9312 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009313#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009314 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009315#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009316#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009317 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009318#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009319 { BUILTIN_SPEC_REG "times" , timescmd },
9320 { BUILTIN_SPEC_REG "trap" , trapcmd },
9321 { BUILTIN_REGULAR "true" , truecmd },
9322 { BUILTIN_NOSPEC "type" , typecmd },
9323 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9324 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009325#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009326 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009327#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009328 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9329 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009330};
9331
Denis Vlasenko80591b02008-03-25 07:49:43 +00009332/* Should match the above table! */
9333#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009334 /* . : */ 2 + \
9335 /* [ */ 1 * ENABLE_ASH_BUILTIN_TEST + \
9336 /* [[ */ 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9337 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9338 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9339 /* break cd cddir */ 3)
9340#define EVALCMD (COMMANDCMD + \
9341 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9342 /* continue */ 1 + \
9343 /* echo */ 1 * ENABLE_ASH_BUILTIN_ECHO + \
9344 0)
9345#define EXECCMD (EVALCMD + \
9346 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009347
9348/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009349 * Search the table of builtin commands.
9350 */
Denys Vlasenko888527c2016-10-02 16:54:17 +02009351static int
9352pstrcmp1(const void *a, const void *b)
9353{
9354 return strcmp((char*)a, *(char**)b + 1);
9355}
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009356static struct builtincmd *
9357find_builtin(const char *name)
9358{
9359 struct builtincmd *bp;
9360
9361 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009362 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denys Vlasenko888527c2016-10-02 16:54:17 +02009363 pstrcmp1
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009364 );
9365 return bp;
9366}
9367
9368/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009369 * Execute a simple command.
9370 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009371static int
9372isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009373{
9374 const char *q = endofname(p);
9375 if (p == q)
9376 return 0;
9377 return *q == '=';
9378}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009379static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009380bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009381{
9382 /* Preserve exitstatus of a previous possible redirection
9383 * as POSIX mandates */
9384 return back_exitstatus;
9385}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009386static int
Eric Andersenc470f442003-07-28 09:56:35 +00009387evalcommand(union node *cmd, int flags)
9388{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009389 static const struct builtincmd null_bltin = {
9390 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009391 };
Eric Andersenc470f442003-07-28 09:56:35 +00009392 struct stackmark smark;
9393 union node *argp;
9394 struct arglist arglist;
9395 struct arglist varlist;
9396 char **argv;
9397 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009398 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009399 struct cmdentry cmdentry;
9400 struct job *jp;
9401 char *lastarg;
9402 const char *path;
9403 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009404 int status;
9405 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00009406 struct builtincmd *bcmd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009407 smallint cmd_is_exec;
9408 smallint pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009409
9410 /* First expand the arguments. */
9411 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9412 setstackmark(&smark);
9413 back_exitstatus = 0;
9414
9415 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009416 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009417 varlist.lastp = &varlist.list;
9418 *varlist.lastp = NULL;
9419 arglist.lastp = &arglist.list;
9420 *arglist.lastp = NULL;
9421
9422 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009423 if (cmd->ncmd.args) {
Paul Foxc3850c82005-07-20 18:23:39 +00009424 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9425 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9426 }
9427
Eric Andersenc470f442003-07-28 09:56:35 +00009428 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9429 struct strlist **spp;
9430
9431 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00009432 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00009433 expandarg(argp, &arglist, EXP_VARTILDE);
9434 else
9435 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9436
Eric Andersenc470f442003-07-28 09:56:35 +00009437 for (sp = *spp; sp; sp = sp->next)
9438 argc++;
9439 }
9440
Denys Vlasenko65a8b852016-10-26 22:29:11 +02009441 /* Reserve one extra spot at the front for shellexec. */
9442 nargv = stalloc(sizeof(char *) * (argc + 2));
9443 argv = ++nargv;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009444 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009445 TRACE(("evalcommand arg: %s\n", sp->text));
9446 *nargv++ = sp->text;
9447 }
9448 *nargv = NULL;
9449
9450 lastarg = NULL;
9451 if (iflag && funcnest == 0 && argc > 0)
9452 lastarg = nargv[-1];
9453
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009454 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009455 expredir(cmd->ncmd.redirect);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009456 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009457
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009458 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009459 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9460 struct strlist **spp;
9461 char *p;
9462
9463 spp = varlist.lastp;
9464 expandarg(argp, &varlist, EXP_VARTILDE);
9465
9466 /*
9467 * Modify the command lookup path, if a PATH= assignment
9468 * is present
9469 */
9470 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009471 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009472 path = p;
9473 }
9474
9475 /* Print the command if xflag is set. */
9476 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009477 int n;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009478 const char *p = " %s" + 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009479
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009480 fdprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009481 sp = varlist.list;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009482 for (n = 0; n < 2; n++) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009483 while (sp) {
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009484 fdprintf(preverrout_fd, p, sp->text);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009485 sp = sp->next;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009486 p = " %s";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009487 }
9488 sp = arglist.list;
9489 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009490 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009491 }
9492
9493 cmd_is_exec = 0;
9494 spclbltin = -1;
9495
9496 /* Now locate the command. */
9497 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009498 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02009499#if ENABLE_ASH_CMDCMD
9500 const char *oldpath = path + 5;
9501#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009502 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009503 for (;;) {
9504 find_command(argv[0], &cmdentry, cmd_flag, path);
9505 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009506 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009507 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009508 goto bail;
9509 }
9510
9511 /* implement bltin and command here */
9512 if (cmdentry.cmdtype != CMDBUILTIN)
9513 break;
9514 if (spclbltin < 0)
9515 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9516 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009517 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009518#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009519 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009520 path = oldpath;
9521 nargv = parse_command_args(argv, &path);
9522 if (!nargv)
9523 break;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02009524 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
9525 * nargv => "PROG". path is updated if -p.
9526 */
Eric Andersenc470f442003-07-28 09:56:35 +00009527 argc -= nargv - argv;
9528 argv = nargv;
9529 cmd_flag |= DO_NOFUNC;
9530 } else
9531#endif
9532 break;
9533 }
9534 }
9535
9536 if (status) {
9537 /* We have a redirection error. */
9538 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009539 raise_exception(EXERROR);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009540 bail:
Eric Andersenc470f442003-07-28 09:56:35 +00009541 exitstatus = status;
9542 goto out;
9543 }
9544
9545 /* Execute the command. */
9546 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009547 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009548
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009549#if ENABLE_FEATURE_SH_NOFORK
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009550/* (1) BUG: if variables are set, we need to fork, or save/restore them
9551 * around run_nofork_applet() call.
9552 * (2) Should this check also be done in forkshell()?
9553 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9554 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009555 /* find_command() encodes applet_no as (-2 - applet_no) */
9556 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009557 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009558 listsetvar(varlist.list, VEXPORT|VSTACK);
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009559 /* run <applet>_main() */
Ron Yorston5ccb0e92016-10-20 12:24:02 +01009560 status = run_nofork_applet(applet_no, argv);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009561 break;
9562 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009563#endif
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009564 /* Can we avoid forking off? For example, very last command
9565 * in a script or a subshell does not need forking,
9566 * we can just exec it.
9567 */
Denys Vlasenko238bf182010-05-18 15:49:07 +02009568 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009569 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009570 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00009571 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009572 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009573 /* parent */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009574 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009575 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009576 TRACE(("forked child exited with %d\n", status));
Eric Andersenc470f442003-07-28 09:56:35 +00009577 break;
9578 }
Denys Vlasenko238bf182010-05-18 15:49:07 +02009579 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009580 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +02009581 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +00009582 }
9583 listsetvar(varlist.list, VEXPORT|VSTACK);
9584 shellexec(argv, path, cmdentry.u.index);
9585 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009586 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +00009587 case CMDBUILTIN:
9588 cmdenviron = varlist.list;
9589 if (cmdenviron) {
9590 struct strlist *list = cmdenviron;
9591 int i = VNOSET;
9592 if (spclbltin > 0 || argc == 0) {
9593 i = 0;
9594 if (cmd_is_exec && argc > 1)
9595 i = VEXPORT;
9596 }
9597 listsetvar(list, i);
9598 }
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009599 /* Tight loop with builtins only:
9600 * "while kill -0 $child; do true; done"
9601 * will never exit even if $child died, unless we do this
9602 * to reap the zombie and make kill detect that it's gone: */
9603 dowait(DOWAIT_NONBLOCK, NULL);
9604
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009605 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009606 if (exception_type == EXERROR && spclbltin <= 0) {
9607 FORCE_INT_ON;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02009608 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009609 }
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009610 raise:
9611 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009612 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009613 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009614
9615 case CMDFUNCTION:
9616 listsetvar(varlist.list, 0);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009617 /* See above for the rationale */
9618 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009619 if (evalfun(cmdentry.u.func, argc, argv, flags))
9620 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009621 readstatus:
9622 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009623 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009624 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +00009625
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009626 out:
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02009627 if (cmd->ncmd.redirect)
9628 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009629 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +00009630 /* dsl: I think this is intended to be used to support
9631 * '_' in 'vi' command mode during line editing...
9632 * However I implemented that within libedit itself.
9633 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009634 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009635 }
Eric Andersenc470f442003-07-28 09:56:35 +00009636 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009637
9638 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009639}
9640
9641static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009642evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009643{
Eric Andersenc470f442003-07-28 09:56:35 +00009644 char *volatile savecmdname;
9645 struct jmploc *volatile savehandler;
9646 struct jmploc jmploc;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009647 int status;
Eric Andersenc470f442003-07-28 09:56:35 +00009648 int i;
9649
9650 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009651 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009652 i = setjmp(jmploc.loc);
9653 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +00009654 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009655 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00009656 commandname = argv[0];
9657 argptr = argv + 1;
9658 optptr = NULL; /* initialize nextopt */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009659 if (cmd == EVALCMD)
9660 status = evalcmd(argc, argv, flags);
9661 else
9662 status = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009663 flush_stdout_stderr();
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009664 status |= ferror(stdout);
9665 exitstatus = status;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009666 cmddone:
Rob Landleyf296f0b2006-07-06 01:09:21 +00009667 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009668 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009669 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +00009670
9671 return i;
9672}
9673
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009674static int
9675goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009676{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02009677 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009678}
9679
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009680
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009681/*
9682 * Search for a command. This is called before we fork so that the
9683 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009684 * the child. The check for "goodname" is an overly conservative
9685 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009686 */
Eric Andersenc470f442003-07-28 09:56:35 +00009687static void
9688prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009689{
9690 struct cmdentry entry;
9691
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009692 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9693 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009694}
9695
Eric Andersencb57d552001-06-28 07:25:16 +00009696
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009697/* ============ Builtin commands
9698 *
9699 * Builtin commands whose functions are closely tied to evaluation
9700 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +00009701 */
9702
9703/*
Eric Andersencb57d552001-06-28 07:25:16 +00009704 * Handle break and continue commands. Break, continue, and return are
9705 * all handled by setting the evalskip flag. The evaluation routines
9706 * above all check this flag, and if it is set they start skipping
9707 * commands rather than executing them. The variable skipcount is
9708 * the number of loops to break/continue, or the number of function
9709 * levels to return. (The latter is always 1.) It should probably
9710 * be an error to break out of more loops than exist, but it isn't
9711 * in the standard shell so we don't make it one here.
9712 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009713static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009714breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009715{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009716 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009717
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00009718 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009719 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009720 if (n > loopnest)
9721 n = loopnest;
9722 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009723 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00009724 skipcount = n;
9725 }
9726 return 0;
9727}
9728
Eric Andersenc470f442003-07-28 09:56:35 +00009729
Denys Vlasenko70392332016-10-27 02:31:55 +02009730/*
Eric Andersen90898442003-08-06 11:20:52 +00009731 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00009732 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009733
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009734enum {
9735 INPUT_PUSH_FILE = 1,
9736 INPUT_NOFILE_OK = 2,
9737};
Eric Andersencb57d552001-06-28 07:25:16 +00009738
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009739static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009740/* values of checkkwd variable */
9741#define CHKALIAS 0x1
9742#define CHKKWD 0x2
9743#define CHKNL 0x4
9744
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009745/*
9746 * Push a string back onto the input at this current parsefile level.
9747 * We handle aliases this way.
9748 */
9749#if !ENABLE_ASH_ALIAS
9750#define pushstring(s, ap) pushstring(s)
9751#endif
9752static void
9753pushstring(char *s, struct alias *ap)
9754{
9755 struct strpush *sp;
9756 int len;
9757
9758 len = strlen(s);
9759 INT_OFF;
9760 if (g_parsefile->strpush) {
9761 sp = ckzalloc(sizeof(*sp));
9762 sp->prev = g_parsefile->strpush;
9763 } else {
9764 sp = &(g_parsefile->basestrpush);
9765 }
9766 g_parsefile->strpush = sp;
9767 sp->prev_string = g_parsefile->next_to_pgetc;
9768 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009769 sp->unget = g_parsefile->unget;
9770 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009771#if ENABLE_ASH_ALIAS
9772 sp->ap = ap;
9773 if (ap) {
9774 ap->flag |= ALIASINUSE;
9775 sp->string = s;
9776 }
9777#endif
9778 g_parsefile->next_to_pgetc = s;
9779 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009780 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009781 INT_ON;
9782}
9783
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009784static void
9785popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009786{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009787 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +00009788
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009789 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009790#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009791 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009792 if (g_parsefile->next_to_pgetc[-1] == ' '
9793 || g_parsefile->next_to_pgetc[-1] == '\t'
9794 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009795 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009796 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009797 if (sp->string != sp->ap->val) {
9798 free(sp->string);
9799 }
9800 sp->ap->flag &= ~ALIASINUSE;
9801 if (sp->ap->flag & ALIASDEAD) {
9802 unalias(sp->ap->name);
9803 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009804 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009805#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009806 g_parsefile->next_to_pgetc = sp->prev_string;
9807 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009808 g_parsefile->unget = sp->unget;
9809 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009810 g_parsefile->strpush = sp->prev;
9811 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009812 free(sp);
9813 INT_ON;
9814}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009815
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009816static int
9817preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009818{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009819 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00009820 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009821
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009822 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +00009823#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +00009824 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009825 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +01009826 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009827 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009828 int timeout = -1;
9829# if ENABLE_ASH_IDLE_TIMEOUT
9830 if (iflag) {
9831 const char *tmout_var = lookupvar("TMOUT");
9832 if (tmout_var) {
9833 timeout = atoi(tmout_var) * 1000;
9834 if (timeout <= 0)
9835 timeout = -1;
9836 }
9837 }
9838# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009839# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009840 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009841# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02009842 reinit_unicode_for_ash();
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009843 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009844 if (nr == 0) {
9845 /* Ctrl+C pressed */
9846 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009847 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009848 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009849 raise(SIGINT);
9850 return 1;
9851 }
Eric Andersenc470f442003-07-28 09:56:35 +00009852 goto retry;
9853 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009854 if (nr < 0) {
9855 if (errno == 0) {
9856 /* Ctrl+D pressed */
9857 nr = 0;
9858 }
9859# if ENABLE_ASH_IDLE_TIMEOUT
9860 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +02009861 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009862 exitshell();
9863 }
9864# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009865 }
Eric Andersencb57d552001-06-28 07:25:16 +00009866 }
9867#else
Ron Yorston61d6ae22015-04-19 10:50:25 +01009868 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00009869#endif
9870
Denys Vlasenko80c5b682011-05-08 21:21:10 +02009871#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +00009872 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00009873 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +00009874 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +00009875 if (flags >= 0 && (flags & O_NONBLOCK)) {
9876 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00009877 if (fcntl(0, F_SETFL, flags) >= 0) {
9878 out2str("sh: turning off NDELAY mode\n");
9879 goto retry;
9880 }
9881 }
9882 }
9883 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +00009884#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009885 return nr;
9886}
9887
9888/*
9889 * Refill the input buffer and return the next input character:
9890 *
9891 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009892 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9893 * or we are reading from a string so we can't refill the buffer,
9894 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +02009895 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +00009896 * 4) Process input up to the next newline, deleting nul characters.
9897 */
Denis Vlasenko727752d2008-11-28 03:41:47 +00009898//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9899#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009900static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009901static int
Eric Andersenc470f442003-07-28 09:56:35 +00009902preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009903{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009904 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +00009905 int more;
Eric Andersencb57d552001-06-28 07:25:16 +00009906
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009907 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +00009908#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009909 if (g_parsefile->left_in_line == -1
9910 && g_parsefile->strpush->ap
9911 && g_parsefile->next_to_pgetc[-1] != ' '
9912 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +00009913 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009914 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +00009915 return PEOA;
9916 }
Eric Andersen2870d962001-07-02 17:27:21 +00009917#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009918 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009919 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +00009920 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009921 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009922 * "pgetc" needs refilling.
9923 */
9924
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009925 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009926 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009927 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009928 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009929 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009930 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009931 /* even in failure keep left_in_line and next_to_pgetc
9932 * in lock step, for correct multi-layer pungetc.
9933 * left_in_line was decremented before preadbuffer(),
9934 * must inc next_to_pgetc: */
9935 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009936 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009937 }
Eric Andersencb57d552001-06-28 07:25:16 +00009938
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009939 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009940 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009941 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009942 again:
9943 more = preadfd();
9944 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009945 /* don't try reading again */
9946 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009947 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009948 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009949 return PEOF;
9950 }
9951 }
9952
Denis Vlasenko727752d2008-11-28 03:41:47 +00009953 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009954 * Set g_parsefile->left_in_line
9955 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009956 * NUL chars are deleted.
9957 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009958 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009959 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009960 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00009961
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009962 more--;
Eric Andersenc470f442003-07-28 09:56:35 +00009963
Denis Vlasenko727752d2008-11-28 03:41:47 +00009964 c = *q;
9965 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009966 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009967 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009968 q++;
9969 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009970 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009971 break;
9972 }
Eric Andersencb57d552001-06-28 07:25:16 +00009973 }
9974
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009975 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009976 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9977 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00009978 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009979 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009980 }
9981 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009982 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +00009983
Eric Andersencb57d552001-06-28 07:25:16 +00009984 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009985 char save = *q;
9986 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009987 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009988 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +00009989 }
9990
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009991 pgetc_debug("preadbuffer at %d:%p'%s'",
9992 g_parsefile->left_in_line,
9993 g_parsefile->next_to_pgetc,
9994 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +01009995 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009996}
9997
Denys Vlasenkoce332a22016-10-02 23:47:34 +02009998static void
9999nlprompt(void)
10000{
10001 g_parsefile->linno++;
10002 setprompt_if(doprompt, 2);
10003}
10004static void
10005nlnoprompt(void)
10006{
10007 g_parsefile->linno++;
10008 needprompt = doprompt;
10009}
10010
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010011static int
10012pgetc(void)
10013{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010014 int c;
10015
10016 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010017 g_parsefile->left_in_line,
10018 g_parsefile->next_to_pgetc,
10019 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010020 if (g_parsefile->unget)
10021 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010022
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010023 if (--g_parsefile->left_in_line >= 0)
10024 c = (signed char)*g_parsefile->next_to_pgetc++;
10025 else
10026 c = preadbuffer();
10027
10028 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10029 g_parsefile->lastc[0] = c;
10030
10031 return c;
10032}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010033
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010034#if ENABLE_ASH_ALIAS
10035static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010036pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010037{
10038 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010039 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010040 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010041 g_parsefile->left_in_line,
10042 g_parsefile->next_to_pgetc,
10043 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010044 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010045 } while (c == PEOA);
10046 return c;
10047}
10048#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010049# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010050#endif
10051
10052/*
10053 * Read a line from the script.
10054 */
10055static char *
10056pfgets(char *line, int len)
10057{
10058 char *p = line;
10059 int nleft = len;
10060 int c;
10061
10062 while (--nleft > 0) {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010063 c = pgetc_without_PEOA();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010064 if (c == PEOF) {
10065 if (p == line)
10066 return NULL;
10067 break;
10068 }
10069 *p++ = c;
10070 if (c == '\n')
10071 break;
10072 }
10073 *p = '\0';
10074 return line;
10075}
10076
Eric Andersenc470f442003-07-28 09:56:35 +000010077/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010078 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010079 * PEOF may be pushed back.
10080 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010081static void
Eric Andersenc470f442003-07-28 09:56:35 +000010082pungetc(void)
10083{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010084 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010085}
10086
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010087/* This one eats backslash+newline */
10088static int
10089pgetc_eatbnl(void)
10090{
10091 int c;
10092
10093 while ((c = pgetc()) == '\\') {
10094 if (pgetc() != '\n') {
10095 pungetc();
10096 break;
10097 }
10098
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010099 nlprompt();
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010100 }
10101
10102 return c;
10103}
10104
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010105/*
10106 * To handle the "." command, a stack of input files is used. Pushfile
10107 * adds a new entry to the stack and popfile restores the previous level.
10108 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010109static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010110pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010111{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010112 struct parsefile *pf;
10113
Denis Vlasenko597906c2008-02-20 16:38:54 +000010114 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010115 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010116 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010117 /*pf->strpush = NULL; - ckzalloc did it */
10118 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010119 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010120 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010121}
10122
10123static void
10124popfile(void)
10125{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010126 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010127
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010010128 if (pf == &basepf)
10129 return;
10130
Denis Vlasenkob012b102007-02-19 22:43:01 +000010131 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010132 if (pf->pf_fd >= 0)
10133 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010134 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010135 while (pf->strpush)
10136 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010137 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010138 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010139 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010140}
10141
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010142/*
10143 * Return to top level.
10144 */
10145static void
10146popallfiles(void)
10147{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010148 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010149 popfile();
10150}
10151
10152/*
10153 * Close the file(s) that the shell is reading commands from. Called
10154 * after a fork is done.
10155 */
10156static void
10157closescript(void)
10158{
10159 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010160 if (g_parsefile->pf_fd > 0) {
10161 close(g_parsefile->pf_fd);
10162 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010163 }
10164}
10165
10166/*
10167 * Like setinputfile, but takes an open file descriptor. Call this with
10168 * interrupts off.
10169 */
10170static void
10171setinputfd(int fd, int push)
10172{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010173 if (push) {
10174 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010175 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010176 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010177 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010178 if (g_parsefile->buf == NULL)
10179 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010180 g_parsefile->left_in_buffer = 0;
10181 g_parsefile->left_in_line = 0;
10182 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010183}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010184
Eric Andersenc470f442003-07-28 09:56:35 +000010185/*
10186 * Set the input to take input from a file. If push is set, push the
10187 * old input onto the stack first.
10188 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010189static int
10190setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010191{
10192 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010193
Denis Vlasenkob012b102007-02-19 22:43:01 +000010194 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010195 fd = open(fname, O_RDONLY);
10196 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010197 if (flags & INPUT_NOFILE_OK)
10198 goto out;
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010199 exitstatus = 127;
Denis Vlasenko9604e1b2009-03-03 18:47:56 +000010200 ash_msg_and_raise_error("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010201 }
Denys Vlasenko64774602016-10-26 15:24:30 +020010202 if (fd < 10)
10203 fd = savefd(fd);
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020010204 else
10205 close_on_exec_on(fd);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010206 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010207 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010208 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010209 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010210}
10211
Eric Andersencb57d552001-06-28 07:25:16 +000010212/*
10213 * Like setinputfile, but takes input from a string.
10214 */
Eric Andersenc470f442003-07-28 09:56:35 +000010215static void
10216setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010217{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010218 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010219 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010220 g_parsefile->next_to_pgetc = string;
10221 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010222 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010223 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010224 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010225}
10226
10227
Denys Vlasenko70392332016-10-27 02:31:55 +020010228/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010229 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010230 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010231
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010232#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010233
Denys Vlasenko23841622015-10-09 15:52:03 +020010234/* Hash of mtimes of mailboxes */
10235static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010236/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010237static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010238
Eric Andersencb57d552001-06-28 07:25:16 +000010239/*
Eric Andersenc470f442003-07-28 09:56:35 +000010240 * Print appropriate message(s) if mail has arrived.
10241 * If mail_var_path_changed is set,
10242 * then the value of MAIL has mail_var_path_changed,
10243 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010244 */
Eric Andersenc470f442003-07-28 09:56:35 +000010245static void
10246chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010247{
Eric Andersencb57d552001-06-28 07:25:16 +000010248 const char *mpath;
10249 char *p;
10250 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010251 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010252 struct stackmark smark;
10253 struct stat statb;
10254
Eric Andersencb57d552001-06-28 07:25:16 +000010255 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010256 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010257 new_hash = 0;
10258 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010259 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010260 if (p == NULL)
10261 break;
10262 if (*p == '\0')
10263 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010264 for (q = p; *q; q++)
10265 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010266#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010267 if (q[-1] != '/')
10268 abort();
10269#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010270 q[-1] = '\0'; /* delete trailing '/' */
10271 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010272 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010273 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010274 /* Very simplistic "hash": just a sum of all mtimes */
10275 new_hash += (unsigned)statb.st_mtime;
10276 }
10277 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010278 if (mailtime_hash != 0)
10279 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010280 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010281 }
Eric Andersenc470f442003-07-28 09:56:35 +000010282 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010283 popstackmark(&smark);
10284}
Eric Andersencb57d552001-06-28 07:25:16 +000010285
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010286static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010287changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010288{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010289 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010290}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010291
Denis Vlasenko131ae172007-02-18 13:00:19 +000010292#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010293
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010294
10295/* ============ ??? */
10296
Eric Andersencb57d552001-06-28 07:25:16 +000010297/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010298 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010299 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010300static void
10301setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010302{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010303 char **newparam;
10304 char **ap;
10305 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010306
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010307 for (nparam = 0; argv[nparam]; nparam++)
10308 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010309 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10310 while (*argv) {
10311 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010312 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010313 *ap = NULL;
10314 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010315 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010316 shellparam.nparam = nparam;
10317 shellparam.p = newparam;
10318#if ENABLE_ASH_GETOPTS
10319 shellparam.optind = 1;
10320 shellparam.optoff = -1;
10321#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010322}
10323
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010324/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010325 * Process shell options. The global variable argptr contains a pointer
10326 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010327 *
10328 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10329 * For a non-interactive shell, an error condition encountered
10330 * by a special built-in ... shall cause the shell to write a diagnostic message
10331 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010332 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010333 * ...
10334 * Utility syntax error (option or operand error) Shall exit
10335 * ...
10336 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10337 * we see that bash does not do that (set "finishes" with error code 1 instead,
10338 * and shell continues), and people rely on this behavior!
10339 * Testcase:
10340 * set -o barfoo 2>/dev/null
10341 * echo $?
10342 *
10343 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010344 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010345static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010346plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010347{
10348 int i;
10349
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010350 if (name) {
10351 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010352 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010353 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010354 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010355 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010356 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010357 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010358 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010359 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010360 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010361 if (val) {
10362 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10363 } else {
10364 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10365 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010366 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010367 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010368}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010369static void
10370setoption(int flag, int val)
10371{
10372 int i;
10373
10374 for (i = 0; i < NOPTS; i++) {
10375 if (optletters(i) == flag) {
10376 optlist[i] = val;
10377 return;
10378 }
10379 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010380 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010381 /* NOTREACHED */
10382}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010383static int
Eric Andersenc470f442003-07-28 09:56:35 +000010384options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +000010385{
10386 char *p;
10387 int val;
10388 int c;
10389
10390 if (cmdline)
10391 minusc = NULL;
10392 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010393 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010394 if (c != '-' && c != '+')
10395 break;
10396 argptr++;
10397 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010398 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010399 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010400 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010401 if (!cmdline) {
10402 /* "-" means turn off -x and -v */
10403 if (p[0] == '\0')
10404 xflag = vflag = 0;
10405 /* "--" means reset params */
10406 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010407 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010408 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010409 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010410 }
Eric Andersencb57d552001-06-28 07:25:16 +000010411 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010412 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010413 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010414 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010415 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010416 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010417 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010418 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010419 /* it already printed err message */
10420 return 1; /* error */
10421 }
Eric Andersencb57d552001-06-28 07:25:16 +000010422 if (*argptr)
10423 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010424 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10425 isloginsh = 1;
10426 /* bash does not accept +-login, we also won't */
10427 } else if (cmdline && val && (c == '-')) { /* long options */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010428 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +000010429 isloginsh = 1;
10430 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010431 } else {
10432 setoption(c, val);
10433 }
10434 }
10435 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010436 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010437}
10438
Eric Andersencb57d552001-06-28 07:25:16 +000010439/*
Eric Andersencb57d552001-06-28 07:25:16 +000010440 * The shift builtin command.
10441 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010442static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010443shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010444{
10445 int n;
10446 char **ap1, **ap2;
10447
10448 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010449 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010450 n = number(argv[1]);
10451 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010452 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010453 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010454 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010455 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010456 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010457 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010458 }
10459 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010460 while ((*ap2++ = *ap1++) != NULL)
10461 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010462#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010463 shellparam.optind = 1;
10464 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010465#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010466 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010467 return 0;
10468}
10469
Eric Andersencb57d552001-06-28 07:25:16 +000010470/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010471 * POSIX requires that 'set' (but not export or readonly) output the
10472 * variables in lexicographic order - by the locale's collating order (sigh).
10473 * Maybe we could keep them in an ordered balanced binary tree
10474 * instead of hashed lists.
10475 * For now just roll 'em through qsort for printing...
10476 */
10477static int
10478showvars(const char *sep_prefix, int on, int off)
10479{
10480 const char *sep;
10481 char **ep, **epend;
10482
10483 ep = listvars(on, off, &epend);
10484 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10485
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010486 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010487
10488 for (; ep < epend; ep++) {
10489 const char *p;
10490 const char *q;
10491
10492 p = strchrnul(*ep, '=');
10493 q = nullstr;
10494 if (*p)
10495 q = single_quote(++p);
10496 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10497 }
10498 return 0;
10499}
10500
10501/*
Eric Andersencb57d552001-06-28 07:25:16 +000010502 * The set command builtin.
10503 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010504static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010505setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010506{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010507 int retval;
10508
Denis Vlasenko68404f12008-03-17 09:00:54 +000010509 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010510 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010511
Denis Vlasenkob012b102007-02-19 22:43:01 +000010512 INT_OFF;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010513 retval = options(/*cmdline:*/ 0);
10514 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010515 optschanged();
10516 if (*argptr != NULL) {
10517 setparam(argptr);
10518 }
Eric Andersencb57d552001-06-28 07:25:16 +000010519 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010520 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010521 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010522}
10523
Denis Vlasenko131ae172007-02-18 13:00:19 +000010524#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010525static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010526change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010527{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010528 uint32_t t;
10529
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010530 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010531 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010532 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010533 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010534 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010535 vrandom.flags &= ~VNOFUNC;
10536 } else {
10537 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010538 t = strtoul(value, NULL, 10);
10539 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010540 }
Eric Andersenef02f822004-03-11 13:34:24 +000010541}
Eric Andersen16767e22004-03-16 05:14:10 +000010542#endif
10543
Denis Vlasenko131ae172007-02-18 13:00:19 +000010544#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010545static int
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010546getopts(char *optstr, char *optvar, char **optfirst)
Eric Andersencb57d552001-06-28 07:25:16 +000010547{
10548 char *p, *q;
10549 char c = '?';
10550 int done = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010551 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000010552 char **optnext;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010553 int ind = shellparam.optind;
10554 int off = shellparam.optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010555
Denys Vlasenko9c541002015-10-07 15:44:36 +020010556 sbuf[1] = '\0';
10557
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010558 shellparam.optind = -1;
10559 optnext = optfirst + ind - 1;
Eric Andersena48b0a32003-10-22 10:56:47 +000010560
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010561 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
Eric Andersencb57d552001-06-28 07:25:16 +000010562 p = NULL;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010563 else
10564 p = optnext[-1] + off;
Eric Andersencb57d552001-06-28 07:25:16 +000010565 if (p == NULL || *p == '\0') {
10566 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010567 p = *optnext;
10568 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010569 atend:
Eric Andersencb57d552001-06-28 07:25:16 +000010570 p = NULL;
10571 done = 1;
10572 goto out;
10573 }
10574 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010575 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010576 goto atend;
10577 }
10578
10579 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010580 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010581 if (*q == '\0') {
10582 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010583 sbuf[0] = c;
10584 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010585 setvar0("OPTARG", sbuf);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010586 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010587 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010588 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010589 }
10590 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010591 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010592 }
10593 if (*++q == ':')
10594 q++;
10595 }
10596
10597 if (*++q == ':') {
10598 if (*p == '\0' && (p = *optnext) == NULL) {
10599 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010600 sbuf[0] = c;
10601 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010602 setvar0("OPTARG", sbuf);
Eric Andersencb57d552001-06-28 07:25:16 +000010603 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010604 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010605 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010606 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010607 c = '?';
10608 }
Eric Andersenc470f442003-07-28 09:56:35 +000010609 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010610 }
10611
10612 if (p == *optnext)
10613 optnext++;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010614 setvar0("OPTARG", p);
Eric Andersencb57d552001-06-28 07:25:16 +000010615 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010616 } else
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010617 setvar0("OPTARG", nullstr);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010618 out:
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010619 ind = optnext - optfirst + 1;
10620 setvar("OPTIND", itoa(ind), VNOFUNC);
Denys Vlasenko9c541002015-10-07 15:44:36 +020010621 sbuf[0] = c;
10622 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010623 setvar0(optvar, sbuf);
10624
10625 shellparam.optoff = p ? p - *(optnext - 1) : -1;
10626 shellparam.optind = ind;
10627
Eric Andersencb57d552001-06-28 07:25:16 +000010628 return done;
10629}
Eric Andersenc470f442003-07-28 09:56:35 +000010630
10631/*
10632 * The getopts builtin. Shellparam.optnext points to the next argument
10633 * to be processed. Shellparam.optptr points to the next character to
10634 * be processed in the current argument. If shellparam.optnext is NULL,
10635 * then it's the first time getopts has been called.
10636 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010637static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000010638getoptscmd(int argc, char **argv)
10639{
10640 char **optbase;
10641
10642 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010643 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010644 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000010645 optbase = shellparam.p;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010646 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
Eric Andersenc470f442003-07-28 09:56:35 +000010647 shellparam.optind = 1;
10648 shellparam.optoff = -1;
10649 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010650 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010651 optbase = &argv[3];
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010652 if ((unsigned)shellparam.optind > argc - 2) {
Eric Andersenc470f442003-07-28 09:56:35 +000010653 shellparam.optind = 1;
10654 shellparam.optoff = -1;
10655 }
10656 }
10657
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010658 return getopts(argv[1], argv[2], optbase);
Eric Andersenc470f442003-07-28 09:56:35 +000010659}
Denis Vlasenko131ae172007-02-18 13:00:19 +000010660#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000010661
Eric Andersencb57d552001-06-28 07:25:16 +000010662
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010663/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000010664
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010665struct heredoc {
10666 struct heredoc *next; /* next here document in list */
10667 union node *here; /* redirection node */
10668 char *eofmark; /* string indicating end of input */
10669 smallint striptabs; /* if set, strip leading tabs */
10670};
10671
10672static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010673static smallint quoteflag; /* set if (part of) last token was quoted */
10674static token_id_t lasttoken; /* last token read (integer id Txxx) */
10675static struct heredoc *heredoclist; /* list of here documents to read */
10676static char *wordtext; /* text of last word returned by readtoken */
10677static struct nodelist *backquotelist;
10678static union node *redirnode;
10679static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010680
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010681static const char *
10682tokname(char *buf, int tok)
10683{
10684 if (tok < TSEMI)
Denys Vlasenko888527c2016-10-02 16:54:17 +020010685 return tokname_array[tok];
10686 sprintf(buf, "\"%s\"", tokname_array[tok]);
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010687 return buf;
10688}
10689
10690/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010691 * Called when an unexpected token is read during the parse. The argument
10692 * is the token that is expected, or -1 if more than one type of token can
10693 * occur at this point.
10694 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010695static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010696static void
10697raise_error_unexpected_syntax(int token)
10698{
10699 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010700 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010701 int l;
10702
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010703 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010704 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010705 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010706 raise_error_syntax(msg);
10707 /* NOTREACHED */
10708}
Eric Andersencb57d552001-06-28 07:25:16 +000010709
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010710#define EOFMARKLEN 79
Eric Andersencb57d552001-06-28 07:25:16 +000010711
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010712/* parsing is heavily cross-recursive, need these forward decls */
10713static union node *andor(void);
10714static union node *pipeline(void);
10715static union node *parse_command(void);
10716static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000010717static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010718static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000010719
Eric Andersenc470f442003-07-28 09:56:35 +000010720static union node *
10721list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000010722{
10723 union node *n1, *n2, *n3;
10724 int tok;
10725
Eric Andersencb57d552001-06-28 07:25:16 +000010726 n1 = NULL;
10727 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010728 switch (peektoken()) {
10729 case TNL:
10730 if (!(nlflag & 1))
10731 break;
10732 parseheredoc();
10733 return n1;
10734
10735 case TEOF:
10736 if (!n1 && (nlflag & 1))
10737 n1 = NODE_EOF;
10738 parseheredoc();
10739 return n1;
10740 }
10741
10742 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko888527c2016-10-02 16:54:17 +020010743 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
Ron Yorstonc0e00762015-10-29 11:30:55 +000010744 return n1;
10745 nlflag |= 2;
10746
Eric Andersencb57d552001-06-28 07:25:16 +000010747 n2 = andor();
10748 tok = readtoken();
10749 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000010750 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010751 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010752 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010753 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010754 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000010755 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010756 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010757 n2 = n3;
10758 }
10759 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000010760 }
10761 }
10762 if (n1 == NULL) {
10763 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010764 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010765 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010766 n3->type = NSEMI;
10767 n3->nbinary.ch1 = n1;
10768 n3->nbinary.ch2 = n2;
10769 n1 = n3;
10770 }
10771 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010772 case TNL:
10773 case TEOF:
10774 tokpushback = 1;
10775 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000010776 case TBACKGND:
10777 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000010778 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010779 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000010780 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010781 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010782 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010783 return n1;
10784 }
10785 }
10786}
10787
Eric Andersenc470f442003-07-28 09:56:35 +000010788static union node *
10789andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010790{
Eric Andersencb57d552001-06-28 07:25:16 +000010791 union node *n1, *n2, *n3;
10792 int t;
10793
Eric Andersencb57d552001-06-28 07:25:16 +000010794 n1 = pipeline();
10795 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010796 t = readtoken();
10797 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000010798 t = NAND;
10799 } else if (t == TOR) {
10800 t = NOR;
10801 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010802 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010803 return n1;
10804 }
Eric Andersenc470f442003-07-28 09:56:35 +000010805 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010806 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010807 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010808 n3->type = t;
10809 n3->nbinary.ch1 = n1;
10810 n3->nbinary.ch2 = n2;
10811 n1 = n3;
10812 }
10813}
10814
Eric Andersenc470f442003-07-28 09:56:35 +000010815static union node *
10816pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010817{
Eric Andersencb57d552001-06-28 07:25:16 +000010818 union node *n1, *n2, *pipenode;
10819 struct nodelist *lp, *prev;
10820 int negate;
10821
10822 negate = 0;
10823 TRACE(("pipeline: entered\n"));
10824 if (readtoken() == TNOT) {
10825 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000010826 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010827 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010828 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010829 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010830 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010831 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000010832 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010833 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010834 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000010835 pipenode->npipe.cmdlist = lp;
10836 lp->n = n1;
10837 do {
10838 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010839 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000010840 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010841 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010842 prev->next = lp;
10843 } while (readtoken() == TPIPE);
10844 lp->next = NULL;
10845 n1 = pipenode;
10846 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010847 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010848 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010849 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000010850 n2->type = NNOT;
10851 n2->nnot.com = n1;
10852 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010853 }
10854 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000010855}
10856
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010857static union node *
10858makename(void)
10859{
10860 union node *n;
10861
Denis Vlasenko597906c2008-02-20 16:38:54 +000010862 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010863 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010864 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010865 n->narg.text = wordtext;
10866 n->narg.backquote = backquotelist;
10867 return n;
10868}
10869
10870static void
10871fixredir(union node *n, const char *text, int err)
10872{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010873 int fd;
10874
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010875 TRACE(("Fix redir %s %d\n", text, err));
10876 if (!err)
10877 n->ndup.vname = NULL;
10878
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010879 fd = bb_strtou(text, NULL, 10);
10880 if (!errno && fd >= 0)
10881 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010882 else if (LONE_DASH(text))
10883 n->ndup.dupfd = -1;
10884 else {
10885 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010886 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010887 n->ndup.vname = makename();
10888 }
10889}
10890
10891/*
10892 * Returns true if the text contains nothing to expand (no dollar signs
10893 * or backquotes).
10894 */
10895static int
Denis Vlasenko68819d12008-12-15 11:26:36 +000010896noexpand(const char *text)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010897{
Denys Vlasenkocd716832009-11-28 22:14:02 +010010898 unsigned char c;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010899
Denys Vlasenkocd716832009-11-28 22:14:02 +010010900 while ((c = *text++) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010901 if (c == CTLQUOTEMARK)
10902 continue;
10903 if (c == CTLESC)
Denys Vlasenkocd716832009-11-28 22:14:02 +010010904 text++;
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010010905 else if (SIT(c, BASESYNTAX) == CCTL)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010906 return 0;
10907 }
10908 return 1;
10909}
10910
10911static void
10912parsefname(void)
10913{
10914 union node *n = redirnode;
10915
10916 if (readtoken() != TWORD)
10917 raise_error_unexpected_syntax(-1);
10918 if (n->type == NHERE) {
10919 struct heredoc *here = heredoc;
10920 struct heredoc *p;
10921 int i;
10922
10923 if (quoteflag == 0)
10924 n->type = NXHERE;
10925 TRACE(("Here document %d\n", n->type));
10926 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010927 raise_error_syntax("illegal eof marker for << redirection");
Denys Vlasenkob6c84342009-08-29 20:23:20 +020010928 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010929 here->eofmark = wordtext;
10930 here->next = NULL;
10931 if (heredoclist == NULL)
10932 heredoclist = here;
10933 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010934 for (p = heredoclist; p->next; p = p->next)
10935 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010936 p->next = here;
10937 }
10938 } else if (n->type == NTOFD || n->type == NFROMFD) {
10939 fixredir(n, wordtext, 0);
10940 } else {
10941 n->nfile.fname = makename();
10942 }
10943}
Eric Andersencb57d552001-06-28 07:25:16 +000010944
Eric Andersenc470f442003-07-28 09:56:35 +000010945static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010946simplecmd(void)
10947{
10948 union node *args, **app;
10949 union node *n = NULL;
10950 union node *vars, **vpp;
10951 union node **rpp, *redir;
10952 int savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010953#if ENABLE_ASH_BASH_COMPAT
10954 smallint double_brackets_flag = 0;
Ron Yorston95ebcf72015-11-03 09:42:23 +000010955 smallint function_flag = 0;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010956#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010957
10958 args = NULL;
10959 app = &args;
10960 vars = NULL;
10961 vpp = &vars;
10962 redir = NULL;
10963 rpp = &redir;
10964
10965 savecheckkwd = CHKALIAS;
10966 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000010967 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010968 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010969 t = readtoken();
10970 switch (t) {
10971#if ENABLE_ASH_BASH_COMPAT
Ron Yorston95ebcf72015-11-03 09:42:23 +000010972 case TFUNCTION:
10973 if (peektoken() != TWORD)
10974 raise_error_unexpected_syntax(TWORD);
10975 function_flag = 1;
10976 break;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010977 case TAND: /* "&&" */
10978 case TOR: /* "||" */
10979 if (!double_brackets_flag) {
10980 tokpushback = 1;
10981 goto out;
10982 }
10983 wordtext = (char *) (t == TAND ? "-a" : "-o");
10984#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010985 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000010986 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010987 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010988 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010989 n->narg.text = wordtext;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010990#if ENABLE_ASH_BASH_COMPAT
10991 if (strcmp("[[", wordtext) == 0)
10992 double_brackets_flag = 1;
10993 else if (strcmp("]]", wordtext) == 0)
10994 double_brackets_flag = 0;
10995#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010996 n->narg.backquote = backquotelist;
10997 if (savecheckkwd && isassignment(wordtext)) {
10998 *vpp = n;
10999 vpp = &n->narg.next;
11000 } else {
11001 *app = n;
11002 app = &n->narg.next;
11003 savecheckkwd = 0;
11004 }
Ron Yorston95ebcf72015-11-03 09:42:23 +000011005#if ENABLE_ASH_BASH_COMPAT
11006 if (function_flag) {
11007 checkkwd = CHKNL | CHKKWD;
11008 switch (peektoken()) {
11009 case TBEGIN:
11010 case TIF:
11011 case TCASE:
11012 case TUNTIL:
11013 case TWHILE:
11014 case TFOR:
11015 goto do_func;
11016 case TLP:
11017 function_flag = 0;
11018 break;
11019 case TWORD:
11020 if (strcmp("[[", wordtext) == 0)
11021 goto do_func;
11022 /* fall through */
11023 default:
11024 raise_error_unexpected_syntax(-1);
11025 }
11026 }
11027#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011028 break;
11029 case TREDIR:
11030 *rpp = n = redirnode;
11031 rpp = &n->nfile.next;
11032 parsefname(); /* read name of redirection file */
11033 break;
11034 case TLP:
Ron Yorston95ebcf72015-11-03 09:42:23 +000011035 IF_ASH_BASH_COMPAT(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011036 if (args && app == &args->narg.next
11037 && !vars && !redir
11038 ) {
11039 struct builtincmd *bcmd;
11040 const char *name;
11041
11042 /* We have a function */
Ron Yorston95ebcf72015-11-03 09:42:23 +000011043 if (IF_ASH_BASH_COMPAT(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011044 raise_error_unexpected_syntax(TRP);
11045 name = n->narg.text;
11046 if (!goodname(name)
11047 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11048 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011049 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011050 }
11051 n->type = NDEFUN;
11052 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11053 n->narg.next = parse_command();
11054 return n;
11055 }
Ron Yorston95ebcf72015-11-03 09:42:23 +000011056 IF_ASH_BASH_COMPAT(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011057 /* fall through */
11058 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011059 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011060 goto out;
11061 }
11062 }
11063 out:
11064 *app = NULL;
11065 *vpp = NULL;
11066 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011067 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011068 n->type = NCMD;
11069 n->ncmd.args = args;
11070 n->ncmd.assign = vars;
11071 n->ncmd.redirect = redir;
11072 return n;
11073}
11074
11075static union node *
11076parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011077{
Eric Andersencb57d552001-06-28 07:25:16 +000011078 union node *n1, *n2;
11079 union node *ap, **app;
11080 union node *cp, **cpp;
11081 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011082 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011083 int t;
11084
11085 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011086 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011087
Eric Andersencb57d552001-06-28 07:25:16 +000011088 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011089 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011090 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011091 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011092 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011093 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011094 n1->type = NIF;
11095 n1->nif.test = list(0);
11096 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011097 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011098 n1->nif.ifpart = list(0);
11099 n2 = n1;
11100 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011101 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011102 n2 = n2->nif.elsepart;
11103 n2->type = NIF;
11104 n2->nif.test = list(0);
11105 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011106 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011107 n2->nif.ifpart = list(0);
11108 }
11109 if (lasttoken == TELSE)
11110 n2->nif.elsepart = list(0);
11111 else {
11112 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011113 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011114 }
Eric Andersenc470f442003-07-28 09:56:35 +000011115 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011116 break;
11117 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011118 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011119 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011120 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011121 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011122 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011123 got = readtoken();
11124 if (got != TDO) {
Denys Vlasenko888527c2016-10-02 16:54:17 +020011125 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
Denis Vlasenko131ae172007-02-18 13:00:19 +000011126 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011127 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011128 }
11129 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011130 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011131 break;
11132 }
11133 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011134 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011135 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011136 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011137 n1->type = NFOR;
11138 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011139 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011140 if (readtoken() == TIN) {
11141 app = &ap;
11142 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011143 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011144 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011145 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011146 n2->narg.text = wordtext;
11147 n2->narg.backquote = backquotelist;
11148 *app = n2;
11149 app = &n2->narg.next;
11150 }
11151 *app = NULL;
11152 n1->nfor.args = ap;
11153 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011154 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011155 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011156 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011157 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011158 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011159 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011160 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011161 n1->nfor.args = n2;
11162 /*
11163 * Newline or semicolon here is optional (but note
11164 * that the original Bourne shell only allowed NL).
11165 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011166 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011167 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011168 }
Eric Andersenc470f442003-07-28 09:56:35 +000011169 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011170 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011171 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011172 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011173 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011174 break;
11175 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011176 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011177 n1->type = NCASE;
11178 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011179 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011180 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011181 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011182 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011183 n2->narg.text = wordtext;
11184 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011185 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11186 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011187 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011188 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011189 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011190 checkkwd = CHKNL | CHKKWD;
11191 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011192 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011193 if (lasttoken == TLP)
11194 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011195 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011196 cp->type = NCLIST;
11197 app = &cp->nclist.pattern;
11198 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011199 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011200 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011201 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011202 ap->narg.text = wordtext;
11203 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011204 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011205 break;
11206 app = &ap->narg.next;
11207 readtoken();
11208 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011209 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011210 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011211 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011212 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011213
Eric Andersenc470f442003-07-28 09:56:35 +000011214 cpp = &cp->nclist.next;
11215
11216 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011217 t = readtoken();
11218 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011219 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011220 raise_error_unexpected_syntax(TENDCASE);
11221 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011222 }
Eric Andersenc470f442003-07-28 09:56:35 +000011223 }
Eric Andersencb57d552001-06-28 07:25:16 +000011224 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011225 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011226 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011227 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011228 n1->type = NSUBSHELL;
11229 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011230 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011231 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011232 break;
11233 case TBEGIN:
11234 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011235 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011236 break;
Ron Yorston95ebcf72015-11-03 09:42:23 +000011237 IF_ASH_BASH_COMPAT(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011238 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011239 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011240 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011241 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011242 }
11243
Eric Andersenc470f442003-07-28 09:56:35 +000011244 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011245 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011246
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011247 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011248 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011249 checkkwd = CHKKWD | CHKALIAS;
11250 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011251 while (readtoken() == TREDIR) {
11252 *rpp = n2 = redirnode;
11253 rpp = &n2->nfile.next;
11254 parsefname();
11255 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011256 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011257 *rpp = NULL;
11258 if (redir) {
11259 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011260 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011261 n2->type = NREDIR;
11262 n2->nredir.n = n1;
11263 n1 = n2;
11264 }
11265 n1->nredir.redirect = redir;
11266 }
Eric Andersencb57d552001-06-28 07:25:16 +000011267 return n1;
11268}
11269
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011270#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko37dc08b2016-10-02 04:38:07 +020011271static int
11272decode_dollar_squote(void)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011273{
11274 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11275 int c, cnt;
11276 char *p;
11277 char buf[4];
11278
11279 c = pgetc();
11280 p = strchr(C_escapes, c);
11281 if (p) {
11282 buf[0] = c;
11283 p = buf;
11284 cnt = 3;
11285 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11286 do {
11287 c = pgetc();
11288 *++p = c;
11289 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11290 pungetc();
11291 } else if (c == 'x') { /* \xHH */
11292 do {
11293 c = pgetc();
11294 *++p = c;
11295 } while (isxdigit(c) && --cnt);
11296 pungetc();
11297 if (cnt == 3) { /* \x but next char is "bad" */
11298 c = 'x';
11299 goto unrecognized;
11300 }
11301 } else { /* simple seq like \\ or \t */
11302 p++;
11303 }
11304 *p = '\0';
11305 p = buf;
11306 c = bb_process_escape_sequence((void*)&p);
11307 } else { /* unrecognized "\z": print both chars unless ' or " */
11308 if (c != '\'' && c != '"') {
11309 unrecognized:
11310 c |= 0x100; /* "please encode \, then me" */
11311 }
11312 }
11313 return c;
11314}
11315#endif
11316
Eric Andersencb57d552001-06-28 07:25:16 +000011317/*
11318 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11319 * is not NULL, read a here document. In the latter case, eofmark is the
11320 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011321 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011322 * is the first character of the input token or document.
11323 *
11324 * Because C does not have internal subroutines, I have simulated them
11325 * using goto's to implement the subroutine linkage. The following macros
11326 * will run code that appears at the end of readtoken1.
11327 */
Eric Andersen2870d962001-07-02 17:27:21 +000011328#define CHECKEND() {goto checkend; checkend_return:;}
11329#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11330#define PARSESUB() {goto parsesub; parsesub_return:;}
11331#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11332#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11333#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011334static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011335readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011336{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011337 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011338 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011339 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020011340 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +000011341 char line[EOFMARKLEN + 1];
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011342 struct nodelist *bqlist;
11343 smallint quotef;
11344 smallint dblquote;
11345 smallint oldstyle;
11346 smallint prevsyntax; /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011347#if ENABLE_ASH_EXPAND_PRMT
11348 smallint pssyntax; /* we are expanding a prompt string */
11349#endif
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011350 int varnest; /* levels of variables expansion */
11351 int arinest; /* levels of arithmetic expansion */
11352 int parenlevel; /* levels of parens in arithmetic */
11353 int dqvarnest; /* levels of variables expansion within double quotes */
11354
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011355 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011356
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011357 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011358 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011359 quotef = 0;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011360 prevsyntax = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000011361#if ENABLE_ASH_EXPAND_PRMT
11362 pssyntax = (syntax == PSSYNTAX);
11363 if (pssyntax)
11364 syntax = DQSYNTAX;
11365#endif
11366 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011367 varnest = 0;
11368 arinest = 0;
11369 parenlevel = 0;
11370 dqvarnest = 0;
11371
11372 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011373 loop:
11374 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011375 CHECKEND(); /* set c to PEOF if at end of here document */
11376 for (;;) { /* until end of line or end of word */
11377 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11378 switch (SIT(c, syntax)) {
11379 case CNL: /* '\n' */
11380 if (syntax == BASESYNTAX)
11381 goto endword; /* exit outer loop */
11382 USTPUTC(c, out);
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011383 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011384 c = pgetc();
11385 goto loop; /* continue outer loop */
11386 case CWORD:
11387 USTPUTC(c, out);
11388 break;
11389 case CCTL:
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011390#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011391 if (c == '\\' && bash_dollar_squote) {
11392 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020011393 if (c == '\0') {
11394 /* skip $'\000', $'\x00' (like bash) */
11395 break;
11396 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011397 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020011398 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011399 c = (unsigned char)c;
Denys Vlasenko13f20912016-09-25 20:54:25 +020011400 if (eofmark == NULL || dblquote)
11401 USTPUTC(CTLESC, out);
11402 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011403 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011404 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011405#endif
Denys Vlasenko13f20912016-09-25 20:54:25 +020011406 if (eofmark == NULL || dblquote)
11407 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011408 USTPUTC(c, out);
11409 break;
11410 case CBACK: /* backslash */
11411 c = pgetc_without_PEOA();
11412 if (c == PEOF) {
11413 USTPUTC(CTLESC, out);
11414 USTPUTC('\\', out);
11415 pungetc();
11416 } else if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011417 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011418 } else {
11419#if ENABLE_ASH_EXPAND_PRMT
11420 if (c == '$' && pssyntax) {
Eric Andersenc470f442003-07-28 09:56:35 +000011421 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011422 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011423 }
Denis Vlasenko46a53062007-09-24 18:30:02 +000011424#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011425 /* Backslash is retained if we are in "str" and next char isn't special */
11426 if (dblquote
11427 && c != '\\'
11428 && c != '`'
11429 && c != '$'
11430 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011431 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011432 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011433 }
Ron Yorston549deab2015-05-18 09:57:51 +020011434 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011435 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011436 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011437 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011438 break;
11439 case CSQUOTE:
11440 syntax = SQSYNTAX;
11441 quotemark:
11442 if (eofmark == NULL) {
11443 USTPUTC(CTLQUOTEMARK, out);
11444 }
11445 break;
11446 case CDQUOTE:
11447 syntax = DQSYNTAX;
11448 dblquote = 1;
11449 goto quotemark;
11450 case CENDQUOTE:
11451 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020011452 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011453 USTPUTC(c, out);
11454 } else {
11455 if (dqvarnest == 0) {
11456 syntax = BASESYNTAX;
11457 dblquote = 0;
11458 }
11459 quotef = 1;
11460 goto quotemark;
11461 }
11462 break;
11463 case CVAR: /* '$' */
11464 PARSESUB(); /* parse substitution */
11465 break;
11466 case CENDVAR: /* '}' */
11467 if (varnest > 0) {
11468 varnest--;
11469 if (dqvarnest > 0) {
11470 dqvarnest--;
11471 }
11472 c = CTLENDVAR;
11473 }
11474 USTPUTC(c, out);
11475 break;
11476#if ENABLE_SH_MATH_SUPPORT
11477 case CLP: /* '(' in arithmetic */
11478 parenlevel++;
11479 USTPUTC(c, out);
11480 break;
11481 case CRP: /* ')' in arithmetic */
11482 if (parenlevel > 0) {
11483 parenlevel--;
11484 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011485 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020011486 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011487 if (--arinest == 0) {
11488 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011489 }
11490 } else {
11491 /*
11492 * unbalanced parens
11493 * (don't 2nd guess - no error)
11494 */
11495 pungetc();
11496 }
11497 }
11498 USTPUTC(c, out);
11499 break;
11500#endif
11501 case CBQUOTE: /* '`' */
11502 PARSEBACKQOLD();
11503 break;
11504 case CENDFILE:
11505 goto endword; /* exit outer loop */
11506 case CIGN:
11507 break;
11508 default:
11509 if (varnest == 0) {
11510#if ENABLE_ASH_BASH_COMPAT
11511 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011512//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020011513 if (pgetc() == '>')
11514 c = 0x100 + '>'; /* flag &> */
11515 pungetc();
11516 }
11517#endif
11518 goto endword; /* exit outer loop */
11519 }
11520 IF_ASH_ALIAS(if (c != PEOA))
11521 USTPUTC(c, out);
11522 }
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020011523 c = pgetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011524 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011525 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011526
Mike Frysinger98c52642009-04-02 10:02:37 +000011527#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011528 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011529 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011530#endif
Ron Yorston0e056f72015-07-01 16:45:40 +010011531 if (syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011532 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011533 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011534 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011535 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011536 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011537 }
11538 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011539 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011540 out = stackblock();
11541 if (eofmark == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011542 if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011543 && quotef == 0
11544 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011545 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011546 PARSEREDIR(); /* passed as params: out, c */
11547 lasttoken = TREDIR;
11548 return lasttoken;
11549 }
11550 /* else: non-number X seen, interpret it
11551 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011552 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011553 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011554 }
11555 quoteflag = quotef;
11556 backquotelist = bqlist;
11557 grabstackblock(len);
11558 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011559 lasttoken = TWORD;
11560 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011561/* end of readtoken routine */
11562
Eric Andersencb57d552001-06-28 07:25:16 +000011563/*
11564 * Check to see whether we are at the end of the here document. When this
11565 * is called, c is set to the first character of the next input line. If
11566 * we are at the end of the here document, this routine sets the c to PEOF.
11567 */
Eric Andersenc470f442003-07-28 09:56:35 +000011568checkend: {
11569 if (eofmark) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000011570#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011571 if (c == PEOA)
11572 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011573#endif
11574 if (striptabs) {
11575 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011576 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011577 }
Eric Andersenc470f442003-07-28 09:56:35 +000011578 }
11579 if (c == *eofmark) {
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011580 if (pfgets(line, sizeof(line)) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000011581 char *p, *q;
Denys Vlasenko350e6862016-10-26 16:26:45 +020011582 int cc;
Eric Andersencb57d552001-06-28 07:25:16 +000011583
Eric Andersenc470f442003-07-28 09:56:35 +000011584 p = line;
Denys Vlasenko350e6862016-10-26 16:26:45 +020011585 for (q = eofmark + 1;; p++, q++) {
11586 cc = *p;
11587 if (cc == '\n')
11588 cc = 0;
11589 if (!*q || cc != *q)
11590 break;
11591 }
11592 if (cc == *q) {
Eric Andersenc470f442003-07-28 09:56:35 +000011593 c = PEOF;
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011594 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011595 } else {
11596 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011597 }
11598 }
11599 }
11600 }
Eric Andersenc470f442003-07-28 09:56:35 +000011601 goto checkend_return;
11602}
Eric Andersencb57d552001-06-28 07:25:16 +000011603
Eric Andersencb57d552001-06-28 07:25:16 +000011604/*
11605 * Parse a redirection operator. The variable "out" points to a string
11606 * specifying the fd to be redirected. The variable "c" contains the
11607 * first character of the redirection operator.
11608 */
Eric Andersenc470f442003-07-28 09:56:35 +000011609parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011610 /* out is already checked to be a valid number or "" */
11611 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000011612 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000011613
Denis Vlasenko597906c2008-02-20 16:38:54 +000011614 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000011615 if (c == '>') {
11616 np->nfile.fd = 1;
11617 c = pgetc();
11618 if (c == '>')
11619 np->type = NAPPEND;
11620 else if (c == '|')
11621 np->type = NCLOBBER;
11622 else if (c == '&')
11623 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011624 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000011625 else {
11626 np->type = NTO;
11627 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011628 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000011629 }
11630#if ENABLE_ASH_BASH_COMPAT
11631 else if (c == 0x100 + '>') { /* this flags &> redirection */
11632 np->nfile.fd = 1;
11633 pgetc(); /* this is '>', no need to check */
11634 np->type = NTO2;
11635 }
11636#endif
11637 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000011638 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011639 c = pgetc();
11640 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000011641 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011642 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011643 np = stzalloc(sizeof(struct nhere));
11644 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011645 }
11646 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011647 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000011648 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011649 c = pgetc();
11650 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000011651 heredoc->striptabs = 1;
11652 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011653 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011654 pungetc();
11655 }
11656 break;
11657
11658 case '&':
11659 np->type = NFROMFD;
11660 break;
11661
11662 case '>':
11663 np->type = NFROMTO;
11664 break;
11665
11666 default:
11667 np->type = NFROM;
11668 pungetc();
11669 break;
11670 }
Eric Andersencb57d552001-06-28 07:25:16 +000011671 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011672 if (fd >= 0)
11673 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011674 redirnode = np;
11675 goto parseredir_return;
11676}
Eric Andersencb57d552001-06-28 07:25:16 +000011677
Eric Andersencb57d552001-06-28 07:25:16 +000011678/*
11679 * Parse a substitution. At this point, we have read the dollar sign
11680 * and nothing else.
11681 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000011682
11683/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11684 * (assuming ascii char codes, as the original implementation did) */
11685#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011686 (((unsigned)(c) - 33 < 32) \
11687 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000011688parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010011689 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011690 int typeloc;
Eric Andersencb57d552001-06-28 07:25:16 +000011691
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011692 c = pgetc_eatbnl();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011693 if (c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011694 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000011695 ) {
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011696#if ENABLE_ASH_BASH_COMPAT
Ron Yorston84ba50c2016-04-03 22:43:14 +010011697 if (syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011698 bash_dollar_squote = 1;
11699 else
11700#endif
11701 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011702 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011703 } else if (c == '(') {
11704 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011705 if (pgetc_eatbnl() == '(') {
Mike Frysinger98c52642009-04-02 10:02:37 +000011706#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000011707 PARSEARITH();
11708#else
Mike Frysinger98a6f562008-06-09 09:38:45 +000011709 raise_error_syntax("you disabled math support for $((arith)) syntax");
Eric Andersenc470f442003-07-28 09:56:35 +000011710#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011711 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011712 pungetc();
11713 PARSEBACKQNEW();
11714 }
11715 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011716 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000011717 USTPUTC(CTLVAR, out);
11718 typeloc = out - (char *)stackblock();
Denys Vlasenko3df14102016-10-26 16:41:13 +020011719 STADJUST(1, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011720 subtype = VSNORMAL;
11721 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011722 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011723 subtype = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011724 }
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011725 varname:
Denys Vlasenko3df14102016-10-26 16:41:13 +020011726 if (is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011727 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011728 do {
11729 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011730 c = pgetc_eatbnl();
Denys Vlasenko3df14102016-10-26 16:41:13 +020011731 } while (is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011732 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011733 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011734 do {
11735 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011736 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011737 } while (isdigit(c));
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011738 } else if (is_special(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011739 /* $[{[#]]<specialchar>[}] */
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011740 int cc = c;
11741
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011742 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011743 if (!subtype && cc == '#') {
11744 subtype = VSLENGTH;
11745 if (c == '_' || isalnum(c))
11746 goto varname;
11747 cc = c;
11748 c = pgetc_eatbnl();
11749 if (cc == '}' || c != '}') {
11750 pungetc();
11751 subtype = 0;
11752 c = cc;
11753 cc = '#';
11754 }
11755 }
11756 USTPUTC(cc, out);
Denis Vlasenko559691a2008-10-05 18:39:31 +000011757 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020011758 goto badsub;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011759 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011760 if (c != '}' && subtype == VSLENGTH) {
11761 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020011762 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011763 }
Eric Andersencb57d552001-06-28 07:25:16 +000011764
Eric Andersenc470f442003-07-28 09:56:35 +000011765 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011766 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011767 /* ${VAR...} but not $VAR or ${#VAR} */
11768 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000011769 switch (c) {
11770 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011771 c = pgetc_eatbnl();
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011772#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011773 /* This check is only needed to not misinterpret
11774 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
11775 * constructs.
11776 */
11777 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011778 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011779 pungetc();
Denys Vlasenko88e15702016-10-26 01:55:56 +020011780 break; /* "goto badsub" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011781 }
11782#endif
Denys Vlasenko3df14102016-10-26 16:41:13 +020011783 subtype = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000011784 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011785 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011786 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000011787 if (p == NULL)
Denys Vlasenko88e15702016-10-26 01:55:56 +020011788 break;
Denys Vlasenko3df14102016-10-26 16:41:13 +020011789 subtype |= p - types + VSNORMAL;
Eric Andersenc470f442003-07-28 09:56:35 +000011790 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011791 }
Eric Andersenc470f442003-07-28 09:56:35 +000011792 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011793 case '#': {
11794 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011795 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011796 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011797 if (c != cc)
Denys Vlasenko88e15702016-10-26 01:55:56 +020011798 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011799 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011800 break;
11801 }
11802#if ENABLE_ASH_BASH_COMPAT
11803 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011804 /* ${v/[/]pattern/repl} */
11805//TODO: encode pattern and repl separately.
11806// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011807 subtype = VSREPLACE;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011808 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011809 if (c != '/')
Denys Vlasenko88e15702016-10-26 01:55:56 +020011810 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011811 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011812 break;
11813#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011814 }
Eric Andersenc470f442003-07-28 09:56:35 +000011815 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020011816 badsub:
Eric Andersenc470f442003-07-28 09:56:35 +000011817 pungetc();
11818 }
Denys Vlasenko3df14102016-10-26 16:41:13 +020011819 ((unsigned char *)stackblock())[typeloc] = subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011820 if (subtype != VSNORMAL) {
11821 varnest++;
Denys Vlasenko3df14102016-10-26 16:41:13 +020011822 if (dblquote)
Eric Andersenc470f442003-07-28 09:56:35 +000011823 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000011824 }
Denys Vlasenko88e15702016-10-26 01:55:56 +020011825 STPUTC('=', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011826 }
Eric Andersenc470f442003-07-28 09:56:35 +000011827 goto parsesub_return;
11828}
Eric Andersencb57d552001-06-28 07:25:16 +000011829
Eric Andersencb57d552001-06-28 07:25:16 +000011830/*
11831 * Called to parse command substitutions. Newstyle is set if the command
11832 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11833 * list of commands (passed by reference), and savelen is the number of
11834 * characters on the top of the stack which must be preserved.
11835 */
Eric Andersenc470f442003-07-28 09:56:35 +000011836parsebackq: {
11837 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011838 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010011839 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000011840 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011841 smallint saveprompt = 0;
11842
Eric Andersenc470f442003-07-28 09:56:35 +000011843 str = NULL;
11844 savelen = out - (char *)stackblock();
11845 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011846 /*
11847 * FIXME: this can allocate very large block on stack and SEGV.
11848 * Example:
11849 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020011850 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011851 * a hundred command substitutions stack overflows.
11852 * With larger prepended string, SEGV happens sooner.
11853 */
Ron Yorston072fc602015-07-01 16:46:18 +010011854 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000011855 memcpy(str, stackblock(), savelen);
11856 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011857
Eric Andersenc470f442003-07-28 09:56:35 +000011858 if (oldstyle) {
11859 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010011860 * treatment to some slashes, and then push the string and
11861 * reread it as input, interpreting it normally.
11862 */
Eric Andersenc470f442003-07-28 09:56:35 +000011863 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000011864 size_t psavelen;
11865 char *pstr;
11866
Eric Andersenc470f442003-07-28 09:56:35 +000011867 STARTSTACKSTR(pout);
11868 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011869 int pc;
11870
11871 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011872 pc = pgetc();
11873 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000011874 case '`':
11875 goto done;
11876
11877 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011878 pc = pgetc();
11879 if (pc == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011880 nlprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011881 /*
11882 * If eating a newline, avoid putting
11883 * the newline into the new character
11884 * stream (via the STPUTC after the
11885 * switch).
11886 */
11887 continue;
11888 }
11889 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011890 && (!dblquote || pc != '"')
11891 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000011892 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011893 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011894 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000011895 break;
11896 }
11897 /* fall through */
11898
11899 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011900 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011901 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011902 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000011903
11904 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011905 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011906 break;
11907
11908 default:
11909 break;
11910 }
11911 STPUTC(pc, pout);
11912 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011913 done:
Eric Andersenc470f442003-07-28 09:56:35 +000011914 STPUTC('\0', pout);
11915 psavelen = pout - (char *)stackblock();
11916 if (psavelen > 0) {
11917 pstr = grabstackstr(pout);
11918 setinputstring(pstr);
11919 }
11920 }
11921 nlpp = &bqlist;
11922 while (*nlpp)
11923 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011924 *nlpp = stzalloc(sizeof(**nlpp));
11925 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011926
11927 if (oldstyle) {
11928 saveprompt = doprompt;
11929 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011930 }
11931
Eric Andersenc470f442003-07-28 09:56:35 +000011932 n = list(2);
11933
11934 if (oldstyle)
11935 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011936 else if (readtoken() != TRP)
11937 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011938
11939 (*nlpp)->n = n;
11940 if (oldstyle) {
11941 /*
11942 * Start reading from old file again, ignoring any pushed back
11943 * tokens left from the backquote parsing
11944 */
11945 popfile();
11946 tokpushback = 0;
11947 }
11948 while (stackblocksize() <= savelen)
11949 growstackblock();
11950 STARTSTACKSTR(out);
11951 if (str) {
11952 memcpy(out, str, savelen);
11953 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011954 }
Ron Yorston549deab2015-05-18 09:57:51 +020011955 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011956 if (oldstyle)
11957 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011958 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000011959}
11960
Mike Frysinger98c52642009-04-02 10:02:37 +000011961#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011962/*
11963 * Parse an arithmetic expansion (indicate start of one and set state)
11964 */
Eric Andersenc470f442003-07-28 09:56:35 +000011965parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000011966 if (++arinest == 1) {
11967 prevsyntax = syntax;
11968 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000011969 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020011970 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011971 goto parsearith_return;
11972}
11973#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011974} /* end of readtoken */
11975
Eric Andersencb57d552001-06-28 07:25:16 +000011976/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011977 * Read the next input token.
11978 * If the token is a word, we set backquotelist to the list of cmds in
11979 * backquotes. We set quoteflag to true if any part of the word was
11980 * quoted.
11981 * If the token is TREDIR, then we set redirnode to a structure containing
11982 * the redirection.
11983 * In all cases, the variable startlinno is set to the number of the line
11984 * on which the token starts.
11985 *
11986 * [Change comment: here documents and internal procedures]
11987 * [Readtoken shouldn't have any arguments. Perhaps we should make the
11988 * word parsing code into a separate routine. In this case, readtoken
11989 * doesn't need to have any internal procedures, but parseword does.
11990 * We could also make parseoperator in essence the main routine, and
11991 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000011992 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011993#define NEW_xxreadtoken
11994#ifdef NEW_xxreadtoken
11995/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011996static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000011997 '\n', '(', ')', /* singles */
11998 '&', '|', ';', /* doubles */
11999 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012000};
Eric Andersencb57d552001-06-28 07:25:16 +000012001
Denis Vlasenko834dee72008-10-07 09:18:30 +000012002#define xxreadtoken_singles 3
12003#define xxreadtoken_doubles 3
12004
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012005static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012006 TNL, TLP, TRP, /* only single occurrence allowed */
12007 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12008 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012009 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012010};
12011
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012012static int
12013xxreadtoken(void)
12014{
12015 int c;
12016
12017 if (tokpushback) {
12018 tokpushback = 0;
12019 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012020 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012021 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012022 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012023 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012024 c = pgetc();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000012025 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012026 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012027
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012028 if (c == '#') {
12029 while ((c = pgetc()) != '\n' && c != PEOF)
12030 continue;
12031 pungetc();
12032 } else if (c == '\\') {
12033 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012034 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012035 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012036 }
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012037 nlprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012038 } else {
12039 const char *p;
12040
12041 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12042 if (c != PEOF) {
12043 if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012044 nlnoprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012045 }
12046
12047 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000012048 if (p == NULL)
12049 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012050
Denis Vlasenko834dee72008-10-07 09:18:30 +000012051 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12052 int cc = pgetc();
12053 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012054 p += xxreadtoken_doubles + 1;
12055 } else {
12056 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012057#if ENABLE_ASH_BASH_COMPAT
12058 if (c == '&' && cc == '>') /* &> */
12059 break; /* return readtoken1(...) */
12060#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012061 }
12062 }
12063 }
12064 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12065 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012066 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012067 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012068
12069 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012070}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012071#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012072#define RETURN(token) return lasttoken = token
12073static int
12074xxreadtoken(void)
12075{
12076 int c;
12077
12078 if (tokpushback) {
12079 tokpushback = 0;
12080 return lasttoken;
12081 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012082 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012083 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012084 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012085 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012086 switch (c) {
12087 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012088 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012089 continue;
12090 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012091 while ((c = pgetc()) != '\n' && c != PEOF)
12092 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012093 pungetc();
12094 continue;
12095 case '\\':
12096 if (pgetc() == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012097 nlprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012098 continue;
12099 }
12100 pungetc();
12101 goto breakloop;
12102 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012103 nlnoprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012104 RETURN(TNL);
12105 case PEOF:
12106 RETURN(TEOF);
12107 case '&':
12108 if (pgetc() == '&')
12109 RETURN(TAND);
12110 pungetc();
12111 RETURN(TBACKGND);
12112 case '|':
12113 if (pgetc() == '|')
12114 RETURN(TOR);
12115 pungetc();
12116 RETURN(TPIPE);
12117 case ';':
12118 if (pgetc() == ';')
12119 RETURN(TENDCASE);
12120 pungetc();
12121 RETURN(TSEMI);
12122 case '(':
12123 RETURN(TLP);
12124 case ')':
12125 RETURN(TRP);
12126 default:
12127 goto breakloop;
12128 }
12129 }
12130 breakloop:
12131 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12132#undef RETURN
12133}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012134#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012135
12136static int
12137readtoken(void)
12138{
12139 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012140 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012141#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012142 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012143#endif
12144
12145#if ENABLE_ASH_ALIAS
12146 top:
12147#endif
12148
12149 t = xxreadtoken();
12150
12151 /*
12152 * eat newlines
12153 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012154 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012155 while (t == TNL) {
12156 parseheredoc();
12157 t = xxreadtoken();
12158 }
12159 }
12160
12161 if (t != TWORD || quoteflag) {
12162 goto out;
12163 }
12164
12165 /*
12166 * check for keywords
12167 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012168 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012169 const char *const *pp;
12170
12171 pp = findkwd(wordtext);
12172 if (pp) {
12173 lasttoken = t = pp - tokname_array;
Denys Vlasenko888527c2016-10-02 16:54:17 +020012174 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012175 goto out;
12176 }
12177 }
12178
12179 if (checkkwd & CHKALIAS) {
12180#if ENABLE_ASH_ALIAS
12181 struct alias *ap;
12182 ap = lookupalias(wordtext, 1);
12183 if (ap != NULL) {
12184 if (*ap->val) {
12185 pushstring(ap->val, ap);
12186 }
12187 goto top;
12188 }
12189#endif
12190 }
12191 out:
12192 checkkwd = 0;
12193#if DEBUG
12194 if (!alreadyseen)
Denys Vlasenko888527c2016-10-02 16:54:17 +020012195 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012196 else
Denys Vlasenko888527c2016-10-02 16:54:17 +020012197 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012198#endif
12199 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012200}
12201
Ron Yorstonc0e00762015-10-29 11:30:55 +000012202static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012203peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012204{
12205 int t;
12206
12207 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012208 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012209 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012210}
Eric Andersencb57d552001-06-28 07:25:16 +000012211
12212/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012213 * Read and parse a command. Returns NODE_EOF on end of file.
12214 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012215 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012216static union node *
12217parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012218{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012219 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012220 checkkwd = 0;
12221 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012222 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012223 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012224 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012225 return list(1);
12226}
12227
12228/*
12229 * Input any here documents.
12230 */
12231static void
12232parseheredoc(void)
12233{
12234 struct heredoc *here;
12235 union node *n;
12236
12237 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012238 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012239
12240 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012241 setprompt_if(needprompt, 2);
12242 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012243 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012244 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012245 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012246 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012247 n->narg.text = wordtext;
12248 n->narg.backquote = backquotelist;
12249 here->here->nhere.doc = n;
12250 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012251 }
Eric Andersencb57d552001-06-28 07:25:16 +000012252}
12253
12254
12255/*
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012256 * called by editline -- any expansions to the prompt should be added here.
Eric Andersencb57d552001-06-28 07:25:16 +000012257 */
Denis Vlasenko131ae172007-02-18 13:00:19 +000012258#if ENABLE_ASH_EXPAND_PRMT
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012259static const char *
12260expandstr(const char *ps)
12261{
12262 union node n;
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012263 int saveprompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012264
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000012265 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12266 * and token processing _can_ alter it (delete NULs etc). */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012267 setinputstring((char *)ps);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012268
12269 saveprompt = doprompt;
12270 doprompt = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000012271 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012272 doprompt = saveprompt;
12273
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012274 popfile();
12275
12276 n.narg.type = NARG;
12277 n.narg.next = NULL;
12278 n.narg.text = wordtext;
12279 n.narg.backquote = backquotelist;
12280
Ron Yorston549deab2015-05-18 09:57:51 +020012281 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012282 return stackblock();
12283}
12284#endif
12285
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012286/*
12287 * Execute a command or commands contained in a string.
12288 */
12289static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012290evalstring(char *s, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000012291{
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012292 struct jmploc *volatile savehandler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012293 struct jmploc jmploc;
12294 int ex;
12295
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012296 union node *n;
12297 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012298 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012299
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012300 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012301 setinputstring(s);
12302 setstackmark(&smark);
12303
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012304 status = 0;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012305 /* On exception inside execution loop, we must popfile().
12306 * Try interactively:
12307 * readonly a=a
12308 * command eval "a=b" # throws "is read only" error
12309 * "command BLTIN" is not supposed to abort (even in non-interactive use).
12310 * But if we skip popfile(), we hit EOF in eval's string, and exit.
12311 */
12312 savehandler = exception_handler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012313 ex = setjmp(jmploc.loc);
12314 if (ex)
12315 goto out;
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012316 exception_handler = &jmploc;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012317
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012318 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012319 int i;
12320
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012321 i = evaltree(n, flags);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012322 if (n)
12323 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012324 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012325 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012326 break;
12327 }
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012328 out:
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012329 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012330 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012331 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012332
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012333 exception_handler = savehandler;
12334 if (ex)
12335 longjmp(exception_handler->loc, ex);
12336
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012337 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000012338}
12339
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012340/*
12341 * The eval command.
12342 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012343static int FAST_FUNC
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012344evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012345{
12346 char *p;
12347 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012348
Denis Vlasenko68404f12008-03-17 09:00:54 +000012349 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012350 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012351 argv += 2;
12352 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012353 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012354 for (;;) {
12355 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012356 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012357 if (p == NULL)
12358 break;
12359 STPUTC(' ', concat);
12360 }
12361 STPUTC('\0', concat);
12362 p = grabstackstr(concat);
12363 }
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012364 return evalstring(p, flags & EV_TESTED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012365 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012366 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012367}
12368
12369/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012370 * Read and execute commands.
12371 * "Top" is nonzero for the top level command loop;
12372 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012373 */
12374static int
12375cmdloop(int top)
12376{
12377 union node *n;
12378 struct stackmark smark;
12379 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012380 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012381 int numeof = 0;
12382
12383 TRACE(("cmdloop(%d) called\n", top));
12384 for (;;) {
12385 int skip;
12386
12387 setstackmark(&smark);
12388#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012389 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020012390 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012391#endif
12392 inter = 0;
12393 if (iflag && top) {
12394 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012395 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012396 }
12397 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012398#if DEBUG
12399 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012400 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012401#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012402 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012403 if (!top || numeof >= 50)
12404 break;
12405 if (!stoppedjobs()) {
12406 if (!Iflag)
12407 break;
12408 out2str("\nUse \"exit\" to leave shell.\n");
12409 }
12410 numeof++;
12411 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012412 int i;
12413
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012414 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12415 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012416 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012417 i = evaltree(n, 0);
12418 if (n)
12419 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012420 }
12421 popstackmark(&smark);
12422 skip = evalskip;
12423
12424 if (skip) {
Denys Vlasenko6a0710e2016-09-30 14:18:34 +020012425 evalskip &= ~SKIPFUNC;
Denys Vlasenko0840c912016-10-01 15:27:44 +020012426 break;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012427 }
12428 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012429 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012430}
12431
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012432/*
12433 * Take commands from a file. To be compatible we should do a path
12434 * search for the file, which is necessary to find sub-commands.
12435 */
12436static char *
12437find_dot_file(char *name)
12438{
12439 char *fullname;
12440 const char *path = pathval();
12441 struct stat statb;
12442
12443 /* don't try this for absolute or relative paths */
12444 if (strchr(name, '/'))
12445 return name;
12446
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012447 /* IIRC standards do not say whether . is to be searched.
12448 * And it is even smaller this way, making it unconditional for now:
12449 */
12450 if (1) { /* ENABLE_ASH_BASH_COMPAT */
12451 fullname = name;
12452 goto try_cur_dir;
12453 }
12454
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012455 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012456 try_cur_dir:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012457 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12458 /*
12459 * Don't bother freeing here, since it will
12460 * be freed by the caller.
12461 */
12462 return fullname;
12463 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012464 if (fullname != name)
12465 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012466 }
12467
12468 /* not found in the PATH */
12469 ash_msg_and_raise_error("%s: not found", name);
12470 /* NOTREACHED */
12471}
12472
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012473static int FAST_FUNC
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012474dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012475{
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012476 /* "false; . empty_file; echo $?" should print 0, not 1: */
12477 int status = 0;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012478 char *fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012479 char **argv;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012480 struct strlist *sp;
12481 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012482
12483 for (sp = cmdenviron; sp; sp = sp->next)
Denis Vlasenko4222ae42007-02-25 02:37:49 +000012484 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012485
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012486 nextopt(nullstr); /* handle possible "--" */
12487 argv = argptr;
12488
12489 if (!argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012490 /* bash says: "bash: .: filename argument required" */
12491 return 2; /* bash compat */
12492 }
12493
Denys Vlasenko091f8312013-03-17 14:25:22 +010012494 /* This aborts if file isn't found, which is POSIXly correct.
12495 * bash returns exitcode 1 instead.
12496 */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012497 fullname = find_dot_file(argv[0]);
12498 argv++;
12499 if (argv[0]) { /* . FILE ARGS, ARGS exist */
12500 int argc;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012501 saveparam = shellparam;
12502 shellparam.malloced = 0;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012503 argc = 1;
12504 while (argv[argc])
12505 argc++;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012506 shellparam.nparam = argc;
12507 shellparam.p = argv;
12508 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012509
Denys Vlasenko091f8312013-03-17 14:25:22 +010012510 /* This aborts if file can't be opened, which is POSIXly correct.
12511 * bash returns exitcode 1 instead.
12512 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012513 setinputfile(fullname, INPUT_PUSH_FILE);
12514 commandname = fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012515 status = cmdloop(0);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012516 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012517
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012518 if (argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012519 freeparam(&shellparam);
12520 shellparam = saveparam;
12521 };
12522
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012523 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012524}
12525
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012526static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012527exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012528{
12529 if (stoppedjobs())
12530 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012531 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012532 exitstatus = number(argv[1]);
12533 raise_exception(EXEXIT);
12534 /* NOTREACHED */
12535}
12536
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012537/*
12538 * Read a file containing shell functions.
12539 */
12540static void
12541readcmdfile(char *name)
12542{
12543 setinputfile(name, INPUT_PUSH_FILE);
12544 cmdloop(0);
12545 popfile();
12546}
12547
12548
Denis Vlasenkocc571512007-02-23 21:10:35 +000012549/* ============ find_command inplementation */
12550
12551/*
12552 * Resolve a command name. If you change this routine, you may have to
12553 * change the shellexec routine as well.
12554 */
12555static void
12556find_command(char *name, struct cmdentry *entry, int act, const char *path)
12557{
12558 struct tblentry *cmdp;
12559 int idx;
12560 int prev;
12561 char *fullname;
12562 struct stat statb;
12563 int e;
12564 int updatetbl;
12565 struct builtincmd *bcmd;
12566
12567 /* If name contains a slash, don't use PATH or hash table */
12568 if (strchr(name, '/') != NULL) {
12569 entry->u.index = -1;
12570 if (act & DO_ABS) {
12571 while (stat(name, &statb) < 0) {
12572#ifdef SYSV
12573 if (errno == EINTR)
12574 continue;
12575#endif
12576 entry->cmdtype = CMDUNKNOWN;
12577 return;
12578 }
12579 }
12580 entry->cmdtype = CMDNORMAL;
12581 return;
12582 }
12583
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012584/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012585
12586 updatetbl = (path == pathval());
12587 if (!updatetbl) {
12588 act |= DO_ALTPATH;
12589 if (strstr(path, "%builtin") != NULL)
12590 act |= DO_ALTBLTIN;
12591 }
12592
12593 /* If name is in the table, check answer will be ok */
12594 cmdp = cmdlookup(name, 0);
12595 if (cmdp != NULL) {
12596 int bit;
12597
12598 switch (cmdp->cmdtype) {
12599 default:
12600#if DEBUG
12601 abort();
12602#endif
12603 case CMDNORMAL:
12604 bit = DO_ALTPATH;
12605 break;
12606 case CMDFUNCTION:
12607 bit = DO_NOFUNC;
12608 break;
12609 case CMDBUILTIN:
12610 bit = DO_ALTBLTIN;
12611 break;
12612 }
12613 if (act & bit) {
12614 updatetbl = 0;
12615 cmdp = NULL;
12616 } else if (cmdp->rehash == 0)
12617 /* if not invalidated by cd, we're done */
12618 goto success;
12619 }
12620
12621 /* If %builtin not in path, check for builtin next */
12622 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012623 if (bcmd) {
12624 if (IS_BUILTIN_REGULAR(bcmd))
12625 goto builtin_success;
12626 if (act & DO_ALTPATH) {
12627 if (!(act & DO_ALTBLTIN))
12628 goto builtin_success;
12629 } else if (builtinloc <= 0) {
12630 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000012631 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012632 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000012633
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012634#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000012635 {
12636 int applet_no = find_applet_by_name(name);
12637 if (applet_no >= 0) {
12638 entry->cmdtype = CMDNORMAL;
12639 entry->u.index = -2 - applet_no;
12640 return;
12641 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012642 }
12643#endif
12644
Denis Vlasenkocc571512007-02-23 21:10:35 +000012645 /* We have to search path. */
12646 prev = -1; /* where to start */
12647 if (cmdp && cmdp->rehash) { /* doing a rehash */
12648 if (cmdp->cmdtype == CMDBUILTIN)
12649 prev = builtinloc;
12650 else
12651 prev = cmdp->param.index;
12652 }
12653
12654 e = ENOENT;
12655 idx = -1;
12656 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012657 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000012658 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012659 /* NB: code below will still use fullname
12660 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012661 idx++;
12662 if (pathopt) {
12663 if (prefix(pathopt, "builtin")) {
12664 if (bcmd)
12665 goto builtin_success;
12666 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000012667 }
12668 if ((act & DO_NOFUNC)
12669 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020012670 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012671 continue;
12672 }
12673 }
12674 /* if rehash, don't redo absolute path names */
12675 if (fullname[0] == '/' && idx <= prev) {
12676 if (idx < prev)
12677 continue;
12678 TRACE(("searchexec \"%s\": no change\n", name));
12679 goto success;
12680 }
12681 while (stat(fullname, &statb) < 0) {
12682#ifdef SYSV
12683 if (errno == EINTR)
12684 continue;
12685#endif
12686 if (errno != ENOENT && errno != ENOTDIR)
12687 e = errno;
12688 goto loop;
12689 }
12690 e = EACCES; /* if we fail, this will be the error */
12691 if (!S_ISREG(statb.st_mode))
12692 continue;
12693 if (pathopt) { /* this is a %func directory */
12694 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012695 /* NB: stalloc will return space pointed by fullname
12696 * (because we don't have any intervening allocations
12697 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012698 readcmdfile(fullname);
12699 cmdp = cmdlookup(name, 0);
12700 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12701 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12702 stunalloc(fullname);
12703 goto success;
12704 }
12705 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12706 if (!updatetbl) {
12707 entry->cmdtype = CMDNORMAL;
12708 entry->u.index = idx;
12709 return;
12710 }
12711 INT_OFF;
12712 cmdp = cmdlookup(name, 1);
12713 cmdp->cmdtype = CMDNORMAL;
12714 cmdp->param.index = idx;
12715 INT_ON;
12716 goto success;
12717 }
12718
12719 /* We failed. If there was an entry for this command, delete it */
12720 if (cmdp && updatetbl)
12721 delete_cmd_entry();
12722 if (act & DO_ERR)
12723 ash_msg("%s: %s", name, errmsg(e, "not found"));
12724 entry->cmdtype = CMDUNKNOWN;
12725 return;
12726
12727 builtin_success:
12728 if (!updatetbl) {
12729 entry->cmdtype = CMDBUILTIN;
12730 entry->u.cmd = bcmd;
12731 return;
12732 }
12733 INT_OFF;
12734 cmdp = cmdlookup(name, 1);
12735 cmdp->cmdtype = CMDBUILTIN;
12736 cmdp->param.cmd = bcmd;
12737 INT_ON;
12738 success:
12739 cmdp->rehash = 0;
12740 entry->cmdtype = cmdp->cmdtype;
12741 entry->u = cmdp->param;
12742}
12743
12744
Eric Andersencb57d552001-06-28 07:25:16 +000012745/*
Eric Andersencb57d552001-06-28 07:25:16 +000012746 * The trap builtin.
12747 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012748static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012749trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012750{
12751 char *action;
12752 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012753 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012754
Eric Andersenc470f442003-07-28 09:56:35 +000012755 nextopt(nullstr);
12756 ap = argptr;
12757 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012758 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012759 char *tr = trap_ptr[signo];
12760 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012761 /* note: bash adds "SIG", but only if invoked
12762 * as "bash". If called as "sh", or if set -o posix,
12763 * then it prints short signal names.
12764 * We are printing short names: */
12765 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012766 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012767 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012768 /* trap_ptr != trap only if we are in special-cased `trap` code.
12769 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012770 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012771 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000012772 }
12773 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012774 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012775 if (trap_ptr != trap) {
12776 free(trap_ptr);
12777 trap_ptr = trap;
12778 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012779 */
Eric Andersencb57d552001-06-28 07:25:16 +000012780 return 0;
12781 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012782
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012783 action = NULL;
12784 if (ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000012785 action = *ap++;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012786 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012787 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012788 signo = get_signum(*ap);
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012789 if (signo < 0) {
12790 /* Mimic bash message exactly */
12791 ash_msg("%s: invalid signal specification", *ap);
12792 exitcode = 1;
12793 goto next;
12794 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000012795 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000012796 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000012797 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000012798 action = NULL;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020012799 else {
12800 if (action[0]) /* not NULL and not "" and not "-" */
12801 may_have_traps = 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012802 action = ckstrdup(action);
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020012803 }
Eric Andersencb57d552001-06-28 07:25:16 +000012804 }
Denis Vlasenko60818682007-09-28 22:07:23 +000012805 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000012806 trap[signo] = action;
12807 if (signo != 0)
12808 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012809 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012810 next:
Eric Andersencb57d552001-06-28 07:25:16 +000012811 ap++;
12812 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012813 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012814}
12815
Eric Andersenc470f442003-07-28 09:56:35 +000012816
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012817/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000012818
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012819#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012820static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012821helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012822{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000012823 unsigned col;
12824 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000012825
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020012826 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000012827 "Built-in commands:\n"
12828 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000012829 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012830 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000012831 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000012832 if (col > 60) {
12833 out1fmt("\n");
12834 col = 0;
12835 }
12836 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012837# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000012838 {
12839 const char *a = applet_names;
12840 while (*a) {
12841 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12842 if (col > 60) {
12843 out1fmt("\n");
12844 col = 0;
12845 }
Ron Yorston2b919582016-04-08 11:57:20 +010012846 while (*a++ != '\0')
12847 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000012848 }
12849 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012850# endif
Denys Vlasenkoebedb942016-10-02 18:45:09 +020012851 newline_and_flush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000012852 return EXIT_SUCCESS;
12853}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012854#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012855
Flemming Madsend96ffda2013-04-07 18:47:24 +020012856#if MAX_HISTORY
12857static int FAST_FUNC
12858historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12859{
12860 show_history(line_input_state);
12861 return EXIT_SUCCESS;
12862}
12863#endif
12864
Eric Andersencb57d552001-06-28 07:25:16 +000012865/*
Eric Andersencb57d552001-06-28 07:25:16 +000012866 * The export and readonly commands.
12867 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012868static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012869exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012870{
12871 struct var *vp;
12872 char *name;
12873 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012874 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020012875 char opt;
12876 int flag;
12877 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000012878
Denys Vlasenkod5275882012-10-01 13:41:17 +020012879 /* "readonly" in bash accepts, but ignores -n.
12880 * We do the same: it saves a conditional in nextopt's param.
12881 */
12882 flag_off = 0;
12883 while ((opt = nextopt("np")) != '\0') {
12884 if (opt == 'n')
12885 flag_off = VEXPORT;
12886 }
12887 flag = VEXPORT;
12888 if (argv[0][0] == 'r') {
12889 flag = VREADONLY;
12890 flag_off = 0; /* readonly ignores -n */
12891 }
12892 flag_off = ~flag_off;
12893
12894 /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */
12895 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012896 aptr = argptr;
12897 name = *aptr;
12898 if (name) {
12899 do {
12900 p = strchr(name, '=');
12901 if (p != NULL) {
12902 p++;
12903 } else {
12904 vp = *findvar(hashvar(name), name);
12905 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020012906 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012907 continue;
12908 }
Eric Andersencb57d552001-06-28 07:25:16 +000012909 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012910 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012911 } while ((name = *++aptr) != NULL);
12912 return 0;
12913 }
Eric Andersencb57d552001-06-28 07:25:16 +000012914 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012915
12916 /* No arguments. Show the list of exported or readonly vars.
12917 * -n is ignored.
12918 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012919 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012920 return 0;
12921}
12922
Eric Andersencb57d552001-06-28 07:25:16 +000012923/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012924 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000012925 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000012926static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012927unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012928{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012929 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000012930
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012931 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012932 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012933 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000012934}
12935
Eric Andersencb57d552001-06-28 07:25:16 +000012936/*
Eric Andersencb57d552001-06-28 07:25:16 +000012937 * The unset builtin command. We unset the function before we unset the
12938 * variable to allow a function to be unset when there is a readonly variable
12939 * with the same name.
12940 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012941static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012942unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012943{
12944 char **ap;
12945 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012946 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012947 int ret = 0;
12948
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012949 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000012950 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012951 }
Eric Andersencb57d552001-06-28 07:25:16 +000012952
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012953 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012954 if (flag != 'f') {
12955 i = unsetvar(*ap);
12956 ret |= i;
12957 if (!(i & 2))
12958 continue;
12959 }
12960 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012961 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012962 }
Eric Andersenc470f442003-07-28 09:56:35 +000012963 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012964}
12965
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012966static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012967 ' ', offsetof(struct tms, tms_utime),
12968 '\n', offsetof(struct tms, tms_stime),
12969 ' ', offsetof(struct tms, tms_cutime),
12970 '\n', offsetof(struct tms, tms_cstime),
12971 0
12972};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012973static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012974timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012975{
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012976 unsigned long clk_tck, s, t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012977 const unsigned char *p;
12978 struct tms buf;
12979
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020012980 clk_tck = bb_clk_tck();
Eric Andersencb57d552001-06-28 07:25:16 +000012981 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012982
12983 p = timescmd_str;
12984 do {
12985 t = *(clock_t *)(((char *) &buf) + p[1]);
12986 s = t / clk_tck;
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012987 t = t % clk_tck;
12988 out1fmt("%lum%lu.%03lus%c",
12989 s / 60, s % 60,
12990 (t * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012991 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012992 p += 2;
12993 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012994
Eric Andersencb57d552001-06-28 07:25:16 +000012995 return 0;
12996}
12997
Mike Frysinger98c52642009-04-02 10:02:37 +000012998#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000012999/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013000 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013001 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000013002 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013003 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000013004 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013005static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013006letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013007{
Denis Vlasenko68404f12008-03-17 09:00:54 +000013008 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000013009
Denis Vlasenko68404f12008-03-17 09:00:54 +000013010 argv++;
13011 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000013012 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000013013 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013014 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013015 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013016
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000013017 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000013018}
Eric Andersenc470f442003-07-28 09:56:35 +000013019#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013020
Eric Andersenc470f442003-07-28 09:56:35 +000013021/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013022 * The read builtin. Options:
13023 * -r Do not interpret '\' specially
13024 * -s Turn off echo (tty only)
13025 * -n NCHARS Read NCHARS max
13026 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13027 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13028 * -u FD Read from given FD instead of fd 0
Eric Andersenc470f442003-07-28 09:56:35 +000013029 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013030 * TODO: bash also has:
13031 * -a ARRAY Read into array[0],[1],etc
13032 * -d DELIM End on DELIM char, not newline
13033 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000013034 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013035static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013036readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013037{
Denys Vlasenko73067272010-01-12 22:11:24 +010013038 char *opt_n = NULL;
13039 char *opt_p = NULL;
13040 char *opt_t = NULL;
13041 char *opt_u = NULL;
13042 int read_flags = 0;
13043 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000013044 int i;
13045
Denys Vlasenko73067272010-01-12 22:11:24 +010013046 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000013047 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000013048 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010013049 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013050 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013051 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010013052 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013053 break;
13054 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010013055 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000013056 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013057 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010013058 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013059 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013060 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010013061 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000013062 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013063 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010013064 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013065 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013066 default:
13067 break;
13068 }
Eric Andersenc470f442003-07-28 09:56:35 +000013069 }
Paul Fox02eb9342005-09-07 16:56:02 +000013070
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013071 /* "read -s" needs to save/restore termios, can't allow ^C
13072 * to jump out of it.
13073 */
13074 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013075 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010013076 argptr,
13077 bltinlookup("IFS"), /* can be NULL */
13078 read_flags,
13079 opt_n,
13080 opt_p,
13081 opt_t,
13082 opt_u
13083 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013084 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000013085
Denys Vlasenko73067272010-01-12 22:11:24 +010013086 if ((uintptr_t)r > 1)
13087 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000013088
Denys Vlasenko73067272010-01-12 22:11:24 +010013089 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000013090}
13091
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013092static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020013093umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013094{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013095 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000013096
Eric Andersenc470f442003-07-28 09:56:35 +000013097 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000013098 int symbolic_mode = 0;
13099
13100 while (nextopt("S") != '\0') {
13101 symbolic_mode = 1;
13102 }
13103
Denis Vlasenkob012b102007-02-19 22:43:01 +000013104 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013105 mask = umask(0);
13106 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013107 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013108
Denys Vlasenko6283f982015-10-07 16:56:20 +020013109 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013110 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013111 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013112 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013113 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013114
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013115 i = 2;
13116 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013117 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013118 *p++ = permuser[i];
13119 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013120 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013121 if (!(mask & 0400)) *p++ = 'r';
13122 if (!(mask & 0200)) *p++ = 'w';
13123 if (!(mask & 0100)) *p++ = 'x';
13124 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013125 if (--i < 0)
13126 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013127 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013128 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013129 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013130 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013131 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013132 }
13133 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013134 char *modestr = *argptr;
13135 /* numeric umasks are taken as-is */
13136 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
13137 if (!isdigit(modestr[0]))
13138 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013139 mask = bb_parse_mode(modestr, mask);
13140 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013141 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013142 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013143 if (!isdigit(modestr[0]))
13144 mask ^= 0777;
13145 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013146 }
13147 return 0;
13148}
13149
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013150static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013151ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013152{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013153 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013154}
13155
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013156/* ============ main() and helpers */
13157
13158/*
13159 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013160 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013161static void
13162exitshell(void)
13163{
13164 struct jmploc loc;
13165 char *p;
13166 int status;
13167
Denys Vlasenkobede2152011-09-04 16:12:33 +020013168#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13169 save_history(line_input_state);
13170#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013171 status = exitstatus;
13172 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13173 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013174 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013175 status = exitstatus;
13176 goto out;
13177 }
13178 exception_handler = &loc;
13179 p = trap[0];
13180 if (p) {
13181 trap[0] = NULL;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013182 evalskip = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013183 evalstring(p, 0);
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013184 /*free(p); - we'll exit soon */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013185 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013186 out:
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013187 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13188 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13189 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013190 setjobctl(0);
Denys Vlasenkocaee80c2016-10-25 20:49:53 +020013191 flush_stdout_stderr();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013192 _exit(status);
13193 /* NOTREACHED */
13194}
13195
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013196static void
13197init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013198{
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013199 /* we will never free this */
13200 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013201
Denys Vlasenko458c1f22016-10-27 23:51:19 +020013202 sigmode[SIGCHLD - 1] = S_DFL;
13203 setsignal(SIGCHLD);
13204
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013205 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13206 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13207 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013208 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013209
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013210 {
13211 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013212 const char *p;
13213 struct stat st1, st2;
13214
13215 initvar();
13216 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenkob6838b52016-09-30 11:33:47 +020013217 p = endofname(*envp);
13218 if (p != *envp && *p == '=') {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013219 setvareq(*envp, VEXPORT|VTEXTFIXED);
13220 }
13221 }
13222
Denys Vlasenkoe627ac92016-09-30 14:36:59 +020013223 setvareq((char*)defoptindvar, VTEXTFIXED);
13224
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013225 setvar0("PPID", utoa(getppid()));
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013226#if ENABLE_ASH_BASH_COMPAT
13227 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013228 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013229 if (!lookupvar("HOSTNAME")) {
13230 struct utsname uts;
13231 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013232 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013233 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013234#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013235 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013236 if (p) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013237 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013238 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13239 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013240 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013241 }
13242 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013243 setpwd(p, 0);
13244 }
13245}
13246
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013247
13248//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013249//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013250//usage:#define ash_full_usage "\n\n"
13251//usage: "Unix shell interpreter"
13252
13253//usage:#if ENABLE_FEATURE_SH_IS_ASH
13254//usage:# define sh_trivial_usage ash_trivial_usage
13255//usage:# define sh_full_usage ash_full_usage
13256//usage:#endif
13257//usage:#if ENABLE_FEATURE_BASH_IS_ASH
13258//usage:# define bash_trivial_usage ash_trivial_usage
13259//usage:# define bash_full_usage ash_full_usage
13260//usage:#endif
13261
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013262/*
13263 * Process the shell command line arguments.
13264 */
13265static void
Denis Vlasenko68404f12008-03-17 09:00:54 +000013266procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013267{
13268 int i;
13269 const char *xminusc;
13270 char **xargv;
13271
13272 xargv = argv;
13273 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013274 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013275 xargv++;
13276 for (i = 0; i < NOPTS; i++)
13277 optlist[i] = 2;
13278 argptr = xargv;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013279 if (options(/*cmdline:*/ 1)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013280 /* it already printed err message */
13281 raise_exception(EXERROR);
13282 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013283 xargv = argptr;
13284 xminusc = minusc;
13285 if (*xargv == NULL) {
13286 if (xminusc)
13287 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13288 sflag = 1;
13289 }
13290 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13291 iflag = 1;
13292 if (mflag == 2)
13293 mflag = iflag;
13294 for (i = 0; i < NOPTS; i++)
13295 if (optlist[i] == 2)
13296 optlist[i] = 0;
13297#if DEBUG == 2
13298 debug = 1;
13299#endif
13300 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13301 if (xminusc) {
13302 minusc = *xargv++;
13303 if (*xargv)
13304 goto setarg0;
13305 } else if (!sflag) {
13306 setinputfile(*xargv, 0);
13307 setarg0:
13308 arg0 = *xargv++;
13309 commandname = arg0;
13310 }
13311
13312 shellparam.p = xargv;
13313#if ENABLE_ASH_GETOPTS
13314 shellparam.optind = 1;
13315 shellparam.optoff = -1;
13316#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013317 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013318 while (*xargv) {
13319 shellparam.nparam++;
13320 xargv++;
13321 }
13322 optschanged();
13323}
13324
13325/*
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013326 * Read /etc/profile, ~/.profile, $ENV.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013327 */
13328static void
13329read_profile(const char *name)
13330{
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013331 name = expandstr(name);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013332 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13333 return;
Denys Vlasenko0840c912016-10-01 15:27:44 +020013334 cmdloop(0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013335 popfile();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013336}
13337
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013338/*
13339 * This routine is called when an error or an interrupt occurs in an
13340 * interactive shell and control is returned to the main command loop.
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013341 * (In dash, this function is auto-generated by build machinery).
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013342 */
13343static void
13344reset(void)
13345{
13346 /* from eval.c: */
13347 evalskip = 0;
13348 loopnest = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013349
13350 /* from expand.c: */
13351 ifsfree();
13352
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013353 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013354 g_parsefile->left_in_buffer = 0;
13355 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013356 popallfiles();
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013357
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013358 /* from redir.c: */
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020013359 while (redirlist)
13360 popredir(/*drop:*/ 0, /*restore:*/ 0);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013361}
13362
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013363#if PROFILE
13364static short profile_buf[16384];
13365extern int etext();
13366#endif
13367
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013368/*
13369 * Main routine. We initialize things, parse the arguments, execute
13370 * profiles if we're a login shell, and then call cmdloop to execute
13371 * commands. The setjmp call sets up the location to jump to when an
13372 * exception occurs. When an exception occurs the variable "state"
13373 * is used to figure out how far we had gotten.
13374 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013375int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013376int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013377{
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013378 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013379 struct jmploc jmploc;
13380 struct stackmark smark;
13381
Denis Vlasenko01631112007-12-16 17:20:38 +000013382 /* Initialize global data */
13383 INIT_G_misc();
13384 INIT_G_memstack();
13385 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013386#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013387 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013388#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013389 INIT_G_cmdtable();
13390
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013391#if PROFILE
13392 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13393#endif
13394
13395#if ENABLE_FEATURE_EDITING
13396 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13397#endif
13398 state = 0;
13399 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013400 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013401 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013402
13403 reset();
13404
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013405 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013406 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013407 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013408 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013409 }
13410 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020013411 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013412 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013413
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013414 popstackmark(&smark);
13415 FORCE_INT_ON; /* enable interrupts */
13416 if (s == 1)
13417 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013418 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013419 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013420 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013421 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013422 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013423 }
13424 exception_handler = &jmploc;
13425#if DEBUG
13426 opentrace();
Denis Vlasenko653d8e72009-03-19 21:59:35 +000013427 TRACE(("Shell args: "));
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013428 trace_puts_args(argv);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013429#endif
13430 rootpid = getpid();
13431
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013432 init();
13433 setstackmark(&smark);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013434 procargs(argv);
13435
Denys Vlasenko6088e132010-12-25 23:58:42 +010013436 if (argv[0] && argv[0][0] == '-')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013437 isloginsh = 1;
13438 if (isloginsh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013439 const char *hp;
13440
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013441 state = 1;
13442 read_profile("/etc/profile");
13443 state1:
13444 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013445 hp = lookupvar("HOME");
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013446 if (hp)
13447 read_profile("$HOME/.profile");
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013448 }
13449 state2:
13450 state = 3;
13451 if (
13452#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013453 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013454#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013455 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013456 ) {
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013457 const char *shinit = lookupvar("ENV");
13458 if (shinit != NULL && *shinit != '\0')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013459 read_profile(shinit);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013460 }
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013461 popstackmark(&smark);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013462 state3:
13463 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013464 if (minusc) {
13465 /* evalstring pushes parsefile stack.
13466 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013467 * is one of stacked source fds.
13468 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013469 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013470 // ^^ not necessary since now we special-case fd 0
13471 // in is_hidden_fd() to not be considered "hidden fd"
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013472 evalstring(minusc, 0);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013473 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013474
13475 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020013476#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013477 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013478 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013479 if (!hp) {
13480 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013481 if (hp) {
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013482 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013483 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013484 free((char*)hp);
13485 hp = lookupvar("HISTFILE");
13486 }
13487 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013488 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013489 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013490# if ENABLE_FEATURE_SH_HISTFILESIZE
13491 hp = lookupvar("HISTFILESIZE");
13492 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13493# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013494 }
13495#endif
13496 state4: /* XXX ??? - why isn't this before the "if" statement */
13497 cmdloop(1);
13498 }
13499#if PROFILE
13500 monitor(0);
13501#endif
13502#ifdef GPROF
13503 {
13504 extern void _mcleanup(void);
13505 _mcleanup();
13506 }
13507#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013508 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013509 exitshell();
13510 /* NOTREACHED */
13511}
13512
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013513
Eric Andersendf82f612001-06-28 07:46:40 +000013514/*-
13515 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013516 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013517 *
13518 * This code is derived from software contributed to Berkeley by
13519 * Kenneth Almquist.
13520 *
13521 * Redistribution and use in source and binary forms, with or without
13522 * modification, are permitted provided that the following conditions
13523 * are met:
13524 * 1. Redistributions of source code must retain the above copyright
13525 * notice, this list of conditions and the following disclaimer.
13526 * 2. Redistributions in binary form must reproduce the above copyright
13527 * notice, this list of conditions and the following disclaimer in the
13528 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013529 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013530 * may be used to endorse or promote products derived from this software
13531 * without specific prior written permission.
13532 *
13533 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13534 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13535 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13536 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13537 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13538 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13539 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13540 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13541 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13542 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13543 * SUCH DAMAGE.
13544 */