blob: 1e720aec405be34504aeb64040fd1db7fdc9ecc3 [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 */
Denys Vlasenko771f1992010-07-16 14:31:34 +020018//config:config ASH
Denys Vlasenko4eed2c62017-07-18 22:01:24 +020019//config: bool "ash (77 kb)"
Denys Vlasenko771f1992010-07-16 14:31:34 +020020//config: default y
21//config: depends on !NOMMU
22//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020023//config: The most complete and most pedantically correct shell included with
24//config: busybox. This shell is actually a derivative of the Debian 'dash'
25//config: shell (by Herbert Xu), which was created by porting the 'ash' shell
26//config: (written by Kenneth Almquist) from NetBSD.
Denys Vlasenko771f1992010-07-16 14:31:34 +020027//config:
Kang-Che Sung6cd02942017-01-06 17:02:03 +010028//config:# ash options
29//config:# note: Don't remove !NOMMU part in the next line; it would break
30//config:# menuconfig's indenting.
31//config:if !NOMMU && (ASH || SH_IS_ASH || BASH_IS_ASH)
32//config:
Denys Vlasenko514b51d2016-10-01 14:33:08 +020033//config:config ASH_OPTIMIZE_FOR_SIZE
34//config: bool "Optimize for size instead of speed"
35//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010036//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020037//config:
38//config:config ASH_INTERNAL_GLOB
39//config: bool "Use internal glob() implementation"
Denys Vlasenko326edc32016-12-22 14:36:49 +010040//config: default y # Y is bigger, but because of uclibc glob() bug, let Y be default for now
Denys Vlasenko0b883582016-12-23 16:49:07 +010041//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020042//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020043//config: Do not use glob() function from libc, use internal implementation.
44//config: Use this if you are getting "glob.h: No such file or directory"
45//config: or similar build errors.
46//config: Note that as of now (2017-01), uclibc and musl glob() both have bugs
47//config: which would break ash if you select N here.
Denys Vlasenkof5604222017-01-10 14:58:54 +010048//config:
49//config:config ASH_BASH_COMPAT
50//config: bool "bash-compatible extensions"
51//config: default y
52//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
53//config:
54//config:config ASH_JOB_CONTROL
55//config: bool "Job control"
56//config: default y
57//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
58//config:
59//config:config ASH_ALIAS
60//config: bool "Alias support"
61//config: default y
62//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020063//config:
64//config:config ASH_RANDOM_SUPPORT
65//config: bool "Pseudorandom generator and $RANDOM variable"
66//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010067//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020068//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020069//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
70//config: Each read of "$RANDOM" will generate a new pseudorandom value.
71//config: You can reset the generator by using a specified start value.
72//config: After "unset RANDOM" the generator will switch off and this
73//config: variable will no longer have special treatment.
Denys Vlasenko514b51d2016-10-01 14:33:08 +020074//config:
75//config:config ASH_EXPAND_PRMT
76//config: bool "Expand prompt string"
77//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010078//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020079//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020080//config: $PS# may contain volatile content, such as backquote commands.
81//config: This option recreates the prompt string from the environment
82//config: variable each time it is displayed.
Denys Vlasenko514b51d2016-10-01 14:33:08 +020083//config:
Denys Vlasenko046341e2011-02-04 17:53:59 +010084//config:config ASH_IDLE_TIMEOUT
Denys Vlasenkof5604222017-01-10 14:58:54 +010085//config: bool "Idle timeout variable $TMOUT"
Denys Vlasenko771f1992010-07-16 14:31:34 +020086//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010087//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +020088//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020089//config: Enable bash-like auto-logout after $TMOUT seconds of idle time.
Denys Vlasenko771f1992010-07-16 14:31:34 +020090//config:
Denys Vlasenkof5604222017-01-10 14:58:54 +010091//config:config ASH_MAIL
92//config: bool "Check for new mail in interactive shell"
Denys Vlasenko771f1992010-07-16 14:31:34 +020093//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010094//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +020095//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020096//config: Enable "check for new mail" function:
97//config: if set, $MAIL file and $MAILPATH list of files
98//config: are checked for mtime changes, and "you have mail"
99//config: message is printed if change is detected.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200100//config:
Denys Vlasenko265062d2017-01-10 15:13:30 +0100101//config:config ASH_ECHO
Denys Vlasenkof5604222017-01-10 14:58:54 +0100102//config: bool "echo builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200103//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100104//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200105//config:
Denys Vlasenko265062d2017-01-10 15:13:30 +0100106//config:config ASH_PRINTF
Denys Vlasenkof5604222017-01-10 14:58:54 +0100107//config: bool "printf builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200108//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100109//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200110//config:
Denys Vlasenko265062d2017-01-10 15:13:30 +0100111//config:config ASH_TEST
Denys Vlasenkof5604222017-01-10 14:58:54 +0100112//config: bool "test builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200113//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100114//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200115//config:
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200116//config:config ASH_HELP
117//config: bool "help builtin"
118//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100119//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenkof5604222017-01-10 14:58:54 +0100120//config:
121//config:config ASH_GETOPTS
122//config: bool "getopts builtin"
123//config: default y
124//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200125//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200126//config:config ASH_CMDCMD
Denys Vlasenkof5604222017-01-10 14:58:54 +0100127//config: bool "command builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200128//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100129//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200130//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200131//config: Enable support for the 'command' builtin, which allows
132//config: you to run the specified command or builtin,
133//config: even when there is a function with the same name.
Kang-Che Sung6cd02942017-01-06 17:02:03 +0100134//config:
135//config:endif # ash options
Denys Vlasenko771f1992010-07-16 14:31:34 +0200136
Denys Vlasenko20704f02011-03-23 17:59:27 +0100137//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
Denys Vlasenko205d48e2017-01-29 14:57:33 +0100138// APPLET_ODDNAME:name main location suid_type help
139//applet:IF_SH_IS_ASH( APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
Denys Vlasenko0b883582016-12-23 16:49:07 +0100140//applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
Denys Vlasenko20704f02011-03-23 17:59:27 +0100141
142//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
Denys Vlasenko0b883582016-12-23 16:49:07 +0100143//kbuild:lib-$(CONFIG_SH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
144//kbuild:lib-$(CONFIG_BASH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
Denys Vlasenko20704f02011-03-23 17:59:27 +0100145//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
146
Denys Vlasenko67047462016-12-22 15:21:58 +0100147/*
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100148 * DEBUG=1 to compile in debugging ('set -o debug' turns on)
149 * DEBUG=2 to compile in and turn on debugging.
150 * When debugging is on ("set -o debug" was executed, or DEBUG=2),
151 * debugging info is written to ./trace, quit signal generates core dump.
Denys Vlasenko67047462016-12-22 15:21:58 +0100152 */
153#define DEBUG 0
154/* Tweak debug output verbosity here */
155#define DEBUG_TIME 0
156#define DEBUG_PID 1
157#define DEBUG_SIG 1
158#define DEBUG_INTONOFF 0
159
160#define PROFILE 0
161
162#define JOBS ENABLE_ASH_JOB_CONTROL
163
164#include <setjmp.h>
165#include <fnmatch.h>
166#include <sys/times.h>
167#include <sys/utsname.h> /* for setting $HOSTNAME */
Denys Vlasenko67047462016-12-22 15:21:58 +0100168#include "busybox.h" /* for applet_names */
169
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100170/* So far, all bash compat is controlled by one config option */
171/* Separate defines document which part of code implements what */
172/* function keyword */
173#define BASH_FUNCTION ENABLE_ASH_BASH_COMPAT
174#define IF_BASH_FUNCTION IF_ASH_BASH_COMPAT
175/* &>file */
176#define BASH_REDIR_OUTPUT ENABLE_ASH_BASH_COMPAT
177#define IF_BASH_REDIR_OUTPUT IF_ASH_BASH_COMPAT
178/* $'...' */
179#define BASH_DOLLAR_SQUOTE ENABLE_ASH_BASH_COMPAT
180#define IF_BASH_DOLLAR_SQUOTE IF_ASH_BASH_COMPAT
181#define BASH_PATTERN_SUBST ENABLE_ASH_BASH_COMPAT
182#define IF_BASH_PATTERN_SUBST IF_ASH_BASH_COMPAT
183#define BASH_SUBSTR ENABLE_ASH_BASH_COMPAT
184#define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT
185/* [[ EXPR ]] */
186#define BASH_TEST2 (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST)
187#define BASH_SOURCE ENABLE_ASH_BASH_COMPAT
188#define BASH_PIPEFAIL ENABLE_ASH_BASH_COMPAT
189#define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT
190#define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT
191
Denys Vlasenko67047462016-12-22 15:21:58 +0100192#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
193/* Bionic at least up to version 24 has no glob() */
194# undef ENABLE_ASH_INTERNAL_GLOB
195# define ENABLE_ASH_INTERNAL_GLOB 1
196#endif
197
198#if !ENABLE_ASH_INTERNAL_GLOB && defined(__UCLIBC__)
199# error uClibc glob() is buggy, use ASH_INTERNAL_GLOB.
200# error The bug is: for "$PWD"/<pattern> ash will escape e.g. dashes in "$PWD"
201# error with backslash, even ones which do not need to be: "/a-b" -> "/a\-b"
202# error glob() should unbackslash them and match. uClibc does not unbackslash,
203# error fails to match dirname, subsequently not expanding <pattern> in it.
204// Testcase:
205// if (glob("/etc/polkit\\-1", 0, NULL, &pglob)) - this returns 0 on uclibc, no bug
206// if (glob("/etc/polkit\\-1/*", 0, NULL, &pglob)) printf("uclibc bug!\n");
207#endif
208
209#if !ENABLE_ASH_INTERNAL_GLOB
210# include <glob.h>
211#endif
212
213#include "unicode.h"
214#include "shell_common.h"
Denys Vlasenko0b883582016-12-23 16:49:07 +0100215#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko67047462016-12-22 15:21:58 +0100216# include "math.h"
Denys Vlasenkocf3a7962017-07-26 14:38:19 +0200217#else
218typedef long arith_t;
219# define ARITH_FMT "%ld"
Denys Vlasenko67047462016-12-22 15:21:58 +0100220#endif
221#if ENABLE_ASH_RANDOM_SUPPORT
222# include "random.h"
223#else
224# define CLEAR_RANDOM_T(rnd) ((void)0)
225#endif
226
227#include "NUM_APPLETS.h"
228#if NUM_APPLETS == 1
229/* STANDALONE does not make sense, and won't compile */
230# undef CONFIG_FEATURE_SH_STANDALONE
231# undef ENABLE_FEATURE_SH_STANDALONE
232# undef IF_FEATURE_SH_STANDALONE
233# undef IF_NOT_FEATURE_SH_STANDALONE
234# define ENABLE_FEATURE_SH_STANDALONE 0
235# define IF_FEATURE_SH_STANDALONE(...)
236# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
237#endif
238
239#ifndef PIPE_BUF
240# define PIPE_BUF 4096 /* amount of buffering in a pipe */
241#endif
242
243#if !BB_MMU
244# error "Do not even bother, ash will not run on NOMMU machine"
245#endif
246
Denis Vlasenkob012b102007-02-19 22:43:01 +0000247
Denis Vlasenko01631112007-12-16 17:20:38 +0000248/* ============ Hash table sizes. Configurable. */
249
250#define VTABSIZE 39
251#define ATABSIZE 39
252#define CMDTABLESIZE 31 /* should be prime */
253
254
Denis Vlasenkob012b102007-02-19 22:43:01 +0000255/* ============ Shell options */
256
257static const char *const optletters_optnames[] = {
258 "e" "errexit",
259 "f" "noglob",
260 "I" "ignoreeof",
261 "i" "interactive",
262 "m" "monitor",
263 "n" "noexec",
264 "s" "stdin",
265 "x" "xtrace",
266 "v" "verbose",
267 "C" "noclobber",
268 "a" "allexport",
269 "b" "notify",
270 "u" "nounset",
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100271 "\0" "vi"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100272#if BASH_PIPEFAIL
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100273 ,"\0" "pipefail"
Michael Abbott359da5e2009-12-04 23:03:29 +0100274#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000275#if DEBUG
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000276 ,"\0" "nolog"
277 ,"\0" "debug"
Denis Vlasenkob012b102007-02-19 22:43:01 +0000278#endif
279};
280
Denys Vlasenko285ad152009-12-04 23:02:27 +0100281#define optletters(n) optletters_optnames[n][0]
282#define optnames(n) (optletters_optnames[n] + 1)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000283
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000284enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
Denis Vlasenkob012b102007-02-19 22:43:01 +0000285
Eric Andersenc470f442003-07-28 09:56:35 +0000286
Denis Vlasenkob012b102007-02-19 22:43:01 +0000287/* ============ Misc data */
Eric Andersenc470f442003-07-28 09:56:35 +0000288
Denys Vlasenkoea8b2522010-06-02 12:57:26 +0200289#define msg_illnum "Illegal number: %s"
Denis Vlasenkoaa744452007-02-23 01:04:22 +0000290
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +0000291/*
Eric Andersenc470f442003-07-28 09:56:35 +0000292 * We enclose jmp_buf in a structure so that we can declare pointers to
293 * jump locations. The global variable handler contains the location to
Denis Vlasenkof1733952009-03-19 23:21:55 +0000294 * jump to when an exception occurs, and the global variable exception_type
Eric Andersenaff114c2004-04-14 17:51:38 +0000295 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000296 * exception handlers, the user should save the value of handler on entry
297 * to an inner scope, set handler to point to a jmploc structure for the
298 * inner scope, and restore handler on exit from the scope.
299 */
Eric Andersenc470f442003-07-28 09:56:35 +0000300struct jmploc {
301 jmp_buf loc;
302};
Denis Vlasenko01631112007-12-16 17:20:38 +0000303
304struct globals_misc {
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200305 uint8_t exitstatus; /* exit status of last command */
306 uint8_t back_exitstatus;/* exit status of backquoted command */
307 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
308 int rootpid; /* pid of main shell */
Denis Vlasenko01631112007-12-16 17:20:38 +0000309 /* shell level: 0 for the main shell, 1 for its children, and so on */
310 int shlvl;
311#define rootshell (!shlvl)
312 char *minusc; /* argument to -c option */
313
314 char *curdir; // = nullstr; /* current working directory */
315 char *physdir; // = nullstr; /* physical working directory */
316
317 char *arg0; /* value of $0 */
318
319 struct jmploc *exception_handler;
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000320
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200321 volatile int suppress_int; /* counter */
322 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200323 volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +0200324 volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000325 smallint exception_type; /* kind of exception (0..5) */
Denis Vlasenko01631112007-12-16 17:20:38 +0000326 /* exceptions */
Eric Andersenc470f442003-07-28 09:56:35 +0000327#define EXINT 0 /* SIGINT received */
328#define EXERROR 1 /* a generic error */
Eric Andersenc470f442003-07-28 09:56:35 +0000329#define EXEXIT 4 /* exit the shell */
Eric Andersen2870d962001-07-02 17:27:21 +0000330
Denis Vlasenko01631112007-12-16 17:20:38 +0000331 smallint isloginsh;
Denis Vlasenkob07a4962008-06-22 13:16:23 +0000332 char nullstr[1]; /* zero length string */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000333
334 char optlist[NOPTS];
335#define eflag optlist[0]
336#define fflag optlist[1]
337#define Iflag optlist[2]
338#define iflag optlist[3]
339#define mflag optlist[4]
340#define nflag optlist[5]
341#define sflag optlist[6]
342#define xflag optlist[7]
343#define vflag optlist[8]
344#define Cflag optlist[9]
345#define aflag optlist[10]
346#define bflag optlist[11]
347#define uflag optlist[12]
348#define viflag optlist[13]
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100349#if BASH_PIPEFAIL
Michael Abbott359da5e2009-12-04 23:03:29 +0100350# define pipefail optlist[14]
351#else
352# define pipefail 0
353#endif
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000354#if DEBUG
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100355# define nolog optlist[14 + BASH_PIPEFAIL]
356# define debug optlist[15 + BASH_PIPEFAIL]
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000357#endif
358
359 /* trap handler commands */
Denis Vlasenko01631112007-12-16 17:20:38 +0000360 /*
361 * Sigmode records the current value of the signal handlers for the various
362 * modes. A value of zero means that the current handler is not known.
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000363 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
Denis Vlasenko01631112007-12-16 17:20:38 +0000364 */
365 char sigmode[NSIG - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000366#define S_DFL 1 /* default signal handling (SIG_DFL) */
367#define S_CATCH 2 /* signal is caught */
368#define S_IGN 3 /* signal is ignored (SIG_IGN) */
Denys Vlasenkoe5814a52016-07-16 18:33:55 +0200369#define S_HARD_IGN 4 /* signal is ignored permanently */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000370
Denis Vlasenko01631112007-12-16 17:20:38 +0000371 /* indicates specified signal received */
Denis Vlasenko4b875702009-03-19 13:30:04 +0000372 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
Denys Vlasenko238bf182010-05-18 15:49:07 +0200373 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000374 char *trap[NSIG];
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200375 char **trap_ptr; /* used only by "trap hack" */
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000376
377 /* Rarely referenced stuff */
378#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200379 random_t random_gen;
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000380#endif
381 pid_t backgndpid; /* pid of last background process */
Denis Vlasenko01631112007-12-16 17:20:38 +0000382};
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000383extern struct globals_misc *const ash_ptr_to_globals_misc;
384#define G_misc (*ash_ptr_to_globals_misc)
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200385#define exitstatus (G_misc.exitstatus )
386#define back_exitstatus (G_misc.back_exitstatus )
387#define job_warning (G_misc.job_warning)
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000388#define rootpid (G_misc.rootpid )
389#define shlvl (G_misc.shlvl )
390#define minusc (G_misc.minusc )
391#define curdir (G_misc.curdir )
392#define physdir (G_misc.physdir )
393#define arg0 (G_misc.arg0 )
Denis Vlasenko01631112007-12-16 17:20:38 +0000394#define exception_handler (G_misc.exception_handler)
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000395#define exception_type (G_misc.exception_type )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200396#define suppress_int (G_misc.suppress_int )
397#define pending_int (G_misc.pending_int )
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200398#define got_sigchld (G_misc.got_sigchld )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200399#define pending_sig (G_misc.pending_sig )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000400#define isloginsh (G_misc.isloginsh )
401#define nullstr (G_misc.nullstr )
402#define optlist (G_misc.optlist )
403#define sigmode (G_misc.sigmode )
404#define gotsig (G_misc.gotsig )
Denys Vlasenko238bf182010-05-18 15:49:07 +0200405#define may_have_traps (G_misc.may_have_traps )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000406#define trap (G_misc.trap )
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200407#define trap_ptr (G_misc.trap_ptr )
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200408#define random_gen (G_misc.random_gen )
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000409#define backgndpid (G_misc.backgndpid )
Denis Vlasenko01631112007-12-16 17:20:38 +0000410#define INIT_G_misc() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000411 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
412 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +0000413 curdir = nullstr; \
414 physdir = nullstr; \
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200415 trap_ptr = trap; \
Denis Vlasenko01631112007-12-16 17:20:38 +0000416} while (0)
417
418
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000419/* ============ DEBUG */
420#if DEBUG
421static void trace_printf(const char *fmt, ...);
422static void trace_vprintf(const char *fmt, va_list va);
423# define TRACE(param) trace_printf param
424# define TRACEV(param) trace_vprintf param
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000425# define close(fd) do { \
426 int dfd = (fd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000427 if (close(dfd) < 0) \
Denys Vlasenko883cea42009-07-11 15:31:59 +0200428 bb_error_msg("bug on %d: closing %d(0x%x)", \
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000429 __LINE__, dfd, dfd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000430} while (0)
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000431#else
432# define TRACE(param)
433# define TRACEV(param)
434#endif
435
436
Denis Vlasenko559691a2008-10-05 18:39:31 +0000437/* ============ Utility functions */
Denys Vlasenko1961aea2013-02-26 00:36:53 +0100438#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
439#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
440
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200441static int
442isdigit_str9(const char *str)
Denis Vlasenko559691a2008-10-05 18:39:31 +0000443{
444 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
445 while (--maxlen && isdigit(*str))
446 str++;
447 return (*str == '\0');
448}
Denis Vlasenko01631112007-12-16 17:20:38 +0000449
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200450static const char *
451var_end(const char *var)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +0200452{
453 while (*var)
454 if (*var++ == '=')
455 break;
456 return var;
457}
458
Denis Vlasenko559691a2008-10-05 18:39:31 +0000459
460/* ============ Interrupts / exceptions */
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100461
462static void exitshell(void) NORETURN;
463
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000464/*
Eric Andersen2870d962001-07-02 17:27:21 +0000465 * These macros allow the user to suspend the handling of interrupt signals
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000466 * over a period of time. This is similar to SIGHOLD or to sigblock, but
Eric Andersen2870d962001-07-02 17:27:21 +0000467 * much more efficient and portable. (But hacking the kernel is so much
468 * more fun than worrying about efficiency and portability. :-))
469 */
Denys Vlasenko06b11492016-11-04 16:43:18 +0100470#if DEBUG_INTONOFF
471# define INT_OFF do { \
472 TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200473 suppress_int++; \
Denys Vlasenkode892052016-10-02 01:49:13 +0200474 barrier(); \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000475} while (0)
Denys Vlasenko06b11492016-11-04 16:43:18 +0100476#else
477# define INT_OFF do { \
478 suppress_int++; \
479 barrier(); \
480} while (0)
481#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000482
483/*
484 * Called to raise an exception. Since C doesn't include exceptions, we
485 * just do a longjmp to the exception handler. The type of exception is
Denis Vlasenko4b875702009-03-19 13:30:04 +0000486 * stored in the global variable "exception_type".
Denis Vlasenkob012b102007-02-19 22:43:01 +0000487 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000488static void raise_exception(int) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000489static void
490raise_exception(int e)
491{
492#if DEBUG
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000493 if (exception_handler == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000494 abort();
495#endif
496 INT_OFF;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000497 exception_type = e;
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000498 longjmp(exception_handler->loc, 1);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000499}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000500#if DEBUG
501#define raise_exception(e) do { \
502 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
503 raise_exception(e); \
504} while (0)
505#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000506
507/*
Denys Vlasenkof37e1152016-10-07 03:17:28 +0200508 * Called when a SIGINT is received. (If the user specifies
Denis Vlasenkob012b102007-02-19 22:43:01 +0000509 * that SIGINT is to be trapped or ignored using the trap builtin, then
510 * this routine is not called.) Suppressint is nonzero when interrupts
511 * are held using the INT_OFF macro. (The test for iflag is just
512 * defensive programming.)
513 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000514static void raise_interrupt(void) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000515static void
516raise_interrupt(void)
517{
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200518 pending_int = 0;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000519 /* Signal is not automatically unmasked after it is raised,
520 * do it ourself - unmask all signals */
Denis Vlasenko3f165fa2008-03-17 08:29:08 +0000521 sigprocmask_allsigs(SIG_UNBLOCK);
Denys Vlasenko238bf182010-05-18 15:49:07 +0200522 /* pending_sig = 0; - now done in signal_handler() */
Denis Vlasenko7c139b42007-03-21 20:17:27 +0000523
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200524 if (!(rootshell && iflag)) {
525 /* Kill ourself with SIGINT */
526 signal(SIGINT, SIG_DFL);
527 raise(SIGINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000528 }
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200529 /* bash: ^C even on empty command line sets $? */
530 exitstatus = SIGINT + 128;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200531 raise_exception(EXINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000532 /* NOTREACHED */
533}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000534#if DEBUG
535#define raise_interrupt() do { \
536 TRACE(("raising interrupt on line %d\n", __LINE__)); \
537 raise_interrupt(); \
538} while (0)
539#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000540
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000541static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000542int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000543{
Denys Vlasenkode892052016-10-02 01:49:13 +0200544 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200545 if (--suppress_int == 0 && pending_int) {
Denis Vlasenkob012b102007-02-19 22:43:01 +0000546 raise_interrupt();
547 }
548}
Denys Vlasenko06b11492016-11-04 16:43:18 +0100549#if DEBUG_INTONOFF
550# define INT_ON do { \
551 TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
552 int_on(); \
553} while (0)
554#else
555# define INT_ON int_on()
556#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000557static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000558force_int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000559{
Denys Vlasenkode892052016-10-02 01:49:13 +0200560 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200561 suppress_int = 0;
562 if (pending_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000563 raise_interrupt();
564}
565#define FORCE_INT_ON force_int_on()
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000566
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200567#define SAVE_INT(v) ((v) = suppress_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000568
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000569#define RESTORE_INT(v) do { \
Denys Vlasenkode892052016-10-02 01:49:13 +0200570 barrier(); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200571 suppress_int = (v); \
572 if (suppress_int == 0 && pending_int) \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000573 raise_interrupt(); \
574} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000575
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000576
Denis Vlasenkobc54cff2007-02-23 01:05:52 +0000577/* ============ Stdout/stderr output */
Eric Andersenc470f442003-07-28 09:56:35 +0000578
Eric Andersenc470f442003-07-28 09:56:35 +0000579static void
Denis Vlasenkob012b102007-02-19 22:43:01 +0000580outstr(const char *p, FILE *file)
Denis Vlasenkoe5570da2007-02-19 22:41:55 +0000581{
Denis Vlasenkob012b102007-02-19 22:43:01 +0000582 INT_OFF;
583 fputs(p, file);
584 INT_ON;
585}
586
587static void
588flush_stdout_stderr(void)
589{
590 INT_OFF;
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100591 fflush_all();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000592 INT_ON;
593}
594
Denys Vlasenko9c541002015-10-07 15:44:36 +0200595/* Was called outcslow(c,FILE*), but c was always '\n' */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000596static void
Denys Vlasenko9c541002015-10-07 15:44:36 +0200597newline_and_flush(FILE *dest)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000598{
599 INT_OFF;
Denys Vlasenko9c541002015-10-07 15:44:36 +0200600 putc('\n', dest);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000601 fflush(dest);
602 INT_ON;
603}
604
605static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
606static int
607out1fmt(const char *fmt, ...)
608{
609 va_list ap;
610 int r;
611
612 INT_OFF;
613 va_start(ap, fmt);
614 r = vprintf(fmt, ap);
615 va_end(ap);
616 INT_ON;
617 return r;
618}
619
620static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
621static int
622fmtstr(char *outbuf, size_t length, const char *fmt, ...)
623{
624 va_list ap;
625 int ret;
626
Denis Vlasenkob012b102007-02-19 22:43:01 +0000627 INT_OFF;
Denys Vlasenkocf3a7962017-07-26 14:38:19 +0200628 va_start(ap, fmt);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000629 ret = vsnprintf(outbuf, length, fmt, ap);
630 va_end(ap);
631 INT_ON;
632 return ret;
633}
634
635static void
636out1str(const char *p)
637{
638 outstr(p, stdout);
639}
640
641static void
642out2str(const char *p)
643{
644 outstr(p, stderr);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100645 flush_stdout_stderr();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000646}
647
648
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000649/* ============ Parser structures */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +0000650
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000651/* control characters in argument strings */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100652#define CTL_FIRST CTLESC
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200653#define CTLESC ((unsigned char)'\201') /* escape next character */
654#define CTLVAR ((unsigned char)'\202') /* variable defn */
655#define CTLENDVAR ((unsigned char)'\203')
656#define CTLBACKQ ((unsigned char)'\204')
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200657#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
658#define CTLENDARI ((unsigned char)'\207')
659#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100660#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000661
662/* variable substitution byte (follows CTLVAR) */
663#define VSTYPE 0x0f /* type of variable substitution */
664#define VSNUL 0x10 /* colon--treat the empty string as unset */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000665
666/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000667#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
668#define VSMINUS 0x2 /* ${var-text} */
669#define VSPLUS 0x3 /* ${var+text} */
670#define VSQUESTION 0x4 /* ${var?message} */
671#define VSASSIGN 0x5 /* ${var=text} */
672#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
673#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
674#define VSTRIMLEFT 0x8 /* ${var#pattern} */
675#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
676#define VSLENGTH 0xa /* ${#var} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100677#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000678#define VSSUBSTR 0xc /* ${var:position:length} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100679#endif
680#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000681#define VSREPLACE 0xd /* ${var/pattern/replacement} */
682#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
683#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000684
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000685static const char dolatstr[] ALIGN1 = {
Ron Yorston549deab2015-05-18 09:57:51 +0200686 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000687};
Ron Yorston549deab2015-05-18 09:57:51 +0200688#define DOLATSTRLEN 6
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000689
Denis Vlasenko559691a2008-10-05 18:39:31 +0000690#define NCMD 0
691#define NPIPE 1
692#define NREDIR 2
693#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000694#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000695#define NAND 5
696#define NOR 6
697#define NSEMI 7
698#define NIF 8
699#define NWHILE 9
700#define NUNTIL 10
701#define NFOR 11
702#define NCASE 12
703#define NCLIST 13
704#define NDEFUN 14
705#define NARG 15
706#define NTO 16
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100707#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +0000708#define NTO2 17
709#endif
710#define NCLOBBER 18
711#define NFROM 19
712#define NFROMTO 20
713#define NAPPEND 21
714#define NTOFD 22
715#define NFROMFD 23
716#define NHERE 24
717#define NXHERE 25
718#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000719#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000720
721union node;
722
723struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000724 smallint type; /* Nxxxx */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000725 union node *assign;
726 union node *args;
727 union node *redirect;
728};
729
730struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000731 smallint type;
732 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000733 struct nodelist *cmdlist;
734};
735
736struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000737 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000738 union node *n;
739 union node *redirect;
740};
741
742struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000743 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000744 union node *ch1;
745 union node *ch2;
746};
747
748struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000749 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000750 union node *test;
751 union node *ifpart;
752 union node *elsepart;
753};
754
755struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000756 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000757 union node *args;
758 union node *body;
759 char *var;
760};
761
762struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000763 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000764 union node *expr;
765 union node *cases;
766};
767
768struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000769 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000770 union node *next;
771 union node *pattern;
772 union node *body;
773};
774
775struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000776 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000777 union node *next;
778 char *text;
779 struct nodelist *backquote;
780};
781
Denis Vlasenko559691a2008-10-05 18:39:31 +0000782/* nfile and ndup layout must match!
783 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
784 * that it is actually NTO2 (>&file), and change its type.
785 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000786struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000787 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000788 union node *next;
789 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000790 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000791 union node *fname;
792 char *expfname;
793};
794
795struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000796 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000797 union node *next;
798 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000799 int dupfd;
800 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000801 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000802};
803
804struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000805 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000806 union node *next;
807 int fd;
808 union node *doc;
809};
810
811struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000812 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000813 union node *com;
814};
815
816union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000817 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000818 struct ncmd ncmd;
819 struct npipe npipe;
820 struct nredir nredir;
821 struct nbinary nbinary;
822 struct nif nif;
823 struct nfor nfor;
824 struct ncase ncase;
825 struct nclist nclist;
826 struct narg narg;
827 struct nfile nfile;
828 struct ndup ndup;
829 struct nhere nhere;
830 struct nnot nnot;
831};
832
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200833/*
834 * NODE_EOF is returned by parsecmd when it encounters an end of file.
835 * It must be distinct from NULL.
836 */
837#define NODE_EOF ((union node *) -1L)
838
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000839struct nodelist {
840 struct nodelist *next;
841 union node *n;
842};
843
844struct funcnode {
845 int count;
846 union node n;
847};
848
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000849/*
850 * Free a parse tree.
851 */
852static void
853freefunc(struct funcnode *f)
854{
855 if (f && --f->count < 0)
856 free(f);
857}
858
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000859
860/* ============ Debugging output */
861
862#if DEBUG
863
864static FILE *tracefile;
865
866static void
867trace_printf(const char *fmt, ...)
868{
869 va_list va;
870
871 if (debug != 1)
872 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000873 if (DEBUG_TIME)
874 fprintf(tracefile, "%u ", (int) time(NULL));
875 if (DEBUG_PID)
876 fprintf(tracefile, "[%u] ", (int) getpid());
877 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200878 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000879 va_start(va, fmt);
880 vfprintf(tracefile, fmt, va);
881 va_end(va);
882}
883
884static void
885trace_vprintf(const char *fmt, va_list va)
886{
887 if (debug != 1)
888 return;
889 vfprintf(tracefile, fmt, va);
Denys Vlasenko474ed062016-10-30 18:30:29 +0100890 fprintf(tracefile, "\n");
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000891}
892
893static void
894trace_puts(const char *s)
895{
896 if (debug != 1)
897 return;
898 fputs(s, tracefile);
899}
900
901static void
902trace_puts_quoted(char *s)
903{
904 char *p;
905 char c;
906
907 if (debug != 1)
908 return;
909 putc('"', tracefile);
910 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100911 switch ((unsigned char)*p) {
912 case '\n': c = 'n'; goto backslash;
913 case '\t': c = 't'; goto backslash;
914 case '\r': c = 'r'; goto backslash;
915 case '\"': c = '\"'; goto backslash;
916 case '\\': c = '\\'; goto backslash;
917 case CTLESC: c = 'e'; goto backslash;
918 case CTLVAR: c = 'v'; goto backslash;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100919 case CTLBACKQ: c = 'q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000920 backslash:
921 putc('\\', tracefile);
922 putc(c, tracefile);
923 break;
924 default:
925 if (*p >= ' ' && *p <= '~')
926 putc(*p, tracefile);
927 else {
928 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +0100929 putc((*p >> 6) & 03, tracefile);
930 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000931 putc(*p & 07, tracefile);
932 }
933 break;
934 }
935 }
936 putc('"', tracefile);
937}
938
939static void
940trace_puts_args(char **ap)
941{
942 if (debug != 1)
943 return;
944 if (!*ap)
945 return;
946 while (1) {
947 trace_puts_quoted(*ap);
948 if (!*++ap) {
949 putc('\n', tracefile);
950 break;
951 }
952 putc(' ', tracefile);
953 }
954}
955
956static void
957opentrace(void)
958{
959 char s[100];
960#ifdef O_APPEND
961 int flags;
962#endif
963
964 if (debug != 1) {
965 if (tracefile)
966 fflush(tracefile);
967 /* leave open because libedit might be using it */
968 return;
969 }
970 strcpy(s, "./trace");
971 if (tracefile) {
972 if (!freopen(s, "a", tracefile)) {
973 fprintf(stderr, "Can't re-open %s\n", s);
974 debug = 0;
975 return;
976 }
977 } else {
978 tracefile = fopen(s, "a");
979 if (tracefile == NULL) {
980 fprintf(stderr, "Can't open %s\n", s);
981 debug = 0;
982 return;
983 }
984 }
985#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000986 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000987 if (flags >= 0)
988 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
989#endif
990 setlinebuf(tracefile);
991 fputs("\nTracing started.\n", tracefile);
992}
993
994static void
995indent(int amount, char *pfx, FILE *fp)
996{
997 int i;
998
999 for (i = 0; i < amount; i++) {
1000 if (pfx && i == amount - 1)
1001 fputs(pfx, fp);
1002 putc('\t', fp);
1003 }
1004}
1005
1006/* little circular references here... */
1007static void shtree(union node *n, int ind, char *pfx, FILE *fp);
1008
1009static void
1010sharg(union node *arg, FILE *fp)
1011{
1012 char *p;
1013 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001014 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001015
1016 if (arg->type != NARG) {
1017 out1fmt("<node type %d>\n", arg->type);
1018 abort();
1019 }
1020 bqlist = arg->narg.backquote;
1021 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01001022 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001023 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -07001024 p++;
1025 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001026 break;
1027 case CTLVAR:
1028 putc('$', fp);
1029 putc('{', fp);
1030 subtype = *++p;
1031 if (subtype == VSLENGTH)
1032 putc('#', fp);
1033
Dan Fandrich77d48722010-09-07 23:38:28 -07001034 while (*p != '=') {
1035 putc(*p, fp);
1036 p++;
1037 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001038
1039 if (subtype & VSNUL)
1040 putc(':', fp);
1041
1042 switch (subtype & VSTYPE) {
1043 case VSNORMAL:
1044 putc('}', fp);
1045 break;
1046 case VSMINUS:
1047 putc('-', fp);
1048 break;
1049 case VSPLUS:
1050 putc('+', fp);
1051 break;
1052 case VSQUESTION:
1053 putc('?', fp);
1054 break;
1055 case VSASSIGN:
1056 putc('=', fp);
1057 break;
1058 case VSTRIMLEFT:
1059 putc('#', fp);
1060 break;
1061 case VSTRIMLEFTMAX:
1062 putc('#', fp);
1063 putc('#', fp);
1064 break;
1065 case VSTRIMRIGHT:
1066 putc('%', fp);
1067 break;
1068 case VSTRIMRIGHTMAX:
1069 putc('%', fp);
1070 putc('%', fp);
1071 break;
1072 case VSLENGTH:
1073 break;
1074 default:
1075 out1fmt("<subtype %d>", subtype);
1076 }
1077 break;
1078 case CTLENDVAR:
1079 putc('}', fp);
1080 break;
1081 case CTLBACKQ:
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001082 putc('$', fp);
1083 putc('(', fp);
1084 shtree(bqlist->n, -1, NULL, fp);
1085 putc(')', fp);
1086 break;
1087 default:
1088 putc(*p, fp);
1089 break;
1090 }
1091 }
1092}
1093
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001094static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001095shcmd(union node *cmd, FILE *fp)
1096{
1097 union node *np;
1098 int first;
1099 const char *s;
1100 int dftfd;
1101
1102 first = 1;
1103 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001104 if (!first)
1105 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001106 sharg(np, fp);
1107 first = 0;
1108 }
1109 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001110 if (!first)
1111 putc(' ', fp);
1112 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001113 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001114 case NTO: s = ">>"+1; dftfd = 1; break;
1115 case NCLOBBER: s = ">|"; dftfd = 1; break;
1116 case NAPPEND: s = ">>"; dftfd = 1; break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01001117#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00001118 case NTO2:
1119#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001120 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001121 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001122 case NFROMFD: s = "<&"; break;
1123 case NFROMTO: s = "<>"; break;
1124 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001125 }
1126 if (np->nfile.fd != dftfd)
1127 fprintf(fp, "%d", np->nfile.fd);
1128 fputs(s, fp);
1129 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1130 fprintf(fp, "%d", np->ndup.dupfd);
1131 } else {
1132 sharg(np->nfile.fname, fp);
1133 }
1134 first = 0;
1135 }
1136}
1137
1138static void
1139shtree(union node *n, int ind, char *pfx, FILE *fp)
1140{
1141 struct nodelist *lp;
1142 const char *s;
1143
1144 if (n == NULL)
1145 return;
1146
1147 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001148
1149 if (n == NODE_EOF) {
1150 fputs("<EOF>", fp);
1151 return;
1152 }
1153
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001154 switch (n->type) {
1155 case NSEMI:
1156 s = "; ";
1157 goto binop;
1158 case NAND:
1159 s = " && ";
1160 goto binop;
1161 case NOR:
1162 s = " || ";
1163 binop:
1164 shtree(n->nbinary.ch1, ind, NULL, fp);
1165 /* if (ind < 0) */
1166 fputs(s, fp);
1167 shtree(n->nbinary.ch2, ind, NULL, fp);
1168 break;
1169 case NCMD:
1170 shcmd(n, fp);
1171 if (ind >= 0)
1172 putc('\n', fp);
1173 break;
1174 case NPIPE:
1175 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001176 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001177 if (lp->next)
1178 fputs(" | ", fp);
1179 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001180 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001181 fputs(" &", fp);
1182 if (ind >= 0)
1183 putc('\n', fp);
1184 break;
1185 default:
1186 fprintf(fp, "<node type %d>", n->type);
1187 if (ind >= 0)
1188 putc('\n', fp);
1189 break;
1190 }
1191}
1192
1193static void
1194showtree(union node *n)
1195{
1196 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001197 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001198}
1199
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001200#endif /* DEBUG */
1201
1202
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001203/* ============ Parser data */
1204
1205/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001206 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1207 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001208struct strlist {
1209 struct strlist *next;
1210 char *text;
1211};
1212
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001213struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001214
Denis Vlasenkob012b102007-02-19 22:43:01 +00001215struct strpush {
1216 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001217 char *prev_string;
1218 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001219#if ENABLE_ASH_ALIAS
1220 struct alias *ap; /* if push was associated with an alias */
1221#endif
1222 char *string; /* remember the string since it may change */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001223
1224 /* Remember last two characters for pungetc. */
1225 int lastc[2];
1226
1227 /* Number of outstanding calls to pungetc. */
1228 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001229};
1230
1231struct parsefile {
1232 struct parsefile *prev; /* preceding file on stack */
1233 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001234 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001235 int left_in_line; /* number of chars left in this line */
1236 int left_in_buffer; /* number of chars left in this buffer past the line */
1237 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001238 char *buf; /* input buffer */
1239 struct strpush *strpush; /* for pushing strings at this level */
1240 struct strpush basestrpush; /* so pushing one is fast */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001241
1242 /* Remember last two characters for pungetc. */
1243 int lastc[2];
1244
1245 /* Number of outstanding calls to pungetc. */
1246 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001247};
1248
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001249static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001250static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001251static int startlinno; /* line # where last token started */
1252static char *commandname; /* currently executing command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001253
1254
1255/* ============ Message printing */
1256
1257static void
1258ash_vmsg(const char *msg, va_list ap)
1259{
1260 fprintf(stderr, "%s: ", arg0);
1261 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001262 if (strcmp(arg0, commandname))
1263 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001264 if (!iflag || g_parsefile->pf_fd > 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001265 fprintf(stderr, "line %d: ", startlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001266 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001267 vfprintf(stderr, msg, ap);
Denys Vlasenko9c541002015-10-07 15:44:36 +02001268 newline_and_flush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001269}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001270
1271/*
1272 * Exverror is called to raise the error exception. If the second argument
1273 * is not NULL then error prints an error message using printf style
1274 * formatting. It then raises the error exception.
1275 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001276static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001277static void
1278ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001279{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001280#if DEBUG
1281 if (msg) {
Denys Vlasenko474ed062016-10-30 18:30:29 +01001282 TRACE(("ash_vmsg_and_raise(%d):", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001283 TRACEV((msg, ap));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001284 } else
Denys Vlasenko474ed062016-10-30 18:30:29 +01001285 TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001286 if (msg)
1287#endif
1288 ash_vmsg(msg, ap);
1289
1290 flush_stdout_stderr();
1291 raise_exception(cond);
1292 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001293}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001294
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001295static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001296static void
1297ash_msg_and_raise_error(const char *msg, ...)
1298{
1299 va_list ap;
1300
Ron Yorstonea7d2f62017-01-03 11:18:23 +01001301 exitstatus = 2;
1302
Denis Vlasenkob012b102007-02-19 22:43:01 +00001303 va_start(ap, msg);
1304 ash_vmsg_and_raise(EXERROR, msg, ap);
1305 /* NOTREACHED */
1306 va_end(ap);
1307}
1308
Ron Yorstonbe366e52017-07-27 13:53:39 +01001309/*
1310 * Use '%m' to append error string on platforms that support it, '%s' and
1311 * strerror() on those that don't.
1312 *
1313 * 'fmt' must be a string literal.
1314 */
1315#ifdef HAVE_PRINTF_PERCENTM
1316#define ash_msg_and_raise_perror(fmt, ...) ash_msg_and_raise_error(fmt ": %m", ##__VA_ARGS__)
1317#else
1318#define ash_msg_and_raise_perror(fmt, ...) ash_msg_and_raise_error(fmt ": %s", ##__VA_ARGS__, strerror(errno))
1319#endif
1320
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001321static void raise_error_syntax(const char *) NORETURN;
1322static void
1323raise_error_syntax(const char *msg)
1324{
1325 ash_msg_and_raise_error("syntax error: %s", msg);
1326 /* NOTREACHED */
1327}
1328
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001329static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001330static void
1331ash_msg_and_raise(int cond, const char *msg, ...)
1332{
1333 va_list ap;
1334
1335 va_start(ap, msg);
1336 ash_vmsg_and_raise(cond, msg, ap);
1337 /* NOTREACHED */
1338 va_end(ap);
1339}
1340
1341/*
1342 * error/warning routines for external builtins
1343 */
1344static void
1345ash_msg(const char *fmt, ...)
1346{
1347 va_list ap;
1348
1349 va_start(ap, fmt);
1350 ash_vmsg(fmt, ap);
1351 va_end(ap);
1352}
1353
1354/*
1355 * Return a string describing an error. The returned string may be a
1356 * pointer to a static buffer that will be overwritten on the next call.
1357 * Action describes the operation that got the error.
1358 */
1359static const char *
1360errmsg(int e, const char *em)
1361{
1362 if (e == ENOENT || e == ENOTDIR) {
1363 return em;
1364 }
1365 return strerror(e);
1366}
1367
1368
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001369/* ============ Memory allocation */
1370
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001371#if 0
1372/* I consider these wrappers nearly useless:
1373 * ok, they return you to nearest exception handler, but
1374 * how much memory do you leak in the process, making
1375 * memory starvation worse?
1376 */
1377static void *
1378ckrealloc(void * p, size_t nbytes)
1379{
1380 p = realloc(p, nbytes);
1381 if (!p)
1382 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1383 return p;
1384}
1385
1386static void *
1387ckmalloc(size_t nbytes)
1388{
1389 return ckrealloc(NULL, nbytes);
1390}
1391
1392static void *
1393ckzalloc(size_t nbytes)
1394{
1395 return memset(ckmalloc(nbytes), 0, nbytes);
1396}
1397
1398static char *
1399ckstrdup(const char *s)
1400{
1401 char *p = strdup(s);
1402 if (!p)
1403 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1404 return p;
1405}
1406#else
1407/* Using bbox equivalents. They exit if out of memory */
1408# define ckrealloc xrealloc
1409# define ckmalloc xmalloc
1410# define ckzalloc xzalloc
1411# define ckstrdup xstrdup
1412#endif
1413
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001414/*
1415 * It appears that grabstackstr() will barf with such alignments
1416 * because stalloc() will return a string allocated in a new stackblock.
1417 */
1418#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1419enum {
1420 /* Most machines require the value returned from malloc to be aligned
1421 * in some way. The following macro will get this right
1422 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001423 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001424 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001425 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001426};
1427
1428struct stack_block {
1429 struct stack_block *prev;
1430 char space[MINSIZE];
1431};
1432
1433struct stackmark {
1434 struct stack_block *stackp;
1435 char *stacknxt;
1436 size_t stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001437};
1438
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001439
Denis Vlasenko01631112007-12-16 17:20:38 +00001440struct globals_memstack {
1441 struct stack_block *g_stackp; // = &stackbase;
Denis Vlasenko01631112007-12-16 17:20:38 +00001442 char *g_stacknxt; // = stackbase.space;
1443 char *sstrend; // = stackbase.space + MINSIZE;
1444 size_t g_stacknleft; // = MINSIZE;
Denis Vlasenko01631112007-12-16 17:20:38 +00001445 struct stack_block stackbase;
1446};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001447extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1448#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001449#define g_stackp (G_memstack.g_stackp )
Denis Vlasenko01631112007-12-16 17:20:38 +00001450#define g_stacknxt (G_memstack.g_stacknxt )
1451#define sstrend (G_memstack.sstrend )
1452#define g_stacknleft (G_memstack.g_stacknleft)
Denis Vlasenko01631112007-12-16 17:20:38 +00001453#define stackbase (G_memstack.stackbase )
1454#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001455 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1456 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001457 g_stackp = &stackbase; \
1458 g_stacknxt = stackbase.space; \
1459 g_stacknleft = MINSIZE; \
1460 sstrend = stackbase.space + MINSIZE; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001461} while (0)
1462
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001463
Denis Vlasenko01631112007-12-16 17:20:38 +00001464#define stackblock() ((void *)g_stacknxt)
1465#define stackblocksize() g_stacknleft
1466
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001467/*
1468 * Parse trees for commands are allocated in lifo order, so we use a stack
1469 * to make this more efficient, and also to avoid all sorts of exception
1470 * handling code to handle interrupts in the middle of a parse.
1471 *
1472 * The size 504 was chosen because the Ultrix malloc handles that size
1473 * well.
1474 */
1475static void *
1476stalloc(size_t nbytes)
1477{
1478 char *p;
1479 size_t aligned;
1480
1481 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001482 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001483 size_t len;
1484 size_t blocksize;
1485 struct stack_block *sp;
1486
1487 blocksize = aligned;
1488 if (blocksize < MINSIZE)
1489 blocksize = MINSIZE;
1490 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1491 if (len < blocksize)
1492 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1493 INT_OFF;
1494 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001495 sp->prev = g_stackp;
1496 g_stacknxt = sp->space;
1497 g_stacknleft = blocksize;
1498 sstrend = g_stacknxt + blocksize;
1499 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001500 INT_ON;
1501 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001502 p = g_stacknxt;
1503 g_stacknxt += aligned;
1504 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001505 return p;
1506}
1507
Denis Vlasenko597906c2008-02-20 16:38:54 +00001508static void *
1509stzalloc(size_t nbytes)
1510{
1511 return memset(stalloc(nbytes), 0, nbytes);
1512}
1513
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001514static void
1515stunalloc(void *p)
1516{
1517#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001518 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001519 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001520 abort();
1521 }
1522#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001523 g_stacknleft += g_stacknxt - (char *)p;
1524 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001525}
1526
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001527/*
1528 * Like strdup but works with the ash stack.
1529 */
1530static char *
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02001531sstrdup(const char *p)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001532{
1533 size_t len = strlen(p) + 1;
1534 return memcpy(stalloc(len), p, len);
1535}
1536
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001537static inline void
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001538grabstackblock(size_t len)
1539{
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001540 stalloc(len);
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001541}
1542
1543static void
1544pushstackmark(struct stackmark *mark, size_t len)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001545{
Denis Vlasenko01631112007-12-16 17:20:38 +00001546 mark->stackp = g_stackp;
1547 mark->stacknxt = g_stacknxt;
1548 mark->stacknleft = g_stacknleft;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001549 grabstackblock(len);
1550}
1551
1552static void
1553setstackmark(struct stackmark *mark)
1554{
1555 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001556}
1557
1558static void
1559popstackmark(struct stackmark *mark)
1560{
1561 struct stack_block *sp;
1562
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001563 if (!mark->stackp)
1564 return;
1565
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001566 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001567 while (g_stackp != mark->stackp) {
1568 sp = g_stackp;
1569 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001570 free(sp);
1571 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001572 g_stacknxt = mark->stacknxt;
1573 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001574 sstrend = mark->stacknxt + mark->stacknleft;
1575 INT_ON;
1576}
1577
1578/*
1579 * When the parser reads in a string, it wants to stick the string on the
1580 * stack and only adjust the stack pointer when it knows how big the
1581 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1582 * of space on top of the stack and stackblocklen returns the length of
1583 * this block. Growstackblock will grow this space by at least one byte,
1584 * possibly moving it (like realloc). Grabstackblock actually allocates the
1585 * part of the block that has been used.
1586 */
1587static void
1588growstackblock(void)
1589{
1590 size_t newlen;
1591
Denis Vlasenko01631112007-12-16 17:20:38 +00001592 newlen = g_stacknleft * 2;
1593 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001594 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1595 if (newlen < 128)
1596 newlen += 128;
1597
Denis Vlasenko01631112007-12-16 17:20:38 +00001598 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001599 struct stack_block *sp;
1600 struct stack_block *prevstackp;
1601 size_t grosslen;
1602
1603 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001604 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001605 prevstackp = sp->prev;
1606 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1607 sp = ckrealloc(sp, grosslen);
1608 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001609 g_stackp = sp;
1610 g_stacknxt = sp->space;
1611 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001612 sstrend = sp->space + newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001613 INT_ON;
1614 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001615 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001616 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001617 char *p = stalloc(newlen);
1618
1619 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001620 g_stacknxt = memcpy(p, oldspace, oldlen);
1621 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001622 }
1623}
1624
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001625/*
1626 * The following routines are somewhat easier to use than the above.
1627 * The user declares a variable of type STACKSTR, which may be declared
1628 * to be a register. The macro STARTSTACKSTR initializes things. Then
1629 * the user uses the macro STPUTC to add characters to the string. In
1630 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1631 * grown as necessary. When the user is done, she can just leave the
1632 * string there and refer to it using stackblock(). Or she can allocate
1633 * the space for it using grabstackstr(). If it is necessary to allow
1634 * someone else to use the stack temporarily and then continue to grow
1635 * the string, the user should use grabstack to allocate the space, and
1636 * then call ungrabstr(p) to return to the previous mode of operation.
1637 *
1638 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1639 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1640 * is space for at least one character.
1641 */
1642static void *
1643growstackstr(void)
1644{
1645 size_t len = stackblocksize();
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001646 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001647 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001648}
1649
1650/*
1651 * Called from CHECKSTRSPACE.
1652 */
1653static char *
1654makestrspace(size_t newlen, char *p)
1655{
Denis Vlasenko01631112007-12-16 17:20:38 +00001656 size_t len = p - g_stacknxt;
Denys Vlasenko53d6e032016-09-30 11:24:12 +02001657 size_t size;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001658
1659 for (;;) {
1660 size_t nleft;
1661
1662 size = stackblocksize();
1663 nleft = size - len;
1664 if (nleft >= newlen)
1665 break;
1666 growstackblock();
1667 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001668 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001669}
1670
1671static char *
1672stack_nputstr(const char *s, size_t n, char *p)
1673{
1674 p = makestrspace(n, p);
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02001675 p = (char *)mempcpy(p, s, n);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001676 return p;
1677}
1678
1679static char *
1680stack_putstr(const char *s, char *p)
1681{
1682 return stack_nputstr(s, strlen(s), p);
1683}
1684
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001685static char *
1686_STPUTC(int c, char *p)
1687{
1688 if (p == sstrend)
1689 p = growstackstr();
1690 *p++ = c;
1691 return p;
1692}
1693
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001694#define STARTSTACKSTR(p) ((p) = stackblock())
1695#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001696#define CHECKSTRSPACE(n, p) do { \
1697 char *q = (p); \
1698 size_t l = (n); \
1699 size_t m = sstrend - q; \
1700 if (l > m) \
1701 (p) = makestrspace(l, q); \
1702} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001703#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001704#define STACKSTRNUL(p) do { \
1705 if ((p) == sstrend) \
1706 (p) = growstackstr(); \
1707 *(p) = '\0'; \
1708} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001709#define STUNPUTC(p) (--(p))
1710#define STTOPC(p) ((p)[-1])
1711#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001712
1713#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001714#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001715#define stackstrend() ((void *)sstrend)
1716
1717
1718/* ============ String helpers */
1719
1720/*
1721 * prefix -- see if pfx is a prefix of string.
1722 */
1723static char *
1724prefix(const char *string, const char *pfx)
1725{
1726 while (*pfx) {
1727 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001728 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001729 }
1730 return (char *) string;
1731}
1732
1733/*
1734 * Check for a valid number. This should be elsewhere.
1735 */
1736static int
1737is_number(const char *p)
1738{
1739 do {
1740 if (!isdigit(*p))
1741 return 0;
1742 } while (*++p != '\0');
1743 return 1;
1744}
1745
1746/*
1747 * Convert a string of digits to an integer, printing an error message on
1748 * failure.
1749 */
1750static int
1751number(const char *s)
1752{
1753 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001754 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001755 return atoi(s);
1756}
1757
1758/*
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001759 * Produce a single quoted string suitable as input to the shell.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001760 * The return string is allocated on the stack.
1761 */
1762static char *
1763single_quote(const char *s)
1764{
1765 char *p;
1766
1767 STARTSTACKSTR(p);
1768
1769 do {
1770 char *q;
1771 size_t len;
1772
1773 len = strchrnul(s, '\'') - s;
1774
1775 q = p = makestrspace(len + 3, p);
1776
1777 *q++ = '\'';
Denys Vlasenko94af83e2017-07-23 21:55:40 +02001778 q = (char *)mempcpy(q, s, len);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001779 *q++ = '\'';
1780 s += len;
1781
1782 STADJUST(q - p, p);
1783
Denys Vlasenkocd716832009-11-28 22:14:02 +01001784 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001785 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001786 len = 0;
1787 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001788
1789 q = p = makestrspace(len + 3, p);
1790
1791 *q++ = '"';
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02001792 q = (char *)mempcpy(q, s - len, len);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001793 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001794
1795 STADJUST(q - p, p);
1796 } while (*s);
1797
Denys Vlasenkocd716832009-11-28 22:14:02 +01001798 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001799
1800 return stackblock();
1801}
1802
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001803/*
1804 * Produce a possibly single quoted string suitable as input to the shell.
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001805 * If quoting was done, the return string is allocated on the stack,
1806 * otherwise a pointer to the original string is returned.
1807 */
1808static const char *
1809maybe_single_quote(const char *s)
1810{
1811 const char *p = s;
1812
1813 while (*p) {
1814 /* Assuming ACSII */
1815 /* quote ctrl_chars space !"#$%&'()* */
1816 if (*p < '+')
1817 goto need_quoting;
1818 /* quote ;<=>? */
1819 if (*p >= ';' && *p <= '?')
1820 goto need_quoting;
1821 /* quote `[\ */
1822 if (*p == '`')
1823 goto need_quoting;
1824 if (*p == '[')
1825 goto need_quoting;
1826 if (*p == '\\')
1827 goto need_quoting;
1828 /* quote {|}~ DEL and high bytes */
1829 if (*p > 'z')
1830 goto need_quoting;
1831 /* Not quoting these: +,-./ 0-9 :@ A-Z ]^_ a-z */
1832 /* TODO: maybe avoid quoting % */
1833 p++;
1834 }
1835 return s;
1836
1837 need_quoting:
1838 return single_quote(s);
1839}
1840
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001841
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001842/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001843
1844static char **argptr; /* argument list for builtin commands */
1845static char *optionarg; /* set by nextopt (like getopt) */
1846static char *optptr; /* used by nextopt */
1847
1848/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001849 * XXX - should get rid of. Have all builtins use getopt(3).
1850 * The library getopt must have the BSD extension static variable
1851 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001852 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001853 * Standard option processing (a la getopt) for builtin routines.
1854 * The only argument that is passed to nextopt is the option string;
1855 * the other arguments are unnecessary. It returns the character,
1856 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001857 */
1858static int
1859nextopt(const char *optstring)
1860{
1861 char *p;
1862 const char *q;
1863 char c;
1864
1865 p = optptr;
1866 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001867 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001868 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001869 if (p == NULL)
1870 return '\0';
1871 if (*p != '-')
1872 return '\0';
1873 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001874 return '\0';
1875 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001876 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001877 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001878 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001879 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001880 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001881 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001882 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001883 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001884 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001885 if (*++q == ':')
1886 q++;
1887 }
1888 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001889 if (*p == '\0') {
1890 p = *argptr++;
1891 if (p == NULL)
1892 ash_msg_and_raise_error("no arg for -%c option", c);
1893 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001894 optionarg = p;
1895 p = NULL;
1896 }
1897 optptr = p;
1898 return c;
1899}
1900
1901
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001902/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001903
Denis Vlasenko01631112007-12-16 17:20:38 +00001904/*
1905 * The parsefile structure pointed to by the global variable parsefile
1906 * contains information about the current file being read.
1907 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001908struct shparam {
1909 int nparam; /* # of positional parameters (without $0) */
1910#if ENABLE_ASH_GETOPTS
1911 int optind; /* next parameter to be processed by getopts */
1912 int optoff; /* used by getopts */
1913#endif
1914 unsigned char malloced; /* if parameter list dynamically allocated */
1915 char **p; /* parameter list */
1916};
1917
1918/*
1919 * Free the list of positional parameters.
1920 */
1921static void
1922freeparam(volatile struct shparam *param)
1923{
Denis Vlasenko01631112007-12-16 17:20:38 +00001924 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001925 char **ap, **ap1;
1926 ap = ap1 = param->p;
1927 while (*ap)
1928 free(*ap++);
1929 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001930 }
1931}
1932
1933#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001934static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001935#endif
1936
1937struct var {
1938 struct var *next; /* next entry in hash list */
1939 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001940 const char *var_text; /* name=value */
1941 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001942 /* the variable gets set/unset */
1943};
1944
1945struct localvar {
1946 struct localvar *next; /* next local variable in list */
1947 struct var *vp; /* the variable that was made local */
1948 int flags; /* saved flags */
1949 const char *text; /* saved text */
1950};
1951
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001952/* flags */
1953#define VEXPORT 0x01 /* variable is exported */
1954#define VREADONLY 0x02 /* variable cannot be modified */
1955#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1956#define VTEXTFIXED 0x08 /* text is statically allocated */
1957#define VSTACK 0x10 /* text is allocated on the stack */
1958#define VUNSET 0x20 /* the variable is not set */
1959#define VNOFUNC 0x40 /* don't call the callback function */
1960#define VNOSET 0x80 /* do not set variable - just readonly test */
1961#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001962#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001963# define VDYNAMIC 0x200 /* dynamic variable */
1964#else
1965# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001966#endif
1967
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001968
Denis Vlasenko01631112007-12-16 17:20:38 +00001969/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001970#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001971static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001972change_lc_all(const char *value)
1973{
1974 if (value && *value != '\0')
1975 setlocale(LC_ALL, value);
1976}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001977static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001978change_lc_ctype(const char *value)
1979{
1980 if (value && *value != '\0')
1981 setlocale(LC_CTYPE, value);
1982}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001983#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001984#if ENABLE_ASH_MAIL
1985static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01001986static void changemail(const char *var_value) FAST_FUNC;
1987#else
1988# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001989#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001990static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001991#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001992static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001993#endif
1994
Denis Vlasenko01631112007-12-16 17:20:38 +00001995static const struct {
1996 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001997 const char *var_text;
1998 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00001999} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02002000 /*
2001 * Note: VEXPORT would not work correctly here for NOFORK applets:
2002 * some environment strings may be constant.
2003 */
Denis Vlasenko01631112007-12-16 17:20:38 +00002004 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002005#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002006 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
2007 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002008#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00002009 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
2010 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
2011 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
2012 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002013#if ENABLE_ASH_GETOPTS
Denys Vlasenkoe627ac92016-09-30 14:36:59 +02002014 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002015#endif
2016#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002017 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002018#endif
2019#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002020 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
2021 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002022#endif
2023#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002024 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002025#endif
2026};
2027
Denis Vlasenko0b769642008-07-24 07:54:57 +00002028struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00002029
2030struct globals_var {
2031 struct shparam shellparam; /* $@ current positional parameters */
2032 struct redirtab *redirlist;
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02002033 int preverrout_fd; /* stderr fd: usually 2, unless redirect moved it */
Denis Vlasenko01631112007-12-16 17:20:38 +00002034 struct var *vartab[VTABSIZE];
2035 struct var varinit[ARRAY_SIZE(varinit_data)];
2036};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00002037extern struct globals_var *const ash_ptr_to_globals_var;
2038#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00002039#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00002040//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00002041#define preverrout_fd (G_var.preverrout_fd)
2042#define vartab (G_var.vartab )
2043#define varinit (G_var.varinit )
2044#define INIT_G_var() do { \
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00002045 unsigned i; \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00002046 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
2047 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00002048 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002049 varinit[i].flags = varinit_data[i].flags; \
2050 varinit[i].var_text = varinit_data[i].var_text; \
2051 varinit[i].var_func = varinit_data[i].var_func; \
Denis Vlasenko01631112007-12-16 17:20:38 +00002052 } \
2053} while (0)
2054
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002055#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002056#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002057# define vmail (&vifs)[1]
2058# define vmpath (&vmail)[1]
2059# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002060#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002061# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002062#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002063#define vps1 (&vpath)[1]
2064#define vps2 (&vps1)[1]
2065#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002066#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002067# define voptind (&vps4)[1]
2068# if ENABLE_ASH_RANDOM_SUPPORT
2069# define vrandom (&voptind)[1]
2070# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002071#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002072# if ENABLE_ASH_RANDOM_SUPPORT
2073# define vrandom (&vps4)[1]
2074# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002075#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002076
2077/*
2078 * The following macros access the values of the above variables.
2079 * They have to skip over the name. They return the null string
2080 * for unset variables.
2081 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002082#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002083#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002084#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002085# define mailval() (vmail.var_text + 5)
2086# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002087# define mpathset() ((vmpath.flags & VUNSET) == 0)
2088#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002089#define pathval() (vpath.var_text + 5)
2090#define ps1val() (vps1.var_text + 4)
2091#define ps2val() (vps2.var_text + 4)
2092#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002093#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002094# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002095#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002096
Denis Vlasenko01631112007-12-16 17:20:38 +00002097#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002098static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002099getoptsreset(const char *value)
2100{
Denys Vlasenkoa513bf32016-10-26 02:03:37 +02002101 shellparam.optind = number(value) ?: 1;
Denis Vlasenko01631112007-12-16 17:20:38 +00002102 shellparam.optoff = -1;
2103}
2104#endif
2105
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002106/*
2107 * Compares two strings up to the first = or '\0'. The first
2108 * string must be terminated by '='; the second may be terminated by
2109 * either '=' or '\0'.
2110 */
2111static int
2112varcmp(const char *p, const char *q)
2113{
2114 int c, d;
2115
2116 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002117 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002118 goto out;
2119 p++;
2120 q++;
2121 }
2122 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002123 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002124 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002125 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002126 out:
2127 return c - d;
2128}
2129
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002130/*
2131 * Find the appropriate entry in the hash table from the name.
2132 */
2133static struct var **
2134hashvar(const char *p)
2135{
2136 unsigned hashval;
2137
2138 hashval = ((unsigned char) *p) << 4;
2139 while (*p && *p != '=')
2140 hashval += (unsigned char) *p++;
2141 return &vartab[hashval % VTABSIZE];
2142}
2143
2144static int
2145vpcmp(const void *a, const void *b)
2146{
2147 return varcmp(*(const char **)a, *(const char **)b);
2148}
2149
2150/*
2151 * This routine initializes the builtin variables.
2152 */
2153static void
2154initvar(void)
2155{
2156 struct var *vp;
2157 struct var *end;
2158 struct var **vpp;
2159
2160 /*
2161 * PS1 depends on uid
2162 */
2163#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002164 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002165#else
2166 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002167 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002168#endif
2169 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002170 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002171 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002172 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002173 vp->next = *vpp;
2174 *vpp = vp;
2175 } while (++vp < end);
2176}
2177
2178static struct var **
2179findvar(struct var **vpp, const char *name)
2180{
2181 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002182 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002183 break;
2184 }
2185 }
2186 return vpp;
2187}
2188
2189/*
2190 * Find the value of a variable. Returns NULL if not set.
2191 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002192static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002193lookupvar(const char *name)
2194{
2195 struct var *v;
2196
2197 v = *findvar(hashvar(name), name);
2198 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002199#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002200 /*
2201 * Dynamic variables are implemented roughly the same way they are
2202 * in bash. Namely, they're "special" so long as they aren't unset.
2203 * As soon as they're unset, they're no longer dynamic, and dynamic
2204 * lookup will no longer happen at that point. -- PFM.
2205 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002206 if (v->flags & VDYNAMIC)
2207 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002208#endif
2209 if (!(v->flags & VUNSET))
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002210 return var_end(v->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002211 }
2212 return NULL;
2213}
2214
Denys Vlasenko0b883582016-12-23 16:49:07 +01002215#if ENABLE_UNICODE_SUPPORT
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02002216static void
2217reinit_unicode_for_ash(void)
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002218{
2219 /* Unicode support should be activated even if LANG is set
2220 * _during_ shell execution, not only if it was set when
2221 * shell was started. Therefore, re-check LANG every time:
2222 */
2223 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2224 || ENABLE_UNICODE_USING_LOCALE
2225 ) {
2226 const char *s = lookupvar("LC_ALL");
2227 if (!s) s = lookupvar("LC_CTYPE");
2228 if (!s) s = lookupvar("LANG");
2229 reinit_unicode(s);
2230 }
2231}
Denys Vlasenko0b883582016-12-23 16:49:07 +01002232#else
2233# define reinit_unicode_for_ash() ((void)0)
2234#endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002235
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002236/*
2237 * Search the environment of a builtin command.
2238 */
Denys Vlasenko488e6092017-07-26 23:08:36 +02002239static ALWAYS_INLINE const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002240bltinlookup(const char *name)
2241{
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002242 return lookupvar(name);
2243}
2244
2245/*
2246 * Same as setvar except that the variable and value are passed in
2247 * the first argument as name=value. Since the first argument will
2248 * be actually stored in the table, it should not be a string that
2249 * will go away.
2250 * Called with interrupts off.
2251 */
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002252static struct var *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002253setvareq(char *s, int flags)
2254{
2255 struct var *vp, **vpp;
2256
2257 vpp = hashvar(s);
2258 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002259 vpp = findvar(vpp, s);
2260 vp = *vpp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002261 if (vp) {
2262 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2263 const char *n;
2264
2265 if (flags & VNOSAVE)
2266 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002267 n = vp->var_text;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02002268 exitstatus = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002269 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2270 }
2271
2272 if (flags & VNOSET)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002273 goto out;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002274
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002275 if (vp->var_func && !(flags & VNOFUNC))
2276 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002277
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002278 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2279 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002280
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002281 if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) {
2282 *vpp = vp->next;
2283 free(vp);
2284 out_free:
2285 if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE)
2286 free(s);
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002287 goto out;
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002288 }
2289
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002290 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2291 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002292 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002293 if (flags & VNOSET)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002294 goto out;
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002295 if ((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
2296 goto out_free;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002297 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002298 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002299 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002300 *vpp = vp;
2301 }
2302 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2303 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002304 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002305 vp->flags = flags;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002306
2307 out:
2308 return vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002309}
2310
2311/*
2312 * Set the value of a variable. The flags argument is ored with the
2313 * flags of the variable. If val is NULL, the variable is unset.
2314 */
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002315static struct var *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002316setvar(const char *name, const char *val, int flags)
2317{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002318 const char *q;
2319 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002320 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002321 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002322 size_t vallen;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002323 struct var *vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002324
2325 q = endofname(name);
2326 p = strchrnul(q, '=');
2327 namelen = p - name;
2328 if (!namelen || p != q)
2329 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2330 vallen = 0;
2331 if (val == NULL) {
2332 flags |= VUNSET;
2333 } else {
2334 vallen = strlen(val);
2335 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002336
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002337 INT_OFF;
2338 nameeq = ckmalloc(namelen + vallen + 2);
Denys Vlasenkoda2244f2017-07-21 18:51:29 +02002339 p = mempcpy(nameeq, name, namelen);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002340 if (val) {
2341 *p++ = '=';
Denys Vlasenkoda2244f2017-07-21 18:51:29 +02002342 p = mempcpy(p, val, vallen);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002343 }
2344 *p = '\0';
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002345 vp = setvareq(nameeq, flags | VNOSAVE);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002346 INT_ON;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002347
2348 return vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002349}
2350
Denys Vlasenko03dad222010-01-12 23:29:57 +01002351static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002352setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002353{
2354 setvar(name, val, 0);
2355}
2356
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002357/*
2358 * Unset the specified variable.
2359 */
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002360static void
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002361unsetvar(const char *s)
2362{
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02002363 setvar(s, NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002364}
2365
2366/*
2367 * Process a linked list of variable assignments.
2368 */
2369static void
2370listsetvar(struct strlist *list_set_var, int flags)
2371{
2372 struct strlist *lp = list_set_var;
2373
2374 if (!lp)
2375 return;
2376 INT_OFF;
2377 do {
2378 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002379 lp = lp->next;
2380 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002381 INT_ON;
2382}
2383
2384/*
2385 * Generate a list of variables satisfying the given conditions.
2386 */
2387static char **
2388listvars(int on, int off, char ***end)
2389{
2390 struct var **vpp;
2391 struct var *vp;
2392 char **ep;
2393 int mask;
2394
2395 STARTSTACKSTR(ep);
2396 vpp = vartab;
2397 mask = on | off;
2398 do {
2399 for (vp = *vpp; vp; vp = vp->next) {
2400 if ((vp->flags & mask) == on) {
2401 if (ep == stackstrend())
2402 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002403 *ep++ = (char*)vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002404 }
2405 }
2406 } while (++vpp < vartab + VTABSIZE);
2407 if (ep == stackstrend())
2408 ep = growstackstr();
2409 if (end)
2410 *end = ep;
2411 *ep++ = NULL;
2412 return grabstackstr(ep);
2413}
2414
2415
2416/* ============ Path search helper
2417 *
2418 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002419 * of the path before the first call; path_advance will update
2420 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002421 * the possible path expansions in sequence. If an option (indicated by
2422 * a percent sign) appears in the path entry then the global variable
2423 * pathopt will be set to point to it; otherwise pathopt will be set to
2424 * NULL.
2425 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002426static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002427
2428static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002429path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002430{
2431 const char *p;
2432 char *q;
2433 const char *start;
2434 size_t len;
2435
2436 if (*path == NULL)
2437 return NULL;
2438 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002439 for (p = start; *p && *p != ':' && *p != '%'; p++)
2440 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002441 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2442 while (stackblocksize() < len)
2443 growstackblock();
2444 q = stackblock();
2445 if (p != start) {
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02002446 q = mempcpy(q, start, p - start);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002447 *q++ = '/';
2448 }
2449 strcpy(q, name);
2450 pathopt = NULL;
2451 if (*p == '%') {
2452 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002453 while (*p && *p != ':')
2454 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002455 }
2456 if (*p == ':')
2457 *path = p + 1;
2458 else
2459 *path = NULL;
2460 return stalloc(len);
2461}
2462
2463
2464/* ============ Prompt */
2465
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002466static smallint doprompt; /* if set, prompt the user */
2467static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002468
2469#if ENABLE_FEATURE_EDITING
2470static line_input_t *line_input_state;
2471static const char *cmdedit_prompt;
2472static void
2473putprompt(const char *s)
2474{
2475 if (ENABLE_ASH_EXPAND_PRMT) {
2476 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002477 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002478 return;
2479 }
2480 cmdedit_prompt = s;
2481}
2482#else
2483static void
2484putprompt(const char *s)
2485{
2486 out2str(s);
2487}
2488#endif
2489
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002490/* expandstr() needs parsing machinery, so it is far away ahead... */
Denys Vlasenko46999802017-07-29 21:12:29 +02002491static const char *expandstr(const char *ps, int syntax_type);
2492/* Values for syntax param */
2493#define BASESYNTAX 0 /* not in quotes */
2494#define DQSYNTAX 1 /* in double quotes */
2495#define SQSYNTAX 2 /* in single quotes */
2496#define ARISYNTAX 3 /* in arithmetic */
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +02002497#if ENABLE_ASH_EXPAND_PRMT
2498# define PSSYNTAX 4 /* prompt. never passed to SIT() */
2499#endif
Denys Vlasenko46999802017-07-29 21:12:29 +02002500/* PSSYNTAX expansion is identical to DQSYNTAX, except keeping '\$' as '\$' */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002501
Denys Vlasenko46999802017-07-29 21:12:29 +02002502/*
2503 * called by editline -- any expansions to the prompt should be added here.
2504 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002505static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002506setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002507{
2508 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002509 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2510
2511 if (!do_set)
2512 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002513
2514 needprompt = 0;
2515
2516 switch (whichprompt) {
2517 case 1:
2518 prompt = ps1val();
2519 break;
2520 case 2:
2521 prompt = ps2val();
2522 break;
2523 default: /* 0 */
2524 prompt = nullstr;
2525 }
2526#if ENABLE_ASH_EXPAND_PRMT
Denys Vlasenko60ca8342016-09-30 11:21:21 +02002527 pushstackmark(&smark, stackblocksize());
Denys Vlasenko46999802017-07-29 21:12:29 +02002528 putprompt(expandstr(prompt, PSSYNTAX));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002529 popstackmark(&smark);
Denys Vlasenko48c803a2017-07-01 23:24:48 +02002530#else
2531 putprompt(prompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002532#endif
2533}
2534
2535
2536/* ============ The cd and pwd commands */
2537
2538#define CD_PHYSICAL 1
2539#define CD_PRINT 2
2540
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002541static int
2542cdopt(void)
2543{
2544 int flags = 0;
2545 int i, j;
2546
2547 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002548 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002549 if (i != j) {
2550 flags ^= CD_PHYSICAL;
2551 j = i;
2552 }
2553 }
2554
2555 return flags;
2556}
2557
2558/*
2559 * Update curdir (the name of the current directory) in response to a
2560 * cd command.
2561 */
2562static const char *
2563updatepwd(const char *dir)
2564{
2565 char *new;
2566 char *p;
2567 char *cdcomppath;
2568 const char *lim;
2569
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02002570 cdcomppath = sstrdup(dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002571 STARTSTACKSTR(new);
2572 if (*dir != '/') {
2573 if (curdir == nullstr)
2574 return 0;
2575 new = stack_putstr(curdir, new);
2576 }
2577 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002578 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002579 if (*dir != '/') {
2580 if (new[-1] != '/')
2581 USTPUTC('/', new);
2582 if (new > lim && *lim == '/')
2583 lim++;
2584 } else {
2585 USTPUTC('/', new);
2586 cdcomppath++;
2587 if (dir[1] == '/' && dir[2] != '/') {
2588 USTPUTC('/', new);
2589 cdcomppath++;
2590 lim++;
2591 }
2592 }
2593 p = strtok(cdcomppath, "/");
2594 while (p) {
2595 switch (*p) {
2596 case '.':
2597 if (p[1] == '.' && p[2] == '\0') {
2598 while (new > lim) {
2599 STUNPUTC(new);
2600 if (new[-1] == '/')
2601 break;
2602 }
2603 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002604 }
2605 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002606 break;
2607 /* fall through */
2608 default:
2609 new = stack_putstr(p, new);
2610 USTPUTC('/', new);
2611 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002612 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002613 }
2614 if (new > lim)
2615 STUNPUTC(new);
2616 *new = 0;
2617 return stackblock();
2618}
2619
2620/*
2621 * Find out what the current directory is. If we already know the current
2622 * directory, this routine returns immediately.
2623 */
2624static char *
2625getpwd(void)
2626{
Denis Vlasenko01631112007-12-16 17:20:38 +00002627 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002628 return dir ? dir : nullstr;
2629}
2630
2631static void
2632setpwd(const char *val, int setold)
2633{
2634 char *oldcur, *dir;
2635
2636 oldcur = dir = curdir;
2637
2638 if (setold) {
2639 setvar("OLDPWD", oldcur, VEXPORT);
2640 }
2641 INT_OFF;
2642 if (physdir != nullstr) {
2643 if (physdir != oldcur)
2644 free(physdir);
2645 physdir = nullstr;
2646 }
2647 if (oldcur == val || !val) {
2648 char *s = getpwd();
2649 physdir = s;
2650 if (!val)
2651 dir = s;
2652 } else
2653 dir = ckstrdup(val);
2654 if (oldcur != dir && oldcur != nullstr) {
2655 free(oldcur);
2656 }
2657 curdir = dir;
2658 INT_ON;
2659 setvar("PWD", dir, VEXPORT);
2660}
2661
2662static void hashcd(void);
2663
2664/*
Denys Vlasenko70392332016-10-27 02:31:55 +02002665 * Actually do the chdir. We also call hashcd to let other routines
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002666 * know that the current directory has changed.
2667 */
2668static int
2669docd(const char *dest, int flags)
2670{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002671 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002672 int err;
2673
2674 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2675
2676 INT_OFF;
2677 if (!(flags & CD_PHYSICAL)) {
2678 dir = updatepwd(dest);
2679 if (dir)
2680 dest = dir;
2681 }
2682 err = chdir(dest);
2683 if (err)
2684 goto out;
2685 setpwd(dir, 1);
2686 hashcd();
2687 out:
2688 INT_ON;
2689 return err;
2690}
2691
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002692static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002693cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002694{
2695 const char *dest;
2696 const char *path;
2697 const char *p;
2698 char c;
2699 struct stat statb;
2700 int flags;
2701
2702 flags = cdopt();
2703 dest = *argptr;
2704 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002705 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002706 else if (LONE_DASH(dest)) {
2707 dest = bltinlookup("OLDPWD");
2708 flags |= CD_PRINT;
2709 }
2710 if (!dest)
2711 dest = nullstr;
2712 if (*dest == '/')
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002713 goto step6;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002714 if (*dest == '.') {
2715 c = dest[1];
2716 dotdot:
2717 switch (c) {
2718 case '\0':
2719 case '/':
2720 goto step6;
2721 case '.':
2722 c = dest[2];
2723 if (c != '.')
2724 goto dotdot;
2725 }
2726 }
2727 if (!*dest)
2728 dest = ".";
2729 path = bltinlookup("CDPATH");
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002730 while (path) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002731 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002732 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002733 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2734 if (c && c != ':')
2735 flags |= CD_PRINT;
2736 docd:
2737 if (!docd(p, flags))
2738 goto out;
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002739 goto err;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002740 }
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002741 }
2742
2743 step6:
2744 p = dest;
2745 goto docd;
2746
2747 err:
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002748 ash_msg_and_raise_error("can't cd to %s", dest);
2749 /* NOTREACHED */
2750 out:
2751 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002752 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002753 return 0;
2754}
2755
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002756static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002757pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002758{
2759 int flags;
2760 const char *dir = curdir;
2761
2762 flags = cdopt();
2763 if (flags) {
2764 if (physdir == nullstr)
2765 setpwd(dir, 0);
2766 dir = physdir;
2767 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002768 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002769 return 0;
2770}
2771
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002772
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002773/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002774
Denis Vlasenko834dee72008-10-07 09:18:30 +00002775
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002776#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002777
Eric Andersenc470f442003-07-28 09:56:35 +00002778/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002779#define CWORD 0 /* character is nothing special */
2780#define CNL 1 /* newline character */
2781#define CBACK 2 /* a backslash character */
2782#define CSQUOTE 3 /* single quote */
2783#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002784#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002785#define CBQUOTE 6 /* backwards single quote */
2786#define CVAR 7 /* a dollar sign */
2787#define CENDVAR 8 /* a '}' character */
2788#define CLP 9 /* a left paren in arithmetic */
2789#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002790#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002791#define CCTL 12 /* like CWORD, except it must be escaped */
2792#define CSPCL 13 /* these terminate a word */
2793#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002794
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002795#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002796#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002797# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002798#endif
2799
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002800#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002801
Denys Vlasenko0b883582016-12-23 16:49:07 +01002802#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002803# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002804#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002805# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002806#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002807static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002808#if ENABLE_ASH_ALIAS
2809 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2810#endif
2811 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2812 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2813 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2814 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2815 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2816 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2817 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2818 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2819 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2820 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2821 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002822#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002823 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2824 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2825 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2826#endif
2827#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002828};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002829/* Constants below must match table above */
2830enum {
2831#if ENABLE_ASH_ALIAS
2832 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2833#endif
2834 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2835 CNL_CNL_CNL_CNL , /* 2 */
2836 CWORD_CCTL_CCTL_CWORD , /* 3 */
2837 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2838 CVAR_CVAR_CWORD_CVAR , /* 5 */
2839 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2840 CSPCL_CWORD_CWORD_CLP , /* 7 */
2841 CSPCL_CWORD_CWORD_CRP , /* 8 */
2842 CBACK_CBACK_CCTL_CBACK , /* 9 */
2843 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2844 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2845 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2846 CWORD_CWORD_CWORD_CWORD , /* 13 */
2847 CCTL_CCTL_CCTL_CCTL , /* 14 */
2848};
Eric Andersen2870d962001-07-02 17:27:21 +00002849
Denys Vlasenkocd716832009-11-28 22:14:02 +01002850/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2851 * caller must ensure proper cast on it if c is *char_ptr!
2852 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002853#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002854
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002855static int
2856SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002857{
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002858 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2859 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2860 /*
2861 * This causes '/' to be prepended with CTLESC in dquoted string,
2862 * making "./file"* treated incorrectly because we feed
2863 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2864 * The "homegrown" glob implementation is okay with that,
2865 * but glibc one isn't. With '/' always treated as CWORD,
2866 * both work fine.
2867 */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002868# if ENABLE_ASH_ALIAS
2869 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002870 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002871 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002872 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2873 11, 3 /* "}~" */
2874 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002875# else
2876 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002877 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002878 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002879 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2880 10, 2 /* "}~" */
2881 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002882# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002883 const char *s;
2884 int indx;
2885
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002886 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002887 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002888# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002889 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002890 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002891 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002892# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002893 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002894 /* Cast is purely for paranoia here,
2895 * just in case someone passed signed char to us */
2896 if ((unsigned char)c >= CTL_FIRST
2897 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002898 ) {
2899 return CCTL;
2900 }
2901 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002902 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002903 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002904 indx = syntax_index_table[s - spec_symbls];
2905 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002906 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002907}
2908
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002909#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002910
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002911static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002912 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002913 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2914 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2915 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2916 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2917 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2918 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2919 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2920 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2921 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2922 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2923 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2924 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2925 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2926 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2927 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2928 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2929 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2930 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2931 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2932 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2933 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2934 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2935 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2936 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2937 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2938 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2939 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2940 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2941 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2942 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2943 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2944 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2945 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2946 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2947 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2948 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2950 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2952 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2953 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2954 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2955 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2956 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2958 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2959 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002960/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
2961 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkocd716832009-11-28 22:14:02 +01002962 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2973 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2974 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2975 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2976 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2977 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2978 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2983 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2986 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2987 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2988 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2989 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2990 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2991 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2992 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2993 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2994 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2995 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2996 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2997 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2998 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2999 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
3000 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
3001 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
3002 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
3003 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
3004 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
3005 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
3006 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
3007 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
3008 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
3009 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
3010 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
3011 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
3012 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
3013 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
3014 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
3015 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
3016 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
3017 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
3018 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
3019 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
3020 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
3021 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
3022 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
3023 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
3024 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
3025 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
3026 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
3027 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
3028 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
3029 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
3030 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
3031 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
3032 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
3033 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
3034 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
3035 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
3036 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
3037 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
3038 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
3039 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3040 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
3041 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
3042 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
3044 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
3045 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
3046 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
3047 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
3048 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
3049 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
3050 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3051 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3112 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3113 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3114 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3115 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3116 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3117 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3118 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3119 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3120 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3121 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3122 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3123 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3124 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3125 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3126 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3127 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3128 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3129 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3130 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3131 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3132 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3133 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3134 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3135 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3136 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3137 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3138 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3139 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3140 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3141 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3142 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3143 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3144 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3145 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3146 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3147 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3148 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3149 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3150 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3151 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3152 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3153 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3154 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3155 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3156 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3157 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3158 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3159 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3160 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3161 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3162 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3163 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3164 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3165 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3166 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3167 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3168 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3169 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003170 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003171# if ENABLE_ASH_ALIAS
3172 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3173# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003174};
3175
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003176#if 1
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003177# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003178#else /* debug version, caught one signed char bug */
3179# define SIT(c, syntax) \
3180 ({ \
3181 if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3182 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
Denys Vlasenko0b883582016-12-23 16:49:07 +01003183 if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003184 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3185 ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3186 })
3187#endif
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003188
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003189#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003190
Eric Andersen2870d962001-07-02 17:27:21 +00003191
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003192/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003193
Denis Vlasenko131ae172007-02-18 13:00:19 +00003194#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003195
3196#define ALIASINUSE 1
3197#define ALIASDEAD 2
3198
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003199struct alias {
3200 struct alias *next;
3201 char *name;
3202 char *val;
3203 int flag;
3204};
3205
Denis Vlasenko01631112007-12-16 17:20:38 +00003206
3207static struct alias **atab; // [ATABSIZE];
3208#define INIT_G_alias() do { \
3209 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3210} while (0)
3211
Eric Andersen2870d962001-07-02 17:27:21 +00003212
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003213static struct alias **
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02003214__lookupalias(const char *name)
3215{
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003216 unsigned int hashval;
3217 struct alias **app;
3218 const char *p;
3219 unsigned int ch;
3220
3221 p = name;
3222
3223 ch = (unsigned char)*p;
3224 hashval = ch << 4;
3225 while (ch) {
3226 hashval += ch;
3227 ch = (unsigned char)*++p;
3228 }
3229 app = &atab[hashval % ATABSIZE];
3230
3231 for (; *app; app = &(*app)->next) {
3232 if (strcmp(name, (*app)->name) == 0) {
3233 break;
3234 }
3235 }
3236
3237 return app;
3238}
3239
3240static struct alias *
3241lookupalias(const char *name, int check)
3242{
3243 struct alias *ap = *__lookupalias(name);
3244
3245 if (check && ap && (ap->flag & ALIASINUSE))
3246 return NULL;
3247 return ap;
3248}
3249
3250static struct alias *
3251freealias(struct alias *ap)
3252{
3253 struct alias *next;
3254
3255 if (ap->flag & ALIASINUSE) {
3256 ap->flag |= ALIASDEAD;
3257 return ap;
3258 }
3259
3260 next = ap->next;
3261 free(ap->name);
3262 free(ap->val);
3263 free(ap);
3264 return next;
3265}
Eric Andersencb57d552001-06-28 07:25:16 +00003266
Eric Andersenc470f442003-07-28 09:56:35 +00003267static void
3268setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003269{
3270 struct alias *ap, **app;
3271
3272 app = __lookupalias(name);
3273 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003274 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003275 if (ap) {
3276 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003277 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003278 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003279 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003280 ap->flag &= ~ALIASDEAD;
3281 } else {
3282 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003283 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003284 ap->name = ckstrdup(name);
3285 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003286 /*ap->flag = 0; - ckzalloc did it */
3287 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003288 *app = ap;
3289 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003290 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003291}
3292
Eric Andersenc470f442003-07-28 09:56:35 +00003293static int
3294unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003295{
Eric Andersencb57d552001-06-28 07:25:16 +00003296 struct alias **app;
3297
3298 app = __lookupalias(name);
3299
3300 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003301 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003302 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003303 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003304 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003305 }
3306
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003307 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003308}
3309
Eric Andersenc470f442003-07-28 09:56:35 +00003310static void
3311rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003312{
Eric Andersencb57d552001-06-28 07:25:16 +00003313 struct alias *ap, **app;
3314 int i;
3315
Denis Vlasenkob012b102007-02-19 22:43:01 +00003316 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003317 for (i = 0; i < ATABSIZE; i++) {
3318 app = &atab[i];
3319 for (ap = *app; ap; ap = *app) {
3320 *app = freealias(*app);
3321 if (ap == *app) {
3322 app = &ap->next;
3323 }
3324 }
3325 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003326 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003327}
3328
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003329static void
3330printalias(const struct alias *ap)
3331{
3332 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3333}
3334
Eric Andersencb57d552001-06-28 07:25:16 +00003335/*
3336 * TODO - sort output
3337 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003338static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003339aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003340{
3341 char *n, *v;
3342 int ret = 0;
3343 struct alias *ap;
3344
Denis Vlasenko68404f12008-03-17 09:00:54 +00003345 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003346 int i;
3347
Denis Vlasenko68404f12008-03-17 09:00:54 +00003348 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003349 for (ap = atab[i]; ap; ap = ap->next) {
3350 printalias(ap);
3351 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003352 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003353 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003354 }
3355 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003356 v = strchr(n+1, '=');
3357 if (v == NULL) { /* n+1: funny ksh stuff */
3358 ap = *__lookupalias(n);
3359 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003360 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003361 ret = 1;
3362 } else
3363 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003364 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003365 *v++ = '\0';
3366 setalias(n, v);
3367 }
3368 }
3369
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003370 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003371}
3372
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003373static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003374unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003375{
3376 int i;
3377
Denys Vlasenko6c149f42017-04-12 21:31:32 +02003378 while (nextopt("a") != '\0') {
3379 rmaliases();
3380 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003381 }
3382 for (i = 0; *argptr; argptr++) {
3383 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003384 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003385 i = 1;
3386 }
3387 }
3388
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003389 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003390}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003391
Denis Vlasenko131ae172007-02-18 13:00:19 +00003392#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003393
Eric Andersenc470f442003-07-28 09:56:35 +00003394
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003395/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003396#define FORK_FG 0
3397#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003398#define FORK_NOJOB 2
3399
3400/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003401#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3402#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3403#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003404#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003405
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003406/*
3407 * A job structure contains information about a job. A job is either a
3408 * single process or a set of processes contained in a pipeline. In the
3409 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3410 * array of pids.
3411 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003412struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003413 pid_t ps_pid; /* process id */
3414 int ps_status; /* last process status from wait() */
3415 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003416};
3417
3418struct job {
3419 struct procstat ps0; /* status of process */
3420 struct procstat *ps; /* status or processes when more than one */
3421#if JOBS
3422 int stopstatus; /* status of a stopped job */
3423#endif
Denys Vlasenko4c179372017-01-11 18:44:15 +01003424 unsigned nprocs; /* number of processes */
3425
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003426#define JOBRUNNING 0 /* at least one proc running */
3427#define JOBSTOPPED 1 /* all procs are stopped */
3428#define JOBDONE 2 /* all procs are completed */
Denys Vlasenko4c179372017-01-11 18:44:15 +01003429 unsigned
3430 state: 8,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003431#if JOBS
3432 sigint: 1, /* job was killed by SIGINT */
3433 jobctl: 1, /* job running under job control */
3434#endif
3435 waited: 1, /* true if this entry has been waited for */
3436 used: 1, /* true if this entry is in used */
3437 changed: 1; /* true if status has changed */
3438 struct job *prev_job; /* previous job */
3439};
3440
Denis Vlasenko68404f12008-03-17 09:00:54 +00003441static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003442static int forkshell(struct job *, union node *, int);
3443static int waitforjob(struct job *);
3444
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003445#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003446enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003447#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003448#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003449static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003450static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003451#endif
3452
3453/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003454 * Ignore a signal.
3455 */
3456static void
3457ignoresig(int signo)
3458{
3459 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3460 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3461 /* No, need to do it */
3462 signal(signo, SIG_IGN);
3463 }
3464 sigmode[signo - 1] = S_HARD_IGN;
3465}
3466
3467/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003468 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003469 */
3470static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003471signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003472{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003473 if (signo == SIGCHLD) {
3474 got_sigchld = 1;
3475 if (!trap[SIGCHLD])
3476 return;
3477 }
3478
Denis Vlasenko4b875702009-03-19 13:30:04 +00003479 gotsig[signo - 1] = 1;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003480 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003481
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003482 if (signo == SIGINT && !trap[SIGINT]) {
3483 if (!suppress_int) {
3484 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003485 raise_interrupt(); /* does not return */
3486 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003487 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003488 }
3489}
3490
3491/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003492 * Set the signal handler for the specified signal. The routine figures
3493 * out what it should be set to.
3494 */
3495static void
3496setsignal(int signo)
3497{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003498 char *t;
3499 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003500 struct sigaction act;
3501
3502 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003503 new_act = S_DFL;
3504 if (t != NULL) { /* trap for this sig is set */
3505 new_act = S_CATCH;
3506 if (t[0] == '\0') /* trap is "": ignore this sig */
3507 new_act = S_IGN;
3508 }
3509
3510 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003511 switch (signo) {
3512 case SIGINT:
3513 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003514 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003515 break;
3516 case SIGQUIT:
3517#if DEBUG
3518 if (debug)
3519 break;
3520#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003521 /* man bash:
3522 * "In all cases, bash ignores SIGQUIT. Non-builtin
3523 * commands run by bash have signal handlers
3524 * set to the values inherited by the shell
3525 * from its parent". */
3526 new_act = S_IGN;
3527 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003528 case SIGTERM:
3529 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003530 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003531 break;
3532#if JOBS
3533 case SIGTSTP:
3534 case SIGTTOU:
3535 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003536 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003537 break;
3538#endif
3539 }
3540 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003541//TODO: if !rootshell, we reset SIGQUIT to DFL,
3542//whereas we have to restore it to what shell got on entry
3543//from the parent. See comment above
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003544
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003545 if (signo == SIGCHLD)
3546 new_act = S_CATCH;
3547
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003548 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003549 cur_act = *t;
3550 if (cur_act == 0) {
3551 /* current setting is not yet known */
3552 if (sigaction(signo, NULL, &act)) {
3553 /* pretend it worked; maybe we should give a warning,
3554 * but other shells don't. We don't alter sigmode,
3555 * so we retry every time.
3556 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003557 return;
3558 }
3559 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003560 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003561 if (mflag
3562 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3563 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003564 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003565 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003566 }
3567 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003568 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003569 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003570
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003571 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003572 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003573 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003574 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003575 break;
3576 case S_IGN:
3577 act.sa_handler = SIG_IGN;
3578 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003579 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003580
3581 /* flags and mask matter only if !DFL and !IGN, but we do it
3582 * for all cases for more deterministic behavior:
3583 */
3584 act.sa_flags = 0;
3585 sigfillset(&act.sa_mask);
3586
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003587 sigaction_set(signo, &act);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003588
3589 *t = new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003590}
3591
3592/* mode flags for set_curjob */
3593#define CUR_DELETE 2
3594#define CUR_RUNNING 1
3595#define CUR_STOPPED 0
3596
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003597#if JOBS
3598/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003599static int initialpgrp; //references:2
3600static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003601#endif
3602/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003603static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003604/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003605static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003606/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003607static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003608/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003609static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003610
Denys Vlasenko098b7132017-01-11 19:59:03 +01003611#if 0
3612/* Bash has a feature: it restores termios after a successful wait for
3613 * a foreground job which had at least one stopped or sigkilled member.
3614 * The probable rationale is that SIGSTOP and SIGKILL can preclude task from
3615 * properly restoring tty state. Should we do this too?
3616 * A reproducer: ^Z an interactive python:
3617 *
3618 * # python
3619 * Python 2.7.12 (...)
3620 * >>> ^Z
3621 * { python leaves tty in -icanon -echo state. We do survive that... }
3622 * [1]+ Stopped python
3623 * { ...however, next program (python #2) does not survive it well: }
3624 * # python
3625 * Python 2.7.12 (...)
3626 * >>> Traceback (most recent call last):
3627 * { above, I typed "qwerty<CR>", but -echo state is still in effect }
3628 * File "<stdin>", line 1, in <module>
3629 * NameError: name 'qwerty' is not defined
3630 *
3631 * The implementation below is modeled on bash code and seems to work.
3632 * However, I'm not sure we should do this. For one: what if I'd fg
3633 * the stopped python instead? It'll be confused by "restored" tty state.
3634 */
3635static struct termios shell_tty_info;
3636static void
3637get_tty_state(void)
3638{
3639 if (rootshell && ttyfd >= 0)
3640 tcgetattr(ttyfd, &shell_tty_info);
3641}
3642static void
3643set_tty_state(void)
3644{
3645 /* if (rootshell) - caller ensures this */
3646 if (ttyfd >= 0)
3647 tcsetattr(ttyfd, TCSADRAIN, &shell_tty_info);
3648}
3649static int
3650job_signal_status(struct job *jp)
3651{
3652 int status;
3653 unsigned i;
3654 struct procstat *ps = jp->ps;
3655 for (i = 0; i < jp->nprocs; i++) {
3656 status = ps[i].ps_status;
3657 if (WIFSIGNALED(status) || WIFSTOPPED(status))
3658 return status;
3659 }
3660 return 0;
3661}
3662static void
3663restore_tty_if_stopped_or_signaled(struct job *jp)
3664{
3665//TODO: check what happens if we come from waitforjob() in expbackq()
3666 if (rootshell) {
3667 int s = job_signal_status(jp);
3668 if (s) /* WIFSIGNALED(s) || WIFSTOPPED(s) */
3669 set_tty_state();
3670 }
3671}
3672#else
3673# define get_tty_state() ((void)0)
3674# define restore_tty_if_stopped_or_signaled(jp) ((void)0)
3675#endif
3676
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003677static void
3678set_curjob(struct job *jp, unsigned mode)
3679{
3680 struct job *jp1;
3681 struct job **jpp, **curp;
3682
3683 /* first remove from list */
3684 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003685 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003686 jp1 = *jpp;
3687 if (jp1 == jp)
3688 break;
3689 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003690 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003691 *jpp = jp1->prev_job;
3692
3693 /* Then re-insert in correct position */
3694 jpp = curp;
3695 switch (mode) {
3696 default:
3697#if DEBUG
3698 abort();
3699#endif
3700 case CUR_DELETE:
3701 /* job being deleted */
3702 break;
3703 case CUR_RUNNING:
3704 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003705 * put after all stopped jobs.
3706 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003707 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003708 jp1 = *jpp;
3709#if JOBS
3710 if (!jp1 || jp1->state != JOBSTOPPED)
3711#endif
3712 break;
3713 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003714 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003715 /* FALLTHROUGH */
3716#if JOBS
3717 case CUR_STOPPED:
3718#endif
3719 /* newly stopped job - becomes curjob */
3720 jp->prev_job = *jpp;
3721 *jpp = jp;
3722 break;
3723 }
3724}
3725
3726#if JOBS || DEBUG
3727static int
3728jobno(const struct job *jp)
3729{
3730 return jp - jobtab + 1;
3731}
3732#endif
3733
3734/*
3735 * Convert a job name to a job structure.
3736 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003737#if !JOBS
3738#define getjob(name, getctl) getjob(name)
3739#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003740static struct job *
3741getjob(const char *name, int getctl)
3742{
3743 struct job *jp;
3744 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003745 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003746 unsigned num;
3747 int c;
3748 const char *p;
3749 char *(*match)(const char *, const char *);
3750
3751 jp = curjob;
3752 p = name;
3753 if (!p)
3754 goto currentjob;
3755
3756 if (*p != '%')
3757 goto err;
3758
3759 c = *++p;
3760 if (!c)
3761 goto currentjob;
3762
3763 if (!p[1]) {
3764 if (c == '+' || c == '%') {
3765 currentjob:
3766 err_msg = "No current job";
3767 goto check;
3768 }
3769 if (c == '-') {
3770 if (jp)
3771 jp = jp->prev_job;
3772 err_msg = "No previous job";
3773 check:
3774 if (!jp)
3775 goto err;
3776 goto gotit;
3777 }
3778 }
3779
3780 if (is_number(p)) {
3781 num = atoi(p);
Denys Vlasenko46a45ce2016-09-29 01:10:08 +02003782 if (num > 0 && num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003783 jp = jobtab + num - 1;
3784 if (jp->used)
3785 goto gotit;
3786 goto err;
3787 }
3788 }
3789
3790 match = prefix;
3791 if (*p == '?') {
3792 match = strstr;
3793 p++;
3794 }
3795
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003796 found = NULL;
3797 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003798 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003799 if (found)
3800 goto err;
3801 found = jp;
3802 err_msg = "%s: ambiguous";
3803 }
3804 jp = jp->prev_job;
3805 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003806 if (!found)
3807 goto err;
3808 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003809
3810 gotit:
3811#if JOBS
3812 err_msg = "job %s not created under job control";
3813 if (getctl && jp->jobctl == 0)
3814 goto err;
3815#endif
3816 return jp;
3817 err:
3818 ash_msg_and_raise_error(err_msg, name);
3819}
3820
3821/*
3822 * Mark a job structure as unused.
3823 */
3824static void
3825freejob(struct job *jp)
3826{
3827 struct procstat *ps;
3828 int i;
3829
3830 INT_OFF;
3831 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003832 if (ps->ps_cmd != nullstr)
3833 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003834 }
3835 if (jp->ps != &jp->ps0)
3836 free(jp->ps);
3837 jp->used = 0;
3838 set_curjob(jp, CUR_DELETE);
3839 INT_ON;
3840}
3841
3842#if JOBS
3843static void
3844xtcsetpgrp(int fd, pid_t pgrp)
3845{
3846 if (tcsetpgrp(fd, pgrp))
Ron Yorstonbe366e52017-07-27 13:53:39 +01003847 ash_msg_and_raise_perror("can't set tty process group");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003848}
3849
3850/*
3851 * Turn job control on and off.
3852 *
3853 * Note: This code assumes that the third arg to ioctl is a character
3854 * pointer, which is true on Berkeley systems but not System V. Since
3855 * System V doesn't have job control yet, this isn't a problem now.
3856 *
3857 * Called with interrupts off.
3858 */
3859static void
3860setjobctl(int on)
3861{
3862 int fd;
3863 int pgrp;
3864
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003865 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003866 return;
3867 if (on) {
3868 int ofd;
3869 ofd = fd = open(_PATH_TTY, O_RDWR);
3870 if (fd < 0) {
3871 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3872 * That sometimes helps to acquire controlling tty.
3873 * Obviously, a workaround for bugs when someone
3874 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003875 fd = 2;
3876 while (!isatty(fd))
3877 if (--fd < 0)
3878 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003879 }
Denys Vlasenko64774602016-10-26 15:24:30 +02003880 /* fd is a tty at this point */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003881 fd = fcntl(fd, F_DUPFD, 10);
Denys Vlasenko10ad6222017-04-17 16:13:32 +02003882 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, don't */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003883 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003884 if (fd < 0)
Denys Vlasenko64774602016-10-26 15:24:30 +02003885 goto out; /* F_DUPFD failed */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003886 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003887 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003888 pgrp = tcgetpgrp(fd);
3889 if (pgrp < 0) {
3890 out:
3891 ash_msg("can't access tty; job control turned off");
3892 mflag = on = 0;
3893 goto close;
3894 }
3895 if (pgrp == getpgrp())
3896 break;
3897 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003898 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003899 initialpgrp = pgrp;
3900
3901 setsignal(SIGTSTP);
3902 setsignal(SIGTTOU);
3903 setsignal(SIGTTIN);
3904 pgrp = rootpid;
3905 setpgid(0, pgrp);
3906 xtcsetpgrp(fd, pgrp);
3907 } else {
3908 /* turning job control off */
3909 fd = ttyfd;
3910 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003911 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003912 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003913 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003914 setpgid(0, pgrp);
3915 setsignal(SIGTSTP);
3916 setsignal(SIGTTOU);
3917 setsignal(SIGTTIN);
3918 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003919 if (fd >= 0)
3920 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003921 fd = -1;
3922 }
3923 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003924 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003925}
3926
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003927static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003928killcmd(int argc, char **argv)
3929{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003930 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003931 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003932 do {
3933 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003934 /*
3935 * "kill %N" - job kill
3936 * Converting to pgrp / pid kill
3937 */
3938 struct job *jp;
3939 char *dst;
3940 int j, n;
3941
3942 jp = getjob(argv[i], 0);
3943 /*
3944 * In jobs started under job control, we signal
3945 * entire process group by kill -PGRP_ID.
3946 * This happens, f.e., in interactive shell.
3947 *
3948 * Otherwise, we signal each child via
3949 * kill PID1 PID2 PID3.
3950 * Testcases:
3951 * sh -c 'sleep 1|sleep 1 & kill %1'
3952 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3953 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3954 */
3955 n = jp->nprocs; /* can't be 0 (I hope) */
3956 if (jp->jobctl)
3957 n = 1;
3958 dst = alloca(n * sizeof(int)*4);
3959 argv[i] = dst;
3960 for (j = 0; j < n; j++) {
3961 struct procstat *ps = &jp->ps[j];
3962 /* Skip non-running and not-stopped members
3963 * (i.e. dead members) of the job
3964 */
3965 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3966 continue;
3967 /*
3968 * kill_main has matching code to expect
3969 * leading space. Needed to not confuse
3970 * negative pids with "kill -SIGNAL_NO" syntax
3971 */
3972 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3973 }
3974 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003975 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003976 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003977 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003978 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003979}
3980
3981static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01003982showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003983{
Denys Vlasenko285ad152009-12-04 23:02:27 +01003984 struct procstat *ps;
3985 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003986
Denys Vlasenko285ad152009-12-04 23:02:27 +01003987 psend = jp->ps + jp->nprocs;
3988 for (ps = jp->ps + 1; ps < psend; ps++)
3989 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003990 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003991 flush_stdout_stderr();
3992}
3993
3994
3995static int
3996restartjob(struct job *jp, int mode)
3997{
3998 struct procstat *ps;
3999 int i;
4000 int status;
4001 pid_t pgid;
4002
4003 INT_OFF;
4004 if (jp->state == JOBDONE)
4005 goto out;
4006 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004007 pgid = jp->ps[0].ps_pid;
Denys Vlasenko098b7132017-01-11 19:59:03 +01004008 if (mode == FORK_FG) {
4009 get_tty_state();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004010 xtcsetpgrp(ttyfd, pgid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01004011 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004012 killpg(pgid, SIGCONT);
4013 ps = jp->ps;
4014 i = jp->nprocs;
4015 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004016 if (WIFSTOPPED(ps->ps_status)) {
4017 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004018 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004019 ps++;
4020 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004021 out:
4022 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
4023 INT_ON;
4024 return status;
4025}
4026
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004027static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004028fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004029{
4030 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004031 int mode;
4032 int retval;
4033
4034 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
4035 nextopt(nullstr);
4036 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004037 do {
4038 jp = getjob(*argv, 1);
4039 if (mode == FORK_BG) {
4040 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004041 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004042 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004043 out1str(jp->ps[0].ps_cmd);
4044 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004045 retval = restartjob(jp, mode);
4046 } while (*argv && *++argv);
4047 return retval;
4048}
4049#endif
4050
4051static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02004052sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004053{
4054 int col;
4055 int st;
4056
4057 col = 0;
4058 if (!WIFEXITED(status)) {
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004059#if JOBS
4060 if (WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004061 st = WSTOPSIG(status);
4062 else
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004063#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004064 st = WTERMSIG(status);
4065 if (sigonly) {
4066 if (st == SIGINT || st == SIGPIPE)
4067 goto out;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004068#if JOBS
4069 if (WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004070 goto out;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004071#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004072 }
4073 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01004074//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004075 col = fmtstr(s, 32, strsignal(st));
4076 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004077 strcpy(s + col, " (core dumped)");
4078 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004079 }
4080 } else if (!sigonly) {
4081 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004082 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004083 }
4084 out:
4085 return col;
4086}
4087
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004088static int
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004089wait_block_or_sig(int *status)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004090{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004091 int pid;
4092
4093 do {
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004094 sigset_t mask;
4095
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004096 /* Poll all children for changes in their state */
4097 got_sigchld = 0;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004098 /* if job control is active, accept stopped processes too */
4099 pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004100 if (pid != 0)
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004101 break; /* Error (e.g. EINTR, ECHILD) or pid */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004102
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004103 /* Children exist, but none are ready. Sleep until interesting signal */
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004104#if 1
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004105 sigfillset(&mask);
4106 sigprocmask(SIG_SETMASK, &mask, &mask);
4107 while (!got_sigchld && !pending_sig)
4108 sigsuspend(&mask);
4109 sigprocmask(SIG_SETMASK, &mask, NULL);
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004110#else /* unsafe: a signal can set pending_sig after check, but before pause() */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004111 while (!got_sigchld && !pending_sig)
4112 pause();
4113#endif
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004114
4115 /* If it was SIGCHLD, poll children again */
4116 } while (got_sigchld);
4117
4118 return pid;
4119}
4120
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004121#define DOWAIT_NONBLOCK 0
4122#define DOWAIT_BLOCK 1
4123#define DOWAIT_BLOCK_OR_SIG 2
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004124
4125static int
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004126dowait(int block, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004127{
4128 int pid;
4129 int status;
4130 struct job *jp;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004131 struct job *thisjob = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004132
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004133 TRACE(("dowait(0x%x) called\n", block));
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00004134
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004135 /* It's wrong to call waitpid() outside of INT_OFF region:
4136 * signal can arrive just after syscall return and handler can
4137 * longjmp away, losing stop/exit notification processing.
4138 * Thus, for "jobs" builtin, and for waiting for a fg job,
4139 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4140 *
4141 * However, for "wait" builtin it is wrong to simply call waitpid()
4142 * in INT_OFF region: "wait" needs to wait for any running job
4143 * to change state, but should exit on any trap too.
4144 * In INT_OFF region, a signal just before syscall entry can set
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004145 * pending_sig variables, but we can't check them, and we would
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004146 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004147 *
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004148 * Because of this, we run inside INT_OFF, but use a special routine
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004149 * which combines waitpid() and sigsuspend().
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004150 * This is the reason why we need to have a handler for SIGCHLD:
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004151 * SIG_DFL handler does not wake sigsuspend().
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004152 */
4153 INT_OFF;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004154 if (block == DOWAIT_BLOCK_OR_SIG) {
4155 pid = wait_block_or_sig(&status);
4156 } else {
4157 int wait_flags = 0;
4158 if (block == DOWAIT_NONBLOCK)
4159 wait_flags = WNOHANG;
4160 /* if job control is active, accept stopped processes too */
4161 if (doing_jobctl)
4162 wait_flags |= WUNTRACED;
4163 /* NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004164 pid = waitpid(-1, &status, wait_flags);
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004165 }
Denis Vlasenkob21f3792009-03-19 23:09:58 +00004166 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4167 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004168 if (pid <= 0)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004169 goto out;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004170
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004171 thisjob = NULL;
4172 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004173 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004174 struct procstat *ps;
4175 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004176 if (jp->state == JOBDONE)
4177 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004178 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004179 ps = jp->ps;
4180 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004181 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004182 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004183 TRACE(("Job %d: changing status of proc %d "
4184 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01004185 jobno(jp), pid, ps->ps_status, status));
4186 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004187 thisjob = jp;
4188 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004189 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004190 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004191#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004192 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004193 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004194 if (WIFSTOPPED(ps->ps_status)) {
4195 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004196 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004197 }
4198#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004199 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004200 if (!thisjob)
4201 continue;
4202
4203 /* Found the job where one of its processes changed its state.
4204 * Is there at least one live and running process in this job? */
4205 if (jobstate != JOBRUNNING) {
4206 /* No. All live processes in the job are stopped
4207 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4208 */
4209 thisjob->changed = 1;
4210 if (thisjob->state != jobstate) {
4211 TRACE(("Job %d: changing state from %d to %d\n",
4212 jobno(thisjob), thisjob->state, jobstate));
4213 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004214#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004215 if (jobstate == JOBSTOPPED)
4216 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004217#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004218 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004219 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004220 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004221 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004222 /* The process wasn't found in job list */
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004223#if JOBS
4224 if (!WIFSTOPPED(status))
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004225 jobless--;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004226#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004227 out:
4228 INT_ON;
4229
4230 if (thisjob && thisjob == job) {
4231 char s[48 + 1];
4232 int len;
4233
Denys Vlasenko9c541002015-10-07 15:44:36 +02004234 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004235 if (len) {
4236 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004237 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004238 out2str(s);
4239 }
4240 }
4241 return pid;
4242}
4243
4244#if JOBS
4245static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004246showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004247{
4248 struct procstat *ps;
4249 struct procstat *psend;
4250 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004251 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004252 char s[16 + 16 + 48];
4253 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004254
4255 ps = jp->ps;
4256
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004257 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004258 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004259 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004260 return;
4261 }
4262
4263 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004264 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004265
4266 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004267 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004268 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004269 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004270
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004271 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004272 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004273
4274 psend = ps + jp->nprocs;
4275
4276 if (jp->state == JOBRUNNING) {
4277 strcpy(s + col, "Running");
4278 col += sizeof("Running") - 1;
4279 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004280 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004281 if (jp->state == JOBSTOPPED)
4282 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004283 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004284 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004285 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004286
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004287 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4288 * or prints several "PID | <cmdN>" lines,
4289 * depending on SHOW_PIDS bit.
4290 * We do not print status of individual processes
4291 * between PID and <cmdN>. bash does it, but not very well:
4292 * first line shows overall job status, not process status,
4293 * making it impossible to know 1st process status.
4294 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004295 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004296 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004297 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004298 s[0] = '\0';
4299 col = 33;
4300 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004301 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004302 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004303 fprintf(out, "%s%*c%s%s",
4304 s,
4305 33 - col >= 0 ? 33 - col : 0, ' ',
4306 ps == jp->ps ? "" : "| ",
4307 ps->ps_cmd
4308 );
4309 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004310 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004311
4312 jp->changed = 0;
4313
4314 if (jp->state == JOBDONE) {
4315 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4316 freejob(jp);
4317 }
4318}
4319
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004320/*
4321 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4322 * statuses have changed since the last call to showjobs.
4323 */
4324static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004325showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004326{
4327 struct job *jp;
4328
Denys Vlasenko883cea42009-07-11 15:31:59 +02004329 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004330
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004331 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004332 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004333 continue;
4334
4335 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004336 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004337 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004338 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004339 }
4340}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004341
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004342static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004343jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004344{
4345 int mode, m;
4346
4347 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004348 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004349 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004350 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004351 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004352 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004353 }
4354
4355 argv = argptr;
4356 if (*argv) {
4357 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004358 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004359 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004360 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004361 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004362 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004363
4364 return 0;
4365}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004366#endif /* JOBS */
4367
Michael Abbott359da5e2009-12-04 23:03:29 +01004368/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004369static int
4370getstatus(struct job *job)
4371{
4372 int status;
4373 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004374 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004375
Michael Abbott359da5e2009-12-04 23:03:29 +01004376 /* Fetch last member's status */
4377 ps = job->ps + job->nprocs - 1;
4378 status = ps->ps_status;
4379 if (pipefail) {
4380 /* "set -o pipefail" mode: use last _nonzero_ status */
4381 while (status == 0 && --ps >= job->ps)
4382 status = ps->ps_status;
4383 }
4384
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004385 retval = WEXITSTATUS(status);
4386 if (!WIFEXITED(status)) {
4387#if JOBS
4388 retval = WSTOPSIG(status);
4389 if (!WIFSTOPPED(status))
4390#endif
4391 {
4392 /* XXX: limits number of signals */
4393 retval = WTERMSIG(status);
4394#if JOBS
4395 if (retval == SIGINT)
4396 job->sigint = 1;
4397#endif
4398 }
4399 retval += 128;
4400 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004401 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004402 jobno(job), job->nprocs, status, retval));
4403 return retval;
4404}
4405
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004406static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004407waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004408{
4409 struct job *job;
4410 int retval;
4411 struct job *jp;
4412
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004413 nextopt(nullstr);
4414 retval = 0;
4415
4416 argv = argptr;
4417 if (!*argv) {
4418 /* wait for all jobs */
4419 for (;;) {
4420 jp = curjob;
4421 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004422 if (!jp) /* no running procs */
4423 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004424 if (jp->state == JOBRUNNING)
4425 break;
4426 jp->waited = 1;
4427 jp = jp->prev_job;
4428 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004429 /* man bash:
4430 * "When bash is waiting for an asynchronous command via
4431 * the wait builtin, the reception of a signal for which a trap
4432 * has been set will cause the wait builtin to return immediately
4433 * with an exit status greater than 128, immediately after which
4434 * the trap is executed."
Denys Vlasenko69188112016-10-27 20:18:18 +02004435 */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004436 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004437 /* if child sends us a signal *and immediately exits*,
4438 * dowait() returns pid > 0. Check this case,
4439 * not "if (dowait() < 0)"!
4440 */
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004441 if (pending_sig)
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004442 goto sigout;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004443 }
4444 }
4445
4446 retval = 127;
4447 do {
4448 if (**argv != '%') {
4449 pid_t pid = number(*argv);
4450 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004451 while (1) {
4452 if (!job)
4453 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004454 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004455 break;
4456 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004457 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004458 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004459 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004460 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004461 /* loop until process terminated or stopped */
Denys Vlasenko69188112016-10-27 20:18:18 +02004462 while (job->state == JOBRUNNING) {
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004463 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004464 if (pending_sig)
4465 goto sigout;
Denys Vlasenko69188112016-10-27 20:18:18 +02004466 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004467 job->waited = 1;
4468 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004469 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004470 } while (*++argv);
4471
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004472 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004473 return retval;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004474 sigout:
4475 retval = 128 + pending_sig;
4476 return retval;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004477}
4478
4479static struct job *
4480growjobtab(void)
4481{
4482 size_t len;
4483 ptrdiff_t offset;
4484 struct job *jp, *jq;
4485
4486 len = njobs * sizeof(*jp);
4487 jq = jobtab;
4488 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4489
4490 offset = (char *)jp - (char *)jq;
4491 if (offset) {
4492 /* Relocate pointers */
4493 size_t l = len;
4494
4495 jq = (struct job *)((char *)jq + l);
4496 while (l) {
4497 l -= sizeof(*jp);
4498 jq--;
4499#define joff(p) ((struct job *)((char *)(p) + l))
4500#define jmove(p) (p) = (void *)((char *)(p) + offset)
4501 if (joff(jp)->ps == &jq->ps0)
4502 jmove(joff(jp)->ps);
4503 if (joff(jp)->prev_job)
4504 jmove(joff(jp)->prev_job);
4505 }
4506 if (curjob)
4507 jmove(curjob);
4508#undef joff
4509#undef jmove
4510 }
4511
4512 njobs += 4;
4513 jobtab = jp;
4514 jp = (struct job *)((char *)jp + len);
4515 jq = jp + 3;
4516 do {
4517 jq->used = 0;
4518 } while (--jq >= jp);
4519 return jp;
4520}
4521
4522/*
4523 * Return a new job structure.
4524 * Called with interrupts off.
4525 */
4526static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004527makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004528{
4529 int i;
4530 struct job *jp;
4531
4532 for (i = njobs, jp = jobtab; ; jp++) {
4533 if (--i < 0) {
4534 jp = growjobtab();
4535 break;
4536 }
4537 if (jp->used == 0)
4538 break;
4539 if (jp->state != JOBDONE || !jp->waited)
4540 continue;
4541#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004542 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004543 continue;
4544#endif
4545 freejob(jp);
4546 break;
4547 }
4548 memset(jp, 0, sizeof(*jp));
4549#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004550 /* jp->jobctl is a bitfield.
Denys Vlasenko098b7132017-01-11 19:59:03 +01004551 * "jp->jobctl |= doing_jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004552 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004553 jp->jobctl = 1;
4554#endif
4555 jp->prev_job = curjob;
4556 curjob = jp;
4557 jp->used = 1;
4558 jp->ps = &jp->ps0;
4559 if (nprocs > 1) {
4560 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4561 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004562 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004563 jobno(jp)));
4564 return jp;
4565}
4566
4567#if JOBS
4568/*
4569 * Return a string identifying a command (to be printed by the
4570 * jobs command).
4571 */
4572static char *cmdnextc;
4573
4574static void
4575cmdputs(const char *s)
4576{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004577 static const char vstype[VSTYPE + 1][3] = {
4578 "", "}", "-", "+", "?", "=",
4579 "%", "%%", "#", "##"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004580 IF_BASH_SUBSTR(, ":")
4581 IF_BASH_PATTERN_SUBST(, "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004582 };
4583
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004584 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004585 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004586 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004587 unsigned char c;
4588 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004589 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004590
Denys Vlasenko46a14772009-12-10 21:27:13 +01004591 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004592 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4593 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004594 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004595 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004596 switch (c) {
4597 case CTLESC:
4598 c = *p++;
4599 break;
4600 case CTLVAR:
4601 subtype = *p++;
4602 if ((subtype & VSTYPE) == VSLENGTH)
4603 str = "${#";
4604 else
4605 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004606 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004607 case CTLENDVAR:
4608 str = "\"}" + !(quoted & 1);
4609 quoted >>= 1;
4610 subtype = 0;
4611 goto dostr;
4612 case CTLBACKQ:
4613 str = "$(...)";
4614 goto dostr;
Denys Vlasenko0b883582016-12-23 16:49:07 +01004615#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004616 case CTLARI:
4617 str = "$((";
4618 goto dostr;
4619 case CTLENDARI:
4620 str = "))";
4621 goto dostr;
4622#endif
4623 case CTLQUOTEMARK:
4624 quoted ^= 1;
4625 c = '"';
4626 break;
4627 case '=':
4628 if (subtype == 0)
4629 break;
4630 if ((subtype & VSTYPE) != VSNORMAL)
4631 quoted <<= 1;
4632 str = vstype[subtype & VSTYPE];
4633 if (subtype & VSNUL)
4634 c = ':';
4635 else
4636 goto checkstr;
4637 break;
4638 case '\'':
4639 case '\\':
4640 case '"':
4641 case '$':
4642 /* These can only happen inside quotes */
4643 cc[0] = c;
4644 str = cc;
4645 c = '\\';
4646 break;
4647 default:
4648 break;
4649 }
4650 USTPUTC(c, nextc);
4651 checkstr:
4652 if (!str)
4653 continue;
4654 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004655 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004656 USTPUTC(c, nextc);
4657 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004658 } /* while *p++ not NUL */
4659
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004660 if (quoted & 1) {
4661 USTPUTC('"', nextc);
4662 }
4663 *nextc = 0;
4664 cmdnextc = nextc;
4665}
4666
4667/* cmdtxt() and cmdlist() call each other */
4668static void cmdtxt(union node *n);
4669
4670static void
4671cmdlist(union node *np, int sep)
4672{
4673 for (; np; np = np->narg.next) {
4674 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004675 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004676 cmdtxt(np);
4677 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004678 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004679 }
4680}
4681
4682static void
4683cmdtxt(union node *n)
4684{
4685 union node *np;
4686 struct nodelist *lp;
4687 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004688
4689 if (!n)
4690 return;
4691 switch (n->type) {
4692 default:
4693#if DEBUG
4694 abort();
4695#endif
4696 case NPIPE:
4697 lp = n->npipe.cmdlist;
4698 for (;;) {
4699 cmdtxt(lp->n);
4700 lp = lp->next;
4701 if (!lp)
4702 break;
4703 cmdputs(" | ");
4704 }
4705 break;
4706 case NSEMI:
4707 p = "; ";
4708 goto binop;
4709 case NAND:
4710 p = " && ";
4711 goto binop;
4712 case NOR:
4713 p = " || ";
4714 binop:
4715 cmdtxt(n->nbinary.ch1);
4716 cmdputs(p);
4717 n = n->nbinary.ch2;
4718 goto donode;
4719 case NREDIR:
4720 case NBACKGND:
4721 n = n->nredir.n;
4722 goto donode;
4723 case NNOT:
4724 cmdputs("!");
4725 n = n->nnot.com;
4726 donode:
4727 cmdtxt(n);
4728 break;
4729 case NIF:
4730 cmdputs("if ");
4731 cmdtxt(n->nif.test);
4732 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004733 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004734 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004735 cmdputs("; else ");
4736 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004737 } else {
4738 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004739 }
4740 p = "; fi";
4741 goto dotail;
4742 case NSUBSHELL:
4743 cmdputs("(");
4744 n = n->nredir.n;
4745 p = ")";
4746 goto dotail;
4747 case NWHILE:
4748 p = "while ";
4749 goto until;
4750 case NUNTIL:
4751 p = "until ";
4752 until:
4753 cmdputs(p);
4754 cmdtxt(n->nbinary.ch1);
4755 n = n->nbinary.ch2;
4756 p = "; done";
4757 dodo:
4758 cmdputs("; do ");
4759 dotail:
4760 cmdtxt(n);
4761 goto dotail2;
4762 case NFOR:
4763 cmdputs("for ");
4764 cmdputs(n->nfor.var);
4765 cmdputs(" in ");
4766 cmdlist(n->nfor.args, 1);
4767 n = n->nfor.body;
4768 p = "; done";
4769 goto dodo;
4770 case NDEFUN:
4771 cmdputs(n->narg.text);
4772 p = "() { ... }";
4773 goto dotail2;
4774 case NCMD:
4775 cmdlist(n->ncmd.args, 1);
4776 cmdlist(n->ncmd.redirect, 0);
4777 break;
4778 case NARG:
4779 p = n->narg.text;
4780 dotail2:
4781 cmdputs(p);
4782 break;
4783 case NHERE:
4784 case NXHERE:
4785 p = "<<...";
4786 goto dotail2;
4787 case NCASE:
4788 cmdputs("case ");
4789 cmdputs(n->ncase.expr->narg.text);
4790 cmdputs(" in ");
4791 for (np = n->ncase.cases; np; np = np->nclist.next) {
4792 cmdtxt(np->nclist.pattern);
4793 cmdputs(") ");
4794 cmdtxt(np->nclist.body);
4795 cmdputs(";; ");
4796 }
4797 p = "esac";
4798 goto dotail2;
4799 case NTO:
4800 p = ">";
4801 goto redir;
4802 case NCLOBBER:
4803 p = ">|";
4804 goto redir;
4805 case NAPPEND:
4806 p = ">>";
4807 goto redir;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004808#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00004809 case NTO2:
4810#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004811 case NTOFD:
4812 p = ">&";
4813 goto redir;
4814 case NFROM:
4815 p = "<";
4816 goto redir;
4817 case NFROMFD:
4818 p = "<&";
4819 goto redir;
4820 case NFROMTO:
4821 p = "<>";
4822 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004823 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004824 cmdputs(p);
4825 if (n->type == NTOFD || n->type == NFROMFD) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004826 cmdputs(utoa(n->ndup.dupfd));
4827 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004828 }
4829 n = n->nfile.fname;
4830 goto donode;
4831 }
4832}
4833
4834static char *
4835commandtext(union node *n)
4836{
4837 char *name;
4838
4839 STARTSTACKSTR(cmdnextc);
4840 cmdtxt(n);
4841 name = stackblock();
Denys Vlasenko6a94cee2016-10-25 17:40:25 +02004842 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004843 return ckstrdup(name);
4844}
4845#endif /* JOBS */
4846
4847/*
4848 * Fork off a subshell. If we are doing job control, give the subshell its
4849 * own process group. Jp is a job structure that the job is to be added to.
4850 * N is the command that will be evaluated by the child. Both jp and n may
4851 * be NULL. The mode parameter can be one of the following:
4852 * FORK_FG - Fork off a foreground process.
4853 * FORK_BG - Fork off a background process.
4854 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4855 * process group even if job control is on.
4856 *
4857 * When job control is turned off, background processes have their standard
4858 * input redirected to /dev/null (except for the second and later processes
4859 * in a pipeline).
4860 *
4861 * Called with interrupts off.
4862 */
4863/*
4864 * Clear traps on a fork.
4865 */
4866static void
4867clear_traps(void)
4868{
4869 char **tp;
4870
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004871 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004872 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004873 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004874 if (trap_ptr == trap)
4875 free(*tp);
4876 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004877 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004878 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004879 setsignal(tp - trap);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004880 }
4881 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004882 may_have_traps = 0;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004883 INT_ON;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004884}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004885
4886/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004887static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004888
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004889/* Called after fork(), in child */
Denys Vlasenko70392332016-10-27 02:31:55 +02004890/* jp and n are NULL when called by openhere() for heredoc support */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004891static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004892forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004893{
4894 int oldlvl;
4895
4896 TRACE(("Child shell %d\n", getpid()));
4897 oldlvl = shlvl;
4898 shlvl++;
4899
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004900 /* man bash: "Non-builtin commands run by bash have signal handlers
4901 * set to the values inherited by the shell from its parent".
4902 * Do we do it correctly? */
4903
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004904 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004905
4906 if (mode == FORK_NOJOB /* is it `xxx` ? */
4907 && n && n->type == NCMD /* is it single cmd? */
4908 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004909 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004910 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4911 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4912 ) {
4913 TRACE(("Trap hack\n"));
4914 /* Awful hack for `trap` or $(trap).
4915 *
4916 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4917 * contains an example where "trap" is executed in a subshell:
4918 *
4919 * save_traps=$(trap)
4920 * ...
4921 * eval "$save_traps"
4922 *
4923 * Standard does not say that "trap" in subshell shall print
4924 * parent shell's traps. It only says that its output
4925 * must have suitable form, but then, in the above example
4926 * (which is not supposed to be normative), it implies that.
4927 *
4928 * bash (and probably other shell) does implement it
4929 * (traps are reset to defaults, but "trap" still shows them),
4930 * but as a result, "trap" logic is hopelessly messed up:
4931 *
4932 * # trap
4933 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4934 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4935 * # true | trap <--- trap is in subshell - no output (ditto)
4936 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4937 * trap -- 'echo Ho' SIGWINCH
4938 * # echo `(trap)` <--- in subshell in subshell - output
4939 * trap -- 'echo Ho' SIGWINCH
4940 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4941 * trap -- 'echo Ho' SIGWINCH
4942 *
4943 * The rules when to forget and when to not forget traps
4944 * get really complex and nonsensical.
4945 *
4946 * Our solution: ONLY bare $(trap) or `trap` is special.
4947 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004948 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02004949 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004950 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004951 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004952 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004953#if JOBS
4954 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004955 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004956 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004957 pid_t pgrp;
4958
4959 if (jp->nprocs == 0)
4960 pgrp = getpid();
4961 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004962 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004963 /* this can fail because we are doing it in the parent also */
4964 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004965 if (mode == FORK_FG)
4966 xtcsetpgrp(ttyfd, pgrp);
4967 setsignal(SIGTSTP);
4968 setsignal(SIGTTOU);
4969 } else
4970#endif
4971 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004972 /* man bash: "When job control is not in effect,
4973 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004974 ignoresig(SIGINT);
4975 ignoresig(SIGQUIT);
4976 if (jp->nprocs == 0) {
4977 close(0);
4978 if (open(bb_dev_null, O_RDONLY) != 0)
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00004979 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004980 }
4981 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004982 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004983 if (iflag) { /* why if iflag only? */
4984 setsignal(SIGINT);
4985 setsignal(SIGTERM);
4986 }
4987 /* man bash:
4988 * "In all cases, bash ignores SIGQUIT. Non-builtin
4989 * commands run by bash have signal handlers
4990 * set to the values inherited by the shell
4991 * from its parent".
4992 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004993 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004994 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004995#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02004996 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01004997 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004998 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004999 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02005000 /* "jobs": we do not want to clear job list for it,
5001 * instead we remove only _its_ own_ job from job list.
5002 * This makes "jobs .... | cat" more useful.
5003 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005004 freejob(curjob);
5005 return;
5006 }
5007#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005008 for (jp = curjob; jp; jp = jp->prev_job)
5009 freejob(jp);
5010 jobless = 0;
5011}
5012
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00005013/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00005014#if !JOBS
5015#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
5016#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005017static void
5018forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5019{
5020 TRACE(("In parent shell: child = %d\n", pid));
5021 if (!jp) {
Denys Vlasenko70392332016-10-27 02:31:55 +02005022 /* jp is NULL when called by openhere() for heredoc support */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00005023 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
5024 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005025 jobless++;
5026 return;
5027 }
5028#if JOBS
5029 if (mode != FORK_NOJOB && jp->jobctl) {
5030 int pgrp;
5031
5032 if (jp->nprocs == 0)
5033 pgrp = pid;
5034 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01005035 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005036 /* This can fail because we are doing it in the child also */
5037 setpgid(pid, pgrp);
5038 }
5039#endif
5040 if (mode == FORK_BG) {
5041 backgndpid = pid; /* set $! */
5042 set_curjob(jp, CUR_RUNNING);
5043 }
5044 if (jp) {
5045 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01005046 ps->ps_pid = pid;
5047 ps->ps_status = -1;
5048 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005049#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005050 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01005051 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005052#endif
5053 }
5054}
5055
Denys Vlasenko70392332016-10-27 02:31:55 +02005056/* jp and n are NULL when called by openhere() for heredoc support */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005057static int
5058forkshell(struct job *jp, union node *n, int mode)
5059{
5060 int pid;
5061
5062 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5063 pid = fork();
5064 if (pid < 0) {
5065 TRACE(("Fork failed, errno=%d", errno));
5066 if (jp)
5067 freejob(jp);
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +00005068 ash_msg_and_raise_error("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005069 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02005070 if (pid == 0) {
5071 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005072 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005073 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005074 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005075 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005076 return pid;
5077}
5078
5079/*
5080 * Wait for job to finish.
5081 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005082 * Under job control we have the problem that while a child process
5083 * is running interrupts generated by the user are sent to the child
5084 * but not to the shell. This means that an infinite loop started by
5085 * an interactive user may be hard to kill. With job control turned off,
5086 * an interactive user may place an interactive program inside a loop.
5087 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005088 * these interrupts to also abort the loop. The approach we take here
5089 * is to have the shell ignore interrupt signals while waiting for a
5090 * foreground process to terminate, and then send itself an interrupt
5091 * signal if the child process was terminated by an interrupt signal.
5092 * Unfortunately, some programs want to do a bit of cleanup and then
5093 * exit on interrupt; unless these processes terminate themselves by
5094 * sending a signal to themselves (instead of calling exit) they will
5095 * confuse this approach.
5096 *
5097 * Called with interrupts off.
5098 */
5099static int
5100waitforjob(struct job *jp)
5101{
5102 int st;
5103
5104 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005105
5106 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005107 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005108 /* In non-interactive shells, we _can_ get
5109 * a keyboard signal here and be EINTRed,
5110 * but we just loop back, waiting for command to complete.
5111 *
5112 * man bash:
5113 * "If bash is waiting for a command to complete and receives
5114 * a signal for which a trap has been set, the trap
5115 * will not be executed until the command completes."
5116 *
5117 * Reality is that even if trap is not set, bash
5118 * will not act on the signal until command completes.
5119 * Try this. sleep5intoff.c:
5120 * #include <signal.h>
5121 * #include <unistd.h>
5122 * int main() {
5123 * sigset_t set;
5124 * sigemptyset(&set);
5125 * sigaddset(&set, SIGINT);
5126 * sigaddset(&set, SIGQUIT);
5127 * sigprocmask(SIG_BLOCK, &set, NULL);
5128 * sleep(5);
5129 * return 0;
5130 * }
5131 * $ bash -c './sleep5intoff; echo hi'
5132 * ^C^C^C^C <--- pressing ^C once a second
5133 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005134 * $ bash -c './sleep5intoff; echo hi'
5135 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5136 * $ _
5137 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005138 dowait(DOWAIT_BLOCK, jp);
5139 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005140 INT_ON;
5141
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005142 st = getstatus(jp);
5143#if JOBS
5144 if (jp->jobctl) {
5145 xtcsetpgrp(ttyfd, rootpid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01005146 restore_tty_if_stopped_or_signaled(jp);
5147
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005148 /*
5149 * This is truly gross.
5150 * If we're doing job control, then we did a TIOCSPGRP which
5151 * caused us (the shell) to no longer be in the controlling
5152 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
5153 * intuit from the subprocess exit status whether a SIGINT
5154 * occurred, and if so interrupt ourselves. Yuck. - mycroft
5155 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00005156 if (jp->sigint) /* TODO: do the same with all signals */
5157 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005158 }
5159 if (jp->state == JOBDONE)
5160#endif
5161 freejob(jp);
5162 return st;
5163}
5164
5165/*
5166 * return 1 if there are stopped jobs, otherwise 0
5167 */
5168static int
5169stoppedjobs(void)
5170{
5171 struct job *jp;
5172 int retval;
5173
5174 retval = 0;
5175 if (job_warning)
5176 goto out;
5177 jp = curjob;
5178 if (jp && jp->state == JOBSTOPPED) {
5179 out2str("You have stopped jobs.\n");
5180 job_warning = 2;
5181 retval++;
5182 }
5183 out:
5184 return retval;
5185}
5186
5187
Denys Vlasenko70392332016-10-27 02:31:55 +02005188/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005189 * Code for dealing with input/output redirection.
5190 */
5191
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005192#undef EMPTY
5193#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005194#define EMPTY -2 /* marks an unused slot in redirtab */
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005195#define CLOSED -3 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005196
5197/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005198 * Handle here documents. Normally we fork off a process to write the
5199 * data to a pipe. If the document is short, we can stuff the data in
5200 * the pipe without forking.
5201 */
5202/* openhere needs this forward reference */
5203static void expandhere(union node *arg, int fd);
5204static int
5205openhere(union node *redir)
5206{
5207 int pip[2];
5208 size_t len = 0;
5209
5210 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005211 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005212 if (redir->type == NHERE) {
5213 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005214 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005215 full_write(pip[1], redir->nhere.doc->narg.text, len);
5216 goto out;
5217 }
5218 }
5219 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005220 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005221 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005222 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5223 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5224 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5225 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005226 signal(SIGPIPE, SIG_DFL);
5227 if (redir->type == NHERE)
5228 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005229 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005230 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005231 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005232 }
5233 out:
5234 close(pip[1]);
5235 return pip[0];
5236}
5237
5238static int
5239openredirect(union node *redir)
5240{
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005241 struct stat sb;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005242 char *fname;
5243 int f;
5244
5245 switch (redir->nfile.type) {
Denys Vlasenko557482c2016-09-25 21:24:04 +02005246/* Can't happen, our single caller does this itself */
5247// case NTOFD:
5248// case NFROMFD:
5249// return -1;
5250 case NHERE:
5251 case NXHERE:
5252 return openhere(redir);
5253 }
5254
5255 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5256 * allocated space. Do it only when we know it is safe.
5257 */
5258 fname = redir->nfile.expfname;
5259
5260 switch (redir->nfile.type) {
5261 default:
5262#if DEBUG
5263 abort();
5264#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005265 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005266 f = open(fname, O_RDONLY);
5267 if (f < 0)
5268 goto eopen;
5269 break;
5270 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005271 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005272 if (f < 0)
5273 goto ecreate;
5274 break;
5275 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005276#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005277 case NTO2:
5278#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005279 /* Take care of noclobber mode. */
5280 if (Cflag) {
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005281 if (stat(fname, &sb) < 0) {
5282 f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5283 if (f < 0)
5284 goto ecreate;
5285 } else if (!S_ISREG(sb.st_mode)) {
5286 f = open(fname, O_WRONLY, 0666);
5287 if (f < 0)
5288 goto ecreate;
5289 if (fstat(f, &sb) < 0 && S_ISREG(sb.st_mode)) {
5290 close(f);
5291 errno = EEXIST;
5292 goto ecreate;
5293 }
5294 } else {
5295 errno = EEXIST;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005296 goto ecreate;
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005297 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005298 break;
5299 }
5300 /* FALLTHROUGH */
5301 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005302 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5303 if (f < 0)
5304 goto ecreate;
5305 break;
5306 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005307 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5308 if (f < 0)
5309 goto ecreate;
5310 break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005311 }
5312
5313 return f;
5314 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005315 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005316 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005317 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005318}
5319
5320/*
Denys Vlasenko64774602016-10-26 15:24:30 +02005321 * Copy a file descriptor to be >= 10. Throws exception on error.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005322 */
5323static int
Denys Vlasenko64774602016-10-26 15:24:30 +02005324savefd(int from)
5325{
5326 int newfd;
5327 int err;
5328
5329 newfd = fcntl(from, F_DUPFD, 10);
5330 err = newfd < 0 ? errno : 0;
5331 if (err != EBADF) {
5332 if (err)
Ron Yorstonbe366e52017-07-27 13:53:39 +01005333 ash_msg_and_raise_perror("%d", from);
Denys Vlasenko64774602016-10-26 15:24:30 +02005334 close(from);
5335 fcntl(newfd, F_SETFD, FD_CLOEXEC);
5336 }
5337
5338 return newfd;
5339}
5340static int
5341dup2_or_raise(int from, int to)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005342{
5343 int newfd;
5344
Denys Vlasenko64774602016-10-26 15:24:30 +02005345 newfd = (from != to) ? dup2(from, to) : to;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005346 if (newfd < 0) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005347 /* Happens when source fd is not open: try "echo >&99" */
Ron Yorstonbe366e52017-07-27 13:53:39 +01005348 ash_msg_and_raise_perror("%d", from);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005349 }
5350 return newfd;
5351}
5352
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005353/* Struct def and variable are moved down to the first usage site */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005354struct two_fd_t {
5355 int orig, copy;
5356};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005357struct redirtab {
5358 struct redirtab *next;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005359 int pair_count;
Denys Vlasenko606291b2009-09-23 23:15:43 +02005360 struct two_fd_t two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005361};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005362#define redirlist (G_var.redirlist)
Denys Vlasenko64774602016-10-26 15:24:30 +02005363enum {
5364 COPYFD_RESTORE = (int)~(INT_MAX),
5365};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005366
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005367static int
5368need_to_remember(struct redirtab *rp, int fd)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005369{
5370 int i;
5371
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005372 if (!rp) /* remembering was not requested */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005373 return 0;
5374
5375 for (i = 0; i < rp->pair_count; i++) {
5376 if (rp->two_fd[i].orig == fd) {
5377 /* already remembered */
5378 return 0;
5379 }
5380 }
5381 return 1;
5382}
5383
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005384/* "hidden" fd is a fd used to read scripts, or a copy of such */
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005385static int
5386is_hidden_fd(struct redirtab *rp, int fd)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005387{
5388 int i;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005389 struct parsefile *pf;
5390
5391 if (fd == -1)
5392 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005393 /* Check open scripts' fds */
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005394 pf = g_parsefile;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005395 while (pf) {
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005396 /* We skip pf_fd == 0 case because of the following case:
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005397 * $ ash # running ash interactively
5398 * $ . ./script.sh
5399 * and in script.sh: "exec 9>&0".
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005400 * Even though top-level pf_fd _is_ 0,
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005401 * it's still ok to use it: "read" builtin uses it,
5402 * why should we cripple "exec" builtin?
5403 */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005404 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005405 return 1;
5406 }
5407 pf = pf->prev;
5408 }
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005409
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005410 if (!rp)
5411 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005412 /* Check saved fds of redirects */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005413 fd |= COPYFD_RESTORE;
5414 for (i = 0; i < rp->pair_count; i++) {
5415 if (rp->two_fd[i].copy == fd) {
5416 return 1;
5417 }
5418 }
5419 return 0;
5420}
5421
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005422/*
5423 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5424 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005425 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005426 */
5427/* flags passed to redirect */
5428#define REDIR_PUSH 01 /* save previous values of file descriptors */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005429static void
5430redirect(union node *redir, int flags)
5431{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005432 struct redirtab *sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005433 int sv_pos;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005434 int fd;
5435 int newfd;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005436
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005437 if (!redir)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005438 return;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005439 sv = NULL;
5440 INT_OFF;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005441 if (flags & REDIR_PUSH)
5442 sv = redirlist;
5443 sv_pos = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005444 do {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005445 int right_fd = -1;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005446 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005447 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005448 right_fd = redir->ndup.dupfd;
5449 //bb_error_msg("doing %d > %d", fd, right_fd);
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005450 /* redirect from/to same file descriptor? */
5451 if (right_fd == fd)
5452 continue;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005453 /* "echo >&10" and 10 is a fd opened to a sh script? */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005454 if (is_hidden_fd(sv, right_fd)) {
5455 errno = EBADF; /* as if it is closed */
Ron Yorstonbe366e52017-07-27 13:53:39 +01005456 ash_msg_and_raise_perror("%d", right_fd);
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005457 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005458 newfd = -1;
5459 } else {
5460 newfd = openredirect(redir); /* always >= 0 */
5461 if (fd == newfd) {
5462 /* Descriptor wasn't open before redirect.
5463 * Mark it for close in the future */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005464 if (need_to_remember(sv, fd)) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005465 goto remember_to_close;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005466 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005467 continue;
5468 }
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005469 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005470#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005471 redirect_more:
5472#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005473 if (need_to_remember(sv, fd)) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005474 /* Copy old descriptor */
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005475 /* Careful to not accidentally "save"
5476 * to the same fd as right side fd in N>&M */
5477 int minfd = right_fd < 10 ? 10 : right_fd + 1;
Denys Vlasenko86584e12017-01-07 10:15:01 +01005478#if defined(F_DUPFD_CLOEXEC)
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005479 int copy = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
Denys Vlasenko86584e12017-01-07 10:15:01 +01005480#else
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005481 int copy = fcntl(fd, F_DUPFD, minfd);
Denys Vlasenko86584e12017-01-07 10:15:01 +01005482#endif
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005483 if (copy == -1) {
5484 int e = errno;
5485 if (e != EBADF) {
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005486 /* Strange error (e.g. "too many files" EMFILE?) */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005487 if (newfd >= 0)
5488 close(newfd);
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005489 errno = e;
Ron Yorstonbe366e52017-07-27 13:53:39 +01005490 ash_msg_and_raise_perror("%d", fd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005491 /* NOTREACHED */
5492 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005493 /* EBADF: it is not open - good, remember to close it */
5494 remember_to_close:
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005495 copy = CLOSED;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005496 } else { /* fd is open, save its copy */
Denys Vlasenko86584e12017-01-07 10:15:01 +01005497#if !defined(F_DUPFD_CLOEXEC)
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005498 fcntl(copy, F_SETFD, FD_CLOEXEC);
Denys Vlasenko86584e12017-01-07 10:15:01 +01005499#endif
Denis Vlasenko22f74142008-07-24 22:34:43 +00005500 /* "exec fd>&-" should not close fds
5501 * which point to script file(s).
5502 * Force them to be restored afterwards */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005503 if (is_hidden_fd(sv, fd))
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005504 copy |= COPYFD_RESTORE;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005505 }
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005506 /* if we move stderr, let "set -x" code know */
5507 if (fd == preverrout_fd)
5508 preverrout_fd = copy;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005509 sv->two_fd[sv_pos].orig = fd;
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005510 sv->two_fd[sv_pos].copy = copy;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005511 sv_pos++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005512 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005513 if (newfd < 0) {
5514 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005515 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005516 /* Don't want to trigger debugging */
5517 if (fd != -1)
5518 close(fd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005519 } else {
Denys Vlasenko64774602016-10-26 15:24:30 +02005520 dup2_or_raise(redir->ndup.dupfd, fd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005521 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005522 } else if (fd != newfd) { /* move newfd to fd */
Denys Vlasenko64774602016-10-26 15:24:30 +02005523 dup2_or_raise(newfd, fd);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005524#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005525 if (!(redir->nfile.type == NTO2 && fd == 2))
5526#endif
5527 close(newfd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005528 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005529#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005530 if (redir->nfile.type == NTO2 && fd == 1) {
5531 /* We already redirected it to fd 1, now copy it to 2 */
5532 newfd = 1;
5533 fd = 2;
5534 goto redirect_more;
5535 }
5536#endif
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005537 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005538 INT_ON;
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005539
5540//dash:#define REDIR_SAVEFD2 03 /* set preverrout */
5541#define REDIR_SAVEFD2 0
5542 // dash has a bug: since REDIR_SAVEFD2=3 and REDIR_PUSH=1, this test
5543 // triggers for pure REDIR_PUSH too. Thus, this is done almost always,
5544 // not only for calls with flags containing REDIR_SAVEFD2.
5545 // We do this unconditionally (see code above).
5546 //if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5547 // preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005548}
5549
Denys Vlasenko170f93e2017-07-29 18:54:53 +02005550static int
5551redirectsafe(union node *redir, int flags)
5552{
5553 int err;
5554 volatile int saveint;
5555 struct jmploc *volatile savehandler = exception_handler;
5556 struct jmploc jmploc;
5557
5558 SAVE_INT(saveint);
5559 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5560 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
5561 if (!err) {
5562 exception_handler = &jmploc;
5563 redirect(redir, flags);
5564 }
5565 exception_handler = savehandler;
5566 if (err && exception_type != EXERROR)
5567 longjmp(exception_handler->loc, 1);
5568 RESTORE_INT(saveint);
5569 return err;
5570}
5571
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005572static struct redirtab*
5573pushredir(union node *redir)
5574{
5575 struct redirtab *sv;
5576 int i;
5577
5578 if (!redir)
5579 return redirlist;
5580
5581 i = 0;
5582 do {
5583 i++;
5584#if BASH_REDIR_OUTPUT
5585 if (redir->nfile.type == NTO2)
5586 i++;
5587#endif
5588 redir = redir->nfile.next;
5589 } while (redir);
5590
5591 sv = ckzalloc(sizeof(*sv) + i * sizeof(sv->two_fd[0]));
5592 sv->pair_count = i;
5593 while (--i >= 0)
5594 sv->two_fd[i].orig = sv->two_fd[i].copy = EMPTY;
5595 sv->next = redirlist;
5596 redirlist = sv;
5597 return sv->next;
5598}
5599
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005600/*
5601 * Undo the effects of the last redirection.
5602 */
5603static void
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005604popredir(int drop, int restore)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005605{
5606 struct redirtab *rp;
5607 int i;
5608
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02005609 if (redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005610 return;
5611 INT_OFF;
5612 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005613 for (i = 0; i < rp->pair_count; i++) {
5614 int fd = rp->two_fd[i].orig;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005615 int copy = rp->two_fd[i].copy;
5616 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005617 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005618 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005619 continue;
5620 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005621 if (copy != EMPTY) {
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005622 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
Denis Vlasenko22f74142008-07-24 22:34:43 +00005623 copy &= ~COPYFD_RESTORE;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005624 /*close(fd);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02005625 dup2_or_raise(copy, fd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005626 }
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005627 close(copy & ~COPYFD_RESTORE);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005628 }
5629 }
5630 redirlist = rp->next;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005631 free(rp);
5632 INT_ON;
5633}
5634
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005635static void
5636unwindredir(struct redirtab *stop)
5637{
5638 while (redirlist != stop)
5639 popredir(/*drop:*/ 0, /*restore:*/ 0);
5640}
5641
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005642
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005643/* ============ Routines to expand arguments to commands
5644 *
5645 * We have to deal with backquotes, shell variables, and file metacharacters.
5646 */
5647
Denys Vlasenko0b883582016-12-23 16:49:07 +01005648#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005649static arith_t
5650ash_arith(const char *s)
5651{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005652 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005653 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005654
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005655 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005656 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005657 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005658
5659 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005660 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005661 if (math_state.errmsg)
5662 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005663 INT_ON;
5664
5665 return result;
5666}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005667#endif
5668
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005669/*
5670 * expandarg flags
5671 */
5672#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5673#define EXP_TILDE 0x2 /* do normal tilde expansion */
5674#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5675#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
Denys Vlasenkodb74c6c2016-10-24 21:12:33 +02005676/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5677 * POSIX says for this case:
5678 * Pathname expansion shall not be performed on the word by a
5679 * non-interactive shell; an interactive shell may perform it, but shall
5680 * do so only when the expansion would result in one word.
5681 * Currently, our code complies to the above rule by never globbing
5682 * redirection filenames.
5683 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5684 * (this means that on a typical Linux distro, bash almost always
5685 * performs globbing, and thus diverges from what we do).
5686 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005687#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Ron Yorston549deab2015-05-18 09:57:51 +02005688#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005689#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5690#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005691#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005692/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005693 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005694 */
5695#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5696#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005697#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5698#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Ron Yorston417622c2015-05-18 09:59:14 +02005699#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005700
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005701/* Add CTLESC when necessary. */
Denys Vlasenko2990aa42017-07-25 17:37:57 +02005702#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005703/* Do not skip NUL characters. */
5704#define QUOTES_KEEPNUL EXP_TILDE
5705
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005706/*
5707 * Structure specifying which parts of the string should be searched
5708 * for IFS characters.
5709 */
5710struct ifsregion {
5711 struct ifsregion *next; /* next region in list */
5712 int begoff; /* offset of start of region */
5713 int endoff; /* offset of end of region */
5714 int nulonly; /* search for nul bytes only */
5715};
5716
5717struct arglist {
5718 struct strlist *list;
5719 struct strlist **lastp;
5720};
5721
5722/* output of current string */
5723static char *expdest;
5724/* list of back quote expressions */
5725static struct nodelist *argbackq;
5726/* first struct in list of ifs regions */
5727static struct ifsregion ifsfirst;
5728/* last struct in list */
5729static struct ifsregion *ifslastp;
5730/* holds expanded arg list */
5731static struct arglist exparg;
5732
5733/*
5734 * Our own itoa().
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02005735 * cvtnum() is used even if math support is off (to prepare $? values and such).
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005736 */
5737static int
5738cvtnum(arith_t num)
5739{
5740 int len;
5741
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02005742 /* 32-bit and wider ints require buffer size of bytes*3 (or less) */
5743 len = sizeof(arith_t) * 3;
5744 /* If narrower: worst case, 1-byte ints: need 5 bytes: "-127<NUL>" */
5745 if (sizeof(arith_t) < 4) len += 2;
5746
5747 expdest = makestrspace(len, expdest);
5748 len = fmtstr(expdest, len, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005749 STADJUST(len, expdest);
5750 return len;
5751}
5752
Denys Vlasenko455e4222016-10-27 14:45:13 +02005753/*
5754 * Break the argument string into pieces based upon IFS and add the
5755 * strings to the argument list. The regions of the string to be
5756 * searched for IFS characters have been stored by recordregion.
5757 */
5758static void
5759ifsbreakup(char *string, struct arglist *arglist)
5760{
5761 struct ifsregion *ifsp;
5762 struct strlist *sp;
5763 char *start;
5764 char *p;
5765 char *q;
5766 const char *ifs, *realifs;
5767 int ifsspc;
5768 int nulonly;
5769
5770 start = string;
5771 if (ifslastp != NULL) {
5772 ifsspc = 0;
5773 nulonly = 0;
5774 realifs = ifsset() ? ifsval() : defifs;
5775 ifsp = &ifsfirst;
5776 do {
5777 p = string + ifsp->begoff;
5778 nulonly = ifsp->nulonly;
5779 ifs = nulonly ? nullstr : realifs;
5780 ifsspc = 0;
5781 while (p < string + ifsp->endoff) {
5782 q = p;
5783 if ((unsigned char)*p == CTLESC)
5784 p++;
5785 if (!strchr(ifs, *p)) {
5786 p++;
5787 continue;
5788 }
5789 if (!nulonly)
5790 ifsspc = (strchr(defifs, *p) != NULL);
5791 /* Ignore IFS whitespace at start */
5792 if (q == start && ifsspc) {
5793 p++;
5794 start = p;
5795 continue;
5796 }
5797 *q = '\0';
5798 sp = stzalloc(sizeof(*sp));
5799 sp->text = start;
5800 *arglist->lastp = sp;
5801 arglist->lastp = &sp->next;
5802 p++;
5803 if (!nulonly) {
5804 for (;;) {
5805 if (p >= string + ifsp->endoff) {
5806 break;
5807 }
5808 q = p;
5809 if ((unsigned char)*p == CTLESC)
5810 p++;
5811 if (strchr(ifs, *p) == NULL) {
5812 p = q;
5813 break;
5814 }
5815 if (strchr(defifs, *p) == NULL) {
5816 if (ifsspc) {
5817 p++;
5818 ifsspc = 0;
5819 } else {
5820 p = q;
5821 break;
5822 }
5823 } else
5824 p++;
5825 }
5826 }
5827 start = p;
5828 } /* while */
5829 ifsp = ifsp->next;
5830 } while (ifsp != NULL);
5831 if (nulonly)
5832 goto add;
5833 }
5834
5835 if (!*start)
5836 return;
5837
5838 add:
5839 sp = stzalloc(sizeof(*sp));
5840 sp->text = start;
5841 *arglist->lastp = sp;
5842 arglist->lastp = &sp->next;
5843}
5844
5845static void
5846ifsfree(void)
5847{
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005848 struct ifsregion *p = ifsfirst.next;
5849
5850 if (!p)
5851 goto out;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005852
5853 INT_OFF;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005854 do {
5855 struct ifsregion *ifsp;
5856 ifsp = p->next;
5857 free(p);
5858 p = ifsp;
5859 } while (p);
Denys Vlasenko455e4222016-10-27 14:45:13 +02005860 ifsfirst.next = NULL;
5861 INT_ON;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005862 out:
5863 ifslastp = NULL;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005864}
5865
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005866static size_t
5867esclen(const char *start, const char *p)
5868{
5869 size_t esc = 0;
5870
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005871 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005872 esc++;
5873 }
5874 return esc;
5875}
5876
5877/*
5878 * Remove any CTLESC characters from a string.
5879 */
5880static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005881rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005882{
Ron Yorston417622c2015-05-18 09:59:14 +02005883 static const char qchars[] ALIGN1 = {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005884 IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005885
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005886 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005887 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005888 unsigned protect_against_glob;
5889 unsigned globbing;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005890 IF_BASH_PATTERN_SUBST(unsigned slash = flag & RMESCAPE_SLASH;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005891
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005892 p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005893 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005894 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005895
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005896 q = p;
5897 r = str;
5898 if (flag & RMESCAPE_ALLOC) {
5899 size_t len = p - str;
5900 size_t fulllen = len + strlen(p) + 1;
5901
5902 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005903 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005904 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005905 /* p and str may be invalidated by makestrspace */
5906 str = (char *)stackblock() + strloc;
5907 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005908 } else if (flag & RMESCAPE_HEAP) {
5909 r = ckmalloc(fulllen);
5910 } else {
5911 r = stalloc(fulllen);
5912 }
5913 q = r;
5914 if (len > 0) {
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02005915 q = (char *)mempcpy(q, str, len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005916 }
5917 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005918
Ron Yorston549deab2015-05-18 09:57:51 +02005919 inquotes = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005920 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005921 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005922 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005923 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005924// Note: both inquotes and protect_against_glob only affect whether
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02005925// CTLESC,<ch> gets converted to <ch> or to \<ch>
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005926 inquotes = ~inquotes;
5927 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005928 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005929 continue;
5930 }
Ron Yorston549deab2015-05-18 09:57:51 +02005931 if ((unsigned char)*p == CTLESC) {
5932 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02005933#if DEBUG
5934 if (*p == '\0')
5935 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
5936#endif
Ron Yorston549deab2015-05-18 09:57:51 +02005937 if (protect_against_glob) {
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02005938 /*
5939 * We used to trust glob() and fnmatch() to eat
5940 * superfluous escapes (\z where z has no
5941 * special meaning anyway). But this causes
5942 * bugs such as string of one greek letter rho
Denys Vlasenkoed79a632017-07-05 19:20:43 +02005943 * (unicode-encoded as two bytes "cf,81")
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02005944 * getting encoded as "cf,CTLESC,81"
5945 * and here, converted to "cf,\,81" -
5946 * which does not go well with some flavors
Denys Vlasenko92b8d9c2017-07-05 19:13:44 +02005947 * of fnmatch() in unicode locales
5948 * (for example, glibc <= 2.22).
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02005949 *
5950 * Lets add "\" only on the chars which need it.
Denys Vlasenko4142f012017-07-05 22:19:28 +02005951 * Testcases for less obvious chars are shown.
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02005952 */
5953 if (*p == '*'
5954 || *p == '?'
5955 || *p == '['
Denys Vlasenko4142f012017-07-05 22:19:28 +02005956 || *p == '\\' /* case '\' in \\ ) echo ok;; *) echo WRONG;; esac */
5957 || *p == ']' /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */
5958 || *p == '-' /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */
5959 || *p == '!' /* case '!' in [\!] ) echo ok;; *) echo WRONG;; esac */
5960 /* Some libc support [^negate], that's why "^" also needs love */
5961 || *p == '^' /* case '^' in [\^] ) echo ok;; *) echo WRONG;; esac */
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02005962 ) {
5963 *q++ = '\\';
5964 }
Ron Yorston549deab2015-05-18 09:57:51 +02005965 }
5966 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005967 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005968 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005969 goto copy;
5970 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005971#if BASH_PATTERN_SUBST
Ron Yorston417622c2015-05-18 09:59:14 +02005972 else if (*p == '/' && slash) {
5973 /* stop handling globbing and mark location of slash */
5974 globbing = slash = 0;
5975 *p = CTLESC;
5976 }
5977#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005978 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005979 copy:
5980 *q++ = *p++;
5981 }
5982 *q = '\0';
5983 if (flag & RMESCAPE_GROW) {
5984 expdest = r;
5985 STADJUST(q - r + 1, expdest);
5986 }
5987 return r;
5988}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005989#define pmatch(a, b) !fnmatch((a), (b), 0)
5990
5991/*
5992 * Prepare a pattern for a expmeta (internal glob(3)) call.
5993 *
5994 * Returns an stalloced string.
5995 */
5996static char *
Ron Yorston549deab2015-05-18 09:57:51 +02005997preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005998{
Ron Yorston549deab2015-05-18 09:57:51 +02005999 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006000}
6001
6002/*
6003 * Put a string on the stack.
6004 */
6005static void
6006memtodest(const char *p, size_t len, int syntax, int quotes)
6007{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006008 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006009
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006010 if (!len)
6011 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006012
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006013 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
6014
6015 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006016 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006017 if (c) {
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01006018 if (quotes & QUOTES_ESC) {
6019 int n = SIT(c, syntax);
6020 if (n == CCTL
6021 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
6022 && n == CBACK
6023 )
6024 ) {
6025 USTPUTC(CTLESC, q);
6026 }
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006027 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006028 } else if (!(quotes & QUOTES_KEEPNUL))
6029 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006030 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006031 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006032
6033 expdest = q;
6034}
6035
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006036static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006037strtodest(const char *p, int syntax, int quotes)
6038{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006039 size_t len = strlen(p);
6040 memtodest(p, len, syntax, quotes);
6041 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006042}
6043
6044/*
6045 * Record the fact that we have to scan this region of the
6046 * string for IFS characters.
6047 */
6048static void
6049recordregion(int start, int end, int nulonly)
6050{
6051 struct ifsregion *ifsp;
6052
6053 if (ifslastp == NULL) {
6054 ifsp = &ifsfirst;
6055 } else {
6056 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00006057 ifsp = ckzalloc(sizeof(*ifsp));
6058 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006059 ifslastp->next = ifsp;
6060 INT_ON;
6061 }
6062 ifslastp = ifsp;
6063 ifslastp->begoff = start;
6064 ifslastp->endoff = end;
6065 ifslastp->nulonly = nulonly;
6066}
6067
6068static void
6069removerecordregions(int endoff)
6070{
6071 if (ifslastp == NULL)
6072 return;
6073
6074 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006075 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006076 struct ifsregion *ifsp;
6077 INT_OFF;
6078 ifsp = ifsfirst.next->next;
6079 free(ifsfirst.next);
6080 ifsfirst.next = ifsp;
6081 INT_ON;
6082 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006083 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006084 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006085 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006086 ifslastp = &ifsfirst;
6087 ifsfirst.endoff = endoff;
6088 }
6089 return;
6090 }
6091
6092 ifslastp = &ifsfirst;
6093 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006094 ifslastp = ifslastp->next;
6095 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006096 struct ifsregion *ifsp;
6097 INT_OFF;
6098 ifsp = ifslastp->next->next;
6099 free(ifslastp->next);
6100 ifslastp->next = ifsp;
6101 INT_ON;
6102 }
6103 if (ifslastp->endoff > endoff)
6104 ifslastp->endoff = endoff;
6105}
6106
6107static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006108exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006109{
Denys Vlasenkocd716832009-11-28 22:14:02 +01006110 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006111 char *name;
6112 struct passwd *pw;
6113 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006114 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006115
6116 name = p + 1;
6117
6118 while ((c = *++p) != '\0') {
6119 switch (c) {
6120 case CTLESC:
6121 return startp;
6122 case CTLQUOTEMARK:
6123 return startp;
6124 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006125 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006126 goto done;
6127 break;
6128 case '/':
6129 case CTLENDVAR:
6130 goto done;
6131 }
6132 }
6133 done:
6134 *p = '\0';
6135 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02006136 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006137 } else {
6138 pw = getpwnam(name);
6139 if (pw == NULL)
6140 goto lose;
6141 home = pw->pw_dir;
6142 }
6143 if (!home || !*home)
6144 goto lose;
6145 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006146 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006147 return p;
6148 lose:
6149 *p = c;
6150 return startp;
6151}
6152
6153/*
6154 * Execute a command inside back quotes. If it's a builtin command, we
6155 * want to save its output in a block obtained from malloc. Otherwise
6156 * we fork off a subprocess and get the output of the command via a pipe.
6157 * Should be called with interrupts off.
6158 */
6159struct backcmd { /* result of evalbackcmd */
6160 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006161 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00006162 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006163 struct job *jp; /* job structure for command */
6164};
6165
6166/* These forward decls are needed to use "eval" code for backticks handling: */
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +02006167/* flags in argument to evaltree */
6168#define EV_EXIT 01 /* exit after evaluating tree */
6169#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02006170static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006171
Denys Vlasenko619d9b52017-07-28 15:28:33 +02006172/* An evaltree() which is known to never return.
6173 * Used to use an alias:
6174 * static int evaltreenr(union node *, int) __attribute__((alias("evaltree"),__noreturn__));
6175 * but clang was reported to "transfer" noreturn-ness to evaltree() as well.
6176 */
6177static ALWAYS_INLINE NORETURN void
6178evaltreenr(union node *n, int flags)
6179{
6180 evaltree(n, flags);
6181 bb_unreachable(abort());
6182 /* NOTREACHED */
6183}
6184
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02006185static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006186evalbackcmd(union node *n, struct backcmd *result)
6187{
Denys Vlasenko579ad102016-10-25 21:10:20 +02006188 int pip[2];
6189 struct job *jp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006190
6191 result->fd = -1;
6192 result->buf = NULL;
6193 result->nleft = 0;
6194 result->jp = NULL;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006195 if (n == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006196 goto out;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006197 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006198
Denys Vlasenko579ad102016-10-25 21:10:20 +02006199 if (pipe(pip) < 0)
6200 ash_msg_and_raise_error("pipe call failed");
6201 jp = makejob(/*n,*/ 1);
6202 if (forkshell(jp, n, FORK_NOJOB) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02006203 /* child */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006204 FORCE_INT_ON;
6205 close(pip[0]);
6206 if (pip[1] != 1) {
6207 /*close(1);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02006208 dup2_or_raise(pip[1], 1);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006209 close(pip[1]);
6210 }
Denys Vlasenko960ca382016-10-25 18:12:15 +02006211/* TODO: eflag clearing makes the following not abort:
6212 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6213 * which is what bash does (unless it is in POSIX mode).
6214 * dash deleted "eflag = 0" line in the commit
6215 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6216 * [EVAL] Don't clear eflag in evalbackcmd
6217 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6218 */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006219 eflag = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006220 ifsfree();
Denys Vlasenko619d9b52017-07-28 15:28:33 +02006221 evaltreenr(n, EV_EXIT);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006222 /* NOTREACHED */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006223 }
Denys Vlasenko70392332016-10-27 02:31:55 +02006224 /* parent */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006225 close(pip[1]);
6226 result->fd = pip[0];
6227 result->jp = jp;
6228
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006229 out:
6230 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6231 result->fd, result->buf, result->nleft, result->jp));
6232}
6233
6234/*
6235 * Expand stuff in backwards quotes.
6236 */
6237static void
Ron Yorston549deab2015-05-18 09:57:51 +02006238expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006239{
6240 struct backcmd in;
6241 int i;
6242 char buf[128];
6243 char *p;
6244 char *dest;
6245 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02006246 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006247 struct stackmark smark;
6248
6249 INT_OFF;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02006250 startloc = expdest - (char *)stackblock();
6251 pushstackmark(&smark, startloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006252 evalbackcmd(cmd, &in);
6253 popstackmark(&smark);
6254
6255 p = in.buf;
6256 i = in.nleft;
6257 if (i == 0)
6258 goto read;
6259 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02006260 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006261 read:
6262 if (in.fd < 0)
6263 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01006264 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006265 TRACE(("expbackq: read returns %d\n", i));
6266 if (i <= 0)
6267 break;
6268 p = buf;
6269 }
6270
Denis Vlasenko60818682007-09-28 22:07:23 +00006271 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006272 if (in.fd >= 0) {
6273 close(in.fd);
6274 back_exitstatus = waitforjob(in.jp);
6275 }
6276 INT_ON;
6277
6278 /* Eat all trailing newlines */
6279 dest = expdest;
6280 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6281 STUNPUTC(dest);
6282 expdest = dest;
6283
Ron Yorston549deab2015-05-18 09:57:51 +02006284 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006285 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006286 TRACE(("evalbackq: size:%d:'%.*s'\n",
6287 (int)((dest - (char *)stackblock()) - startloc),
6288 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006289 stackblock() + startloc));
6290}
6291
Denys Vlasenko0b883582016-12-23 16:49:07 +01006292#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006293/*
6294 * Expand arithmetic expression. Backup to start of expression,
6295 * evaluate, place result in (backed up) result, adjust string position.
6296 */
6297static void
Ron Yorston549deab2015-05-18 09:57:51 +02006298expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006299{
6300 char *p, *start;
6301 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006302 int len;
6303
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006304 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006305
6306 /*
6307 * This routine is slightly over-complicated for
6308 * efficiency. Next we scan backwards looking for the
6309 * start of arithmetic.
6310 */
6311 start = stackblock();
6312 p = expdest - 1;
6313 *p = '\0';
6314 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006315 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006316 int esc;
6317
Denys Vlasenkocd716832009-11-28 22:14:02 +01006318 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006319 p--;
6320#if DEBUG
6321 if (p < start) {
6322 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6323 }
6324#endif
6325 }
6326
6327 esc = esclen(start, p);
6328 if (!(esc % 2)) {
6329 break;
6330 }
6331
6332 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006333 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006334
6335 begoff = p - start;
6336
6337 removerecordregions(begoff);
6338
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006339 expdest = p;
6340
Ron Yorston549deab2015-05-18 09:57:51 +02006341 if (flag & QUOTES_ESC)
6342 rmescapes(p + 1, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006343
Ron Yorston549deab2015-05-18 09:57:51 +02006344 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006345
Ron Yorston549deab2015-05-18 09:57:51 +02006346 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006347 recordregion(begoff, begoff + len, 0);
6348}
6349#endif
6350
6351/* argstr needs it */
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006352static char *evalvar(char *p, int flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006353
6354/*
6355 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6356 * characters to allow for further processing. Otherwise treat
6357 * $@ like $* since no splitting will be performed.
6358 */
6359static void
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006360argstr(char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006361{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006362 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006363 '=',
6364 ':',
6365 CTLQUOTEMARK,
6366 CTLENDVAR,
6367 CTLESC,
6368 CTLVAR,
6369 CTLBACKQ,
Denys Vlasenko0b883582016-12-23 16:49:07 +01006370#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006371 CTLENDARI,
6372#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006373 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006374 };
6375 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006376 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006377 int inquotes;
6378 size_t length;
6379 int startloc;
6380
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006381 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006382 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006383 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006384 reject++;
6385 }
6386 inquotes = 0;
6387 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006388 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006389 char *q;
6390
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006391 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006392 tilde:
6393 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006394 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006395 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006396 }
6397 start:
6398 startloc = expdest - (char *)stackblock();
6399 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006400 unsigned char c;
6401
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006402 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006403 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006404 if (c) {
6405 if (!(c & 0x80)
Denys Vlasenko0b883582016-12-23 16:49:07 +01006406 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006407 ) {
6408 /* c == '=' || c == ':' || c == CTLENDARI */
6409 length++;
6410 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006411 }
6412 if (length > 0) {
6413 int newloc;
6414 expdest = stack_nputstr(p, length, expdest);
6415 newloc = expdest - (char *)stackblock();
6416 if (breakall && !inquotes && newloc > startloc) {
6417 recordregion(startloc, newloc, 0);
6418 }
6419 startloc = newloc;
6420 }
6421 p += length + 1;
6422 length = 0;
6423
6424 switch (c) {
6425 case '\0':
6426 goto breakloop;
6427 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006428 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006429 p--;
6430 continue;
6431 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006432 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006433 reject++;
6434 /* fall through */
6435 case ':':
6436 /*
6437 * sort of a hack - expand tildes in variable
6438 * assignments (after the first '=' and after ':'s).
6439 */
6440 if (*--p == '~') {
6441 goto tilde;
6442 }
6443 continue;
6444 }
6445
6446 switch (c) {
6447 case CTLENDVAR: /* ??? */
6448 goto breakloop;
6449 case CTLQUOTEMARK:
Ron Yorston549deab2015-05-18 09:57:51 +02006450 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006451 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006452 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006453 p = evalvar(p + 1, flags | inquotes) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006454 goto start;
6455 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006456 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006457 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006458 p--;
6459 length++;
6460 startloc++;
6461 }
6462 break;
6463 case CTLESC:
6464 startloc++;
6465 length++;
Ron Yorston549deab2015-05-18 09:57:51 +02006466
6467 /*
6468 * Quoted parameter expansion pattern: remove quote
6469 * unless inside inner quotes or we have a literal
6470 * backslash.
6471 */
6472 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6473 EXP_QPAT && *p != '\\')
6474 break;
6475
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006476 goto addquote;
6477 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006478 TRACE(("argstr: evalvar('%s')\n", p));
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006479 p = evalvar(p, flags | inquotes);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006480 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006481 goto start;
6482 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006483 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006484 argbackq = argbackq->next;
6485 goto start;
Denys Vlasenko0b883582016-12-23 16:49:07 +01006486#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006487 case CTLENDARI:
6488 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006489 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006490 goto start;
6491#endif
6492 }
6493 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006494 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006495}
6496
6497static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006498scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6499 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006500{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006501 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006502 char c;
6503
6504 loc = startp;
6505 loc2 = rmesc;
6506 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006507 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006508 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006509
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006510 c = *loc2;
6511 if (zero) {
6512 *loc2 = '\0';
6513 s = rmesc;
6514 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006515 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006516
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006517 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006518 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006519 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006520 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006521 loc++;
6522 loc++;
6523 loc2++;
6524 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006525 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006526}
6527
6528static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006529scanright(char *startp, char *rmesc, char *rmescend,
6530 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006531{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006532#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6533 int try2optimize = match_at_start;
6534#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006535 int esc = 0;
6536 char *loc;
6537 char *loc2;
6538
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006539 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6540 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6541 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6542 * Logic:
6543 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6544 * and on each iteration they go back two/one char until they reach the beginning.
6545 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6546 */
6547 /* TODO: document in what other circumstances we are called. */
6548
6549 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006550 int match;
6551 char c = *loc2;
6552 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006553 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006554 *loc2 = '\0';
6555 s = rmesc;
6556 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006557 match = pmatch(pattern, s);
6558 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006559 *loc2 = c;
6560 if (match)
6561 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006562#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6563 if (try2optimize) {
6564 /* Maybe we can optimize this:
6565 * if pattern ends with unescaped *, we can avoid checking
Denys Vlasenko10ad6222017-04-17 16:13:32 +02006566 * shorter strings: if "foo*" doesn't match "raw_value_of_v",
6567 * it won't match truncated "raw_value_of_" strings too.
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006568 */
6569 unsigned plen = strlen(pattern);
6570 /* Does it end with "*"? */
6571 if (plen != 0 && pattern[--plen] == '*') {
6572 /* "xxxx*" is not escaped */
6573 /* "xxx\*" is escaped */
6574 /* "xx\\*" is not escaped */
6575 /* "x\\\*" is escaped */
6576 int slashes = 0;
6577 while (plen != 0 && pattern[--plen] == '\\')
6578 slashes++;
6579 if (!(slashes & 1))
6580 break; /* ends with unescaped "*" */
6581 }
6582 try2optimize = 0;
6583 }
6584#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006585 loc--;
6586 if (quotes) {
6587 if (--esc < 0) {
6588 esc = esclen(startp, loc);
6589 }
6590 if (esc % 2) {
6591 esc--;
6592 loc--;
6593 }
6594 }
6595 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006596 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006597}
6598
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006599static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006600static void
6601varunset(const char *end, const char *var, const char *umsg, int varflags)
6602{
6603 const char *msg;
6604 const char *tail;
6605
6606 tail = nullstr;
6607 msg = "parameter not set";
6608 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006609 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006610 if (varflags & VSNUL)
6611 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006612 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006613 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006614 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006615 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006616 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006617}
6618
6619static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006620subevalvar(char *p, char *varname, int strloc, int subtype,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006621 int startloc, int varflags, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006622{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006623 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006624 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006625 char *startp;
6626 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006627 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006628 char *str;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006629 int amount, resetloc;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006630 IF_BASH_PATTERN_SUBST(int workloc;)
6631 IF_BASH_PATTERN_SUBST(char *repl = NULL;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006632 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006633 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006634
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006635 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6636 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006637
Ron Yorstoneb6b48b2015-05-18 09:51:35 +02006638 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006639 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0)
6640 );
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006641 STPUTC('\0', expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006642 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006643 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006644
6645 switch (subtype) {
6646 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006647 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006648 amount = startp - expdest;
6649 STADJUST(amount, expdest);
6650 return startp;
6651
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006652 case VSQUESTION:
6653 varunset(p, varname, startp, varflags);
6654 /* NOTREACHED */
6655
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006656#if BASH_SUBSTR
Denys Vlasenko826360f2017-07-17 17:49:11 +02006657 case VSSUBSTR: {
6658 int pos, len, orig_len;
6659 char *colon;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006660
Denys Vlasenko826360f2017-07-17 17:49:11 +02006661 loc = str = stackblock() + strloc;
6662
6663# if !ENABLE_FEATURE_SH_MATH
6664# define ash_arith number
6665# endif
6666 /* Read POS in ${var:POS:LEN} */
6667 colon = strchr(loc, ':');
6668 if (colon) *colon = '\0';
6669 pos = ash_arith(loc);
6670 if (colon) *colon = ':';
6671
6672 /* Read LEN in ${var:POS:LEN} */
6673 len = str - startp - 1;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006674 /* *loc != '\0', guaranteed by parser */
6675 if (quotes) {
6676 char *ptr;
6677
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006678 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006679 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006680 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006681 len--;
6682 ptr++;
6683 }
6684 }
6685 }
6686 orig_len = len;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006687 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006688 /* ${var::LEN} */
Denys Vlasenko826360f2017-07-17 17:49:11 +02006689 len = ash_arith(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006690 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006691 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006692 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006693 while (*loc && *loc != ':') {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006694 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006695 }
6696 if (*loc++ == ':') {
Denys Vlasenko826360f2017-07-17 17:49:11 +02006697 len = ash_arith(loc);
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006698 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006699 }
Denys Vlasenko826360f2017-07-17 17:49:11 +02006700# undef ash_arith
6701
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006702 if (pos < 0) {
6703 /* ${VAR:$((-n)):l} starts n chars from the end */
6704 pos = orig_len + pos;
6705 }
6706 if ((unsigned)pos >= orig_len) {
6707 /* apart from obvious ${VAR:999999:l},
6708 * covers ${VAR:$((-9999999)):l} - result is ""
Denys Vlasenko826360f2017-07-17 17:49:11 +02006709 * (bash compat)
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006710 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006711 pos = 0;
6712 len = 0;
6713 }
Denys Vlasenko826360f2017-07-17 17:49:11 +02006714 if (len < 0) {
6715 /* ${VAR:N:-M} sets LEN to strlen()-M */
6716 len = (orig_len - pos) + len;
6717 }
6718 if ((unsigned)len > (orig_len - pos))
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006719 len = orig_len - pos;
6720
6721 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006722 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006723 str++;
6724 }
6725 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006726 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006727 *loc++ = *str++;
6728 *loc++ = *str++;
6729 }
6730 *loc = '\0';
6731 amount = loc - expdest;
6732 STADJUST(amount, expdest);
6733 return loc;
Denys Vlasenko826360f2017-07-17 17:49:11 +02006734 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006735#endif /* BASH_SUBSTR */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006736 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006737
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006738 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006739
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006740#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006741 /* We'll comeback here if we grow the stack while handling
6742 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6743 * stack will need rebasing, and we'll need to remove our work
6744 * areas each time
6745 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006746 restart:
6747#endif
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006748
6749 amount = expdest - ((char *)stackblock() + resetloc);
6750 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006751 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006752
6753 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006754 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006755 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006756 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006757 if (rmesc != startp) {
6758 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006759 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006760 }
6761 }
6762 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006763 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02006764 /*
6765 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6766 * The result is a_\_z_c (not a\_\_z_c)!
6767 *
6768 * The search pattern and replace string treat backslashes differently!
6769 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6770 * and string. It's only used on the first call.
6771 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006772 preglob(str, IF_BASH_PATTERN_SUBST(
Ron Yorston417622c2015-05-18 09:59:14 +02006773 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006774 RMESCAPE_SLASH : ) 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006775
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006776#if BASH_PATTERN_SUBST
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006777 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006778 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenko826360f2017-07-17 17:49:11 +02006779 int len;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006780 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006781
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006782 if (!repl) {
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006783 repl = strchr(str, CTLESC);
6784 if (repl)
Ron Yorston417622c2015-05-18 09:59:14 +02006785 *repl++ = '\0';
6786 else
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006787 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006788 }
Ron Yorston417622c2015-05-18 09:59:14 +02006789 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006790
6791 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006792 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006793 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006794
6795 len = 0;
6796 idx = startp;
6797 end = str - 1;
6798 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006799 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006800 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006801 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006802 if (!loc) {
6803 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006804 char *restart_detect = stackblock();
6805 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006806 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006807 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006808 idx++;
6809 len++;
6810 STPUTC(*idx, expdest);
6811 }
6812 if (stackblock() != restart_detect)
6813 goto restart;
6814 idx++;
6815 len++;
6816 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006817 /* continue; - prone to quadratic behavior, smarter code: */
6818 if (idx >= end)
6819 break;
6820 if (str[0] == '*') {
6821 /* Pattern is "*foo". If "*foo" does not match "long_string",
6822 * it would never match "ong_string" etc, no point in trying.
6823 */
6824 goto skip_matching;
6825 }
6826 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006827 }
6828
6829 if (subtype == VSREPLACEALL) {
6830 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006831 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006832 idx++;
6833 idx++;
6834 rmesc++;
6835 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006836 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006837 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006838 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006839
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006840 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006841 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006842 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006843 if (quotes && *loc == '\\') {
6844 STPUTC(CTLESC, expdest);
6845 len++;
6846 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006847 STPUTC(*loc, expdest);
6848 if (stackblock() != restart_detect)
6849 goto restart;
6850 len++;
6851 }
6852
6853 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006854 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006855 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006856 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006857 STPUTC(*idx, expdest);
6858 if (stackblock() != restart_detect)
6859 goto restart;
6860 len++;
6861 idx++;
6862 }
6863 break;
6864 }
6865 }
6866
6867 /* We've put the replaced text into a buffer at workloc, now
6868 * move it to the right place and adjust the stack.
6869 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006870 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006871 startp = (char *)stackblock() + startloc;
6872 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006873 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006874 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006875 STADJUST(-amount, expdest);
6876 return startp;
6877 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006878#endif /* BASH_PATTERN_SUBST */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006879
6880 subtype -= VSTRIMRIGHT;
6881#if DEBUG
6882 if (subtype < 0 || subtype > 7)
6883 abort();
6884#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006885 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006886 zero = subtype >> 1;
6887 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6888 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6889
6890 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6891 if (loc) {
6892 if (zero) {
6893 memmove(startp, loc, str - loc);
6894 loc = startp + (str - loc) - 1;
6895 }
6896 *loc = '\0';
6897 amount = loc - expdest;
6898 STADJUST(amount, expdest);
6899 }
6900 return loc;
6901}
6902
6903/*
6904 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006905 * name parameter (examples):
6906 * ash -c 'echo $1' name:'1='
6907 * ash -c 'echo $qwe' name:'qwe='
6908 * ash -c 'echo $$' name:'$='
6909 * ash -c 'echo ${$}' name:'$='
6910 * ash -c 'echo ${$##q}' name:'$=q'
6911 * ash -c 'echo ${#$}' name:'$='
6912 * note: examples with bad shell syntax:
6913 * ash -c 'echo ${#$1}' name:'$=1'
6914 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006915 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02006916static NOINLINE ssize_t
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006917varvalue(char *name, int varflags, int flags, int *quotedp)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006918{
Mike Frysinger98c52642009-04-02 10:02:37 +00006919 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006920 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006921 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006922 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006923 int sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006924 int quoted = *quotedp;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006925 int subtype = varflags & VSTYPE;
6926 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6927 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006928 int syntax;
6929
6930 sep = (flags & EXP_FULL) << CHAR_BIT;
6931 syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006932
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006933 switch (*name) {
6934 case '$':
6935 num = rootpid;
6936 goto numvar;
6937 case '?':
6938 num = exitstatus;
6939 goto numvar;
6940 case '#':
6941 num = shellparam.nparam;
6942 goto numvar;
6943 case '!':
6944 num = backgndpid;
6945 if (num == 0)
6946 return -1;
6947 numvar:
6948 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006949 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006950 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00006951 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006952 for (i = NOPTS - 1; i >= 0; i--) {
6953 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00006954 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006955 len++;
6956 }
6957 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006958 check_1char_name:
6959#if 0
6960 /* handles cases similar to ${#$1} */
6961 if (name[2] != '\0')
6962 raise_error_syntax("bad substitution");
6963#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006964 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006965 case '@':
6966 if (quoted && sep)
6967 goto param;
6968 /* fall through */
6969 case '*': {
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006970 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006971 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006972
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006973 if (quoted)
6974 sep = 0;
6975 sep |= ifsset() ? ifsval()[0] : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006976 param:
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006977 sepc = sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006978 *quotedp = !sepc;
6979 ap = shellparam.p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006980 if (!ap)
6981 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006982 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006983 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006984
6985 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006986 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006987 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006988 }
6989 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006990 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006991 } /* case '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006992 case '0':
6993 case '1':
6994 case '2':
6995 case '3':
6996 case '4':
6997 case '5':
6998 case '6':
6999 case '7':
7000 case '8':
7001 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02007002 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007003 if (num < 0 || num > shellparam.nparam)
7004 return -1;
7005 p = num ? shellparam.p[num - 1] : arg0;
7006 goto value;
7007 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007008 /* NB: name has form "VAR=..." */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007009 p = lookupvar(name);
7010 value:
7011 if (!p)
7012 return -1;
7013
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007014 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007015#if ENABLE_UNICODE_SUPPORT
7016 if (subtype == VSLENGTH && len > 0) {
7017 reinit_unicode_for_ash();
7018 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00007019 STADJUST(-len, expdest);
7020 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007021 len = unicode_strlen(p);
7022 }
7023 }
7024#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007025 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007026 }
7027
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007028 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007029 STADJUST(-len, expdest);
7030 return len;
7031}
7032
7033/*
7034 * Expand a variable, and return a pointer to the next character in the
7035 * input string.
7036 */
7037static char *
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007038evalvar(char *p, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007039{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007040 char varflags;
7041 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02007042 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007043 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007044 char *var;
7045 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007046 int startloc;
7047 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007048
Denys Vlasenkob0d63382009-09-16 16:18:32 +02007049 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007050 subtype = varflags & VSTYPE;
Denys Vlasenko88e15702016-10-26 01:55:56 +02007051
7052 if (!subtype)
7053 raise_error_syntax("bad substitution");
7054
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007055 quoted = flag & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007056 var = p;
7057 easy = (!quoted || (*var == '@' && shellparam.nparam));
7058 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02007059 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007060
7061 again:
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007062 varlen = varvalue(var, varflags, flag, &quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007063 if (varflags & VSNUL)
7064 varlen--;
7065
7066 if (subtype == VSPLUS) {
7067 varlen = -1 - varlen;
7068 goto vsplus;
7069 }
7070
7071 if (subtype == VSMINUS) {
7072 vsplus:
7073 if (varlen < 0) {
7074 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02007075 p,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007076 flag | EXP_TILDE | EXP_WORD
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007077 );
7078 goto end;
7079 }
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007080 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007081 }
7082
7083 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007084 if (varlen >= 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007085 goto record;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007086
7087 subevalvar(p, var, 0, subtype, startloc, varflags,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007088 flag & ~QUOTES_ESC);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007089 varflags &= ~VSNUL;
7090 /*
7091 * Remove any recorded regions beyond
7092 * start of variable
7093 */
7094 removerecordregions(startloc);
7095 goto again;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007096 }
7097
7098 if (varlen < 0 && uflag)
7099 varunset(p, var, 0, 0);
7100
7101 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007102 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007103 goto record;
7104 }
7105
7106 if (subtype == VSNORMAL) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007107 record:
7108 if (!easy)
7109 goto end;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007110 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007111 goto end;
7112 }
7113
7114#if DEBUG
7115 switch (subtype) {
7116 case VSTRIMLEFT:
7117 case VSTRIMLEFTMAX:
7118 case VSTRIMRIGHT:
7119 case VSTRIMRIGHTMAX:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007120#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007121 case VSSUBSTR:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007122#endif
7123#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007124 case VSREPLACE:
7125 case VSREPLACEALL:
7126#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007127 break;
7128 default:
7129 abort();
7130 }
7131#endif
7132
7133 if (varlen >= 0) {
7134 /*
7135 * Terminate the string and start recording the pattern
7136 * right after it
7137 */
7138 STPUTC('\0', expdest);
7139 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007140 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007141 startloc, varflags, flag)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007142 int amount = expdest - (
7143 (char *)stackblock() + patloc - 1
7144 );
7145 STADJUST(-amount, expdest);
7146 }
7147 /* Remove any recorded regions beyond start of variable */
7148 removerecordregions(startloc);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007149 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007150 }
7151
7152 end:
7153 if (subtype != VSNORMAL) { /* skip to end of alternative */
7154 int nesting = 1;
7155 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007156 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007157 if (c == CTLESC)
7158 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02007159 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007160 if (varlen >= 0)
7161 argbackq = argbackq->next;
7162 } else if (c == CTLVAR) {
7163 if ((*p++ & VSTYPE) != VSNORMAL)
7164 nesting++;
7165 } else if (c == CTLENDVAR) {
7166 if (--nesting == 0)
7167 break;
7168 }
7169 }
7170 }
7171 return p;
7172}
7173
7174/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007175 * Add a file name to the list.
7176 */
7177static void
7178addfname(const char *name)
7179{
7180 struct strlist *sp;
7181
Denis Vlasenko597906c2008-02-20 16:38:54 +00007182 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02007183 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007184 *exparg.lastp = sp;
7185 exparg.lastp = &sp->next;
7186}
7187
Felix Fietkaub5b21122017-01-31 21:58:55 +01007188/* Avoid glob() (and thus, stat() et al) for words like "echo" */
7189static int
7190hasmeta(const char *p)
7191{
7192 static const char chars[] ALIGN1 = {
7193 '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
7194 };
7195
7196 for (;;) {
7197 p = strpbrk(p, chars);
7198 if (!p)
7199 break;
7200 switch ((unsigned char) *p) {
7201 case CTLQUOTEMARK:
7202 for (;;) {
7203 p++;
7204 if (*p == CTLQUOTEMARK)
7205 break;
7206 if (*p == CTLESC)
7207 p++;
7208 if (*p == '\0') /* huh? */
7209 return 0;
7210 }
7211 break;
7212 case '\\':
7213 case CTLESC:
7214 p++;
7215 if (*p == '\0')
7216 return 0;
7217 break;
7218 case '[':
7219 if (!strchr(p + 1, ']')) {
7220 /* It's not a properly closed [] pattern,
7221 * but other metas may follow. Continue checking.
7222 * my[file* _is_ globbed by bash
7223 * and matches filenames like "my[file1".
7224 */
7225 break;
7226 }
7227 /* fallthrough */
7228 default:
7229 /* case '*': */
7230 /* case '?': */
7231 return 1;
7232 }
7233 p++;
7234 }
7235
7236 return 0;
7237}
7238
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007239/* If we want to use glob() from libc... */
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007240#if !ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007241
7242/* Add the result of glob() to the list */
7243static void
7244addglob(const glob_t *pglob)
7245{
7246 char **p = pglob->gl_pathv;
7247
7248 do {
7249 addfname(*p);
7250 } while (*++p);
7251}
7252static void
7253expandmeta(struct strlist *str /*, int flag*/)
7254{
7255 /* TODO - EXP_REDIR */
7256
7257 while (str) {
7258 char *p;
7259 glob_t pglob;
7260 int i;
7261
7262 if (fflag)
7263 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007264
Felix Fietkaub5b21122017-01-31 21:58:55 +01007265 if (!hasmeta(str->text))
7266 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007267
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007268 INT_OFF;
7269 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007270// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7271// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7272//
7273// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7274// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7275// Which means you need to unescape the string, right? Not so fast:
7276// if there _is_ a file named "file\?" (with backslash), it is returned
7277// as "file\?" too (whichever pattern you used to find it, say, "file*").
Denys Vlasenko10ad6222017-04-17 16:13:32 +02007278// You DON'T KNOW by looking at the result whether you need to unescape it.
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007279//
7280// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7281// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7282// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7283// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7284// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7285// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7286 i = glob(p, 0, NULL, &pglob);
7287 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007288 if (p != str->text)
7289 free(p);
7290 switch (i) {
7291 case 0:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007292#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007293 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7294 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7295 goto nometa2;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007296#endif
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007297 addglob(&pglob);
7298 globfree(&pglob);
7299 INT_ON;
7300 break;
7301 case GLOB_NOMATCH:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007302 //nometa2:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007303 globfree(&pglob);
7304 INT_ON;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007305 nometa:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007306 *exparg.lastp = str;
7307 rmescapes(str->text, 0);
7308 exparg.lastp = &str->next;
7309 break;
7310 default: /* GLOB_NOSPACE */
7311 globfree(&pglob);
7312 INT_ON;
7313 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7314 }
7315 str = str->next;
7316 }
7317}
7318
7319#else
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007320/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007321
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007322/*
7323 * Do metacharacter (i.e. *, ?, [...]) expansion.
7324 */
7325static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007326expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007327{
7328 char *p;
7329 const char *cp;
7330 char *start;
7331 char *endname;
7332 int metaflag;
7333 struct stat statb;
7334 DIR *dirp;
7335 struct dirent *dp;
7336 int atend;
7337 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007338 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007339
7340 metaflag = 0;
7341 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007342 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007343 if (*p == '*' || *p == '?')
7344 metaflag = 1;
7345 else if (*p == '[') {
7346 char *q = p + 1;
7347 if (*q == '!')
7348 q++;
7349 for (;;) {
7350 if (*q == '\\')
7351 q++;
7352 if (*q == '/' || *q == '\0')
7353 break;
7354 if (*++q == ']') {
7355 metaflag = 1;
7356 break;
7357 }
7358 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007359 } else {
7360 if (*p == '\\')
7361 esc++;
7362 if (p[esc] == '/') {
7363 if (metaflag)
7364 break;
7365 start = p + esc + 1;
7366 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007367 }
7368 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007369 if (metaflag == 0) { /* we've reached the end of the file name */
7370 if (enddir != expdir)
7371 metaflag++;
7372 p = name;
7373 do {
7374 if (*p == '\\')
7375 p++;
7376 *enddir++ = *p;
7377 } while (*p++);
7378 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7379 addfname(expdir);
7380 return;
7381 }
7382 endname = p;
7383 if (name < start) {
7384 p = name;
7385 do {
7386 if (*p == '\\')
7387 p++;
7388 *enddir++ = *p++;
7389 } while (p < start);
7390 }
7391 if (enddir == expdir) {
7392 cp = ".";
7393 } else if (enddir == expdir + 1 && *expdir == '/') {
7394 cp = "/";
7395 } else {
7396 cp = expdir;
7397 enddir[-1] = '\0';
7398 }
7399 dirp = opendir(cp);
7400 if (dirp == NULL)
7401 return;
7402 if (enddir != expdir)
7403 enddir[-1] = '/';
7404 if (*endname == 0) {
7405 atend = 1;
7406 } else {
7407 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007408 *endname = '\0';
7409 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007410 }
7411 matchdot = 0;
7412 p = start;
7413 if (*p == '\\')
7414 p++;
7415 if (*p == '.')
7416 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007417 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007418 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007419 continue;
7420 if (pmatch(start, dp->d_name)) {
7421 if (atend) {
7422 strcpy(enddir, dp->d_name);
7423 addfname(expdir);
7424 } else {
7425 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7426 continue;
7427 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007428 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007429 }
7430 }
7431 }
7432 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007433 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007434 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007435}
7436
7437static struct strlist *
7438msort(struct strlist *list, int len)
7439{
7440 struct strlist *p, *q = NULL;
7441 struct strlist **lpp;
7442 int half;
7443 int n;
7444
7445 if (len <= 1)
7446 return list;
7447 half = len >> 1;
7448 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007449 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007450 q = p;
7451 p = p->next;
7452 }
7453 q->next = NULL; /* terminate first half of list */
7454 q = msort(list, half); /* sort first half of list */
7455 p = msort(p, len - half); /* sort second half */
7456 lpp = &list;
7457 for (;;) {
7458#if ENABLE_LOCALE_SUPPORT
7459 if (strcoll(p->text, q->text) < 0)
7460#else
7461 if (strcmp(p->text, q->text) < 0)
7462#endif
7463 {
7464 *lpp = p;
7465 lpp = &p->next;
7466 p = *lpp;
7467 if (p == NULL) {
7468 *lpp = q;
7469 break;
7470 }
7471 } else {
7472 *lpp = q;
7473 lpp = &q->next;
7474 q = *lpp;
7475 if (q == NULL) {
7476 *lpp = p;
7477 break;
7478 }
7479 }
7480 }
7481 return list;
7482}
7483
7484/*
7485 * Sort the results of file name expansion. It calculates the number of
7486 * strings to sort and then calls msort (short for merge sort) to do the
7487 * work.
7488 */
7489static struct strlist *
7490expsort(struct strlist *str)
7491{
7492 int len;
7493 struct strlist *sp;
7494
7495 len = 0;
7496 for (sp = str; sp; sp = sp->next)
7497 len++;
7498 return msort(str, len);
7499}
7500
7501static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007502expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007503{
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007504 /* TODO - EXP_REDIR */
7505
7506 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007507 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007508 struct strlist **savelastp;
7509 struct strlist *sp;
7510 char *p;
7511
7512 if (fflag)
7513 goto nometa;
Felix Fietkaub5b21122017-01-31 21:58:55 +01007514 if (!hasmeta(str->text))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007515 goto nometa;
7516 savelastp = exparg.lastp;
7517
7518 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007519 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007520 {
7521 int i = strlen(str->text);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007522//BUGGY estimation of how long expanded name can be
7523 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007524 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007525 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007526 free(expdir);
7527 if (p != str->text)
7528 free(p);
7529 INT_ON;
7530 if (exparg.lastp == savelastp) {
7531 /*
7532 * no matches
7533 */
7534 nometa:
7535 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007536 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007537 exparg.lastp = &str->next;
7538 } else {
7539 *exparg.lastp = NULL;
7540 *savelastp = sp = expsort(*savelastp);
7541 while (sp->next != NULL)
7542 sp = sp->next;
7543 exparg.lastp = &sp->next;
7544 }
7545 str = str->next;
7546 }
7547}
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007548#endif /* ENABLE_ASH_INTERNAL_GLOB */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007549
7550/*
7551 * Perform variable substitution and command substitution on an argument,
7552 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7553 * perform splitting and file name expansion. When arglist is NULL, perform
7554 * here document expansion.
7555 */
7556static void
7557expandarg(union node *arg, struct arglist *arglist, int flag)
7558{
7559 struct strlist *sp;
7560 char *p;
7561
7562 argbackq = arg->narg.backquote;
7563 STARTSTACKSTR(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007564 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007565 argstr(arg->narg.text, flag);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007566 p = _STPUTC('\0', expdest);
7567 expdest = p - 1;
7568 if (arglist == NULL) {
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007569 /* here document expanded */
7570 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007571 }
7572 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007573 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007574 exparg.lastp = &exparg.list;
7575 /*
7576 * TODO - EXP_REDIR
7577 */
7578 if (flag & EXP_FULL) {
7579 ifsbreakup(p, &exparg);
7580 *exparg.lastp = NULL;
7581 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007582 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007583 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +00007584 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007585 sp->text = p;
7586 *exparg.lastp = sp;
7587 exparg.lastp = &sp->next;
7588 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007589 *exparg.lastp = NULL;
7590 if (exparg.list) {
7591 *arglist->lastp = exparg.list;
7592 arglist->lastp = exparg.lastp;
7593 }
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007594
7595 out:
7596 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007597}
7598
7599/*
7600 * Expand shell variables and backquotes inside a here document.
7601 */
7602static void
7603expandhere(union node *arg, int fd)
7604{
Ron Yorston549deab2015-05-18 09:57:51 +02007605 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007606 full_write(fd, stackblock(), expdest - (char *)stackblock());
7607}
7608
7609/*
7610 * Returns true if the pattern matches the string.
7611 */
7612static int
7613patmatch(char *pattern, const char *string)
7614{
Denys Vlasenkobd43c672017-07-05 23:12:15 +02007615 char *p = preglob(pattern, 0);
7616 //bb_error_msg("fnmatch(pattern:'%s',str:'%s')", p, string);
7617 return pmatch(p, string);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007618}
7619
7620/*
7621 * See if a pattern matches in a case statement.
7622 */
7623static int
7624casematch(union node *pattern, char *val)
7625{
7626 struct stackmark smark;
7627 int result;
7628
7629 setstackmark(&smark);
7630 argbackq = pattern->narg.backquote;
7631 STARTSTACKSTR(expdest);
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007632 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007633 STACKSTRNUL(expdest);
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007634 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007635 result = patmatch(stackblock(), val);
7636 popstackmark(&smark);
7637 return result;
7638}
7639
7640
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007641/* ============ find_command */
7642
7643struct builtincmd {
7644 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007645 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007646 /* unsigned flags; */
7647};
7648#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007649/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007650 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007651#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007652#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007653
7654struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007655 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007656 union param {
7657 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007658 /* index >= 0 for commands without path (slashes) */
7659 /* (TODO: what exactly does the value mean? PATH position?) */
7660 /* index == -1 for commands with slashes */
7661 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007662 const struct builtincmd *cmd;
7663 struct funcnode *func;
7664 } u;
7665};
7666/* values of cmdtype */
7667#define CMDUNKNOWN -1 /* no entry in table for command */
7668#define CMDNORMAL 0 /* command is an executable program */
7669#define CMDFUNCTION 1 /* command is a shell function */
7670#define CMDBUILTIN 2 /* command is a shell builtin */
7671
7672/* action to find_command() */
7673#define DO_ERR 0x01 /* prints errors */
7674#define DO_ABS 0x02 /* checks absolute paths */
7675#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7676#define DO_ALTPATH 0x08 /* using alternate path */
7677#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7678
7679static void find_command(char *, struct cmdentry *, int, const char *);
7680
7681
7682/* ============ Hashing commands */
7683
7684/*
7685 * When commands are first encountered, they are entered in a hash table.
7686 * This ensures that a full path search will not have to be done for them
7687 * on each invocation.
7688 *
7689 * We should investigate converting to a linear search, even though that
7690 * would make the command name "hash" a misnomer.
7691 */
7692
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007693struct tblentry {
7694 struct tblentry *next; /* next entry in hash chain */
7695 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007696 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007697 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007698 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007699};
7700
Denis Vlasenko01631112007-12-16 17:20:38 +00007701static struct tblentry **cmdtable;
7702#define INIT_G_cmdtable() do { \
7703 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7704} while (0)
7705
7706static int builtinloc = -1; /* index in path of %builtin, or -1 */
7707
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007708
7709static void
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02007710tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007711{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007712#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007713 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007714 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007715 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007716 while (*envp)
7717 putenv(*envp++);
Denys Vlasenkob31b61b2017-07-26 13:42:53 +02007718 popredir(/*drop:*/ 1, /*restore:*/ 0);
Denys Vlasenko69a5ec92017-07-07 19:08:56 +02007719 run_applet_no_and_exit(applet_no, cmd, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007720 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007721 /* re-exec ourselves with the new arguments */
7722 execve(bb_busybox_exec_path, argv, envp);
7723 /* If they called chroot or otherwise made the binary no longer
7724 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007725 }
7726#endif
7727
7728 repeat:
7729#ifdef SYSV
7730 do {
7731 execve(cmd, argv, envp);
7732 } while (errno == EINTR);
7733#else
7734 execve(cmd, argv, envp);
7735#endif
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02007736 if (cmd != bb_busybox_exec_path && errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007737 /* Run "cmd" as a shell script:
7738 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7739 * "If the execve() function fails with ENOEXEC, the shell
7740 * shall execute a command equivalent to having a shell invoked
7741 * with the command name as its first operand,
7742 * with any remaining arguments passed to the new shell"
7743 *
7744 * That is, do not use $SHELL, user's shell, or /bin/sh;
7745 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007746 *
7747 * Note that bash reads ~80 chars of the file, and if it sees
7748 * a zero byte before it sees newline, it doesn't try to
7749 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007750 * message and exit code 126. For one, this prevents attempts
7751 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007752 */
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02007753 argv[0] = (char*) cmd;
7754 cmd = bb_busybox_exec_path;
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007755 /* NB: this is only possible because all callers of shellexec()
7756 * ensure that the argv[-1] slot exists!
7757 */
7758 argv--;
7759 argv[0] = (char*) "ash";
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007760 goto repeat;
7761 }
7762}
7763
7764/*
7765 * Exec a program. Never returns. If you change this routine, you may
7766 * have to change the find_command routine as well.
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007767 * argv[-1] must exist and be writable! See tryexec() for why.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007768 */
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007769static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN;
7770static void shellexec(char *prog, char **argv, const char *path, int idx)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007771{
7772 char *cmdname;
7773 int e;
7774 char **envp;
7775 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007776 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007777
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007778 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007779 if (strchr(prog, '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007780#if ENABLE_FEATURE_SH_STANDALONE
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007781 || (applet_no = find_applet_by_name(prog)) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007782#endif
7783 ) {
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007784 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007785 if (applet_no >= 0) {
7786 /* We tried execing ourself, but it didn't work.
7787 * Maybe /proc/self/exe doesn't exist?
7788 * Try $PATH search.
7789 */
7790 goto try_PATH;
7791 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007792 e = errno;
7793 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007794 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007795 e = ENOENT;
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007796 while ((cmdname = path_advance(&path, prog)) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007797 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007798 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007799 if (errno != ENOENT && errno != ENOTDIR)
7800 e = errno;
7801 }
7802 stunalloc(cmdname);
7803 }
7804 }
7805
7806 /* Map to POSIX errors */
7807 switch (e) {
7808 case EACCES:
7809 exerrno = 126;
7810 break;
7811 case ENOENT:
7812 exerrno = 127;
7813 break;
7814 default:
7815 exerrno = 2;
7816 break;
7817 }
7818 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007819 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007820 prog, e, suppress_int));
7821 ash_msg_and_raise(EXEXIT, "%s: %s", prog, errmsg(e, "not found"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007822 /* NOTREACHED */
7823}
7824
7825static void
7826printentry(struct tblentry *cmdp)
7827{
7828 int idx;
7829 const char *path;
7830 char *name;
7831
7832 idx = cmdp->param.index;
7833 path = pathval();
7834 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007835 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007836 stunalloc(name);
7837 } while (--idx >= 0);
7838 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7839}
7840
7841/*
7842 * Clear out command entries. The argument specifies the first entry in
7843 * PATH which has changed.
7844 */
7845static void
7846clearcmdentry(int firstchange)
7847{
7848 struct tblentry **tblp;
7849 struct tblentry **pp;
7850 struct tblentry *cmdp;
7851
7852 INT_OFF;
7853 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7854 pp = tblp;
7855 while ((cmdp = *pp) != NULL) {
7856 if ((cmdp->cmdtype == CMDNORMAL &&
7857 cmdp->param.index >= firstchange)
7858 || (cmdp->cmdtype == CMDBUILTIN &&
7859 builtinloc >= firstchange)
7860 ) {
7861 *pp = cmdp->next;
7862 free(cmdp);
7863 } else {
7864 pp = &cmdp->next;
7865 }
7866 }
7867 }
7868 INT_ON;
7869}
7870
7871/*
7872 * Locate a command in the command hash table. If "add" is nonzero,
7873 * add the command to the table if it is not already present. The
7874 * variable "lastcmdentry" is set to point to the address of the link
7875 * pointing to the entry, so that delete_cmd_entry can delete the
7876 * entry.
7877 *
7878 * Interrupts must be off if called with add != 0.
7879 */
7880static struct tblentry **lastcmdentry;
7881
7882static struct tblentry *
7883cmdlookup(const char *name, int add)
7884{
7885 unsigned int hashval;
7886 const char *p;
7887 struct tblentry *cmdp;
7888 struct tblentry **pp;
7889
7890 p = name;
7891 hashval = (unsigned char)*p << 4;
7892 while (*p)
7893 hashval += (unsigned char)*p++;
7894 hashval &= 0x7FFF;
7895 pp = &cmdtable[hashval % CMDTABLESIZE];
7896 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7897 if (strcmp(cmdp->cmdname, name) == 0)
7898 break;
7899 pp = &cmdp->next;
7900 }
7901 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007902 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7903 + strlen(name)
7904 /* + 1 - already done because
7905 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007906 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007907 cmdp->cmdtype = CMDUNKNOWN;
7908 strcpy(cmdp->cmdname, name);
7909 }
7910 lastcmdentry = pp;
7911 return cmdp;
7912}
7913
7914/*
7915 * Delete the command entry returned on the last lookup.
7916 */
7917static void
7918delete_cmd_entry(void)
7919{
7920 struct tblentry *cmdp;
7921
7922 INT_OFF;
7923 cmdp = *lastcmdentry;
7924 *lastcmdentry = cmdp->next;
7925 if (cmdp->cmdtype == CMDFUNCTION)
7926 freefunc(cmdp->param.func);
7927 free(cmdp);
7928 INT_ON;
7929}
7930
7931/*
7932 * Add a new command entry, replacing any existing command entry for
7933 * the same name - except special builtins.
7934 */
7935static void
7936addcmdentry(char *name, struct cmdentry *entry)
7937{
7938 struct tblentry *cmdp;
7939
7940 cmdp = cmdlookup(name, 1);
7941 if (cmdp->cmdtype == CMDFUNCTION) {
7942 freefunc(cmdp->param.func);
7943 }
7944 cmdp->cmdtype = entry->cmdtype;
7945 cmdp->param = entry->u;
7946 cmdp->rehash = 0;
7947}
7948
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007949static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007950hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007951{
7952 struct tblentry **pp;
7953 struct tblentry *cmdp;
7954 int c;
7955 struct cmdentry entry;
7956 char *name;
7957
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007958 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007959 clearcmdentry(0);
7960 return 0;
7961 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007962
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007963 if (*argptr == NULL) {
7964 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7965 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7966 if (cmdp->cmdtype == CMDNORMAL)
7967 printentry(cmdp);
7968 }
7969 }
7970 return 0;
7971 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007972
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007973 c = 0;
7974 while ((name = *argptr) != NULL) {
7975 cmdp = cmdlookup(name, 0);
7976 if (cmdp != NULL
7977 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007978 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7979 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007980 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007981 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007982 find_command(name, &entry, DO_ERR, pathval());
7983 if (entry.cmdtype == CMDUNKNOWN)
7984 c = 1;
7985 argptr++;
7986 }
7987 return c;
7988}
7989
7990/*
7991 * Called when a cd is done. Marks all commands so the next time they
7992 * are executed they will be rehashed.
7993 */
7994static void
7995hashcd(void)
7996{
7997 struct tblentry **pp;
7998 struct tblentry *cmdp;
7999
8000 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8001 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008002 if (cmdp->cmdtype == CMDNORMAL
8003 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02008004 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008005 && builtinloc > 0)
8006 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008007 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008008 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008009 }
8010 }
8011}
8012
8013/*
8014 * Fix command hash table when PATH changed.
8015 * Called before PATH is changed. The argument is the new value of PATH;
8016 * pathval() still returns the old value at this point.
8017 * Called with interrupts off.
8018 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008019static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008020changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008021{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008022 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008023 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008024 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008025 int idx_bltin;
8026
8027 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008028 firstchange = 9999; /* assume no change */
8029 idx = 0;
8030 idx_bltin = -1;
8031 for (;;) {
8032 if (*old != *new) {
8033 firstchange = idx;
8034 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008035 || (*old == ':' && *new == '\0')
8036 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008037 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008038 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008039 old = new; /* ignore subsequent differences */
8040 }
8041 if (*new == '\0')
8042 break;
8043 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
8044 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008045 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008046 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008047 new++;
8048 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008049 }
8050 if (builtinloc < 0 && idx_bltin >= 0)
8051 builtinloc = idx_bltin; /* zap builtins */
8052 if (builtinloc >= 0 && idx_bltin < 0)
8053 firstchange = 0;
8054 clearcmdentry(firstchange);
8055 builtinloc = idx_bltin;
8056}
Ron Yorston95ebcf72015-11-03 09:42:23 +00008057enum {
8058 TEOF,
8059 TNL,
8060 TREDIR,
8061 TWORD,
8062 TSEMI,
8063 TBACKGND,
8064 TAND,
8065 TOR,
8066 TPIPE,
8067 TLP,
8068 TRP,
8069 TENDCASE,
8070 TENDBQUOTE,
8071 TNOT,
8072 TCASE,
8073 TDO,
8074 TDONE,
8075 TELIF,
8076 TELSE,
8077 TESAC,
8078 TFI,
8079 TFOR,
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008080#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +00008081 TFUNCTION,
8082#endif
8083 TIF,
8084 TIN,
8085 TTHEN,
8086 TUNTIL,
8087 TWHILE,
8088 TBEGIN,
8089 TEND
8090};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008091typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008092
Denys Vlasenko888527c2016-10-02 16:54:17 +02008093/* Nth bit indicates if token marks the end of a list */
8094enum {
8095 tokendlist = 0
8096 /* 0 */ | (1u << TEOF)
8097 /* 1 */ | (0u << TNL)
8098 /* 2 */ | (0u << TREDIR)
8099 /* 3 */ | (0u << TWORD)
8100 /* 4 */ | (0u << TSEMI)
8101 /* 5 */ | (0u << TBACKGND)
8102 /* 6 */ | (0u << TAND)
8103 /* 7 */ | (0u << TOR)
8104 /* 8 */ | (0u << TPIPE)
8105 /* 9 */ | (0u << TLP)
8106 /* 10 */ | (1u << TRP)
8107 /* 11 */ | (1u << TENDCASE)
8108 /* 12 */ | (1u << TENDBQUOTE)
8109 /* 13 */ | (0u << TNOT)
8110 /* 14 */ | (0u << TCASE)
8111 /* 15 */ | (1u << TDO)
8112 /* 16 */ | (1u << TDONE)
8113 /* 17 */ | (1u << TELIF)
8114 /* 18 */ | (1u << TELSE)
8115 /* 19 */ | (1u << TESAC)
8116 /* 20 */ | (1u << TFI)
8117 /* 21 */ | (0u << TFOR)
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008118#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008119 /* 22 */ | (0u << TFUNCTION)
Denys Vlasenko80729a42016-10-02 22:33:15 +02008120#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008121 /* 23 */ | (0u << TIF)
8122 /* 24 */ | (0u << TIN)
8123 /* 25 */ | (1u << TTHEN)
8124 /* 26 */ | (0u << TUNTIL)
8125 /* 27 */ | (0u << TWHILE)
8126 /* 28 */ | (0u << TBEGIN)
8127 /* 29 */ | (1u << TEND)
8128 , /* thus far 29 bits used */
8129};
8130
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008131static const char *const tokname_array[] = {
Denys Vlasenko888527c2016-10-02 16:54:17 +02008132 "end of file",
8133 "newline",
8134 "redirection",
8135 "word",
8136 ";",
8137 "&",
8138 "&&",
8139 "||",
8140 "|",
8141 "(",
8142 ")",
8143 ";;",
8144 "`",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008145#define KWDOFFSET 13
8146 /* the following are keywords */
Denys Vlasenko888527c2016-10-02 16:54:17 +02008147 "!",
8148 "case",
8149 "do",
8150 "done",
8151 "elif",
8152 "else",
8153 "esac",
8154 "fi",
8155 "for",
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008156#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008157 "function",
Ron Yorston95ebcf72015-11-03 09:42:23 +00008158#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008159 "if",
8160 "in",
8161 "then",
8162 "until",
8163 "while",
8164 "{",
8165 "}",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008166};
8167
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008168/* Wrapper around strcmp for qsort/bsearch/... */
8169static int
8170pstrcmp(const void *a, const void *b)
8171{
Denys Vlasenko888527c2016-10-02 16:54:17 +02008172 return strcmp((char*)a, *(char**)b);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008173}
8174
8175static const char *const *
8176findkwd(const char *s)
8177{
8178 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00008179 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8180 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008181}
8182
8183/*
8184 * Locate and print what a word is...
8185 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008186static int
Ron Yorston3f221112015-08-03 13:47:33 +01008187describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008188{
8189 struct cmdentry entry;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008190#if ENABLE_ASH_ALIAS
8191 const struct alias *ap;
8192#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008193
8194 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008195
8196 if (describe_command_verbose) {
8197 out1str(command);
8198 }
8199
8200 /* First look at the keywords */
8201 if (findkwd(command)) {
8202 out1str(describe_command_verbose ? " is a shell keyword" : command);
8203 goto out;
8204 }
8205
8206#if ENABLE_ASH_ALIAS
8207 /* Then look at the aliases */
8208 ap = lookupalias(command, 0);
8209 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008210 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008211 out1str("alias ");
8212 printalias(ap);
8213 return 0;
8214 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00008215 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008216 goto out;
8217 }
8218#endif
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008219 /* Brute force */
8220 find_command(command, &entry, DO_ABS, path);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008221
8222 switch (entry.cmdtype) {
8223 case CMDNORMAL: {
8224 int j = entry.u.index;
8225 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008226 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008227 p = command;
8228 } else {
8229 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008230 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008231 stunalloc(p);
8232 } while (--j >= 0);
8233 }
8234 if (describe_command_verbose) {
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008235 out1fmt(" is %s", p);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008236 } else {
8237 out1str(p);
8238 }
8239 break;
8240 }
8241
8242 case CMDFUNCTION:
8243 if (describe_command_verbose) {
8244 out1str(" is a shell function");
8245 } else {
8246 out1str(command);
8247 }
8248 break;
8249
8250 case CMDBUILTIN:
8251 if (describe_command_verbose) {
8252 out1fmt(" is a %sshell builtin",
8253 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8254 "special " : nullstr
8255 );
8256 } else {
8257 out1str(command);
8258 }
8259 break;
8260
8261 default:
8262 if (describe_command_verbose) {
8263 out1str(": not found\n");
8264 }
8265 return 127;
8266 }
8267 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008268 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008269 return 0;
8270}
8271
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008272static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008273typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008274{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008275 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008276 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008277 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008278
Denis Vlasenko46846e22007-05-20 13:08:31 +00008279 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008280 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008281 i++;
8282 verbose = 0;
8283 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008284 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008285 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008286 }
8287 return err;
8288}
8289
8290#if ENABLE_ASH_CMDCMD
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008291/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8292static char **
8293parse_command_args(char **argv, const char **path)
8294{
8295 char *cp, c;
8296
8297 for (;;) {
8298 cp = *++argv;
8299 if (!cp)
8300 return NULL;
8301 if (*cp++ != '-')
8302 break;
8303 c = *cp++;
8304 if (!c)
8305 break;
8306 if (c == '-' && !*cp) {
8307 if (!*++argv)
8308 return NULL;
8309 break;
8310 }
8311 do {
8312 switch (c) {
8313 case 'p':
8314 *path = bb_default_path;
8315 break;
8316 default:
8317 /* run 'typecmd' for other options */
8318 return NULL;
8319 }
8320 c = *cp++;
8321 } while (c);
8322 }
8323 return argv;
8324}
8325
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008326static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008327commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008328{
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008329 char *cmd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008330 int c;
8331 enum {
8332 VERIFY_BRIEF = 1,
8333 VERIFY_VERBOSE = 2,
8334 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008335 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008336
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008337 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8338 * never reaches this function.
8339 */
8340
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008341 while ((c = nextopt("pvV")) != '\0')
8342 if (c == 'V')
8343 verify |= VERIFY_VERBOSE;
8344 else if (c == 'v')
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008345 /*verify |= VERIFY_BRIEF*/;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008346#if DEBUG
8347 else if (c != 'p')
8348 abort();
8349#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008350 else
8351 path = bb_default_path;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008352
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008353 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008354 cmd = *argptr;
8355 if (/*verify && */ cmd)
8356 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008357
8358 return 0;
8359}
8360#endif
8361
8362
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008363/*static int funcblocksize; // size of structures in function */
8364/*static int funcstringsize; // size of strings in node */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008365static void *funcblock; /* block to allocate function from */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008366static char *funcstring_end; /* end of block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008367
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008368static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008369 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8370 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8371 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8372 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8373 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8374 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8375 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8376 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8377 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8378 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8379 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8380 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8381 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8382 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8383 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8384 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8385 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008386#if BASH_REDIR_OUTPUT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008387 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008388#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008389 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8390 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8391 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8392 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8393 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8394 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8395 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8396 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8397 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008398};
8399
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008400static int calcsize(int funcblocksize, union node *n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008401
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008402static int
8403sizenodelist(int funcblocksize, struct nodelist *lp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008404{
8405 while (lp) {
8406 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008407 funcblocksize = calcsize(funcblocksize, lp->n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008408 lp = lp->next;
8409 }
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008410 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008411}
8412
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008413static int
8414calcsize(int funcblocksize, union node *n)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008415{
8416 if (n == NULL)
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008417 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008418 funcblocksize += nodesize[n->type];
8419 switch (n->type) {
8420 case NCMD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008421 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8422 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8423 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008424 break;
8425 case NPIPE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008426 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008427 break;
8428 case NREDIR:
8429 case NBACKGND:
8430 case NSUBSHELL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008431 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8432 funcblocksize = calcsize(funcblocksize, n->nredir.n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008433 break;
8434 case NAND:
8435 case NOR:
8436 case NSEMI:
8437 case NWHILE:
8438 case NUNTIL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008439 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8440 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008441 break;
8442 case NIF:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008443 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8444 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8445 funcblocksize = calcsize(funcblocksize, n->nif.test);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008446 break;
8447 case NFOR:
Denys Vlasenko561639a2016-10-07 04:28:33 +02008448 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008449 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8450 funcblocksize = calcsize(funcblocksize, n->nfor.args);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008451 break;
8452 case NCASE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008453 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8454 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008455 break;
8456 case NCLIST:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008457 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8458 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8459 funcblocksize = calcsize(funcblocksize, n->nclist.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008460 break;
8461 case NDEFUN:
8462 case NARG:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008463 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
Denys Vlasenko561639a2016-10-07 04:28:33 +02008464 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008465 funcblocksize = calcsize(funcblocksize, n->narg.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008466 break;
8467 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008468#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008469 case NTO2:
8470#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008471 case NCLOBBER:
8472 case NFROM:
8473 case NFROMTO:
8474 case NAPPEND:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008475 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8476 funcblocksize = calcsize(funcblocksize, n->nfile.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008477 break;
8478 case NTOFD:
8479 case NFROMFD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008480 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8481 funcblocksize = calcsize(funcblocksize, n->ndup.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008482 break;
8483 case NHERE:
8484 case NXHERE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008485 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8486 funcblocksize = calcsize(funcblocksize, n->nhere.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008487 break;
8488 case NNOT:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008489 funcblocksize = calcsize(funcblocksize, n->nnot.com);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008490 break;
8491 };
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008492 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008493}
8494
8495static char *
8496nodeckstrdup(char *s)
8497{
Denys Vlasenko561639a2016-10-07 04:28:33 +02008498 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008499 return strcpy(funcstring_end, s);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008500}
8501
8502static union node *copynode(union node *);
8503
8504static struct nodelist *
8505copynodelist(struct nodelist *lp)
8506{
8507 struct nodelist *start;
8508 struct nodelist **lpp;
8509
8510 lpp = &start;
8511 while (lp) {
8512 *lpp = funcblock;
8513 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8514 (*lpp)->n = copynode(lp->n);
8515 lp = lp->next;
8516 lpp = &(*lpp)->next;
8517 }
8518 *lpp = NULL;
8519 return start;
8520}
8521
8522static union node *
8523copynode(union node *n)
8524{
8525 union node *new;
8526
8527 if (n == NULL)
8528 return NULL;
8529 new = funcblock;
8530 funcblock = (char *) funcblock + nodesize[n->type];
8531
8532 switch (n->type) {
8533 case NCMD:
8534 new->ncmd.redirect = copynode(n->ncmd.redirect);
8535 new->ncmd.args = copynode(n->ncmd.args);
8536 new->ncmd.assign = copynode(n->ncmd.assign);
8537 break;
8538 case NPIPE:
8539 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008540 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008541 break;
8542 case NREDIR:
8543 case NBACKGND:
8544 case NSUBSHELL:
8545 new->nredir.redirect = copynode(n->nredir.redirect);
8546 new->nredir.n = copynode(n->nredir.n);
8547 break;
8548 case NAND:
8549 case NOR:
8550 case NSEMI:
8551 case NWHILE:
8552 case NUNTIL:
8553 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8554 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8555 break;
8556 case NIF:
8557 new->nif.elsepart = copynode(n->nif.elsepart);
8558 new->nif.ifpart = copynode(n->nif.ifpart);
8559 new->nif.test = copynode(n->nif.test);
8560 break;
8561 case NFOR:
8562 new->nfor.var = nodeckstrdup(n->nfor.var);
8563 new->nfor.body = copynode(n->nfor.body);
8564 new->nfor.args = copynode(n->nfor.args);
8565 break;
8566 case NCASE:
8567 new->ncase.cases = copynode(n->ncase.cases);
8568 new->ncase.expr = copynode(n->ncase.expr);
8569 break;
8570 case NCLIST:
8571 new->nclist.body = copynode(n->nclist.body);
8572 new->nclist.pattern = copynode(n->nclist.pattern);
8573 new->nclist.next = copynode(n->nclist.next);
8574 break;
8575 case NDEFUN:
8576 case NARG:
8577 new->narg.backquote = copynodelist(n->narg.backquote);
8578 new->narg.text = nodeckstrdup(n->narg.text);
8579 new->narg.next = copynode(n->narg.next);
8580 break;
8581 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008582#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008583 case NTO2:
8584#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008585 case NCLOBBER:
8586 case NFROM:
8587 case NFROMTO:
8588 case NAPPEND:
8589 new->nfile.fname = copynode(n->nfile.fname);
8590 new->nfile.fd = n->nfile.fd;
8591 new->nfile.next = copynode(n->nfile.next);
8592 break;
8593 case NTOFD:
8594 case NFROMFD:
8595 new->ndup.vname = copynode(n->ndup.vname);
8596 new->ndup.dupfd = n->ndup.dupfd;
8597 new->ndup.fd = n->ndup.fd;
8598 new->ndup.next = copynode(n->ndup.next);
8599 break;
8600 case NHERE:
8601 case NXHERE:
8602 new->nhere.doc = copynode(n->nhere.doc);
8603 new->nhere.fd = n->nhere.fd;
8604 new->nhere.next = copynode(n->nhere.next);
8605 break;
8606 case NNOT:
8607 new->nnot.com = copynode(n->nnot.com);
8608 break;
8609 };
8610 new->type = n->type;
8611 return new;
8612}
8613
8614/*
8615 * Make a copy of a parse tree.
8616 */
8617static struct funcnode *
8618copyfunc(union node *n)
8619{
8620 struct funcnode *f;
8621 size_t blocksize;
8622
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008623 /*funcstringsize = 0;*/
8624 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8625 f = ckzalloc(blocksize /* + funcstringsize */);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008626 funcblock = (char *) f + offsetof(struct funcnode, n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008627 funcstring_end = (char *) f + blocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008628 copynode(n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008629 /* f->count = 0; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008630 return f;
8631}
8632
8633/*
8634 * Define a shell function.
8635 */
8636static void
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008637defun(union node *func)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008638{
8639 struct cmdentry entry;
8640
8641 INT_OFF;
8642 entry.cmdtype = CMDFUNCTION;
8643 entry.u.func = copyfunc(func);
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008644 addcmdentry(func->narg.text, &entry);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008645 INT_ON;
8646}
8647
Denis Vlasenko4b875702009-03-19 13:30:04 +00008648/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008649#define SKIPBREAK (1 << 0)
8650#define SKIPCONT (1 << 1)
8651#define SKIPFUNC (1 << 2)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008652static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008653static int skipcount; /* number of levels to skip */
8654static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008655static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008656
Denis Vlasenko4b875702009-03-19 13:30:04 +00008657/* Forward decl way out to parsing code - dotrap needs it */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008658static int evalstring(char *s, int flags);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008659
Denis Vlasenko4b875702009-03-19 13:30:04 +00008660/* Called to execute a trap.
8661 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008662 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008663 *
8664 * Perhaps we should avoid entering new trap handlers
8665 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008666 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008667static void
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008668dotrap(void)
8669{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008670 uint8_t *g;
8671 int sig;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008672 uint8_t last_status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008673
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008674 if (!pending_sig)
8675 return;
8676
8677 last_status = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008678 pending_sig = 0;
Denys Vlasenkode892052016-10-02 01:49:13 +02008679 barrier();
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008680
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008681 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008682 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008683 char *p;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008684
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008685 if (!*g)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008686 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008687
8688 if (evalskip) {
8689 pending_sig = sig;
8690 break;
8691 }
8692
8693 p = trap[sig];
Denis Vlasenko4b875702009-03-19 13:30:04 +00008694 /* non-trapped SIGINT is handled separately by raise_interrupt,
8695 * don't upset it by resetting gotsig[SIGINT-1] */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008696 if (sig == SIGINT && !p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008697 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008698
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008699 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008700 *g = 0;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008701 if (!p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008702 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008703 evalstring(p, 0);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008704 }
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008705 exitstatus = last_status;
8706 TRACE(("dotrap returns\n"));
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008707}
8708
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008709/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008710static int evalloop(union node *, int);
8711static int evalfor(union node *, int);
8712static int evalcase(union node *, int);
8713static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008714static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008715static int evalpipe(union node *, int);
8716static int evalcommand(union node *, int);
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008717static int evalbltin(const struct builtincmd *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008718static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008719
Eric Andersen62483552001-07-10 06:09:16 +00008720/*
Eric Andersenc470f442003-07-28 09:56:35 +00008721 * Evaluate a parse tree. The value is left in the global variable
8722 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008723 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008724static int
Eric Andersenc470f442003-07-28 09:56:35 +00008725evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008726{
Eric Andersenc470f442003-07-28 09:56:35 +00008727 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008728 int (*evalfn)(union node *, int);
8729 int status = 0;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008730
Eric Andersenc470f442003-07-28 09:56:35 +00008731 if (n == NULL) {
8732 TRACE(("evaltree(NULL) called\n"));
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02008733 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00008734 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008735 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008736
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008737 dotrap();
8738
Eric Andersenc470f442003-07-28 09:56:35 +00008739 switch (n->type) {
8740 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008741#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008742 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008743 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008744 break;
8745#endif
8746 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008747 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008748 goto setstatus;
8749 case NREDIR:
8750 expredir(n->nredir.redirect);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02008751 pushredir(n->nredir.redirect);
Eric Andersenc470f442003-07-28 09:56:35 +00008752 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8753 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008754 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008755 }
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02008756 if (n->nredir.redirect)
8757 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
Eric Andersenc470f442003-07-28 09:56:35 +00008758 goto setstatus;
8759 case NCMD:
8760 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008761 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008762 if (eflag && !(flags & EV_TESTED))
8763 checkexit = ~0;
8764 goto calleval;
8765 case NFOR:
8766 evalfn = evalfor;
8767 goto calleval;
8768 case NWHILE:
8769 case NUNTIL:
8770 evalfn = evalloop;
8771 goto calleval;
8772 case NSUBSHELL:
8773 case NBACKGND:
8774 evalfn = evalsubshell;
Denys Vlasenkocf98b0c2016-10-25 18:19:39 +02008775 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00008776 case NPIPE:
8777 evalfn = evalpipe;
8778 goto checkexit;
8779 case NCASE:
8780 evalfn = evalcase;
8781 goto calleval;
8782 case NAND:
8783 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008784 case NSEMI: {
8785
Eric Andersenc470f442003-07-28 09:56:35 +00008786#if NAND + 1 != NOR
8787#error NAND + 1 != NOR
8788#endif
8789#if NOR + 1 != NSEMI
8790#error NOR + 1 != NSEMI
8791#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008792 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008793 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00008794 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008795 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008796 );
Denys Vlasenkobc1a0082016-10-02 15:31:33 +02008797 if ((!status) == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00008798 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008799 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008800 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008801 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008802 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008803 status = evalfn(n, flags);
8804 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008805 }
Eric Andersenc470f442003-07-28 09:56:35 +00008806 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008807 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008808 if (evalskip)
8809 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008810 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00008811 n = n->nif.ifpart;
8812 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008813 }
8814 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008815 n = n->nif.elsepart;
8816 goto evaln;
8817 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008818 status = 0;
8819 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00008820 case NDEFUN:
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008821 defun(n);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008822 /* Not necessary. To test it:
8823 * "false; f() { qwerty; }; echo $?" should print 0.
8824 */
8825 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008826 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00008827 exitstatus = status;
8828 break;
8829 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008830 out:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008831 /* Order of checks below is important:
8832 * signal handlers trigger before exit caused by "set -e".
8833 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008834 dotrap();
8835
8836 if (checkexit & status)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008837 raise_exception(EXEXIT);
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008838 if (flags & EV_EXIT)
8839 raise_exception(EXEXIT);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008840
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008841 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008842 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00008843}
8844
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02008845static int
8846skiploop(void)
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008847{
8848 int skip = evalskip;
8849
8850 switch (skip) {
8851 case 0:
8852 break;
8853 case SKIPBREAK:
8854 case SKIPCONT:
8855 if (--skipcount <= 0) {
8856 evalskip = 0;
8857 break;
8858 }
8859 skip = SKIPBREAK;
8860 break;
8861 }
8862 return skip;
8863}
8864
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008865static int
Eric Andersenc470f442003-07-28 09:56:35 +00008866evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008867{
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008868 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00008869 int status;
8870
8871 loopnest++;
8872 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008873 flags &= EV_TESTED;
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008874 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008875 int i;
8876
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008877 i = evaltree(n->nbinary.ch1, EV_TESTED);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008878 skip = skiploop();
8879 if (skip == SKIPFUNC)
8880 status = i;
8881 if (skip)
8882 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00008883 if (n->type != NWHILE)
8884 i = !i;
8885 if (i != 0)
8886 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008887 status = evaltree(n->nbinary.ch2, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008888 skip = skiploop();
8889 } while (!(skip & ~SKIPCONT));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008890 loopnest--;
8891
8892 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008893}
8894
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008895static int
Eric Andersenc470f442003-07-28 09:56:35 +00008896evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008897{
8898 struct arglist arglist;
8899 union node *argp;
8900 struct strlist *sp;
8901 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008902 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008903
8904 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008905 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008906 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008907 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02008908 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersencb57d552001-06-28 07:25:16 +00008909 }
8910 *arglist.lastp = NULL;
8911
Eric Andersencb57d552001-06-28 07:25:16 +00008912 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008913 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008914 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008915 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008916 status = evaltree(n->nfor.body, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008917 if (skiploop() & ~SKIPCONT)
Eric Andersencb57d552001-06-28 07:25:16 +00008918 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008919 }
8920 loopnest--;
Eric Andersencb57d552001-06-28 07:25:16 +00008921 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008922
8923 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008924}
8925
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008926static int
Eric Andersenc470f442003-07-28 09:56:35 +00008927evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008928{
8929 union node *cp;
8930 union node *patp;
8931 struct arglist arglist;
8932 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008933 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008934
8935 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008936 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008937 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00008938 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008939 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8940 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008941 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008942 /* Ensure body is non-empty as otherwise
8943 * EV_EXIT may prevent us from setting the
8944 * exit status.
8945 */
8946 if (evalskip == 0 && cp->nclist.body) {
8947 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008948 }
8949 goto out;
8950 }
8951 }
8952 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008953 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008954 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008955
8956 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008957}
8958
Eric Andersenc470f442003-07-28 09:56:35 +00008959/*
8960 * Kick off a subshell to evaluate a tree.
8961 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008962static int
Eric Andersenc470f442003-07-28 09:56:35 +00008963evalsubshell(union node *n, int flags)
8964{
8965 struct job *jp;
Denys Vlasenko098b7132017-01-11 19:59:03 +01008966 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
Eric Andersenc470f442003-07-28 09:56:35 +00008967 int status;
8968
8969 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02008970 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00008971 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008972 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01008973 if (backgnd == FORK_FG)
8974 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00008975 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008976 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02008977 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008978 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008979 flags |= EV_EXIT;
8980 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02008981 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00008982 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00008983 redirect(n->nredir.redirect, 0);
8984 evaltreenr(n->nredir.n, flags);
8985 /* never returns */
8986 }
Denys Vlasenko70392332016-10-27 02:31:55 +02008987 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00008988 status = 0;
Denys Vlasenko098b7132017-01-11 19:59:03 +01008989 if (backgnd == FORK_FG)
Eric Andersenc470f442003-07-28 09:56:35 +00008990 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00008991 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008992 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00008993}
8994
Eric Andersenc470f442003-07-28 09:56:35 +00008995/*
8996 * Compute the names of the files in a redirection list.
8997 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00008998static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008999static void
9000expredir(union node *n)
9001{
9002 union node *redir;
9003
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009004 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009005 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009006
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009007 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009008 fn.lastp = &fn.list;
9009 switch (redir->type) {
9010 case NFROMTO:
9011 case NFROM:
9012 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009013#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009014 case NTO2:
9015#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009016 case NCLOBBER:
9017 case NAPPEND:
9018 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02009019 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009020#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009021 store_expfname:
9022#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009023#if 0
9024// By the design of stack allocator, the loop of this kind:
9025// while true; do while true; do break; done </dev/null; done
9026// will look like a memory leak: ash plans to free expfname's
9027// of "/dev/null" as soon as it finishes running the loop
9028// (in this case, never).
9029// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01009030 if (redir->nfile.expfname)
9031 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009032// It results in corrupted state of stacked allocations.
9033#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009034 redir->nfile.expfname = fn.list->text;
9035 break;
9036 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00009037 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00009038 if (redir->ndup.vname) {
9039 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009040 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009041 ash_msg_and_raise_error("redir error");
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009042#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009043//FIXME: we used expandarg with different args!
9044 if (!isdigit_str9(fn.list->text)) {
9045 /* >&file, not >&fd */
9046 if (redir->nfile.fd != 1) /* 123>&file - BAD */
9047 ash_msg_and_raise_error("redir error");
9048 redir->type = NTO2;
9049 goto store_expfname;
9050 }
9051#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009052 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009053 }
9054 break;
9055 }
9056 }
9057}
9058
Eric Andersencb57d552001-06-28 07:25:16 +00009059/*
Eric Andersencb57d552001-06-28 07:25:16 +00009060 * Evaluate a pipeline. All the processes in the pipeline are children
9061 * of the process creating the pipeline. (This differs from some versions
9062 * of the shell, which make the last process in a pipeline the parent
9063 * of all the rest.)
9064 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009065static int
Eric Andersenc470f442003-07-28 09:56:35 +00009066evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009067{
9068 struct job *jp;
9069 struct nodelist *lp;
9070 int pipelen;
9071 int prevfd;
9072 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009073 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009074
Eric Andersenc470f442003-07-28 09:56:35 +00009075 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00009076 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009077 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00009078 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009079 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009080 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009081 if (n->npipe.pipe_backgnd == 0)
9082 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009083 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00009084 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009085 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009086 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00009087 pip[1] = -1;
9088 if (lp->next) {
9089 if (pipe(pip) < 0) {
9090 close(prevfd);
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00009091 ash_msg_and_raise_error("pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00009092 }
9093 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009094 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02009095 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009096 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00009097 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009098 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00009099 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009100 if (prevfd > 0) {
9101 dup2(prevfd, 0);
9102 close(prevfd);
9103 }
9104 if (pip[1] > 1) {
9105 dup2(pip[1], 1);
9106 close(pip[1]);
9107 }
Eric Andersenc470f442003-07-28 09:56:35 +00009108 evaltreenr(lp->n, flags);
9109 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00009110 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009111 /* parent */
Eric Andersencb57d552001-06-28 07:25:16 +00009112 if (prevfd >= 0)
9113 close(prevfd);
9114 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00009115 /* Don't want to trigger debugging */
9116 if (pip[1] != -1)
9117 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009118 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009119 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009120 status = waitforjob(jp);
9121 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00009122 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009123 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009124
9125 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009126}
9127
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009128/*
9129 * Controls whether the shell is interactive or not.
9130 */
9131static void
9132setinteractive(int on)
9133{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009134 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009135
9136 if (++on == is_interactive)
9137 return;
9138 is_interactive = on;
9139 setsignal(SIGINT);
9140 setsignal(SIGQUIT);
9141 setsignal(SIGTERM);
9142#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9143 if (is_interactive > 1) {
9144 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009145 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009146
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009147 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009148 /* note: ash and hush share this string */
9149 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009150 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9151 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009152 bb_banner,
9153 "built-in shell (ash)"
9154 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009155 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009156 }
9157 }
9158#endif
9159}
9160
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009161static void
9162optschanged(void)
9163{
9164#if DEBUG
9165 opentrace();
9166#endif
9167 setinteractive(iflag);
9168 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009169#if ENABLE_FEATURE_EDITING_VI
9170 if (viflag)
9171 line_input_state->flags |= VI_MODE;
9172 else
9173 line_input_state->flags &= ~VI_MODE;
9174#else
9175 viflag = 0; /* forcibly keep the option off */
9176#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009177}
9178
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009179struct localvar_list {
9180 struct localvar_list *next;
9181 struct localvar *lv;
9182};
9183
9184static struct localvar_list *localvar_stack;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009185
9186/*
9187 * Called after a function returns.
9188 * Interrupts must be off.
9189 */
9190static void
Denys Vlasenko981a0562017-07-26 19:53:11 +02009191poplocalvars(int keep)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009192{
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009193 struct localvar_list *ll;
9194 struct localvar *lvp, *next;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009195 struct var *vp;
9196
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009197 INT_OFF;
9198 ll = localvar_stack;
9199 localvar_stack = ll->next;
9200
9201 next = ll->lv;
9202 free(ll);
9203
9204 while ((lvp = next) != NULL) {
9205 next = lvp->next;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009206 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02009207 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denys Vlasenko981a0562017-07-26 19:53:11 +02009208 if (keep) {
9209 int bits = VSTRFIXED;
9210
9211 if (lvp->flags != VUNSET) {
9212 if (vp->var_text == lvp->text)
9213 bits |= VTEXTFIXED;
9214 else if (!(lvp->flags & (VTEXTFIXED|VSTACK)))
9215 free((char*)lvp->text);
9216 }
9217
9218 vp->flags &= ~bits;
9219 vp->flags |= (lvp->flags & bits);
9220
9221 if ((vp->flags &
9222 (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
9223 unsetvar(vp->var_text);
9224 } else if (vp == NULL) { /* $- saved */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009225 memcpy(optlist, lvp->text, sizeof(optlist));
9226 free((char*)lvp->text);
9227 optschanged();
Denys Vlasenkod5b500c2017-07-26 19:25:40 +02009228 } else if (lvp->flags == VUNSET) {
9229 vp->flags &= ~(VSTRFIXED|VREADONLY);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009230 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009231 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009232 if (vp->var_func)
9233 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009234 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009235 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009236 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009237 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009238 }
9239 free(lvp);
9240 }
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009241 INT_ON;
9242}
9243
9244/*
9245 * Create a new localvar environment.
9246 */
Denys Vlasenko484fc202017-07-26 19:55:31 +02009247static struct localvar_list *
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009248pushlocalvars(void)
9249{
9250 struct localvar_list *ll;
9251
9252 INT_OFF;
9253 ll = ckzalloc(sizeof(*ll));
9254 /*ll->lv = NULL; - zalloc did it */
9255 ll->next = localvar_stack;
9256 localvar_stack = ll;
9257 INT_ON;
Denys Vlasenko484fc202017-07-26 19:55:31 +02009258
9259 return ll->next;
9260}
9261
9262static void
9263unwindlocalvars(struct localvar_list *stop)
9264{
9265 while (localvar_stack != stop)
9266 poplocalvars(0);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009267}
9268
9269static int
9270evalfun(struct funcnode *func, int argc, char **argv, int flags)
9271{
9272 volatile struct shparam saveparam;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009273 struct jmploc *volatile savehandler;
9274 struct jmploc jmploc;
9275 int e;
9276
9277 saveparam = shellparam;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009278 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009279 e = setjmp(jmploc.loc);
9280 if (e) {
9281 goto funcdone;
9282 }
9283 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009284 exception_handler = &jmploc;
Denis Vlasenko01631112007-12-16 17:20:38 +00009285 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009286 func->count++;
9287 funcnest++;
9288 INT_ON;
9289 shellparam.nparam = argc - 1;
9290 shellparam.p = argv + 1;
9291#if ENABLE_ASH_GETOPTS
9292 shellparam.optind = 1;
9293 shellparam.optoff = -1;
9294#endif
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009295 pushlocalvars();
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009296 evaltree(func->n.narg.next, flags & EV_TESTED);
Denys Vlasenko981a0562017-07-26 19:53:11 +02009297 poplocalvars(0);
Denis Vlasenko01631112007-12-16 17:20:38 +00009298 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009299 INT_OFF;
9300 funcnest--;
9301 freefunc(func);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009302 freeparam(&shellparam);
9303 shellparam = saveparam;
9304 exception_handler = savehandler;
9305 INT_ON;
9306 evalskip &= ~SKIPFUNC;
9307 return e;
9308}
9309
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009310/*
9311 * Make a variable a local variable. When a variable is made local, it's
9312 * value and flags are saved in a localvar structure. The saved values
9313 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009314 * "-" as a special case: it makes changes to "set +-options" local
9315 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009316 */
9317static void
9318mklocal(char *name)
9319{
9320 struct localvar *lvp;
9321 struct var **vpp;
9322 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009323 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009324
9325 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009326 /* Cater for duplicate "local". Examples:
9327 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9328 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9329 */
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009330 lvp = localvar_stack->lv;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009331 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009332 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009333 if (eq)
9334 setvareq(name, 0);
9335 /* else:
9336 * it's a duplicate "local VAR" declaration, do nothing
9337 */
Denys Vlasenko06b11492016-11-04 16:43:18 +01009338 goto ret;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009339 }
9340 lvp = lvp->next;
9341 }
9342
9343 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009344 if (LONE_DASH(name)) {
9345 char *p;
9346 p = ckmalloc(sizeof(optlist));
9347 lvp->text = memcpy(p, optlist, sizeof(optlist));
9348 vp = NULL;
9349 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009350 vpp = hashvar(name);
9351 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009352 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009353 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009354 if (eq)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02009355 vp = setvareq(name, VSTRFIXED);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009356 else
Denys Vlasenkod04fc712017-07-26 20:06:48 +02009357 vp = setvar(name, NULL, VSTRFIXED);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009358 lvp->flags = VUNSET;
9359 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009360 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009361 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009362 /* make sure neither "struct var" nor string gets freed
9363 * during (un)setting:
9364 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009365 vp->flags |= VSTRFIXED|VTEXTFIXED;
9366 if (eq)
9367 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009368 else
9369 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009370 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009371 }
9372 }
9373 lvp->vp = vp;
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009374 lvp->next = localvar_stack->lv;
9375 localvar_stack->lv = lvp;
Denys Vlasenko06b11492016-11-04 16:43:18 +01009376 ret:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009377 INT_ON;
9378}
9379
9380/*
9381 * The "local" command.
9382 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009383static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009384localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009385{
9386 char *name;
9387
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009388 if (!localvar_stack)
Ron Yorstonef2386b2015-10-29 16:19:14 +00009389 ash_msg_and_raise_error("not in a function");
9390
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009391 argv = argptr;
9392 while ((name = *argv++) != NULL) {
9393 mklocal(name);
9394 }
9395 return 0;
9396}
9397
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009398static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009399falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009400{
9401 return 1;
9402}
9403
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009404static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009405truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009406{
9407 return 0;
9408}
9409
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009410static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009411execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009412{
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009413 optionarg = NULL;
9414 while (nextopt("a:") != '\0')
9415 /* nextopt() sets optionarg to "-a ARGV0" */;
9416
9417 argv = argptr;
9418 if (argv[0]) {
9419 char *prog;
9420
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009421 iflag = 0; /* exit on error */
9422 mflag = 0;
9423 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009424 /* We should set up signals for "exec CMD"
9425 * the same way as for "CMD" without "exec".
9426 * But optschanged->setinteractive->setsignal
9427 * still thought we are a root shell. Therefore, for example,
9428 * SIGQUIT is still set to IGN. Fix it:
9429 */
9430 shlvl++;
9431 setsignal(SIGQUIT);
9432 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9433 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9434 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9435
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009436 prog = argv[0];
9437 if (optionarg)
9438 argv[0] = optionarg;
9439 shellexec(prog, argv, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009440 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009441 }
9442 return 0;
9443}
9444
9445/*
9446 * The return command.
9447 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009448static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009449returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009450{
9451 /*
9452 * If called outside a function, do what ksh does;
9453 * skip the rest of the file.
9454 */
Denys Vlasenko6a0710e2016-09-30 14:18:34 +02009455 evalskip = SKIPFUNC;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009456 return argv[1] ? number(argv[1]) : exitstatus;
9457}
9458
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009459/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009460static int breakcmd(int, char **) FAST_FUNC;
9461static int dotcmd(int, char **) FAST_FUNC;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009462static int evalcmd(int, char **, int) FAST_FUNC;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009463static int exitcmd(int, char **) FAST_FUNC;
9464static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009465#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009466static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009467#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009468#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009469static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009470#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009471#if MAX_HISTORY
9472static int historycmd(int, char **) FAST_FUNC;
9473#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009474#if ENABLE_FEATURE_SH_MATH
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009475static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009476#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009477static int readcmd(int, char **) FAST_FUNC;
9478static int setcmd(int, char **) FAST_FUNC;
9479static int shiftcmd(int, char **) FAST_FUNC;
9480static int timescmd(int, char **) FAST_FUNC;
9481static int trapcmd(int, char **) FAST_FUNC;
9482static int umaskcmd(int, char **) FAST_FUNC;
9483static int unsetcmd(int, char **) FAST_FUNC;
9484static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009485
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009486#define BUILTIN_NOSPEC "0"
9487#define BUILTIN_SPECIAL "1"
9488#define BUILTIN_REGULAR "2"
9489#define BUILTIN_SPEC_REG "3"
9490#define BUILTIN_ASSIGN "4"
9491#define BUILTIN_SPEC_ASSG "5"
9492#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009493#define BUILTIN_SPEC_REG_ASSG "7"
9494
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009495/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko265062d2017-01-10 15:13:30 +01009496#if ENABLE_ASH_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009497static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009498#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009499#if ENABLE_ASH_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009500static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009501#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009502#if ENABLE_ASH_TEST || BASH_TEST2
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009503static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009504#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009505
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009506/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009507static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009508 { BUILTIN_SPEC_REG "." , dotcmd },
9509 { BUILTIN_SPEC_REG ":" , truecmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009510#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009511 { BUILTIN_REGULAR "[" , testcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009512#endif
9513#if BASH_TEST2
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009514 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009515#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009516#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009517 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009518#endif
9519#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009520 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009521#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009522 { BUILTIN_SPEC_REG "break" , breakcmd },
9523 { BUILTIN_REGULAR "cd" , cdcmd },
9524 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009525#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009526 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009527#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009528 { BUILTIN_SPEC_REG "continue", breakcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009529#if ENABLE_ASH_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009530 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009531#endif
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009532 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009533 { BUILTIN_SPEC_REG "exec" , execcmd },
9534 { BUILTIN_SPEC_REG "exit" , exitcmd },
9535 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9536 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009537#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009538 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009539#endif
9540#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009541 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009542#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009543 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009544#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009545 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009546#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009547#if MAX_HISTORY
9548 { BUILTIN_NOSPEC "history" , historycmd },
9549#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009550#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009551 { BUILTIN_REGULAR "jobs" , jobscmd },
9552 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009553#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009554#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009555 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009556#endif
Denys Vlasenko85241c72017-07-26 20:00:08 +02009557 { BUILTIN_SPEC_REG_ASSG "local" , localcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009558#if ENABLE_ASH_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009559 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009560#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009561 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9562 { BUILTIN_REGULAR "read" , readcmd },
9563 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9564 { BUILTIN_SPEC_REG "return" , returncmd },
9565 { BUILTIN_SPEC_REG "set" , setcmd },
9566 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009567#if BASH_SOURCE
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009568 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009569#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009570#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009571 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009572#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009573 { BUILTIN_SPEC_REG "times" , timescmd },
9574 { BUILTIN_SPEC_REG "trap" , trapcmd },
9575 { BUILTIN_REGULAR "true" , truecmd },
9576 { BUILTIN_NOSPEC "type" , typecmd },
9577 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9578 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009579#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009580 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009581#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009582 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9583 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009584};
9585
Denis Vlasenko80591b02008-03-25 07:49:43 +00009586/* Should match the above table! */
9587#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009588 /* . : */ 2 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009589 /* [ */ 1 * ENABLE_ASH_TEST + \
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009590 /* [[ */ 1 * BASH_TEST2 + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009591 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9592 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9593 /* break cd cddir */ 3)
9594#define EVALCMD (COMMANDCMD + \
9595 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9596 /* continue */ 1 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009597 /* echo */ 1 * ENABLE_ASH_ECHO + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009598 0)
9599#define EXECCMD (EVALCMD + \
9600 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009601
9602/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009603 * Search the table of builtin commands.
9604 */
Denys Vlasenko888527c2016-10-02 16:54:17 +02009605static int
9606pstrcmp1(const void *a, const void *b)
9607{
9608 return strcmp((char*)a, *(char**)b + 1);
9609}
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009610static struct builtincmd *
9611find_builtin(const char *name)
9612{
9613 struct builtincmd *bp;
9614
9615 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009616 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denys Vlasenko888527c2016-10-02 16:54:17 +02009617 pstrcmp1
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009618 );
9619 return bp;
9620}
9621
9622/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009623 * Execute a simple command.
9624 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009625static int
9626isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009627{
9628 const char *q = endofname(p);
9629 if (p == q)
9630 return 0;
9631 return *q == '=';
9632}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009633static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009634bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009635{
9636 /* Preserve exitstatus of a previous possible redirection
9637 * as POSIX mandates */
9638 return back_exitstatus;
9639}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009640static int
Eric Andersenc470f442003-07-28 09:56:35 +00009641evalcommand(union node *cmd, int flags)
9642{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009643 static const struct builtincmd null_bltin = {
9644 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009645 };
Denys Vlasenko484fc202017-07-26 19:55:31 +02009646 struct localvar_list *localvar_stop;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02009647 struct redirtab *redir_stop;
Eric Andersenc470f442003-07-28 09:56:35 +00009648 struct stackmark smark;
9649 union node *argp;
9650 struct arglist arglist;
9651 struct arglist varlist;
9652 char **argv;
9653 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009654 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009655 struct cmdentry cmdentry;
9656 struct job *jp;
9657 char *lastarg;
9658 const char *path;
9659 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009660 int status;
9661 char **nargv;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009662 smallint cmd_is_exec;
Eric Andersenc470f442003-07-28 09:56:35 +00009663
9664 /* First expand the arguments. */
9665 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9666 setstackmark(&smark);
Denys Vlasenko484fc202017-07-26 19:55:31 +02009667 localvar_stop = pushlocalvars();
Eric Andersenc470f442003-07-28 09:56:35 +00009668 back_exitstatus = 0;
9669
9670 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009671 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009672 varlist.lastp = &varlist.list;
9673 *varlist.lastp = NULL;
9674 arglist.lastp = &arglist.list;
9675 *arglist.lastp = NULL;
9676
9677 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009678 if (cmd->ncmd.args) {
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009679 struct builtincmd *bcmd;
9680 smallint pseudovarflag;
9681
Paul Foxc3850c82005-07-20 18:23:39 +00009682 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9683 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Paul Foxc3850c82005-07-20 18:23:39 +00009684
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009685 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9686 struct strlist **spp;
Eric Andersenc470f442003-07-28 09:56:35 +00009687
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009688 spp = arglist.lastp;
9689 if (pseudovarflag && isassignment(argp->narg.text))
9690 expandarg(argp, &arglist, EXP_VARTILDE);
9691 else
9692 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Paul Foxc3850c82005-07-20 18:23:39 +00009693
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009694 for (sp = *spp; sp; sp = sp->next)
9695 argc++;
9696 }
Eric Andersenc470f442003-07-28 09:56:35 +00009697 }
9698
Denys Vlasenko65a8b852016-10-26 22:29:11 +02009699 /* Reserve one extra spot at the front for shellexec. */
9700 nargv = stalloc(sizeof(char *) * (argc + 2));
9701 argv = ++nargv;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009702 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009703 TRACE(("evalcommand arg: %s\n", sp->text));
9704 *nargv++ = sp->text;
9705 }
9706 *nargv = NULL;
9707
9708 lastarg = NULL;
9709 if (iflag && funcnest == 0 && argc > 0)
9710 lastarg = nargv[-1];
9711
9712 expredir(cmd->ncmd.redirect);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02009713 redir_stop = pushredir(cmd->ncmd.redirect);
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009714 preverrout_fd = 2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009715 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009716
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009717 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009718 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9719 struct strlist **spp;
9720 char *p;
9721
9722 spp = varlist.lastp;
9723 expandarg(argp, &varlist, EXP_VARTILDE);
9724
Denys Vlasenko981a0562017-07-26 19:53:11 +02009725 mklocal((*spp)->text);
9726
Eric Andersenc470f442003-07-28 09:56:35 +00009727 /*
9728 * Modify the command lookup path, if a PATH= assignment
9729 * is present
9730 */
9731 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009732 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009733 path = p;
9734 }
9735
9736 /* Print the command if xflag is set. */
9737 if (xflag) {
Denys Vlasenko42ba7572017-07-21 13:20:14 +02009738 const char *pfx = "";
Eric Andersenc470f442003-07-28 09:56:35 +00009739
Denys Vlasenko46999802017-07-29 21:12:29 +02009740 fdprintf(preverrout_fd, "%s", expandstr(ps4val(), DQSYNTAX));
Denys Vlasenko42ba7572017-07-21 13:20:14 +02009741
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009742 sp = varlist.list;
Denys Vlasenko42ba7572017-07-21 13:20:14 +02009743 while (sp) {
9744 char *varval = sp->text;
9745 char *eq = strchrnul(varval, '=');
9746 if (*eq)
9747 eq++;
9748 fdprintf(preverrout_fd, "%s%.*s%s",
9749 pfx,
9750 (int)(eq - varval), varval,
9751 maybe_single_quote(eq)
9752 );
9753 sp = sp->next;
9754 pfx = " ";
9755 }
9756
9757 sp = arglist.list;
9758 while (sp) {
9759 fdprintf(preverrout_fd, "%s%s",
9760 pfx,
9761 /* always quote if matches reserved word: */
9762 findkwd(sp->text)
9763 ? single_quote(sp->text)
9764 : maybe_single_quote(sp->text)
9765 );
9766 sp = sp->next;
9767 pfx = " ";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009768 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009769 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009770 }
9771
9772 cmd_is_exec = 0;
9773 spclbltin = -1;
9774
9775 /* Now locate the command. */
9776 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009777 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02009778#if ENABLE_ASH_CMDCMD
9779 const char *oldpath = path + 5;
9780#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009781 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009782 for (;;) {
9783 find_command(argv[0], &cmdentry, cmd_flag, path);
9784 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009785 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009786 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009787 goto bail;
9788 }
9789
9790 /* implement bltin and command here */
9791 if (cmdentry.cmdtype != CMDBUILTIN)
9792 break;
9793 if (spclbltin < 0)
9794 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9795 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009796 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009797#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009798 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009799 path = oldpath;
9800 nargv = parse_command_args(argv, &path);
9801 if (!nargv)
9802 break;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02009803 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
9804 * nargv => "PROG". path is updated if -p.
9805 */
Eric Andersenc470f442003-07-28 09:56:35 +00009806 argc -= nargv - argv;
9807 argv = nargv;
9808 cmd_flag |= DO_NOFUNC;
9809 } else
9810#endif
9811 break;
9812 }
9813 }
9814
9815 if (status) {
Ron Yorstonea7d2f62017-01-03 11:18:23 +01009816 bail:
9817 exitstatus = status;
9818
Eric Andersenc470f442003-07-28 09:56:35 +00009819 /* We have a redirection error. */
9820 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009821 raise_exception(EXERROR);
Ron Yorstonea7d2f62017-01-03 11:18:23 +01009822
Eric Andersenc470f442003-07-28 09:56:35 +00009823 goto out;
9824 }
9825
9826 /* Execute the command. */
9827 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009828 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009829
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009830#if ENABLE_FEATURE_SH_NOFORK
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009831/* (1) BUG: if variables are set, we need to fork, or save/restore them
9832 * around run_nofork_applet() call.
9833 * (2) Should this check also be done in forkshell()?
9834 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9835 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009836 /* find_command() encodes applet_no as (-2 - applet_no) */
9837 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009838 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009839 listsetvar(varlist.list, VEXPORT|VSTACK);
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009840 /* run <applet>_main() */
Ron Yorston5ccb0e92016-10-20 12:24:02 +01009841 status = run_nofork_applet(applet_no, argv);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009842 break;
9843 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009844#endif
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009845 /* Can we avoid forking off? For example, very last command
9846 * in a script or a subshell does not need forking,
9847 * we can just exec it.
9848 */
Denys Vlasenko238bf182010-05-18 15:49:07 +02009849 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009850 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009851 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009852 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009853 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009854 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009855 /* parent */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009856 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009857 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009858 TRACE(("forked child exited with %d\n", status));
Eric Andersenc470f442003-07-28 09:56:35 +00009859 break;
9860 }
Denys Vlasenko238bf182010-05-18 15:49:07 +02009861 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009862 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +02009863 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +00009864 }
9865 listsetvar(varlist.list, VEXPORT|VSTACK);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02009866 shellexec(argv[0], argv, path, cmdentry.u.index);
Eric Andersenc470f442003-07-28 09:56:35 +00009867 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009868 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +00009869 case CMDBUILTIN:
Denys Vlasenko85241c72017-07-26 20:00:08 +02009870 if (spclbltin > 0 || argc == 0) {
9871 poplocalvars(1);
9872 if (cmd_is_exec && argc > 1)
9873 listsetvar(varlist.list, VEXPORT);
9874 }
Denys Vlasenko981a0562017-07-26 19:53:11 +02009875
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009876 /* Tight loop with builtins only:
9877 * "while kill -0 $child; do true; done"
9878 * will never exit even if $child died, unless we do this
9879 * to reap the zombie and make kill detect that it's gone: */
9880 dowait(DOWAIT_NONBLOCK, NULL);
9881
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009882 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009883 if (exception_type == EXERROR && spclbltin <= 0) {
9884 FORCE_INT_ON;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02009885 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009886 }
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009887 raise:
9888 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009889 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009890 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009891
9892 case CMDFUNCTION:
Denys Vlasenko981a0562017-07-26 19:53:11 +02009893 poplocalvars(1);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009894 /* See above for the rationale */
9895 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009896 if (evalfun(cmdentry.u.func, argc, argv, flags))
9897 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009898 readstatus:
9899 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009900 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009901 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +00009902
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009903 out:
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02009904 if (cmd->ncmd.redirect)
9905 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02009906 unwindredir(redir_stop);
Denys Vlasenko484fc202017-07-26 19:55:31 +02009907 unwindlocalvars(localvar_stop);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009908 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +00009909 /* dsl: I think this is intended to be used to support
9910 * '_' in 'vi' command mode during line editing...
9911 * However I implemented that within libedit itself.
9912 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009913 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009914 }
Eric Andersenc470f442003-07-28 09:56:35 +00009915 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009916
9917 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009918}
9919
9920static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009921evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009922{
Eric Andersenc470f442003-07-28 09:56:35 +00009923 char *volatile savecmdname;
9924 struct jmploc *volatile savehandler;
9925 struct jmploc jmploc;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009926 int status;
Eric Andersenc470f442003-07-28 09:56:35 +00009927 int i;
9928
9929 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009930 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009931 i = setjmp(jmploc.loc);
9932 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +00009933 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009934 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00009935 commandname = argv[0];
9936 argptr = argv + 1;
9937 optptr = NULL; /* initialize nextopt */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009938 if (cmd == EVALCMD)
9939 status = evalcmd(argc, argv, flags);
9940 else
9941 status = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009942 flush_stdout_stderr();
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009943 status |= ferror(stdout);
9944 exitstatus = status;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009945 cmddone:
Rob Landleyf296f0b2006-07-06 01:09:21 +00009946 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009947 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009948 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +00009949
9950 return i;
9951}
9952
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009953static int
9954goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009955{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02009956 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009957}
9958
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009959
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009960/*
9961 * Search for a command. This is called before we fork so that the
9962 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009963 * the child. The check for "goodname" is an overly conservative
9964 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009965 */
Eric Andersenc470f442003-07-28 09:56:35 +00009966static void
9967prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009968{
9969 struct cmdentry entry;
9970
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009971 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9972 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009973}
9974
Eric Andersencb57d552001-06-28 07:25:16 +00009975
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009976/* ============ Builtin commands
9977 *
9978 * Builtin commands whose functions are closely tied to evaluation
9979 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +00009980 */
9981
9982/*
Eric Andersencb57d552001-06-28 07:25:16 +00009983 * Handle break and continue commands. Break, continue, and return are
9984 * all handled by setting the evalskip flag. The evaluation routines
9985 * above all check this flag, and if it is set they start skipping
9986 * commands rather than executing them. The variable skipcount is
9987 * the number of loops to break/continue, or the number of function
9988 * levels to return. (The latter is always 1.) It should probably
9989 * be an error to break out of more loops than exist, but it isn't
9990 * in the standard shell so we don't make it one here.
9991 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009992static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009993breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009994{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009995 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009996
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00009997 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009998 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009999 if (n > loopnest)
10000 n = loopnest;
10001 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000010002 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +000010003 skipcount = n;
10004 }
10005 return 0;
10006}
10007
Eric Andersenc470f442003-07-28 09:56:35 +000010008
Denys Vlasenko70392332016-10-27 02:31:55 +020010009/*
Eric Andersen90898442003-08-06 11:20:52 +000010010 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +000010011 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010012
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010013enum {
10014 INPUT_PUSH_FILE = 1,
10015 INPUT_NOFILE_OK = 2,
10016};
Eric Andersencb57d552001-06-28 07:25:16 +000010017
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010018static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010019/* values of checkkwd variable */
10020#define CHKALIAS 0x1
10021#define CHKKWD 0x2
10022#define CHKNL 0x4
Denys Vlasenkoa7328982017-07-29 19:57:28 +020010023#define CHKEOFMARK 0x8
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010024
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010025/*
10026 * Push a string back onto the input at this current parsefile level.
10027 * We handle aliases this way.
10028 */
10029#if !ENABLE_ASH_ALIAS
10030#define pushstring(s, ap) pushstring(s)
10031#endif
10032static void
10033pushstring(char *s, struct alias *ap)
10034{
10035 struct strpush *sp;
10036 int len;
10037
10038 len = strlen(s);
10039 INT_OFF;
10040 if (g_parsefile->strpush) {
10041 sp = ckzalloc(sizeof(*sp));
10042 sp->prev = g_parsefile->strpush;
10043 } else {
10044 sp = &(g_parsefile->basestrpush);
10045 }
10046 g_parsefile->strpush = sp;
10047 sp->prev_string = g_parsefile->next_to_pgetc;
10048 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010049 sp->unget = g_parsefile->unget;
10050 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010051#if ENABLE_ASH_ALIAS
10052 sp->ap = ap;
10053 if (ap) {
10054 ap->flag |= ALIASINUSE;
10055 sp->string = s;
10056 }
10057#endif
10058 g_parsefile->next_to_pgetc = s;
10059 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010060 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010061 INT_ON;
10062}
10063
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010064static void
10065popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010066{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010067 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +000010068
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010069 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010070#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010071 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010072 if (g_parsefile->next_to_pgetc[-1] == ' '
10073 || g_parsefile->next_to_pgetc[-1] == '\t'
10074 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010075 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010076 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010077 if (sp->string != sp->ap->val) {
10078 free(sp->string);
10079 }
10080 sp->ap->flag &= ~ALIASINUSE;
10081 if (sp->ap->flag & ALIASDEAD) {
10082 unalias(sp->ap->name);
10083 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010084 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010085#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010086 g_parsefile->next_to_pgetc = sp->prev_string;
10087 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010088 g_parsefile->unget = sp->unget;
10089 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010090 g_parsefile->strpush = sp->prev;
10091 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010092 free(sp);
10093 INT_ON;
10094}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010095
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010096static int
10097preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010098{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010099 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +000010100 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010101
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010102 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +000010103#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +000010104 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010105 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +010010106 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010107 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010108 int timeout = -1;
10109# if ENABLE_ASH_IDLE_TIMEOUT
10110 if (iflag) {
10111 const char *tmout_var = lookupvar("TMOUT");
10112 if (tmout_var) {
10113 timeout = atoi(tmout_var) * 1000;
10114 if (timeout <= 0)
10115 timeout = -1;
10116 }
10117 }
10118# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010119# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010120 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010121# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +020010122 reinit_unicode_for_ash();
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010123 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010124 if (nr == 0) {
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010125 /* ^C pressed, "convert" to SIGINT */
10126 write(STDOUT_FILENO, "^C", 2);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010127 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010128 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010129 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010130 raise(SIGINT);
10131 return 1;
10132 }
Denys Vlasenko8660aeb2016-11-24 17:44:02 +010010133 exitstatus = 128 + SIGINT;
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010134 bb_putchar('\n');
Eric Andersenc470f442003-07-28 09:56:35 +000010135 goto retry;
10136 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010137 if (nr < 0) {
10138 if (errno == 0) {
10139 /* Ctrl+D pressed */
10140 nr = 0;
10141 }
10142# if ENABLE_ASH_IDLE_TIMEOUT
10143 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +020010144 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010145 exitshell();
10146 }
10147# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010148 }
Eric Andersencb57d552001-06-28 07:25:16 +000010149 }
10150#else
Ron Yorston61d6ae22015-04-19 10:50:25 +010010151 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +000010152#endif
10153
Denys Vlasenko80c5b682011-05-08 21:21:10 +020010154#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +000010155 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010156 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +000010157 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +000010158 if (flags >= 0 && (flags & O_NONBLOCK)) {
10159 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +000010160 if (fcntl(0, F_SETFL, flags) >= 0) {
10161 out2str("sh: turning off NDELAY mode\n");
10162 goto retry;
10163 }
10164 }
10165 }
10166 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +000010167#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010168 return nr;
10169}
10170
10171/*
10172 * Refill the input buffer and return the next input character:
10173 *
10174 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010175 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
10176 * or we are reading from a string so we can't refill the buffer,
10177 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +020010178 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +000010179 * 4) Process input up to the next newline, deleting nul characters.
10180 */
Denis Vlasenko727752d2008-11-28 03:41:47 +000010181//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
10182#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010183static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010184static int
Eric Andersenc470f442003-07-28 09:56:35 +000010185preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010186{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010187 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010188 int more;
Eric Andersencb57d552001-06-28 07:25:16 +000010189
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010190 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000010191#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010192 if (g_parsefile->left_in_line == -1
10193 && g_parsefile->strpush->ap
10194 && g_parsefile->next_to_pgetc[-1] != ' '
10195 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +000010196 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010197 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +000010198 return PEOA;
10199 }
Eric Andersen2870d962001-07-02 17:27:21 +000010200#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010201 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010202 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010203 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010204 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010205 * "pgetc" needs refilling.
10206 */
10207
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010208 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010209 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010210 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010211 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010212 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010213 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010214 /* even in failure keep left_in_line and next_to_pgetc
10215 * in lock step, for correct multi-layer pungetc.
10216 * left_in_line was decremented before preadbuffer(),
10217 * must inc next_to_pgetc: */
10218 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010219 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010220 }
Eric Andersencb57d552001-06-28 07:25:16 +000010221
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010222 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010223 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010224 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010225 again:
10226 more = preadfd();
10227 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010228 /* don't try reading again */
10229 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010230 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010231 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010232 return PEOF;
10233 }
10234 }
10235
Denis Vlasenko727752d2008-11-28 03:41:47 +000010236 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010237 * Set g_parsefile->left_in_line
10238 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010239 * NUL chars are deleted.
10240 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010241 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010242 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010243 char c;
Eric Andersencb57d552001-06-28 07:25:16 +000010244
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010245 more--;
Eric Andersenc470f442003-07-28 09:56:35 +000010246
Denis Vlasenko727752d2008-11-28 03:41:47 +000010247 c = *q;
10248 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010249 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010250 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010251 q++;
10252 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010253 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010254 break;
10255 }
Eric Andersencb57d552001-06-28 07:25:16 +000010256 }
10257
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010258 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010259 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10260 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010261 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010262 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010263 }
10264 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010265 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +000010266
Eric Andersencb57d552001-06-28 07:25:16 +000010267 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010268 char save = *q;
10269 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010270 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010271 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +000010272 }
10273
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010274 pgetc_debug("preadbuffer at %d:%p'%s'",
10275 g_parsefile->left_in_line,
10276 g_parsefile->next_to_pgetc,
10277 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +010010278 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010279}
10280
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010281static void
10282nlprompt(void)
10283{
10284 g_parsefile->linno++;
10285 setprompt_if(doprompt, 2);
10286}
10287static void
10288nlnoprompt(void)
10289{
10290 g_parsefile->linno++;
10291 needprompt = doprompt;
10292}
10293
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010294static int
10295pgetc(void)
10296{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010297 int c;
10298
10299 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010300 g_parsefile->left_in_line,
10301 g_parsefile->next_to_pgetc,
10302 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010303 if (g_parsefile->unget)
10304 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010305
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010306 if (--g_parsefile->left_in_line >= 0)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +010010307 c = (unsigned char)*g_parsefile->next_to_pgetc++;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010308 else
10309 c = preadbuffer();
10310
10311 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10312 g_parsefile->lastc[0] = c;
10313
10314 return c;
10315}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010316
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010317#if ENABLE_ASH_ALIAS
10318static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010319pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010320{
10321 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010322 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010323 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010324 g_parsefile->left_in_line,
10325 g_parsefile->next_to_pgetc,
10326 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010327 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010328 } while (c == PEOA);
10329 return c;
10330}
10331#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010332# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010333#endif
10334
10335/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010336 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010337 * PEOF may be pushed back.
10338 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010339static void
Eric Andersenc470f442003-07-28 09:56:35 +000010340pungetc(void)
10341{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010342 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010343}
10344
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010345/* This one eats backslash+newline */
10346static int
10347pgetc_eatbnl(void)
10348{
10349 int c;
10350
10351 while ((c = pgetc()) == '\\') {
10352 if (pgetc() != '\n') {
10353 pungetc();
10354 break;
10355 }
10356
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010357 nlprompt();
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010358 }
10359
10360 return c;
10361}
10362
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010363/*
10364 * To handle the "." command, a stack of input files is used. Pushfile
10365 * adds a new entry to the stack and popfile restores the previous level.
10366 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010367static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010368pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010369{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010370 struct parsefile *pf;
10371
Denis Vlasenko597906c2008-02-20 16:38:54 +000010372 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010373 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010374 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010375 /*pf->strpush = NULL; - ckzalloc did it */
10376 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010377 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010378 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010379}
10380
10381static void
10382popfile(void)
10383{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010384 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010385
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010010386 if (pf == &basepf)
10387 return;
10388
Denis Vlasenkob012b102007-02-19 22:43:01 +000010389 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010390 if (pf->pf_fd >= 0)
10391 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010392 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010393 while (pf->strpush)
10394 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010395 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010396 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010397 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010398}
10399
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010400/*
10401 * Return to top level.
10402 */
10403static void
10404popallfiles(void)
10405{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010406 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010407 popfile();
10408}
10409
10410/*
10411 * Close the file(s) that the shell is reading commands from. Called
10412 * after a fork is done.
10413 */
10414static void
10415closescript(void)
10416{
10417 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010418 if (g_parsefile->pf_fd > 0) {
10419 close(g_parsefile->pf_fd);
10420 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010421 }
10422}
10423
10424/*
10425 * Like setinputfile, but takes an open file descriptor. Call this with
10426 * interrupts off.
10427 */
10428static void
10429setinputfd(int fd, int push)
10430{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010431 if (push) {
10432 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010433 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010434 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010435 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010436 if (g_parsefile->buf == NULL)
10437 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010438 g_parsefile->left_in_buffer = 0;
10439 g_parsefile->left_in_line = 0;
10440 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010441}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010442
Eric Andersenc470f442003-07-28 09:56:35 +000010443/*
10444 * Set the input to take input from a file. If push is set, push the
10445 * old input onto the stack first.
10446 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010447static int
10448setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010449{
10450 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010451
Denis Vlasenkob012b102007-02-19 22:43:01 +000010452 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010453 fd = open(fname, O_RDONLY);
10454 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010455 if (flags & INPUT_NOFILE_OK)
10456 goto out;
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010457 exitstatus = 127;
Denis Vlasenko9604e1b2009-03-03 18:47:56 +000010458 ash_msg_and_raise_error("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010459 }
Denys Vlasenko64774602016-10-26 15:24:30 +020010460 if (fd < 10)
10461 fd = savefd(fd);
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020010462 else
10463 close_on_exec_on(fd);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010464 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010465 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010466 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010467 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010468}
10469
Eric Andersencb57d552001-06-28 07:25:16 +000010470/*
10471 * Like setinputfile, but takes input from a string.
10472 */
Eric Andersenc470f442003-07-28 09:56:35 +000010473static void
10474setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010475{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010476 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010477 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010478 g_parsefile->next_to_pgetc = string;
10479 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010480 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010481 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010482 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010483}
10484
10485
Denys Vlasenko70392332016-10-27 02:31:55 +020010486/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010487 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010488 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010489
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010490#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010491
Denys Vlasenko23841622015-10-09 15:52:03 +020010492/* Hash of mtimes of mailboxes */
10493static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010494/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010495static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010496
Eric Andersencb57d552001-06-28 07:25:16 +000010497/*
Eric Andersenc470f442003-07-28 09:56:35 +000010498 * Print appropriate message(s) if mail has arrived.
10499 * If mail_var_path_changed is set,
10500 * then the value of MAIL has mail_var_path_changed,
10501 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010502 */
Eric Andersenc470f442003-07-28 09:56:35 +000010503static void
10504chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010505{
Eric Andersencb57d552001-06-28 07:25:16 +000010506 const char *mpath;
10507 char *p;
10508 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010509 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010510 struct stackmark smark;
10511 struct stat statb;
10512
Eric Andersencb57d552001-06-28 07:25:16 +000010513 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010514 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010515 new_hash = 0;
10516 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010517 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010518 if (p == NULL)
10519 break;
10520 if (*p == '\0')
10521 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010522 for (q = p; *q; q++)
10523 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010524#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010525 if (q[-1] != '/')
10526 abort();
10527#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010528 q[-1] = '\0'; /* delete trailing '/' */
10529 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010530 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010531 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010532 /* Very simplistic "hash": just a sum of all mtimes */
10533 new_hash += (unsigned)statb.st_mtime;
10534 }
10535 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010536 if (mailtime_hash != 0)
10537 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010538 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010539 }
Eric Andersenc470f442003-07-28 09:56:35 +000010540 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010541 popstackmark(&smark);
10542}
Eric Andersencb57d552001-06-28 07:25:16 +000010543
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010544static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010545changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010546{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010547 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010548}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010549
Denis Vlasenko131ae172007-02-18 13:00:19 +000010550#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010551
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010552
10553/* ============ ??? */
10554
Eric Andersencb57d552001-06-28 07:25:16 +000010555/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010556 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010557 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010558static void
10559setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010560{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010561 char **newparam;
10562 char **ap;
10563 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010564
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010565 for (nparam = 0; argv[nparam]; nparam++)
10566 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010567 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10568 while (*argv) {
10569 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010570 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010571 *ap = NULL;
10572 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010573 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010574 shellparam.nparam = nparam;
10575 shellparam.p = newparam;
10576#if ENABLE_ASH_GETOPTS
10577 shellparam.optind = 1;
10578 shellparam.optoff = -1;
10579#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010580}
10581
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010582/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010583 * Process shell options. The global variable argptr contains a pointer
10584 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010585 *
10586 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10587 * For a non-interactive shell, an error condition encountered
10588 * by a special built-in ... shall cause the shell to write a diagnostic message
10589 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010590 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010591 * ...
10592 * Utility syntax error (option or operand error) Shall exit
10593 * ...
10594 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10595 * we see that bash does not do that (set "finishes" with error code 1 instead,
10596 * and shell continues), and people rely on this behavior!
10597 * Testcase:
10598 * set -o barfoo 2>/dev/null
10599 * echo $?
10600 *
10601 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010602 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010603static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010604plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010605{
10606 int i;
10607
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010608 if (name) {
10609 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010610 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010611 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010612 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010613 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010614 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010615 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010616 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010617 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010618 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010619 if (val) {
10620 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10621 } else {
10622 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10623 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010624 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010625 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010626}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010627static void
10628setoption(int flag, int val)
10629{
10630 int i;
10631
10632 for (i = 0; i < NOPTS; i++) {
10633 if (optletters(i) == flag) {
10634 optlist[i] = val;
10635 return;
10636 }
10637 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010638 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010639 /* NOTREACHED */
10640}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010641static int
Eric Andersenc470f442003-07-28 09:56:35 +000010642options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +000010643{
10644 char *p;
10645 int val;
10646 int c;
10647
10648 if (cmdline)
10649 minusc = NULL;
10650 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010651 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010652 if (c != '-' && c != '+')
10653 break;
10654 argptr++;
10655 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010656 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010657 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010658 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010659 if (!cmdline) {
10660 /* "-" means turn off -x and -v */
10661 if (p[0] == '\0')
10662 xflag = vflag = 0;
10663 /* "--" means reset params */
10664 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010665 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010666 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010667 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010668 }
Eric Andersencb57d552001-06-28 07:25:16 +000010669 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010670 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010671 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010672 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010673 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010674 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010675 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010676 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010677 /* it already printed err message */
10678 return 1; /* error */
10679 }
Eric Andersencb57d552001-06-28 07:25:16 +000010680 if (*argptr)
10681 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010682 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10683 isloginsh = 1;
10684 /* bash does not accept +-login, we also won't */
10685 } else if (cmdline && val && (c == '-')) { /* long options */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010686 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +000010687 isloginsh = 1;
10688 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010689 } else {
10690 setoption(c, val);
10691 }
10692 }
10693 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010694 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010695}
10696
Eric Andersencb57d552001-06-28 07:25:16 +000010697/*
Eric Andersencb57d552001-06-28 07:25:16 +000010698 * The shift builtin command.
10699 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010700static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010701shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010702{
10703 int n;
10704 char **ap1, **ap2;
10705
10706 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010707 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010708 n = number(argv[1]);
10709 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010710 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010711 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010712 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010713 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010714 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010715 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010716 }
10717 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010718 while ((*ap2++ = *ap1++) != NULL)
10719 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010720#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010721 shellparam.optind = 1;
10722 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010723#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010724 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010725 return 0;
10726}
10727
Eric Andersencb57d552001-06-28 07:25:16 +000010728/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010729 * POSIX requires that 'set' (but not export or readonly) output the
10730 * variables in lexicographic order - by the locale's collating order (sigh).
10731 * Maybe we could keep them in an ordered balanced binary tree
10732 * instead of hashed lists.
10733 * For now just roll 'em through qsort for printing...
10734 */
10735static int
10736showvars(const char *sep_prefix, int on, int off)
10737{
10738 const char *sep;
10739 char **ep, **epend;
10740
10741 ep = listvars(on, off, &epend);
10742 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10743
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010744 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010745
10746 for (; ep < epend; ep++) {
10747 const char *p;
10748 const char *q;
10749
10750 p = strchrnul(*ep, '=');
10751 q = nullstr;
10752 if (*p)
10753 q = single_quote(++p);
10754 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10755 }
10756 return 0;
10757}
10758
10759/*
Eric Andersencb57d552001-06-28 07:25:16 +000010760 * The set command builtin.
10761 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010762static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010763setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010764{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010765 int retval;
10766
Denis Vlasenko68404f12008-03-17 09:00:54 +000010767 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010768 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010769
Denis Vlasenkob012b102007-02-19 22:43:01 +000010770 INT_OFF;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010771 retval = options(/*cmdline:*/ 0);
10772 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010773 optschanged();
10774 if (*argptr != NULL) {
10775 setparam(argptr);
10776 }
Eric Andersencb57d552001-06-28 07:25:16 +000010777 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010778 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010779 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010780}
10781
Denis Vlasenko131ae172007-02-18 13:00:19 +000010782#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010783static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010784change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010785{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010786 uint32_t t;
10787
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010788 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010789 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010790 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010791 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010792 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010793 vrandom.flags &= ~VNOFUNC;
10794 } else {
10795 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010796 t = strtoul(value, NULL, 10);
10797 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010798 }
Eric Andersenef02f822004-03-11 13:34:24 +000010799}
Eric Andersen16767e22004-03-16 05:14:10 +000010800#endif
10801
Denis Vlasenko131ae172007-02-18 13:00:19 +000010802#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010803static int
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010804getopts(char *optstr, char *optvar, char **optfirst)
Eric Andersencb57d552001-06-28 07:25:16 +000010805{
10806 char *p, *q;
10807 char c = '?';
10808 int done = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010809 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000010810 char **optnext;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010811 int ind = shellparam.optind;
10812 int off = shellparam.optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010813
Denys Vlasenko9c541002015-10-07 15:44:36 +020010814 sbuf[1] = '\0';
10815
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010816 shellparam.optind = -1;
10817 optnext = optfirst + ind - 1;
Eric Andersena48b0a32003-10-22 10:56:47 +000010818
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010819 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
Eric Andersencb57d552001-06-28 07:25:16 +000010820 p = NULL;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010821 else
10822 p = optnext[-1] + off;
Eric Andersencb57d552001-06-28 07:25:16 +000010823 if (p == NULL || *p == '\0') {
10824 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010825 p = *optnext;
10826 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010827 atend:
Eric Andersencb57d552001-06-28 07:25:16 +000010828 p = NULL;
10829 done = 1;
10830 goto out;
10831 }
10832 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010833 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010834 goto atend;
10835 }
10836
10837 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010838 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010839 if (*q == '\0') {
10840 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010841 sbuf[0] = c;
10842 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010843 setvar0("OPTARG", sbuf);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010844 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010845 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010846 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010847 }
10848 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010849 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010850 }
10851 if (*++q == ':')
10852 q++;
10853 }
10854
10855 if (*++q == ':') {
10856 if (*p == '\0' && (p = *optnext) == NULL) {
10857 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010858 sbuf[0] = c;
10859 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010860 setvar0("OPTARG", sbuf);
Eric Andersencb57d552001-06-28 07:25:16 +000010861 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010862 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010863 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010864 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010865 c = '?';
10866 }
Eric Andersenc470f442003-07-28 09:56:35 +000010867 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010868 }
10869
10870 if (p == *optnext)
10871 optnext++;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010872 setvar0("OPTARG", p);
Eric Andersencb57d552001-06-28 07:25:16 +000010873 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010874 } else
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010875 setvar0("OPTARG", nullstr);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010876 out:
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010877 ind = optnext - optfirst + 1;
10878 setvar("OPTIND", itoa(ind), VNOFUNC);
Denys Vlasenko9c541002015-10-07 15:44:36 +020010879 sbuf[0] = c;
10880 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010881 setvar0(optvar, sbuf);
10882
10883 shellparam.optoff = p ? p - *(optnext - 1) : -1;
10884 shellparam.optind = ind;
10885
Eric Andersencb57d552001-06-28 07:25:16 +000010886 return done;
10887}
Eric Andersenc470f442003-07-28 09:56:35 +000010888
10889/*
10890 * The getopts builtin. Shellparam.optnext points to the next argument
10891 * to be processed. Shellparam.optptr points to the next character to
10892 * be processed in the current argument. If shellparam.optnext is NULL,
10893 * then it's the first time getopts has been called.
10894 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010895static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000010896getoptscmd(int argc, char **argv)
10897{
10898 char **optbase;
10899
10900 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010901 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010902 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000010903 optbase = shellparam.p;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010904 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
Eric Andersenc470f442003-07-28 09:56:35 +000010905 shellparam.optind = 1;
10906 shellparam.optoff = -1;
10907 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010908 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010909 optbase = &argv[3];
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010910 if ((unsigned)shellparam.optind > argc - 2) {
Eric Andersenc470f442003-07-28 09:56:35 +000010911 shellparam.optind = 1;
10912 shellparam.optoff = -1;
10913 }
10914 }
10915
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010916 return getopts(argv[1], argv[2], optbase);
Eric Andersenc470f442003-07-28 09:56:35 +000010917}
Denis Vlasenko131ae172007-02-18 13:00:19 +000010918#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000010919
Eric Andersencb57d552001-06-28 07:25:16 +000010920
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010921/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000010922
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010923struct heredoc {
10924 struct heredoc *next; /* next here document in list */
10925 union node *here; /* redirection node */
10926 char *eofmark; /* string indicating end of input */
10927 smallint striptabs; /* if set, strip leading tabs */
10928};
10929
10930static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010931static smallint quoteflag; /* set if (part of) last token was quoted */
10932static token_id_t lasttoken; /* last token read (integer id Txxx) */
10933static struct heredoc *heredoclist; /* list of here documents to read */
10934static char *wordtext; /* text of last word returned by readtoken */
10935static struct nodelist *backquotelist;
10936static union node *redirnode;
10937static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010938
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010939static const char *
10940tokname(char *buf, int tok)
10941{
10942 if (tok < TSEMI)
Denys Vlasenko888527c2016-10-02 16:54:17 +020010943 return tokname_array[tok];
10944 sprintf(buf, "\"%s\"", tokname_array[tok]);
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010945 return buf;
10946}
10947
10948/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010949 * Called when an unexpected token is read during the parse. The argument
10950 * is the token that is expected, or -1 if more than one type of token can
10951 * occur at this point.
10952 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010953static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010954static void
10955raise_error_unexpected_syntax(int token)
10956{
10957 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010958 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010959 int l;
10960
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010961 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010962 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010963 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010964 raise_error_syntax(msg);
10965 /* NOTREACHED */
10966}
Eric Andersencb57d552001-06-28 07:25:16 +000010967
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010968/* parsing is heavily cross-recursive, need these forward decls */
10969static union node *andor(void);
10970static union node *pipeline(void);
10971static union node *parse_command(void);
10972static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000010973static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010974static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000010975
Eric Andersenc470f442003-07-28 09:56:35 +000010976static union node *
10977list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000010978{
10979 union node *n1, *n2, *n3;
10980 int tok;
10981
Eric Andersencb57d552001-06-28 07:25:16 +000010982 n1 = NULL;
10983 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010984 switch (peektoken()) {
10985 case TNL:
10986 if (!(nlflag & 1))
10987 break;
10988 parseheredoc();
10989 return n1;
10990
10991 case TEOF:
10992 if (!n1 && (nlflag & 1))
10993 n1 = NODE_EOF;
10994 parseheredoc();
10995 return n1;
10996 }
10997
10998 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko888527c2016-10-02 16:54:17 +020010999 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
Ron Yorstonc0e00762015-10-29 11:30:55 +000011000 return n1;
11001 nlflag |= 2;
11002
Eric Andersencb57d552001-06-28 07:25:16 +000011003 n2 = andor();
11004 tok = readtoken();
11005 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000011006 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011007 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011008 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011009 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011010 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000011011 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011012 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011013 n2 = n3;
11014 }
11015 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000011016 }
11017 }
11018 if (n1 == NULL) {
11019 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011020 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011021 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011022 n3->type = NSEMI;
11023 n3->nbinary.ch1 = n1;
11024 n3->nbinary.ch2 = n2;
11025 n1 = n3;
11026 }
11027 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011028 case TNL:
11029 case TEOF:
11030 tokpushback = 1;
11031 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000011032 case TBACKGND:
11033 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000011034 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011035 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000011036 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011037 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011038 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011039 return n1;
11040 }
11041 }
11042}
11043
Eric Andersenc470f442003-07-28 09:56:35 +000011044static union node *
11045andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011046{
Eric Andersencb57d552001-06-28 07:25:16 +000011047 union node *n1, *n2, *n3;
11048 int t;
11049
Eric Andersencb57d552001-06-28 07:25:16 +000011050 n1 = pipeline();
11051 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011052 t = readtoken();
11053 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000011054 t = NAND;
11055 } else if (t == TOR) {
11056 t = NOR;
11057 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011058 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011059 return n1;
11060 }
Eric Andersenc470f442003-07-28 09:56:35 +000011061 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011062 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011063 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011064 n3->type = t;
11065 n3->nbinary.ch1 = n1;
11066 n3->nbinary.ch2 = n2;
11067 n1 = n3;
11068 }
11069}
11070
Eric Andersenc470f442003-07-28 09:56:35 +000011071static union node *
11072pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011073{
Eric Andersencb57d552001-06-28 07:25:16 +000011074 union node *n1, *n2, *pipenode;
11075 struct nodelist *lp, *prev;
11076 int negate;
11077
11078 negate = 0;
11079 TRACE(("pipeline: entered\n"));
11080 if (readtoken() == TNOT) {
11081 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000011082 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011083 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011084 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011085 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011086 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011087 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000011088 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011089 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011090 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000011091 pipenode->npipe.cmdlist = lp;
11092 lp->n = n1;
11093 do {
11094 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011095 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000011096 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011097 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011098 prev->next = lp;
11099 } while (readtoken() == TPIPE);
11100 lp->next = NULL;
11101 n1 = pipenode;
11102 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011103 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011104 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011105 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000011106 n2->type = NNOT;
11107 n2->nnot.com = n1;
11108 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011109 }
11110 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000011111}
11112
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011113static union node *
11114makename(void)
11115{
11116 union node *n;
11117
Denis Vlasenko597906c2008-02-20 16:38:54 +000011118 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011119 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011120 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011121 n->narg.text = wordtext;
11122 n->narg.backquote = backquotelist;
11123 return n;
11124}
11125
11126static void
11127fixredir(union node *n, const char *text, int err)
11128{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011129 int fd;
11130
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011131 TRACE(("Fix redir %s %d\n", text, err));
11132 if (!err)
11133 n->ndup.vname = NULL;
11134
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011135 fd = bb_strtou(text, NULL, 10);
11136 if (!errno && fd >= 0)
11137 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011138 else if (LONE_DASH(text))
11139 n->ndup.dupfd = -1;
11140 else {
11141 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011142 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011143 n->ndup.vname = makename();
11144 }
11145}
11146
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011147static void
11148parsefname(void)
11149{
11150 union node *n = redirnode;
11151
Denys Vlasenkoa7328982017-07-29 19:57:28 +020011152 if (n->type == NHERE)
11153 checkkwd = CHKEOFMARK;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011154 if (readtoken() != TWORD)
11155 raise_error_unexpected_syntax(-1);
11156 if (n->type == NHERE) {
11157 struct heredoc *here = heredoc;
11158 struct heredoc *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011159
11160 if (quoteflag == 0)
11161 n->type = NXHERE;
11162 TRACE(("Here document %d\n", n->type));
Denys Vlasenkob6c84342009-08-29 20:23:20 +020011163 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011164 here->eofmark = wordtext;
11165 here->next = NULL;
11166 if (heredoclist == NULL)
11167 heredoclist = here;
11168 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011169 for (p = heredoclist; p->next; p = p->next)
11170 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011171 p->next = here;
11172 }
11173 } else if (n->type == NTOFD || n->type == NFROMFD) {
11174 fixredir(n, wordtext, 0);
11175 } else {
11176 n->nfile.fname = makename();
11177 }
11178}
Eric Andersencb57d552001-06-28 07:25:16 +000011179
Eric Andersenc470f442003-07-28 09:56:35 +000011180static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011181simplecmd(void)
11182{
11183 union node *args, **app;
11184 union node *n = NULL;
11185 union node *vars, **vpp;
11186 union node **rpp, *redir;
11187 int savecheckkwd;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011188#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011189 smallint double_brackets_flag = 0;
11190#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011191 IF_BASH_FUNCTION(smallint function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011192
11193 args = NULL;
11194 app = &args;
11195 vars = NULL;
11196 vpp = &vars;
11197 redir = NULL;
11198 rpp = &redir;
11199
11200 savecheckkwd = CHKALIAS;
11201 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000011202 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011203 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011204 t = readtoken();
11205 switch (t) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011206#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011207 case TFUNCTION:
11208 if (peektoken() != TWORD)
11209 raise_error_unexpected_syntax(TWORD);
11210 function_flag = 1;
11211 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011212#endif
11213#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011214 case TAND: /* "&&" */
11215 case TOR: /* "||" */
11216 if (!double_brackets_flag) {
11217 tokpushback = 1;
11218 goto out;
11219 }
11220 wordtext = (char *) (t == TAND ? "-a" : "-o");
11221#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011222 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011223 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011224 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011225 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011226 n->narg.text = wordtext;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011227#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011228 if (strcmp("[[", wordtext) == 0)
11229 double_brackets_flag = 1;
11230 else if (strcmp("]]", wordtext) == 0)
11231 double_brackets_flag = 0;
11232#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011233 n->narg.backquote = backquotelist;
11234 if (savecheckkwd && isassignment(wordtext)) {
11235 *vpp = n;
11236 vpp = &n->narg.next;
11237 } else {
11238 *app = n;
11239 app = &n->narg.next;
11240 savecheckkwd = 0;
11241 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011242#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011243 if (function_flag) {
11244 checkkwd = CHKNL | CHKKWD;
11245 switch (peektoken()) {
11246 case TBEGIN:
11247 case TIF:
11248 case TCASE:
11249 case TUNTIL:
11250 case TWHILE:
11251 case TFOR:
11252 goto do_func;
11253 case TLP:
11254 function_flag = 0;
11255 break;
11256 case TWORD:
11257 if (strcmp("[[", wordtext) == 0)
11258 goto do_func;
11259 /* fall through */
11260 default:
11261 raise_error_unexpected_syntax(-1);
11262 }
11263 }
11264#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011265 break;
11266 case TREDIR:
11267 *rpp = n = redirnode;
11268 rpp = &n->nfile.next;
11269 parsefname(); /* read name of redirection file */
11270 break;
11271 case TLP:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011272 IF_BASH_FUNCTION(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011273 if (args && app == &args->narg.next
11274 && !vars && !redir
11275 ) {
11276 struct builtincmd *bcmd;
11277 const char *name;
11278
11279 /* We have a function */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011280 if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011281 raise_error_unexpected_syntax(TRP);
11282 name = n->narg.text;
11283 if (!goodname(name)
11284 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11285 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011286 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011287 }
11288 n->type = NDEFUN;
11289 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11290 n->narg.next = parse_command();
11291 return n;
11292 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011293 IF_BASH_FUNCTION(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011294 /* fall through */
11295 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011296 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011297 goto out;
11298 }
11299 }
11300 out:
11301 *app = NULL;
11302 *vpp = NULL;
11303 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011304 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011305 n->type = NCMD;
11306 n->ncmd.args = args;
11307 n->ncmd.assign = vars;
11308 n->ncmd.redirect = redir;
11309 return n;
11310}
11311
11312static union node *
11313parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011314{
Eric Andersencb57d552001-06-28 07:25:16 +000011315 union node *n1, *n2;
11316 union node *ap, **app;
11317 union node *cp, **cpp;
11318 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011319 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011320 int t;
11321
11322 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011323 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011324
Eric Andersencb57d552001-06-28 07:25:16 +000011325 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011326 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011327 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011328 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011329 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011330 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011331 n1->type = NIF;
11332 n1->nif.test = list(0);
11333 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011334 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011335 n1->nif.ifpart = list(0);
11336 n2 = n1;
11337 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011338 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011339 n2 = n2->nif.elsepart;
11340 n2->type = NIF;
11341 n2->nif.test = list(0);
11342 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011343 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011344 n2->nif.ifpart = list(0);
11345 }
11346 if (lasttoken == TELSE)
11347 n2->nif.elsepart = list(0);
11348 else {
11349 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011350 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011351 }
Eric Andersenc470f442003-07-28 09:56:35 +000011352 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011353 break;
11354 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011355 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011356 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011357 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011358 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011359 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011360 got = readtoken();
11361 if (got != TDO) {
Denys Vlasenko888527c2016-10-02 16:54:17 +020011362 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
Denis Vlasenko131ae172007-02-18 13:00:19 +000011363 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011364 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011365 }
11366 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011367 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011368 break;
11369 }
11370 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011371 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011372 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011373 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011374 n1->type = NFOR;
11375 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011376 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011377 if (readtoken() == TIN) {
11378 app = &ap;
11379 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011380 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011381 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011382 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011383 n2->narg.text = wordtext;
11384 n2->narg.backquote = backquotelist;
11385 *app = n2;
11386 app = &n2->narg.next;
11387 }
11388 *app = NULL;
11389 n1->nfor.args = ap;
11390 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011391 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011392 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011393 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011394 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011395 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011396 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011397 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011398 n1->nfor.args = n2;
11399 /*
11400 * Newline or semicolon here is optional (but note
11401 * that the original Bourne shell only allowed NL).
11402 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011403 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011404 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011405 }
Eric Andersenc470f442003-07-28 09:56:35 +000011406 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011407 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011408 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011409 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011410 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011411 break;
11412 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011413 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011414 n1->type = NCASE;
11415 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011416 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011417 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011418 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011419 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011420 n2->narg.text = wordtext;
11421 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011422 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11423 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011424 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011425 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011426 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011427 checkkwd = CHKNL | CHKKWD;
11428 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011429 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011430 if (lasttoken == TLP)
11431 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011432 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011433 cp->type = NCLIST;
11434 app = &cp->nclist.pattern;
11435 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011436 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011437 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011438 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011439 ap->narg.text = wordtext;
11440 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011441 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011442 break;
11443 app = &ap->narg.next;
11444 readtoken();
11445 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011446 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011447 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011448 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011449 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011450
Eric Andersenc470f442003-07-28 09:56:35 +000011451 cpp = &cp->nclist.next;
11452
11453 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011454 t = readtoken();
11455 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011456 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011457 raise_error_unexpected_syntax(TENDCASE);
11458 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011459 }
Eric Andersenc470f442003-07-28 09:56:35 +000011460 }
Eric Andersencb57d552001-06-28 07:25:16 +000011461 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011462 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011463 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011464 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011465 n1->type = NSUBSHELL;
11466 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011467 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011468 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011469 break;
11470 case TBEGIN:
11471 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011472 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011473 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011474 IF_BASH_FUNCTION(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011475 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011476 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011477 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011478 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011479 }
11480
Eric Andersenc470f442003-07-28 09:56:35 +000011481 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011482 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011483
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011484 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011485 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011486 checkkwd = CHKKWD | CHKALIAS;
11487 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011488 while (readtoken() == TREDIR) {
11489 *rpp = n2 = redirnode;
11490 rpp = &n2->nfile.next;
11491 parsefname();
11492 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011493 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011494 *rpp = NULL;
11495 if (redir) {
11496 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011497 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011498 n2->type = NREDIR;
11499 n2->nredir.n = n1;
11500 n1 = n2;
11501 }
11502 n1->nredir.redirect = redir;
11503 }
Eric Andersencb57d552001-06-28 07:25:16 +000011504 return n1;
11505}
11506
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011507#if BASH_DOLLAR_SQUOTE
Denys Vlasenko37dc08b2016-10-02 04:38:07 +020011508static int
11509decode_dollar_squote(void)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011510{
11511 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11512 int c, cnt;
11513 char *p;
11514 char buf[4];
11515
11516 c = pgetc();
11517 p = strchr(C_escapes, c);
11518 if (p) {
11519 buf[0] = c;
11520 p = buf;
11521 cnt = 3;
11522 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11523 do {
11524 c = pgetc();
11525 *++p = c;
11526 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11527 pungetc();
11528 } else if (c == 'x') { /* \xHH */
11529 do {
11530 c = pgetc();
11531 *++p = c;
11532 } while (isxdigit(c) && --cnt);
11533 pungetc();
11534 if (cnt == 3) { /* \x but next char is "bad" */
11535 c = 'x';
11536 goto unrecognized;
11537 }
11538 } else { /* simple seq like \\ or \t */
11539 p++;
11540 }
11541 *p = '\0';
11542 p = buf;
11543 c = bb_process_escape_sequence((void*)&p);
11544 } else { /* unrecognized "\z": print both chars unless ' or " */
11545 if (c != '\'' && c != '"') {
11546 unrecognized:
11547 c |= 0x100; /* "please encode \, then me" */
11548 }
11549 }
11550 return c;
11551}
11552#endif
11553
Denys Vlasenko46999802017-07-29 21:12:29 +020011554/* Used by expandstr to get here-doc like behaviour. */
11555#define FAKEEOFMARK ((char*)(uintptr_t)1)
11556
11557static ALWAYS_INLINE int
11558realeofmark(const char *eofmark)
11559{
11560 return eofmark && eofmark != FAKEEOFMARK;
11561}
11562
Eric Andersencb57d552001-06-28 07:25:16 +000011563/*
11564 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11565 * is not NULL, read a here document. In the latter case, eofmark is the
11566 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011567 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011568 * is the first character of the input token or document.
11569 *
11570 * Because C does not have internal subroutines, I have simulated them
11571 * using goto's to implement the subroutine linkage. The following macros
11572 * will run code that appears at the end of readtoken1.
11573 */
Eric Andersen2870d962001-07-02 17:27:21 +000011574#define CHECKEND() {goto checkend; checkend_return:;}
11575#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11576#define PARSESUB() {goto parsesub; parsesub_return:;}
11577#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11578#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11579#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011580static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011581readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011582{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011583 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011584 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011585 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020011586 size_t len;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011587 struct nodelist *bqlist;
11588 smallint quotef;
11589 smallint dblquote;
11590 smallint oldstyle;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011591 IF_FEATURE_SH_MATH(smallint prevsyntax;) /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011592 smallint pssyntax; /* we are expanding a prompt string */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011593 int varnest; /* levels of variables expansion */
Denys Vlasenko0b883582016-12-23 16:49:07 +010011594 IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */
11595 IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011596 int dqvarnest; /* levels of variables expansion within double quotes */
11597
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011598 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011599
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011600 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011601 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011602 quotef = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011603 IF_FEATURE_SH_MATH(prevsyntax = 0;)
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020011604#if ENABLE_ASH_EXPAND_PRMT
Denis Vlasenko46a53062007-09-24 18:30:02 +000011605 pssyntax = (syntax == PSSYNTAX);
11606 if (pssyntax)
11607 syntax = DQSYNTAX;
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020011608#else
11609 pssyntax = 0; /* constant */
11610#endif
Denis Vlasenko46a53062007-09-24 18:30:02 +000011611 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011612 varnest = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011613 IF_FEATURE_SH_MATH(arinest = 0;)
11614 IF_FEATURE_SH_MATH(parenlevel = 0;)
Eric Andersencb57d552001-06-28 07:25:16 +000011615 dqvarnest = 0;
11616
11617 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011618 loop:
11619 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011620 CHECKEND(); /* set c to PEOF if at end of here document */
11621 for (;;) { /* until end of line or end of word */
11622 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11623 switch (SIT(c, syntax)) {
11624 case CNL: /* '\n' */
11625 if (syntax == BASESYNTAX)
11626 goto endword; /* exit outer loop */
11627 USTPUTC(c, out);
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011628 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011629 c = pgetc();
11630 goto loop; /* continue outer loop */
11631 case CWORD:
11632 USTPUTC(c, out);
11633 break;
11634 case CCTL:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011635#if BASH_DOLLAR_SQUOTE
Denys Vlasenko958581a2010-09-12 15:04:27 +020011636 if (c == '\\' && bash_dollar_squote) {
11637 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020011638 if (c == '\0') {
11639 /* skip $'\000', $'\x00' (like bash) */
11640 break;
11641 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011642 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020011643 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011644 c = (unsigned char)c;
Denys Vlasenko13f20912016-09-25 20:54:25 +020011645 if (eofmark == NULL || dblquote)
11646 USTPUTC(CTLESC, out);
11647 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011648 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011649 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011650#endif
Denys Vlasenko13f20912016-09-25 20:54:25 +020011651 if (eofmark == NULL || dblquote)
11652 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011653 USTPUTC(c, out);
11654 break;
11655 case CBACK: /* backslash */
11656 c = pgetc_without_PEOA();
11657 if (c == PEOF) {
11658 USTPUTC(CTLESC, out);
11659 USTPUTC('\\', out);
11660 pungetc();
11661 } else if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011662 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011663 } else {
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020011664 if (pssyntax && c == '$') {
Eric Andersenc470f442003-07-28 09:56:35 +000011665 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011666 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011667 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011668 /* Backslash is retained if we are in "str" and next char isn't special */
11669 if (dblquote
11670 && c != '\\'
11671 && c != '`'
11672 && c != '$'
11673 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011674 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011675 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011676 }
Ron Yorston549deab2015-05-18 09:57:51 +020011677 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011678 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011679 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011680 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011681 break;
11682 case CSQUOTE:
11683 syntax = SQSYNTAX;
11684 quotemark:
11685 if (eofmark == NULL) {
11686 USTPUTC(CTLQUOTEMARK, out);
11687 }
11688 break;
11689 case CDQUOTE:
11690 syntax = DQSYNTAX;
11691 dblquote = 1;
11692 goto quotemark;
11693 case CENDQUOTE:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011694 IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020011695 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011696 USTPUTC(c, out);
11697 } else {
11698 if (dqvarnest == 0) {
11699 syntax = BASESYNTAX;
11700 dblquote = 0;
11701 }
11702 quotef = 1;
11703 goto quotemark;
11704 }
11705 break;
11706 case CVAR: /* '$' */
11707 PARSESUB(); /* parse substitution */
11708 break;
11709 case CENDVAR: /* '}' */
11710 if (varnest > 0) {
11711 varnest--;
11712 if (dqvarnest > 0) {
11713 dqvarnest--;
11714 }
11715 c = CTLENDVAR;
11716 }
11717 USTPUTC(c, out);
11718 break;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011719#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko958581a2010-09-12 15:04:27 +020011720 case CLP: /* '(' in arithmetic */
11721 parenlevel++;
11722 USTPUTC(c, out);
11723 break;
11724 case CRP: /* ')' in arithmetic */
11725 if (parenlevel > 0) {
11726 parenlevel--;
11727 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011728 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020011729 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011730 if (--arinest == 0) {
11731 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011732 }
11733 } else {
11734 /*
11735 * unbalanced parens
11736 * (don't 2nd guess - no error)
11737 */
11738 pungetc();
11739 }
11740 }
11741 USTPUTC(c, out);
11742 break;
11743#endif
11744 case CBQUOTE: /* '`' */
11745 PARSEBACKQOLD();
11746 break;
11747 case CENDFILE:
11748 goto endword; /* exit outer loop */
11749 case CIGN:
11750 break;
11751 default:
11752 if (varnest == 0) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011753#if BASH_REDIR_OUTPUT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011754 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011755//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020011756 if (pgetc() == '>')
11757 c = 0x100 + '>'; /* flag &> */
11758 pungetc();
11759 }
11760#endif
11761 goto endword; /* exit outer loop */
11762 }
11763 IF_ASH_ALIAS(if (c != PEOA))
11764 USTPUTC(c, out);
11765 }
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020011766 c = pgetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011767 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011768 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011769
Denys Vlasenko0b883582016-12-23 16:49:07 +010011770#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000011771 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011772 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011773#endif
Ron Yorston0e056f72015-07-01 16:45:40 +010011774 if (syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011775 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011776 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011777 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011778 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011779 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011780 }
11781 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011782 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011783 out = stackblock();
11784 if (eofmark == NULL) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011785 if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011786 && quotef == 0
11787 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011788 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011789 PARSEREDIR(); /* passed as params: out, c */
11790 lasttoken = TREDIR;
11791 return lasttoken;
11792 }
11793 /* else: non-number X seen, interpret it
11794 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011795 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011796 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011797 }
11798 quoteflag = quotef;
11799 backquotelist = bqlist;
11800 grabstackblock(len);
11801 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011802 lasttoken = TWORD;
11803 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011804/* end of readtoken routine */
11805
Eric Andersencb57d552001-06-28 07:25:16 +000011806/*
11807 * Check to see whether we are at the end of the here document. When this
11808 * is called, c is set to the first character of the next input line. If
11809 * we are at the end of the here document, this routine sets the c to PEOF.
11810 */
Eric Andersenc470f442003-07-28 09:56:35 +000011811checkend: {
Denys Vlasenko46999802017-07-29 21:12:29 +020011812 if (realeofmark(eofmark)) {
Denys Vlasenkoa7328982017-07-29 19:57:28 +020011813 int markloc;
11814 char *p;
11815
Denis Vlasenko131ae172007-02-18 13:00:19 +000011816#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011817 if (c == PEOA)
11818 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011819#endif
11820 if (striptabs) {
11821 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011822 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011823 }
Eric Andersenc470f442003-07-28 09:56:35 +000011824 }
Eric Andersencb57d552001-06-28 07:25:16 +000011825
Denys Vlasenkoa7328982017-07-29 19:57:28 +020011826 markloc = out - (char *)stackblock();
11827 for (p = eofmark; STPUTC(c, out), *p; p++) {
11828 if (c != *p)
11829 goto more_heredoc;
11830
11831 c = pgetc_without_PEOA();
11832 }
11833
11834 if (c == '\n' || c == PEOF) {
11835 c = PEOF;
11836 g_parsefile->linno++;
11837 needprompt = doprompt;
11838 } else {
11839 int len_here;
11840
11841 more_heredoc:
11842 p = (char *)stackblock() + markloc + 1;
11843 len_here = out - p;
11844
11845 if (len_here) {
11846 len_here -= (c >= PEOF);
11847 c = p[-1];
11848
11849 if (len_here) {
11850 char *str;
11851
11852 str = alloca(len_here + 1);
11853 *(char *)mempcpy(str, p, len_here) = '\0';
11854
11855 pushstring(str, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011856 }
11857 }
11858 }
Denys Vlasenkoa7328982017-07-29 19:57:28 +020011859
11860 STADJUST((char *)stackblock() + markloc - out, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011861 }
Eric Andersenc470f442003-07-28 09:56:35 +000011862 goto checkend_return;
11863}
Eric Andersencb57d552001-06-28 07:25:16 +000011864
Eric Andersencb57d552001-06-28 07:25:16 +000011865/*
11866 * Parse a redirection operator. The variable "out" points to a string
11867 * specifying the fd to be redirected. The variable "c" contains the
11868 * first character of the redirection operator.
11869 */
Eric Andersenc470f442003-07-28 09:56:35 +000011870parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011871 /* out is already checked to be a valid number or "" */
11872 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000011873 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000011874
Denis Vlasenko597906c2008-02-20 16:38:54 +000011875 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000011876 if (c == '>') {
11877 np->nfile.fd = 1;
11878 c = pgetc();
11879 if (c == '>')
11880 np->type = NAPPEND;
11881 else if (c == '|')
11882 np->type = NCLOBBER;
11883 else if (c == '&')
11884 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011885 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000011886 else {
11887 np->type = NTO;
11888 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011889 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000011890 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011891#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000011892 else if (c == 0x100 + '>') { /* this flags &> redirection */
11893 np->nfile.fd = 1;
11894 pgetc(); /* this is '>', no need to check */
11895 np->type = NTO2;
11896 }
11897#endif
11898 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000011899 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011900 c = pgetc();
11901 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000011902 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011903 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011904 np = stzalloc(sizeof(struct nhere));
11905 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011906 }
11907 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011908 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000011909 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011910 c = pgetc();
11911 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000011912 heredoc->striptabs = 1;
11913 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011914 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011915 pungetc();
11916 }
11917 break;
11918
11919 case '&':
11920 np->type = NFROMFD;
11921 break;
11922
11923 case '>':
11924 np->type = NFROMTO;
11925 break;
11926
11927 default:
11928 np->type = NFROM;
11929 pungetc();
11930 break;
11931 }
Eric Andersencb57d552001-06-28 07:25:16 +000011932 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011933 if (fd >= 0)
11934 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011935 redirnode = np;
11936 goto parseredir_return;
11937}
Eric Andersencb57d552001-06-28 07:25:16 +000011938
Eric Andersencb57d552001-06-28 07:25:16 +000011939/*
11940 * Parse a substitution. At this point, we have read the dollar sign
11941 * and nothing else.
11942 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000011943
11944/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11945 * (assuming ascii char codes, as the original implementation did) */
11946#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011947 (((unsigned)(c) - 33 < 32) \
11948 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000011949parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010011950 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011951 int typeloc;
Eric Andersencb57d552001-06-28 07:25:16 +000011952
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011953 c = pgetc_eatbnl();
Denys Vlasenkoa7328982017-07-29 19:57:28 +020011954 if ((checkkwd & CHKEOFMARK)
11955 || c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011956 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000011957 ) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011958#if BASH_DOLLAR_SQUOTE
Ron Yorston84ba50c2016-04-03 22:43:14 +010011959 if (syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011960 bash_dollar_squote = 1;
11961 else
11962#endif
11963 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011964 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011965 } else if (c == '(') {
11966 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011967 if (pgetc_eatbnl() == '(') {
Denys Vlasenko0b883582016-12-23 16:49:07 +010011968#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000011969 PARSEARITH();
11970#else
Denys Vlasenko4f8079d2017-07-17 17:11:48 +020011971 raise_error_syntax("support for $((arith)) is disabled");
Eric Andersenc470f442003-07-28 09:56:35 +000011972#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011973 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011974 pungetc();
11975 PARSEBACKQNEW();
11976 }
11977 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011978 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000011979 USTPUTC(CTLVAR, out);
11980 typeloc = out - (char *)stackblock();
Denys Vlasenko3df14102016-10-26 16:41:13 +020011981 STADJUST(1, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011982 subtype = VSNORMAL;
11983 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011984 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011985 subtype = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011986 }
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011987 varname:
Denys Vlasenko3df14102016-10-26 16:41:13 +020011988 if (is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011989 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011990 do {
11991 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011992 c = pgetc_eatbnl();
Denys Vlasenko3df14102016-10-26 16:41:13 +020011993 } while (is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011994 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011995 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011996 do {
11997 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011998 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011999 } while (isdigit(c));
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012000 } else if (is_special(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012001 /* $[{[#]]<specialchar>[}] */
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012002 int cc = c;
12003
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012004 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012005 if (!subtype && cc == '#') {
12006 subtype = VSLENGTH;
12007 if (c == '_' || isalnum(c))
12008 goto varname;
12009 cc = c;
12010 c = pgetc_eatbnl();
12011 if (cc == '}' || c != '}') {
12012 pungetc();
12013 subtype = 0;
12014 c = cc;
12015 cc = '#';
12016 }
12017 }
12018 USTPUTC(cc, out);
Denis Vlasenko559691a2008-10-05 18:39:31 +000012019 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020012020 goto badsub;
Denis Vlasenko559691a2008-10-05 18:39:31 +000012021 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012022 if (c != '}' && subtype == VSLENGTH) {
12023 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020012024 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012025 }
Eric Andersencb57d552001-06-28 07:25:16 +000012026
Eric Andersenc470f442003-07-28 09:56:35 +000012027 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012028 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012029 /* ${VAR...} but not $VAR or ${#VAR} */
12030 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000012031 switch (c) {
12032 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012033 c = pgetc_eatbnl();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012034#if BASH_SUBSTR
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012035 /* This check is only needed to not misinterpret
12036 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
12037 * constructs.
12038 */
12039 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012040 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012041 pungetc();
Denys Vlasenko88e15702016-10-26 01:55:56 +020012042 break; /* "goto badsub" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012043 }
12044#endif
Denys Vlasenko3df14102016-10-26 16:41:13 +020012045 subtype = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000012046 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012047 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012048 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000012049 if (p == NULL)
Denys Vlasenko88e15702016-10-26 01:55:56 +020012050 break;
Denys Vlasenko3df14102016-10-26 16:41:13 +020012051 subtype |= p - types + VSNORMAL;
Eric Andersenc470f442003-07-28 09:56:35 +000012052 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012053 }
Eric Andersenc470f442003-07-28 09:56:35 +000012054 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012055 case '#': {
12056 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012057 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012058 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012059 if (c != cc)
Denys Vlasenko88e15702016-10-26 01:55:56 +020012060 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012061 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012062 break;
12063 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012064#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012065 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020012066 /* ${v/[/]pattern/repl} */
12067//TODO: encode pattern and repl separately.
12068// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012069 subtype = VSREPLACE;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012070 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012071 if (c != '/')
Denys Vlasenko88e15702016-10-26 01:55:56 +020012072 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012073 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012074 break;
12075#endif
Eric Andersencb57d552001-06-28 07:25:16 +000012076 }
Eric Andersenc470f442003-07-28 09:56:35 +000012077 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020012078 badsub:
Eric Andersenc470f442003-07-28 09:56:35 +000012079 pungetc();
12080 }
Denys Vlasenko3df14102016-10-26 16:41:13 +020012081 ((unsigned char *)stackblock())[typeloc] = subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012082 if (subtype != VSNORMAL) {
12083 varnest++;
Denys Vlasenko3df14102016-10-26 16:41:13 +020012084 if (dblquote)
Eric Andersenc470f442003-07-28 09:56:35 +000012085 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000012086 }
Denys Vlasenko88e15702016-10-26 01:55:56 +020012087 STPUTC('=', out);
Eric Andersencb57d552001-06-28 07:25:16 +000012088 }
Eric Andersenc470f442003-07-28 09:56:35 +000012089 goto parsesub_return;
12090}
Eric Andersencb57d552001-06-28 07:25:16 +000012091
Eric Andersencb57d552001-06-28 07:25:16 +000012092/*
12093 * Called to parse command substitutions. Newstyle is set if the command
12094 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
12095 * list of commands (passed by reference), and savelen is the number of
12096 * characters on the top of the stack which must be preserved.
12097 */
Eric Andersenc470f442003-07-28 09:56:35 +000012098parsebackq: {
12099 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012100 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010012101 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000012102 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012103 smallint saveprompt = 0;
12104
Eric Andersenc470f442003-07-28 09:56:35 +000012105 str = NULL;
12106 savelen = out - (char *)stackblock();
12107 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012108 /*
12109 * FIXME: this can allocate very large block on stack and SEGV.
12110 * Example:
12111 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020012112 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012113 * a hundred command substitutions stack overflows.
12114 * With larger prepended string, SEGV happens sooner.
12115 */
Ron Yorston072fc602015-07-01 16:46:18 +010012116 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000012117 memcpy(str, stackblock(), savelen);
12118 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012119
Eric Andersenc470f442003-07-28 09:56:35 +000012120 if (oldstyle) {
12121 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010012122 * treatment to some slashes, and then push the string and
12123 * reread it as input, interpreting it normally.
12124 */
Eric Andersenc470f442003-07-28 09:56:35 +000012125 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000012126 size_t psavelen;
12127 char *pstr;
12128
Eric Andersenc470f442003-07-28 09:56:35 +000012129 STARTSTACKSTR(pout);
12130 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012131 int pc;
12132
12133 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012134 pc = pgetc();
12135 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000012136 case '`':
12137 goto done;
12138
12139 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012140 pc = pgetc();
12141 if (pc == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012142 nlprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012143 /*
12144 * If eating a newline, avoid putting
12145 * the newline into the new character
12146 * stream (via the STPUTC after the
12147 * switch).
12148 */
12149 continue;
12150 }
12151 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012152 && (!dblquote || pc != '"')
12153 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000012154 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012155 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010012156 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000012157 break;
12158 }
12159 /* fall through */
12160
12161 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012162 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012163 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012164 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000012165
12166 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012167 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012168 break;
12169
12170 default:
12171 break;
12172 }
12173 STPUTC(pc, pout);
12174 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012175 done:
Eric Andersenc470f442003-07-28 09:56:35 +000012176 STPUTC('\0', pout);
12177 psavelen = pout - (char *)stackblock();
12178 if (psavelen > 0) {
12179 pstr = grabstackstr(pout);
12180 setinputstring(pstr);
12181 }
12182 }
12183 nlpp = &bqlist;
12184 while (*nlpp)
12185 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012186 *nlpp = stzalloc(sizeof(**nlpp));
12187 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012188
12189 if (oldstyle) {
12190 saveprompt = doprompt;
12191 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012192 }
12193
Eric Andersenc470f442003-07-28 09:56:35 +000012194 n = list(2);
12195
12196 if (oldstyle)
12197 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012198 else if (readtoken() != TRP)
12199 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000012200
12201 (*nlpp)->n = n;
12202 if (oldstyle) {
12203 /*
12204 * Start reading from old file again, ignoring any pushed back
12205 * tokens left from the backquote parsing
12206 */
12207 popfile();
12208 tokpushback = 0;
12209 }
12210 while (stackblocksize() <= savelen)
12211 growstackblock();
12212 STARTSTACKSTR(out);
12213 if (str) {
12214 memcpy(out, str, savelen);
12215 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012216 }
Ron Yorston549deab2015-05-18 09:57:51 +020012217 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012218 if (oldstyle)
12219 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012220 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000012221}
12222
Denys Vlasenko0b883582016-12-23 16:49:07 +010012223#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000012224/*
12225 * Parse an arithmetic expansion (indicate start of one and set state)
12226 */
Eric Andersenc470f442003-07-28 09:56:35 +000012227parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000012228 if (++arinest == 1) {
12229 prevsyntax = syntax;
12230 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000012231 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020012232 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012233 goto parsearith_return;
12234}
12235#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012236} /* end of readtoken */
12237
Eric Andersencb57d552001-06-28 07:25:16 +000012238/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012239 * Read the next input token.
12240 * If the token is a word, we set backquotelist to the list of cmds in
12241 * backquotes. We set quoteflag to true if any part of the word was
12242 * quoted.
12243 * If the token is TREDIR, then we set redirnode to a structure containing
12244 * the redirection.
12245 * In all cases, the variable startlinno is set to the number of the line
12246 * on which the token starts.
12247 *
12248 * [Change comment: here documents and internal procedures]
12249 * [Readtoken shouldn't have any arguments. Perhaps we should make the
12250 * word parsing code into a separate routine. In this case, readtoken
12251 * doesn't need to have any internal procedures, but parseword does.
12252 * We could also make parseoperator in essence the main routine, and
12253 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000012254 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012255#define NEW_xxreadtoken
12256#ifdef NEW_xxreadtoken
12257/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012258static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000012259 '\n', '(', ')', /* singles */
12260 '&', '|', ';', /* doubles */
12261 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012262};
Eric Andersencb57d552001-06-28 07:25:16 +000012263
Denis Vlasenko834dee72008-10-07 09:18:30 +000012264#define xxreadtoken_singles 3
12265#define xxreadtoken_doubles 3
12266
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012267static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012268 TNL, TLP, TRP, /* only single occurrence allowed */
12269 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12270 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012271 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012272};
12273
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012274static int
12275xxreadtoken(void)
12276{
12277 int c;
12278
12279 if (tokpushback) {
12280 tokpushback = 0;
12281 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012282 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012283 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012284 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012285 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012286 c = pgetc();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000012287 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012288 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012289
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012290 if (c == '#') {
12291 while ((c = pgetc()) != '\n' && c != PEOF)
12292 continue;
12293 pungetc();
12294 } else if (c == '\\') {
12295 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012296 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012297 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012298 }
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012299 nlprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012300 } else {
12301 const char *p;
12302
12303 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12304 if (c != PEOF) {
12305 if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012306 nlnoprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012307 }
12308
12309 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000012310 if (p == NULL)
12311 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012312
Denis Vlasenko834dee72008-10-07 09:18:30 +000012313 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12314 int cc = pgetc();
12315 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012316 p += xxreadtoken_doubles + 1;
12317 } else {
12318 pungetc();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012319#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012320 if (c == '&' && cc == '>') /* &> */
12321 break; /* return readtoken1(...) */
12322#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012323 }
12324 }
12325 }
12326 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12327 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012328 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012329 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012330
12331 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012332}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012333#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012334#define RETURN(token) return lasttoken = token
12335static int
12336xxreadtoken(void)
12337{
12338 int c;
12339
12340 if (tokpushback) {
12341 tokpushback = 0;
12342 return lasttoken;
12343 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012344 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012345 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012346 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012347 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012348 switch (c) {
12349 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012350 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012351 continue;
12352 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012353 while ((c = pgetc()) != '\n' && c != PEOF)
12354 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012355 pungetc();
12356 continue;
12357 case '\\':
12358 if (pgetc() == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012359 nlprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012360 continue;
12361 }
12362 pungetc();
12363 goto breakloop;
12364 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012365 nlnoprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012366 RETURN(TNL);
12367 case PEOF:
12368 RETURN(TEOF);
12369 case '&':
12370 if (pgetc() == '&')
12371 RETURN(TAND);
12372 pungetc();
12373 RETURN(TBACKGND);
12374 case '|':
12375 if (pgetc() == '|')
12376 RETURN(TOR);
12377 pungetc();
12378 RETURN(TPIPE);
12379 case ';':
12380 if (pgetc() == ';')
12381 RETURN(TENDCASE);
12382 pungetc();
12383 RETURN(TSEMI);
12384 case '(':
12385 RETURN(TLP);
12386 case ')':
12387 RETURN(TRP);
12388 default:
12389 goto breakloop;
12390 }
12391 }
12392 breakloop:
12393 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12394#undef RETURN
12395}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012396#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012397
12398static int
12399readtoken(void)
12400{
12401 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012402 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012403#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012404 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012405#endif
12406
12407#if ENABLE_ASH_ALIAS
12408 top:
12409#endif
12410
12411 t = xxreadtoken();
12412
12413 /*
12414 * eat newlines
12415 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012416 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012417 while (t == TNL) {
12418 parseheredoc();
12419 t = xxreadtoken();
12420 }
12421 }
12422
12423 if (t != TWORD || quoteflag) {
12424 goto out;
12425 }
12426
12427 /*
12428 * check for keywords
12429 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012430 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012431 const char *const *pp;
12432
12433 pp = findkwd(wordtext);
12434 if (pp) {
12435 lasttoken = t = pp - tokname_array;
Denys Vlasenko888527c2016-10-02 16:54:17 +020012436 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012437 goto out;
12438 }
12439 }
12440
12441 if (checkkwd & CHKALIAS) {
12442#if ENABLE_ASH_ALIAS
12443 struct alias *ap;
12444 ap = lookupalias(wordtext, 1);
12445 if (ap != NULL) {
12446 if (*ap->val) {
12447 pushstring(ap->val, ap);
12448 }
12449 goto top;
12450 }
12451#endif
12452 }
12453 out:
12454 checkkwd = 0;
12455#if DEBUG
12456 if (!alreadyseen)
Denys Vlasenko888527c2016-10-02 16:54:17 +020012457 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012458 else
Denys Vlasenko888527c2016-10-02 16:54:17 +020012459 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012460#endif
12461 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012462}
12463
Ron Yorstonc0e00762015-10-29 11:30:55 +000012464static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012465peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012466{
12467 int t;
12468
12469 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012470 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012471 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012472}
Eric Andersencb57d552001-06-28 07:25:16 +000012473
12474/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012475 * Read and parse a command. Returns NODE_EOF on end of file.
12476 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012477 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012478static union node *
12479parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012480{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012481 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012482 checkkwd = 0;
12483 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012484 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012485 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012486 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012487 return list(1);
12488}
12489
12490/*
12491 * Input any here documents.
12492 */
12493static void
12494parseheredoc(void)
12495{
12496 struct heredoc *here;
12497 union node *n;
12498
12499 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012500 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012501
12502 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012503 setprompt_if(needprompt, 2);
12504 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012505 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012506 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012507 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012508 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012509 n->narg.text = wordtext;
12510 n->narg.backquote = backquotelist;
12511 here->here->nhere.doc = n;
12512 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012513 }
Eric Andersencb57d552001-06-28 07:25:16 +000012514}
12515
12516
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012517static const char *
Denys Vlasenko46999802017-07-29 21:12:29 +020012518expandstr(const char *ps, int syntax_type)
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012519{
12520 union node n;
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012521 int saveprompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012522
Denys Vlasenko46999802017-07-29 21:12:29 +020012523 /* XXX Fix (char *) cast. */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012524 setinputstring((char *)ps);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012525
12526 saveprompt = doprompt;
12527 doprompt = 0;
Denys Vlasenko46999802017-07-29 21:12:29 +020012528 readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012529 doprompt = saveprompt;
12530
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012531 popfile();
12532
12533 n.narg.type = NARG;
12534 n.narg.next = NULL;
12535 n.narg.text = wordtext;
12536 n.narg.backquote = backquotelist;
12537
Ron Yorston549deab2015-05-18 09:57:51 +020012538 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012539 return stackblock();
12540}
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012541
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020012542static inline int
12543parser_eof(void)
12544{
12545 return tokpushback && lasttoken == TEOF;
12546}
12547
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012548/*
12549 * Execute a command or commands contained in a string.
12550 */
12551static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012552evalstring(char *s, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000012553{
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012554 struct jmploc *volatile savehandler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012555 struct jmploc jmploc;
12556 int ex;
12557
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012558 union node *n;
12559 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012560 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012561
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012562 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012563 setinputstring(s);
12564 setstackmark(&smark);
12565
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012566 status = 0;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012567 /* On exception inside execution loop, we must popfile().
12568 * Try interactively:
12569 * readonly a=a
12570 * command eval "a=b" # throws "is read only" error
12571 * "command BLTIN" is not supposed to abort (even in non-interactive use).
12572 * But if we skip popfile(), we hit EOF in eval's string, and exit.
12573 */
12574 savehandler = exception_handler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012575 ex = setjmp(jmploc.loc);
12576 if (ex)
12577 goto out;
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012578 exception_handler = &jmploc;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012579
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012580 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012581 int i;
12582
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020012583 i = evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT));
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012584 if (n)
12585 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012586 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012587 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012588 break;
12589 }
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012590 out:
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012591 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012592 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012593 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012594
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012595 exception_handler = savehandler;
12596 if (ex)
12597 longjmp(exception_handler->loc, ex);
12598
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012599 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000012600}
12601
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012602/*
12603 * The eval command.
12604 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012605static int FAST_FUNC
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012606evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012607{
12608 char *p;
12609 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012610
Denis Vlasenko68404f12008-03-17 09:00:54 +000012611 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012612 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012613 argv += 2;
12614 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012615 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012616 for (;;) {
12617 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012618 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012619 if (p == NULL)
12620 break;
12621 STPUTC(' ', concat);
12622 }
12623 STPUTC('\0', concat);
12624 p = grabstackstr(concat);
12625 }
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012626 return evalstring(p, flags & EV_TESTED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012627 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012628 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012629}
12630
12631/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012632 * Read and execute commands.
12633 * "Top" is nonzero for the top level command loop;
12634 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012635 */
12636static int
12637cmdloop(int top)
12638{
12639 union node *n;
12640 struct stackmark smark;
12641 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012642 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012643 int numeof = 0;
12644
12645 TRACE(("cmdloop(%d) called\n", top));
12646 for (;;) {
12647 int skip;
12648
12649 setstackmark(&smark);
12650#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012651 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020012652 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012653#endif
12654 inter = 0;
12655 if (iflag && top) {
12656 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012657 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012658 }
12659 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012660#if DEBUG
12661 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012662 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012663#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012664 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012665 if (!top || numeof >= 50)
12666 break;
12667 if (!stoppedjobs()) {
12668 if (!Iflag)
12669 break;
12670 out2str("\nUse \"exit\" to leave shell.\n");
12671 }
12672 numeof++;
12673 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012674 int i;
12675
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012676 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12677 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012678 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012679 i = evaltree(n, 0);
12680 if (n)
12681 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012682 }
12683 popstackmark(&smark);
12684 skip = evalskip;
12685
12686 if (skip) {
Denys Vlasenko6a0710e2016-09-30 14:18:34 +020012687 evalskip &= ~SKIPFUNC;
Denys Vlasenko0840c912016-10-01 15:27:44 +020012688 break;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012689 }
12690 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012691 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012692}
12693
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012694/*
12695 * Take commands from a file. To be compatible we should do a path
12696 * search for the file, which is necessary to find sub-commands.
12697 */
12698static char *
12699find_dot_file(char *name)
12700{
12701 char *fullname;
12702 const char *path = pathval();
12703 struct stat statb;
12704
12705 /* don't try this for absolute or relative paths */
12706 if (strchr(name, '/'))
12707 return name;
12708
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012709 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012710 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12711 /*
12712 * Don't bother freeing here, since it will
12713 * be freed by the caller.
12714 */
12715 return fullname;
12716 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012717 if (fullname != name)
12718 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012719 }
12720
12721 /* not found in the PATH */
12722 ash_msg_and_raise_error("%s: not found", name);
12723 /* NOTREACHED */
12724}
12725
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012726static int FAST_FUNC
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012727dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012728{
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012729 /* "false; . empty_file; echo $?" should print 0, not 1: */
12730 int status = 0;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012731 char *fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012732 char **argv;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012733 char *args_need_save;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012734 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012735
Denys Vlasenko981a0562017-07-26 19:53:11 +020012736//???
12737// struct strlist *sp;
12738// for (sp = cmdenviron; sp; sp = sp->next)
12739// setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012740
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012741 nextopt(nullstr); /* handle possible "--" */
12742 argv = argptr;
12743
12744 if (!argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012745 /* bash says: "bash: .: filename argument required" */
12746 return 2; /* bash compat */
12747 }
12748
Denys Vlasenko091f8312013-03-17 14:25:22 +010012749 /* This aborts if file isn't found, which is POSIXly correct.
12750 * bash returns exitcode 1 instead.
12751 */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012752 fullname = find_dot_file(argv[0]);
12753 argv++;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012754 args_need_save = argv[0];
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010012755 if (args_need_save) { /* ". FILE ARGS", and ARGS are not empty */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012756 int argc;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012757 saveparam = shellparam;
12758 shellparam.malloced = 0;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012759 argc = 1;
12760 while (argv[argc])
12761 argc++;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012762 shellparam.nparam = argc;
12763 shellparam.p = argv;
12764 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012765
Denys Vlasenko091f8312013-03-17 14:25:22 +010012766 /* This aborts if file can't be opened, which is POSIXly correct.
12767 * bash returns exitcode 1 instead.
12768 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012769 setinputfile(fullname, INPUT_PUSH_FILE);
12770 commandname = fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012771 status = cmdloop(0);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012772 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012773
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012774 if (args_need_save) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012775 freeparam(&shellparam);
12776 shellparam = saveparam;
12777 };
12778
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012779 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012780}
12781
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012782static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012783exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012784{
12785 if (stoppedjobs())
12786 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012787 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012788 exitstatus = number(argv[1]);
12789 raise_exception(EXEXIT);
12790 /* NOTREACHED */
12791}
12792
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012793/*
12794 * Read a file containing shell functions.
12795 */
12796static void
12797readcmdfile(char *name)
12798{
12799 setinputfile(name, INPUT_PUSH_FILE);
12800 cmdloop(0);
12801 popfile();
12802}
12803
12804
Denis Vlasenkocc571512007-02-23 21:10:35 +000012805/* ============ find_command inplementation */
12806
12807/*
12808 * Resolve a command name. If you change this routine, you may have to
12809 * change the shellexec routine as well.
12810 */
12811static void
12812find_command(char *name, struct cmdentry *entry, int act, const char *path)
12813{
12814 struct tblentry *cmdp;
12815 int idx;
12816 int prev;
12817 char *fullname;
12818 struct stat statb;
12819 int e;
12820 int updatetbl;
12821 struct builtincmd *bcmd;
12822
12823 /* If name contains a slash, don't use PATH or hash table */
12824 if (strchr(name, '/') != NULL) {
12825 entry->u.index = -1;
12826 if (act & DO_ABS) {
12827 while (stat(name, &statb) < 0) {
12828#ifdef SYSV
12829 if (errno == EINTR)
12830 continue;
12831#endif
12832 entry->cmdtype = CMDUNKNOWN;
12833 return;
12834 }
12835 }
12836 entry->cmdtype = CMDNORMAL;
12837 return;
12838 }
12839
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012840/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012841
12842 updatetbl = (path == pathval());
12843 if (!updatetbl) {
12844 act |= DO_ALTPATH;
12845 if (strstr(path, "%builtin") != NULL)
12846 act |= DO_ALTBLTIN;
12847 }
12848
12849 /* If name is in the table, check answer will be ok */
12850 cmdp = cmdlookup(name, 0);
12851 if (cmdp != NULL) {
12852 int bit;
12853
12854 switch (cmdp->cmdtype) {
12855 default:
12856#if DEBUG
12857 abort();
12858#endif
12859 case CMDNORMAL:
12860 bit = DO_ALTPATH;
12861 break;
12862 case CMDFUNCTION:
12863 bit = DO_NOFUNC;
12864 break;
12865 case CMDBUILTIN:
12866 bit = DO_ALTBLTIN;
12867 break;
12868 }
12869 if (act & bit) {
12870 updatetbl = 0;
12871 cmdp = NULL;
12872 } else if (cmdp->rehash == 0)
12873 /* if not invalidated by cd, we're done */
12874 goto success;
12875 }
12876
12877 /* If %builtin not in path, check for builtin next */
12878 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012879 if (bcmd) {
12880 if (IS_BUILTIN_REGULAR(bcmd))
12881 goto builtin_success;
12882 if (act & DO_ALTPATH) {
12883 if (!(act & DO_ALTBLTIN))
12884 goto builtin_success;
12885 } else if (builtinloc <= 0) {
12886 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000012887 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012888 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000012889
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012890#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000012891 {
12892 int applet_no = find_applet_by_name(name);
12893 if (applet_no >= 0) {
12894 entry->cmdtype = CMDNORMAL;
12895 entry->u.index = -2 - applet_no;
12896 return;
12897 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012898 }
12899#endif
12900
Denis Vlasenkocc571512007-02-23 21:10:35 +000012901 /* We have to search path. */
12902 prev = -1; /* where to start */
12903 if (cmdp && cmdp->rehash) { /* doing a rehash */
12904 if (cmdp->cmdtype == CMDBUILTIN)
12905 prev = builtinloc;
12906 else
12907 prev = cmdp->param.index;
12908 }
12909
12910 e = ENOENT;
12911 idx = -1;
12912 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012913 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000012914 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012915 /* NB: code below will still use fullname
12916 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012917 idx++;
12918 if (pathopt) {
12919 if (prefix(pathopt, "builtin")) {
12920 if (bcmd)
12921 goto builtin_success;
12922 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000012923 }
12924 if ((act & DO_NOFUNC)
12925 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020012926 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012927 continue;
12928 }
12929 }
12930 /* if rehash, don't redo absolute path names */
12931 if (fullname[0] == '/' && idx <= prev) {
12932 if (idx < prev)
12933 continue;
12934 TRACE(("searchexec \"%s\": no change\n", name));
12935 goto success;
12936 }
12937 while (stat(fullname, &statb) < 0) {
12938#ifdef SYSV
12939 if (errno == EINTR)
12940 continue;
12941#endif
12942 if (errno != ENOENT && errno != ENOTDIR)
12943 e = errno;
12944 goto loop;
12945 }
12946 e = EACCES; /* if we fail, this will be the error */
12947 if (!S_ISREG(statb.st_mode))
12948 continue;
12949 if (pathopt) { /* this is a %func directory */
12950 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012951 /* NB: stalloc will return space pointed by fullname
12952 * (because we don't have any intervening allocations
12953 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012954 readcmdfile(fullname);
12955 cmdp = cmdlookup(name, 0);
12956 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12957 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12958 stunalloc(fullname);
12959 goto success;
12960 }
12961 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12962 if (!updatetbl) {
12963 entry->cmdtype = CMDNORMAL;
12964 entry->u.index = idx;
12965 return;
12966 }
12967 INT_OFF;
12968 cmdp = cmdlookup(name, 1);
12969 cmdp->cmdtype = CMDNORMAL;
12970 cmdp->param.index = idx;
12971 INT_ON;
12972 goto success;
12973 }
12974
12975 /* We failed. If there was an entry for this command, delete it */
12976 if (cmdp && updatetbl)
12977 delete_cmd_entry();
12978 if (act & DO_ERR)
12979 ash_msg("%s: %s", name, errmsg(e, "not found"));
12980 entry->cmdtype = CMDUNKNOWN;
12981 return;
12982
12983 builtin_success:
12984 if (!updatetbl) {
12985 entry->cmdtype = CMDBUILTIN;
12986 entry->u.cmd = bcmd;
12987 return;
12988 }
12989 INT_OFF;
12990 cmdp = cmdlookup(name, 1);
12991 cmdp->cmdtype = CMDBUILTIN;
12992 cmdp->param.cmd = bcmd;
12993 INT_ON;
12994 success:
12995 cmdp->rehash = 0;
12996 entry->cmdtype = cmdp->cmdtype;
12997 entry->u = cmdp->param;
12998}
12999
13000
Eric Andersencb57d552001-06-28 07:25:16 +000013001/*
Eric Andersencb57d552001-06-28 07:25:16 +000013002 * The trap builtin.
13003 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013004static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013005trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013006{
13007 char *action;
13008 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013009 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013010
Eric Andersenc470f442003-07-28 09:56:35 +000013011 nextopt(nullstr);
13012 ap = argptr;
13013 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013014 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013015 char *tr = trap_ptr[signo];
13016 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013017 /* note: bash adds "SIG", but only if invoked
13018 * as "bash". If called as "sh", or if set -o posix,
13019 * then it prints short signal names.
13020 * We are printing short names: */
13021 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013022 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013023 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013024 /* trap_ptr != trap only if we are in special-cased `trap` code.
13025 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013026 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013027 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000013028 }
13029 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013030 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013031 if (trap_ptr != trap) {
13032 free(trap_ptr);
13033 trap_ptr = trap;
13034 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013035 */
Eric Andersencb57d552001-06-28 07:25:16 +000013036 return 0;
13037 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013038
Denys Vlasenko86981e32017-07-25 20:06:17 +020013039 /* Why the second check?
13040 * "trap NUM [sig2]..." is the same as "trap - NUM [sig2]..."
13041 * In this case, NUM is signal no, not an action.
13042 */
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013043 action = NULL;
Denys Vlasenko86981e32017-07-25 20:06:17 +020013044 if (ap[1] && !is_number(ap[0]))
Eric Andersencb57d552001-06-28 07:25:16 +000013045 action = *ap++;
Denys Vlasenko86981e32017-07-25 20:06:17 +020013046
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013047 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013048 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000013049 signo = get_signum(*ap);
Denys Vlasenko86981e32017-07-25 20:06:17 +020013050 if (signo < 0) {
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013051 /* Mimic bash message exactly */
13052 ash_msg("%s: invalid signal specification", *ap);
13053 exitcode = 1;
13054 goto next;
13055 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000013056 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000013057 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000013058 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000013059 action = NULL;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013060 else {
13061 if (action[0]) /* not NULL and not "" and not "-" */
13062 may_have_traps = 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013063 action = ckstrdup(action);
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013064 }
Eric Andersencb57d552001-06-28 07:25:16 +000013065 }
Denis Vlasenko60818682007-09-28 22:07:23 +000013066 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000013067 trap[signo] = action;
13068 if (signo != 0)
13069 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013070 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013071 next:
Eric Andersencb57d552001-06-28 07:25:16 +000013072 ap++;
13073 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013074 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013075}
13076
Eric Andersenc470f442003-07-28 09:56:35 +000013077
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013078/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000013079
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013080#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013081static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013082helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013083{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000013084 unsigned col;
13085 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000013086
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020013087 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000013088 "Built-in commands:\n"
13089 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000013090 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013091 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000013092 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013093 if (col > 60) {
13094 out1fmt("\n");
13095 col = 0;
13096 }
13097 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013098# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000013099 {
13100 const char *a = applet_names;
13101 while (*a) {
13102 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
13103 if (col > 60) {
13104 out1fmt("\n");
13105 col = 0;
13106 }
Ron Yorston2b919582016-04-08 11:57:20 +010013107 while (*a++ != '\0')
13108 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013109 }
13110 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013111# endif
Denys Vlasenkoebedb942016-10-02 18:45:09 +020013112 newline_and_flush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000013113 return EXIT_SUCCESS;
13114}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013115#endif
Eric Andersenc470f442003-07-28 09:56:35 +000013116
Flemming Madsend96ffda2013-04-07 18:47:24 +020013117#if MAX_HISTORY
13118static int FAST_FUNC
13119historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13120{
13121 show_history(line_input_state);
13122 return EXIT_SUCCESS;
13123}
13124#endif
13125
Eric Andersencb57d552001-06-28 07:25:16 +000013126/*
Eric Andersencb57d552001-06-28 07:25:16 +000013127 * The export and readonly commands.
13128 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013129static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013130exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000013131{
13132 struct var *vp;
13133 char *name;
13134 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000013135 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020013136 char opt;
13137 int flag;
13138 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000013139
Denys Vlasenkod5275882012-10-01 13:41:17 +020013140 /* "readonly" in bash accepts, but ignores -n.
13141 * We do the same: it saves a conditional in nextopt's param.
13142 */
13143 flag_off = 0;
13144 while ((opt = nextopt("np")) != '\0') {
13145 if (opt == 'n')
13146 flag_off = VEXPORT;
13147 }
13148 flag = VEXPORT;
13149 if (argv[0][0] == 'r') {
13150 flag = VREADONLY;
13151 flag_off = 0; /* readonly ignores -n */
13152 }
13153 flag_off = ~flag_off;
13154
Denys Vlasenko10ad6222017-04-17 16:13:32 +020013155 /*if (opt_p_not_specified) - bash doesn't check this. Try "export -p NAME" */
Denys Vlasenkod5275882012-10-01 13:41:17 +020013156 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013157 aptr = argptr;
13158 name = *aptr;
13159 if (name) {
13160 do {
13161 p = strchr(name, '=');
13162 if (p != NULL) {
13163 p++;
13164 } else {
13165 vp = *findvar(hashvar(name), name);
13166 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020013167 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013168 continue;
13169 }
Eric Andersencb57d552001-06-28 07:25:16 +000013170 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013171 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013172 } while ((name = *++aptr) != NULL);
13173 return 0;
13174 }
Eric Andersencb57d552001-06-28 07:25:16 +000013175 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013176
13177 /* No arguments. Show the list of exported or readonly vars.
13178 * -n is ignored.
13179 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013180 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000013181 return 0;
13182}
13183
Eric Andersencb57d552001-06-28 07:25:16 +000013184/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013185 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000013186 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013187static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013188unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000013189{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013190 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000013191
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013192 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013193 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013194 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000013195}
13196
Eric Andersencb57d552001-06-28 07:25:16 +000013197/*
Eric Andersencb57d552001-06-28 07:25:16 +000013198 * The unset builtin command. We unset the function before we unset the
13199 * variable to allow a function to be unset when there is a readonly variable
13200 * with the same name.
13201 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013202static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013203unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013204{
13205 char **ap;
13206 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013207 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013208
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013209 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000013210 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000013211 }
Eric Andersencb57d552001-06-28 07:25:16 +000013212
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013213 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013214 if (flag != 'f') {
Denys Vlasenkob28d4c32017-07-25 16:29:36 +020013215 unsetvar(*ap);
13216 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013217 }
13218 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000013219 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000013220 }
Denys Vlasenkob28d4c32017-07-25 16:29:36 +020013221 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013222}
13223
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000013224static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013225 ' ', offsetof(struct tms, tms_utime),
13226 '\n', offsetof(struct tms, tms_stime),
13227 ' ', offsetof(struct tms, tms_cutime),
13228 '\n', offsetof(struct tms, tms_cstime),
13229 0
13230};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013231static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013232timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013233{
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020013234 unsigned long clk_tck, s, t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013235 const unsigned char *p;
13236 struct tms buf;
13237
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020013238 clk_tck = bb_clk_tck();
Eric Andersencb57d552001-06-28 07:25:16 +000013239 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013240
13241 p = timescmd_str;
13242 do {
13243 t = *(clock_t *)(((char *) &buf) + p[1]);
13244 s = t / clk_tck;
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020013245 t = t % clk_tck;
13246 out1fmt("%lum%lu.%03lus%c",
13247 s / 60, s % 60,
13248 (t * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013249 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013250 p += 2;
13251 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013252
Eric Andersencb57d552001-06-28 07:25:16 +000013253 return 0;
13254}
13255
Denys Vlasenko0b883582016-12-23 16:49:07 +010013256#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000013257/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013258 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013259 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000013260 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013261 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000013262 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013263static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013264letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013265{
Denis Vlasenko68404f12008-03-17 09:00:54 +000013266 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000013267
Denis Vlasenko68404f12008-03-17 09:00:54 +000013268 argv++;
13269 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000013270 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000013271 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013272 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013273 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013274
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000013275 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000013276}
Eric Andersenc470f442003-07-28 09:56:35 +000013277#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013278
Eric Andersenc470f442003-07-28 09:56:35 +000013279/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013280 * The read builtin. Options:
13281 * -r Do not interpret '\' specially
13282 * -s Turn off echo (tty only)
13283 * -n NCHARS Read NCHARS max
13284 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13285 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13286 * -u FD Read from given FD instead of fd 0
Eric Andersenc470f442003-07-28 09:56:35 +000013287 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013288 * TODO: bash also has:
13289 * -a ARRAY Read into array[0],[1],etc
13290 * -d DELIM End on DELIM char, not newline
13291 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000013292 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013293static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013294readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013295{
Denys Vlasenko73067272010-01-12 22:11:24 +010013296 char *opt_n = NULL;
13297 char *opt_p = NULL;
13298 char *opt_t = NULL;
13299 char *opt_u = NULL;
13300 int read_flags = 0;
13301 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000013302 int i;
13303
Denys Vlasenko73067272010-01-12 22:11:24 +010013304 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000013305 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000013306 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010013307 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013308 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013309 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010013310 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013311 break;
13312 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010013313 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000013314 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013315 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010013316 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013317 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013318 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010013319 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000013320 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013321 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010013322 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013323 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013324 default:
13325 break;
13326 }
Eric Andersenc470f442003-07-28 09:56:35 +000013327 }
Paul Fox02eb9342005-09-07 16:56:02 +000013328
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013329 /* "read -s" needs to save/restore termios, can't allow ^C
13330 * to jump out of it.
13331 */
Denys Vlasenkof5470412017-05-22 19:34:45 +020013332 again:
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013333 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013334 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010013335 argptr,
13336 bltinlookup("IFS"), /* can be NULL */
13337 read_flags,
13338 opt_n,
13339 opt_p,
13340 opt_t,
13341 opt_u
13342 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013343 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000013344
Denys Vlasenkof5470412017-05-22 19:34:45 +020013345 if ((uintptr_t)r == 1 && errno == EINTR) {
13346 /* to get SIGCHLD: sleep 1 & read x; echo $x */
13347 if (pending_sig == 0)
13348 goto again;
13349 }
13350
Denys Vlasenko73067272010-01-12 22:11:24 +010013351 if ((uintptr_t)r > 1)
13352 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000013353
Denys Vlasenko73067272010-01-12 22:11:24 +010013354 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000013355}
13356
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013357static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020013358umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013359{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013360 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000013361
Eric Andersenc470f442003-07-28 09:56:35 +000013362 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000013363 int symbolic_mode = 0;
13364
13365 while (nextopt("S") != '\0') {
13366 symbolic_mode = 1;
13367 }
13368
Denis Vlasenkob012b102007-02-19 22:43:01 +000013369 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013370 mask = umask(0);
13371 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013372 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013373
Denys Vlasenko6283f982015-10-07 16:56:20 +020013374 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013375 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013376 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013377 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013378 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013379
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013380 i = 2;
13381 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013382 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013383 *p++ = permuser[i];
13384 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013385 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013386 if (!(mask & 0400)) *p++ = 'r';
13387 if (!(mask & 0200)) *p++ = 'w';
13388 if (!(mask & 0100)) *p++ = 'x';
13389 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013390 if (--i < 0)
13391 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013392 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013393 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013394 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013395 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013396 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013397 }
13398 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013399 char *modestr = *argptr;
13400 /* numeric umasks are taken as-is */
13401 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
13402 if (!isdigit(modestr[0]))
13403 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013404 mask = bb_parse_mode(modestr, mask);
13405 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013406 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013407 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013408 if (!isdigit(modestr[0]))
13409 mask ^= 0777;
13410 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013411 }
13412 return 0;
13413}
13414
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013415static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013416ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013417{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013418 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013419}
13420
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013421/* ============ main() and helpers */
13422
13423/*
13424 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013425 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013426static void
13427exitshell(void)
13428{
13429 struct jmploc loc;
13430 char *p;
13431 int status;
13432
Denys Vlasenkobede2152011-09-04 16:12:33 +020013433#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13434 save_history(line_input_state);
13435#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013436 status = exitstatus;
13437 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13438 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013439 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013440 status = exitstatus;
13441 goto out;
13442 }
13443 exception_handler = &loc;
13444 p = trap[0];
13445 if (p) {
13446 trap[0] = NULL;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013447 evalskip = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013448 evalstring(p, 0);
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013449 /*free(p); - we'll exit soon */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013450 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013451 out:
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013452 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13453 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13454 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013455 setjobctl(0);
Denys Vlasenkocaee80c2016-10-25 20:49:53 +020013456 flush_stdout_stderr();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013457 _exit(status);
13458 /* NOTREACHED */
13459}
13460
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013461static void
13462init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013463{
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013464 /* we will never free this */
13465 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013466
Denys Vlasenko458c1f22016-10-27 23:51:19 +020013467 sigmode[SIGCHLD - 1] = S_DFL;
13468 setsignal(SIGCHLD);
13469
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013470 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13471 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13472 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013473 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013474
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013475 {
13476 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013477 const char *p;
13478 struct stat st1, st2;
13479
13480 initvar();
13481 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenkob6838b52016-09-30 11:33:47 +020013482 p = endofname(*envp);
13483 if (p != *envp && *p == '=') {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013484 setvareq(*envp, VEXPORT|VTEXTFIXED);
13485 }
13486 }
13487
Denys Vlasenkoe627ac92016-09-30 14:36:59 +020013488 setvareq((char*)defoptindvar, VTEXTFIXED);
13489
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013490 setvar0("PPID", utoa(getppid()));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013491#if BASH_SHLVL_VAR
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013492 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013493 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013494#endif
13495#if BASH_HOSTNAME_VAR
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013496 if (!lookupvar("HOSTNAME")) {
13497 struct utsname uts;
13498 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013499 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013500 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013501#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013502 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013503 if (p) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013504 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013505 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13506 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013507 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013508 }
13509 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013510 setpwd(p, 0);
13511 }
13512}
13513
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013514
13515//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013516//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013517//usage:#define ash_full_usage "\n\n"
13518//usage: "Unix shell interpreter"
13519
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013520/*
13521 * Process the shell command line arguments.
13522 */
13523static void
Denis Vlasenko68404f12008-03-17 09:00:54 +000013524procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013525{
13526 int i;
13527 const char *xminusc;
13528 char **xargv;
13529
13530 xargv = argv;
13531 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013532 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013533 xargv++;
13534 for (i = 0; i < NOPTS; i++)
13535 optlist[i] = 2;
13536 argptr = xargv;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013537 if (options(/*cmdline:*/ 1)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013538 /* it already printed err message */
13539 raise_exception(EXERROR);
13540 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013541 xargv = argptr;
13542 xminusc = minusc;
13543 if (*xargv == NULL) {
13544 if (xminusc)
13545 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13546 sflag = 1;
13547 }
13548 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13549 iflag = 1;
13550 if (mflag == 2)
13551 mflag = iflag;
13552 for (i = 0; i < NOPTS; i++)
13553 if (optlist[i] == 2)
13554 optlist[i] = 0;
13555#if DEBUG == 2
13556 debug = 1;
13557#endif
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013558 /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013559 if (xminusc) {
13560 minusc = *xargv++;
13561 if (*xargv)
13562 goto setarg0;
13563 } else if (!sflag) {
13564 setinputfile(*xargv, 0);
13565 setarg0:
13566 arg0 = *xargv++;
13567 commandname = arg0;
13568 }
13569
13570 shellparam.p = xargv;
13571#if ENABLE_ASH_GETOPTS
13572 shellparam.optind = 1;
13573 shellparam.optoff = -1;
13574#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013575 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013576 while (*xargv) {
13577 shellparam.nparam++;
13578 xargv++;
13579 }
13580 optschanged();
13581}
13582
13583/*
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013584 * Read /etc/profile, ~/.profile, $ENV.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013585 */
13586static void
13587read_profile(const char *name)
13588{
Denys Vlasenko46999802017-07-29 21:12:29 +020013589 name = expandstr(name, DQSYNTAX);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013590 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13591 return;
Denys Vlasenko0840c912016-10-01 15:27:44 +020013592 cmdloop(0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013593 popfile();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013594}
13595
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013596/*
13597 * This routine is called when an error or an interrupt occurs in an
13598 * interactive shell and control is returned to the main command loop.
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013599 * (In dash, this function is auto-generated by build machinery).
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013600 */
13601static void
13602reset(void)
13603{
13604 /* from eval.c: */
13605 evalskip = 0;
13606 loopnest = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013607
13608 /* from expand.c: */
13609 ifsfree();
13610
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013611 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013612 g_parsefile->left_in_buffer = 0;
13613 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013614 popallfiles();
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013615
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013616 /* from redir.c: */
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020013617 unwindredir(NULL);
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +020013618
13619 /* from var.c: */
Denys Vlasenko484fc202017-07-26 19:55:31 +020013620 unwindlocalvars(NULL);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013621}
13622
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013623#if PROFILE
13624static short profile_buf[16384];
13625extern int etext();
13626#endif
13627
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013628/*
13629 * Main routine. We initialize things, parse the arguments, execute
13630 * profiles if we're a login shell, and then call cmdloop to execute
13631 * commands. The setjmp call sets up the location to jump to when an
13632 * exception occurs. When an exception occurs the variable "state"
13633 * is used to figure out how far we had gotten.
13634 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013635int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013636int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013637{
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013638 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013639 struct jmploc jmploc;
13640 struct stackmark smark;
13641
Denis Vlasenko01631112007-12-16 17:20:38 +000013642 /* Initialize global data */
13643 INIT_G_misc();
13644 INIT_G_memstack();
13645 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013646#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013647 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013648#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013649 INIT_G_cmdtable();
13650
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013651#if PROFILE
13652 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13653#endif
13654
13655#if ENABLE_FEATURE_EDITING
13656 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13657#endif
13658 state = 0;
13659 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013660 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013661 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013662
13663 reset();
13664
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013665 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013666 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013667 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013668 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013669 }
13670 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020013671 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013672 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013673
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013674 popstackmark(&smark);
13675 FORCE_INT_ON; /* enable interrupts */
13676 if (s == 1)
13677 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013678 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013679 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013680 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013681 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013682 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013683 }
13684 exception_handler = &jmploc;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013685 rootpid = getpid();
13686
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013687 init();
13688 setstackmark(&smark);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013689 procargs(argv);
Denys Vlasenko474ed062016-10-30 18:30:29 +010013690#if DEBUG
13691 TRACE(("Shell args: "));
13692 trace_puts_args(argv);
13693#endif
Denis Vlasenko68404f12008-03-17 09:00:54 +000013694
Denys Vlasenko6088e132010-12-25 23:58:42 +010013695 if (argv[0] && argv[0][0] == '-')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013696 isloginsh = 1;
13697 if (isloginsh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013698 const char *hp;
13699
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013700 state = 1;
13701 read_profile("/etc/profile");
13702 state1:
13703 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013704 hp = lookupvar("HOME");
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013705 if (hp)
13706 read_profile("$HOME/.profile");
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013707 }
13708 state2:
13709 state = 3;
13710 if (
13711#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013712 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013713#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013714 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013715 ) {
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013716 const char *shinit = lookupvar("ENV");
13717 if (shinit != NULL && *shinit != '\0')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013718 read_profile(shinit);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013719 }
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013720 popstackmark(&smark);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013721 state3:
13722 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013723 if (minusc) {
13724 /* evalstring pushes parsefile stack.
13725 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013726 * is one of stacked source fds.
13727 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013728 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013729 // ^^ not necessary since now we special-case fd 0
13730 // in is_hidden_fd() to not be considered "hidden fd"
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020013731 evalstring(minusc, sflag ? 0 : EV_EXIT);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013732 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013733
13734 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020013735#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013736 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013737 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013738 if (!hp) {
13739 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013740 if (hp) {
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013741 INT_OFF;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013742 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013743 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013744 free((char*)hp);
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013745 INT_ON;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013746 hp = lookupvar("HISTFILE");
13747 }
13748 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013749 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013750 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013751# if ENABLE_FEATURE_SH_HISTFILESIZE
13752 hp = lookupvar("HISTFILESIZE");
13753 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13754# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013755 }
13756#endif
13757 state4: /* XXX ??? - why isn't this before the "if" statement */
13758 cmdloop(1);
13759 }
13760#if PROFILE
13761 monitor(0);
13762#endif
13763#ifdef GPROF
13764 {
13765 extern void _mcleanup(void);
13766 _mcleanup();
13767 }
13768#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013769 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013770 exitshell();
13771 /* NOTREACHED */
13772}
13773
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013774
Eric Andersendf82f612001-06-28 07:46:40 +000013775/*-
13776 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013777 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013778 *
13779 * This code is derived from software contributed to Berkeley by
13780 * Kenneth Almquist.
13781 *
13782 * Redistribution and use in source and binary forms, with or without
13783 * modification, are permitted provided that the following conditions
13784 * are met:
13785 * 1. Redistributions of source code must retain the above copyright
13786 * notice, this list of conditions and the following disclaimer.
13787 * 2. Redistributions in binary form must reproduce the above copyright
13788 * notice, this list of conditions and the following disclaimer in the
13789 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013790 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013791 * may be used to endorse or promote products derived from this software
13792 * without specific prior written permission.
13793 *
13794 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13795 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13796 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13797 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13798 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13799 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13800 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13801 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13802 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13803 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13804 * SUCH DAMAGE.
13805 */