blob: b285e3d33b3f96dd3f5975a6d53f00437454f492 [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 Vlasenkob07a4962008-06-22 13:16:23 +0000331 char nullstr[1]; /* zero length string */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000332
333 char optlist[NOPTS];
334#define eflag optlist[0]
335#define fflag optlist[1]
336#define Iflag optlist[2]
337#define iflag optlist[3]
338#define mflag optlist[4]
339#define nflag optlist[5]
340#define sflag optlist[6]
341#define xflag optlist[7]
342#define vflag optlist[8]
343#define Cflag optlist[9]
344#define aflag optlist[10]
345#define bflag optlist[11]
346#define uflag optlist[12]
347#define viflag optlist[13]
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100348#if BASH_PIPEFAIL
Michael Abbott359da5e2009-12-04 23:03:29 +0100349# define pipefail optlist[14]
350#else
351# define pipefail 0
352#endif
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000353#if DEBUG
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100354# define nolog optlist[14 + BASH_PIPEFAIL]
355# define debug optlist[15 + BASH_PIPEFAIL]
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000356#endif
357
358 /* trap handler commands */
Denis Vlasenko01631112007-12-16 17:20:38 +0000359 /*
360 * Sigmode records the current value of the signal handlers for the various
361 * modes. A value of zero means that the current handler is not known.
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000362 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
Denis Vlasenko01631112007-12-16 17:20:38 +0000363 */
364 char sigmode[NSIG - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000365#define S_DFL 1 /* default signal handling (SIG_DFL) */
366#define S_CATCH 2 /* signal is caught */
367#define S_IGN 3 /* signal is ignored (SIG_IGN) */
Denys Vlasenkoe5814a52016-07-16 18:33:55 +0200368#define S_HARD_IGN 4 /* signal is ignored permanently */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000369
Denis Vlasenko01631112007-12-16 17:20:38 +0000370 /* indicates specified signal received */
Denis Vlasenko4b875702009-03-19 13:30:04 +0000371 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
Denys Vlasenko238bf182010-05-18 15:49:07 +0200372 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000373 char *trap[NSIG];
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200374 char **trap_ptr; /* used only by "trap hack" */
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000375
376 /* Rarely referenced stuff */
377#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200378 random_t random_gen;
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000379#endif
380 pid_t backgndpid; /* pid of last background process */
Denis Vlasenko01631112007-12-16 17:20:38 +0000381};
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000382extern struct globals_misc *const ash_ptr_to_globals_misc;
383#define G_misc (*ash_ptr_to_globals_misc)
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200384#define exitstatus (G_misc.exitstatus )
385#define back_exitstatus (G_misc.back_exitstatus )
386#define job_warning (G_misc.job_warning)
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000387#define rootpid (G_misc.rootpid )
388#define shlvl (G_misc.shlvl )
389#define minusc (G_misc.minusc )
390#define curdir (G_misc.curdir )
391#define physdir (G_misc.physdir )
392#define arg0 (G_misc.arg0 )
Denis Vlasenko01631112007-12-16 17:20:38 +0000393#define exception_handler (G_misc.exception_handler)
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000394#define exception_type (G_misc.exception_type )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200395#define suppress_int (G_misc.suppress_int )
396#define pending_int (G_misc.pending_int )
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200397#define got_sigchld (G_misc.got_sigchld )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200398#define pending_sig (G_misc.pending_sig )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000399#define nullstr (G_misc.nullstr )
400#define optlist (G_misc.optlist )
401#define sigmode (G_misc.sigmode )
402#define gotsig (G_misc.gotsig )
Denys Vlasenko238bf182010-05-18 15:49:07 +0200403#define may_have_traps (G_misc.may_have_traps )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000404#define trap (G_misc.trap )
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200405#define trap_ptr (G_misc.trap_ptr )
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200406#define random_gen (G_misc.random_gen )
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000407#define backgndpid (G_misc.backgndpid )
Denis Vlasenko01631112007-12-16 17:20:38 +0000408#define INIT_G_misc() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000409 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
410 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +0000411 curdir = nullstr; \
412 physdir = nullstr; \
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200413 trap_ptr = trap; \
Denis Vlasenko01631112007-12-16 17:20:38 +0000414} while (0)
415
416
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000417/* ============ DEBUG */
418#if DEBUG
419static void trace_printf(const char *fmt, ...);
420static void trace_vprintf(const char *fmt, va_list va);
421# define TRACE(param) trace_printf param
422# define TRACEV(param) trace_vprintf param
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000423# define close(fd) do { \
424 int dfd = (fd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000425 if (close(dfd) < 0) \
Denys Vlasenko883cea42009-07-11 15:31:59 +0200426 bb_error_msg("bug on %d: closing %d(0x%x)", \
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000427 __LINE__, dfd, dfd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000428} while (0)
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000429#else
430# define TRACE(param)
431# define TRACEV(param)
432#endif
433
434
Denis Vlasenko559691a2008-10-05 18:39:31 +0000435/* ============ Utility functions */
Denys Vlasenko1961aea2013-02-26 00:36:53 +0100436#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
437#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
438
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200439static int
440isdigit_str9(const char *str)
Denis Vlasenko559691a2008-10-05 18:39:31 +0000441{
442 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
443 while (--maxlen && isdigit(*str))
444 str++;
445 return (*str == '\0');
446}
Denis Vlasenko01631112007-12-16 17:20:38 +0000447
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200448static const char *
449var_end(const char *var)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +0200450{
451 while (*var)
452 if (*var++ == '=')
453 break;
454 return var;
455}
456
Denis Vlasenko559691a2008-10-05 18:39:31 +0000457
458/* ============ Interrupts / exceptions */
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100459
460static void exitshell(void) NORETURN;
461
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000462/*
Eric Andersen2870d962001-07-02 17:27:21 +0000463 * These macros allow the user to suspend the handling of interrupt signals
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000464 * over a period of time. This is similar to SIGHOLD or to sigblock, but
Eric Andersen2870d962001-07-02 17:27:21 +0000465 * much more efficient and portable. (But hacking the kernel is so much
466 * more fun than worrying about efficiency and portability. :-))
467 */
Denys Vlasenko06b11492016-11-04 16:43:18 +0100468#if DEBUG_INTONOFF
469# define INT_OFF do { \
470 TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200471 suppress_int++; \
Denys Vlasenkode892052016-10-02 01:49:13 +0200472 barrier(); \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000473} while (0)
Denys Vlasenko06b11492016-11-04 16:43:18 +0100474#else
475# define INT_OFF do { \
476 suppress_int++; \
477 barrier(); \
478} while (0)
479#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000480
481/*
482 * Called to raise an exception. Since C doesn't include exceptions, we
483 * just do a longjmp to the exception handler. The type of exception is
Denis Vlasenko4b875702009-03-19 13:30:04 +0000484 * stored in the global variable "exception_type".
Denis Vlasenkob012b102007-02-19 22:43:01 +0000485 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000486static void raise_exception(int) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000487static void
488raise_exception(int e)
489{
490#if DEBUG
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000491 if (exception_handler == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000492 abort();
493#endif
494 INT_OFF;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000495 exception_type = e;
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000496 longjmp(exception_handler->loc, 1);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000497}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000498#if DEBUG
499#define raise_exception(e) do { \
500 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
501 raise_exception(e); \
502} while (0)
503#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000504
505/*
Denys Vlasenkof37e1152016-10-07 03:17:28 +0200506 * Called when a SIGINT is received. (If the user specifies
Denis Vlasenkob012b102007-02-19 22:43:01 +0000507 * that SIGINT is to be trapped or ignored using the trap builtin, then
508 * this routine is not called.) Suppressint is nonzero when interrupts
509 * are held using the INT_OFF macro. (The test for iflag is just
510 * defensive programming.)
511 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000512static void raise_interrupt(void) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000513static void
514raise_interrupt(void)
515{
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200516 pending_int = 0;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000517 /* Signal is not automatically unmasked after it is raised,
518 * do it ourself - unmask all signals */
Denis Vlasenko3f165fa2008-03-17 08:29:08 +0000519 sigprocmask_allsigs(SIG_UNBLOCK);
Denys Vlasenko238bf182010-05-18 15:49:07 +0200520 /* pending_sig = 0; - now done in signal_handler() */
Denis Vlasenko7c139b42007-03-21 20:17:27 +0000521
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200522 if (!(rootshell && iflag)) {
523 /* Kill ourself with SIGINT */
524 signal(SIGINT, SIG_DFL);
525 raise(SIGINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000526 }
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200527 /* bash: ^C even on empty command line sets $? */
528 exitstatus = SIGINT + 128;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200529 raise_exception(EXINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000530 /* NOTREACHED */
531}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000532#if DEBUG
533#define raise_interrupt() do { \
534 TRACE(("raising interrupt on line %d\n", __LINE__)); \
535 raise_interrupt(); \
536} while (0)
537#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000538
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000539static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000540int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000541{
Denys Vlasenkode892052016-10-02 01:49:13 +0200542 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200543 if (--suppress_int == 0 && pending_int) {
Denis Vlasenkob012b102007-02-19 22:43:01 +0000544 raise_interrupt();
545 }
546}
Denys Vlasenko06b11492016-11-04 16:43:18 +0100547#if DEBUG_INTONOFF
548# define INT_ON do { \
549 TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
550 int_on(); \
551} while (0)
552#else
553# define INT_ON int_on()
554#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000555static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000556force_int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000557{
Denys Vlasenkode892052016-10-02 01:49:13 +0200558 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200559 suppress_int = 0;
560 if (pending_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000561 raise_interrupt();
562}
563#define FORCE_INT_ON force_int_on()
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000564
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200565#define SAVE_INT(v) ((v) = suppress_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000566
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000567#define RESTORE_INT(v) do { \
Denys Vlasenkode892052016-10-02 01:49:13 +0200568 barrier(); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200569 suppress_int = (v); \
570 if (suppress_int == 0 && pending_int) \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000571 raise_interrupt(); \
572} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000573
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000574
Denis Vlasenkobc54cff2007-02-23 01:05:52 +0000575/* ============ Stdout/stderr output */
Eric Andersenc470f442003-07-28 09:56:35 +0000576
Eric Andersenc470f442003-07-28 09:56:35 +0000577static void
Denis Vlasenkob012b102007-02-19 22:43:01 +0000578outstr(const char *p, FILE *file)
Denis Vlasenkoe5570da2007-02-19 22:41:55 +0000579{
Denis Vlasenkob012b102007-02-19 22:43:01 +0000580 INT_OFF;
581 fputs(p, file);
582 INT_ON;
583}
584
585static void
586flush_stdout_stderr(void)
587{
588 INT_OFF;
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100589 fflush_all();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000590 INT_ON;
591}
592
Denys Vlasenko9c541002015-10-07 15:44:36 +0200593/* Was called outcslow(c,FILE*), but c was always '\n' */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000594static void
Denys Vlasenko9c541002015-10-07 15:44:36 +0200595newline_and_flush(FILE *dest)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000596{
597 INT_OFF;
Denys Vlasenko9c541002015-10-07 15:44:36 +0200598 putc('\n', dest);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000599 fflush(dest);
600 INT_ON;
601}
602
603static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
604static int
605out1fmt(const char *fmt, ...)
606{
607 va_list ap;
608 int r;
609
610 INT_OFF;
611 va_start(ap, fmt);
612 r = vprintf(fmt, ap);
613 va_end(ap);
614 INT_ON;
615 return r;
616}
617
618static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
619static int
620fmtstr(char *outbuf, size_t length, const char *fmt, ...)
621{
622 va_list ap;
623 int ret;
624
Denis Vlasenkob012b102007-02-19 22:43:01 +0000625 INT_OFF;
Denys Vlasenkocf3a7962017-07-26 14:38:19 +0200626 va_start(ap, fmt);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000627 ret = vsnprintf(outbuf, length, fmt, ap);
628 va_end(ap);
629 INT_ON;
630 return ret;
631}
632
633static void
634out1str(const char *p)
635{
636 outstr(p, stdout);
637}
638
639static void
640out2str(const char *p)
641{
642 outstr(p, stderr);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100643 flush_stdout_stderr();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000644}
645
646
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000647/* ============ Parser structures */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +0000648
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000649/* control characters in argument strings */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100650#define CTL_FIRST CTLESC
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200651#define CTLESC ((unsigned char)'\201') /* escape next character */
652#define CTLVAR ((unsigned char)'\202') /* variable defn */
653#define CTLENDVAR ((unsigned char)'\203')
654#define CTLBACKQ ((unsigned char)'\204')
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200655#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
656#define CTLENDARI ((unsigned char)'\207')
657#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100658#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000659
660/* variable substitution byte (follows CTLVAR) */
661#define VSTYPE 0x0f /* type of variable substitution */
662#define VSNUL 0x10 /* colon--treat the empty string as unset */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000663
664/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000665#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
666#define VSMINUS 0x2 /* ${var-text} */
667#define VSPLUS 0x3 /* ${var+text} */
668#define VSQUESTION 0x4 /* ${var?message} */
669#define VSASSIGN 0x5 /* ${var=text} */
670#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
671#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
672#define VSTRIMLEFT 0x8 /* ${var#pattern} */
673#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
674#define VSLENGTH 0xa /* ${#var} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100675#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000676#define VSSUBSTR 0xc /* ${var:position:length} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100677#endif
678#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000679#define VSREPLACE 0xd /* ${var/pattern/replacement} */
680#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
681#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000682
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000683static const char dolatstr[] ALIGN1 = {
Ron Yorston549deab2015-05-18 09:57:51 +0200684 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000685};
Ron Yorston549deab2015-05-18 09:57:51 +0200686#define DOLATSTRLEN 6
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000687
Denis Vlasenko559691a2008-10-05 18:39:31 +0000688#define NCMD 0
689#define NPIPE 1
690#define NREDIR 2
691#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000692#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000693#define NAND 5
694#define NOR 6
695#define NSEMI 7
696#define NIF 8
697#define NWHILE 9
698#define NUNTIL 10
699#define NFOR 11
700#define NCASE 12
701#define NCLIST 13
702#define NDEFUN 14
703#define NARG 15
704#define NTO 16
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100705#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +0000706#define NTO2 17
707#endif
708#define NCLOBBER 18
709#define NFROM 19
710#define NFROMTO 20
711#define NAPPEND 21
712#define NTOFD 22
713#define NFROMFD 23
714#define NHERE 24
715#define NXHERE 25
716#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000717#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000718
719union node;
720
721struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000722 smallint type; /* Nxxxx */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000723 union node *assign;
724 union node *args;
725 union node *redirect;
726};
727
728struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000729 smallint type;
730 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000731 struct nodelist *cmdlist;
732};
733
734struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000735 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000736 union node *n;
737 union node *redirect;
738};
739
740struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000741 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000742 union node *ch1;
743 union node *ch2;
744};
745
746struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000747 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000748 union node *test;
749 union node *ifpart;
750 union node *elsepart;
751};
752
753struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000754 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000755 union node *args;
756 union node *body;
757 char *var;
758};
759
760struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000761 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000762 union node *expr;
763 union node *cases;
764};
765
766struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000767 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000768 union node *next;
769 union node *pattern;
770 union node *body;
771};
772
773struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000774 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000775 union node *next;
776 char *text;
777 struct nodelist *backquote;
778};
779
Denis Vlasenko559691a2008-10-05 18:39:31 +0000780/* nfile and ndup layout must match!
781 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
782 * that it is actually NTO2 (>&file), and change its type.
783 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000784struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000785 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000786 union node *next;
787 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000788 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000789 union node *fname;
790 char *expfname;
791};
792
793struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000794 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000795 union node *next;
796 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000797 int dupfd;
798 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000799 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000800};
801
802struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000803 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000804 union node *next;
805 int fd;
806 union node *doc;
807};
808
809struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000810 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000811 union node *com;
812};
813
814union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000815 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000816 struct ncmd ncmd;
817 struct npipe npipe;
818 struct nredir nredir;
819 struct nbinary nbinary;
820 struct nif nif;
821 struct nfor nfor;
822 struct ncase ncase;
823 struct nclist nclist;
824 struct narg narg;
825 struct nfile nfile;
826 struct ndup ndup;
827 struct nhere nhere;
828 struct nnot nnot;
829};
830
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200831/*
832 * NODE_EOF is returned by parsecmd when it encounters an end of file.
833 * It must be distinct from NULL.
834 */
835#define NODE_EOF ((union node *) -1L)
836
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000837struct nodelist {
838 struct nodelist *next;
839 union node *n;
840};
841
842struct funcnode {
843 int count;
844 union node n;
845};
846
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000847/*
848 * Free a parse tree.
849 */
850static void
851freefunc(struct funcnode *f)
852{
853 if (f && --f->count < 0)
854 free(f);
855}
856
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000857
858/* ============ Debugging output */
859
860#if DEBUG
861
862static FILE *tracefile;
863
864static void
865trace_printf(const char *fmt, ...)
866{
867 va_list va;
868
869 if (debug != 1)
870 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000871 if (DEBUG_TIME)
872 fprintf(tracefile, "%u ", (int) time(NULL));
873 if (DEBUG_PID)
874 fprintf(tracefile, "[%u] ", (int) getpid());
875 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200876 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000877 va_start(va, fmt);
878 vfprintf(tracefile, fmt, va);
879 va_end(va);
880}
881
882static void
883trace_vprintf(const char *fmt, va_list va)
884{
885 if (debug != 1)
886 return;
887 vfprintf(tracefile, fmt, va);
Denys Vlasenko474ed062016-10-30 18:30:29 +0100888 fprintf(tracefile, "\n");
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000889}
890
891static void
892trace_puts(const char *s)
893{
894 if (debug != 1)
895 return;
896 fputs(s, tracefile);
897}
898
899static void
900trace_puts_quoted(char *s)
901{
902 char *p;
903 char c;
904
905 if (debug != 1)
906 return;
907 putc('"', tracefile);
908 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100909 switch ((unsigned char)*p) {
910 case '\n': c = 'n'; goto backslash;
911 case '\t': c = 't'; goto backslash;
912 case '\r': c = 'r'; goto backslash;
913 case '\"': c = '\"'; goto backslash;
914 case '\\': c = '\\'; goto backslash;
915 case CTLESC: c = 'e'; goto backslash;
916 case CTLVAR: c = 'v'; goto backslash;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100917 case CTLBACKQ: c = 'q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000918 backslash:
919 putc('\\', tracefile);
920 putc(c, tracefile);
921 break;
922 default:
923 if (*p >= ' ' && *p <= '~')
924 putc(*p, tracefile);
925 else {
926 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +0100927 putc((*p >> 6) & 03, tracefile);
928 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000929 putc(*p & 07, tracefile);
930 }
931 break;
932 }
933 }
934 putc('"', tracefile);
935}
936
937static void
938trace_puts_args(char **ap)
939{
940 if (debug != 1)
941 return;
942 if (!*ap)
943 return;
944 while (1) {
945 trace_puts_quoted(*ap);
946 if (!*++ap) {
947 putc('\n', tracefile);
948 break;
949 }
950 putc(' ', tracefile);
951 }
952}
953
954static void
955opentrace(void)
956{
957 char s[100];
958#ifdef O_APPEND
959 int flags;
960#endif
961
962 if (debug != 1) {
963 if (tracefile)
964 fflush(tracefile);
965 /* leave open because libedit might be using it */
966 return;
967 }
968 strcpy(s, "./trace");
969 if (tracefile) {
970 if (!freopen(s, "a", tracefile)) {
971 fprintf(stderr, "Can't re-open %s\n", s);
972 debug = 0;
973 return;
974 }
975 } else {
976 tracefile = fopen(s, "a");
977 if (tracefile == NULL) {
978 fprintf(stderr, "Can't open %s\n", s);
979 debug = 0;
980 return;
981 }
982 }
983#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000984 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000985 if (flags >= 0)
986 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
987#endif
988 setlinebuf(tracefile);
989 fputs("\nTracing started.\n", tracefile);
990}
991
992static void
993indent(int amount, char *pfx, FILE *fp)
994{
995 int i;
996
997 for (i = 0; i < amount; i++) {
998 if (pfx && i == amount - 1)
999 fputs(pfx, fp);
1000 putc('\t', fp);
1001 }
1002}
1003
1004/* little circular references here... */
1005static void shtree(union node *n, int ind, char *pfx, FILE *fp);
1006
1007static void
1008sharg(union node *arg, FILE *fp)
1009{
1010 char *p;
1011 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001012 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001013
1014 if (arg->type != NARG) {
1015 out1fmt("<node type %d>\n", arg->type);
1016 abort();
1017 }
1018 bqlist = arg->narg.backquote;
1019 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01001020 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001021 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -07001022 p++;
1023 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001024 break;
1025 case CTLVAR:
1026 putc('$', fp);
1027 putc('{', fp);
1028 subtype = *++p;
1029 if (subtype == VSLENGTH)
1030 putc('#', fp);
1031
Dan Fandrich77d48722010-09-07 23:38:28 -07001032 while (*p != '=') {
1033 putc(*p, fp);
1034 p++;
1035 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001036
1037 if (subtype & VSNUL)
1038 putc(':', fp);
1039
1040 switch (subtype & VSTYPE) {
1041 case VSNORMAL:
1042 putc('}', fp);
1043 break;
1044 case VSMINUS:
1045 putc('-', fp);
1046 break;
1047 case VSPLUS:
1048 putc('+', fp);
1049 break;
1050 case VSQUESTION:
1051 putc('?', fp);
1052 break;
1053 case VSASSIGN:
1054 putc('=', fp);
1055 break;
1056 case VSTRIMLEFT:
1057 putc('#', fp);
1058 break;
1059 case VSTRIMLEFTMAX:
1060 putc('#', fp);
1061 putc('#', fp);
1062 break;
1063 case VSTRIMRIGHT:
1064 putc('%', fp);
1065 break;
1066 case VSTRIMRIGHTMAX:
1067 putc('%', fp);
1068 putc('%', fp);
1069 break;
1070 case VSLENGTH:
1071 break;
1072 default:
1073 out1fmt("<subtype %d>", subtype);
1074 }
1075 break;
1076 case CTLENDVAR:
1077 putc('}', fp);
1078 break;
1079 case CTLBACKQ:
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001080 putc('$', fp);
1081 putc('(', fp);
1082 shtree(bqlist->n, -1, NULL, fp);
1083 putc(')', fp);
1084 break;
1085 default:
1086 putc(*p, fp);
1087 break;
1088 }
1089 }
1090}
1091
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001092static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001093shcmd(union node *cmd, FILE *fp)
1094{
1095 union node *np;
1096 int first;
1097 const char *s;
1098 int dftfd;
1099
1100 first = 1;
1101 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001102 if (!first)
1103 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001104 sharg(np, fp);
1105 first = 0;
1106 }
1107 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001108 if (!first)
1109 putc(' ', fp);
1110 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001111 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001112 case NTO: s = ">>"+1; dftfd = 1; break;
1113 case NCLOBBER: s = ">|"; dftfd = 1; break;
1114 case NAPPEND: s = ">>"; dftfd = 1; break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01001115#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00001116 case NTO2:
1117#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001118 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001119 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001120 case NFROMFD: s = "<&"; break;
1121 case NFROMTO: s = "<>"; break;
1122 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001123 }
1124 if (np->nfile.fd != dftfd)
1125 fprintf(fp, "%d", np->nfile.fd);
1126 fputs(s, fp);
1127 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1128 fprintf(fp, "%d", np->ndup.dupfd);
1129 } else {
1130 sharg(np->nfile.fname, fp);
1131 }
1132 first = 0;
1133 }
1134}
1135
1136static void
1137shtree(union node *n, int ind, char *pfx, FILE *fp)
1138{
1139 struct nodelist *lp;
1140 const char *s;
1141
1142 if (n == NULL)
1143 return;
1144
1145 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001146
1147 if (n == NODE_EOF) {
1148 fputs("<EOF>", fp);
1149 return;
1150 }
1151
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001152 switch (n->type) {
1153 case NSEMI:
1154 s = "; ";
1155 goto binop;
1156 case NAND:
1157 s = " && ";
1158 goto binop;
1159 case NOR:
1160 s = " || ";
1161 binop:
1162 shtree(n->nbinary.ch1, ind, NULL, fp);
1163 /* if (ind < 0) */
1164 fputs(s, fp);
1165 shtree(n->nbinary.ch2, ind, NULL, fp);
1166 break;
1167 case NCMD:
1168 shcmd(n, fp);
1169 if (ind >= 0)
1170 putc('\n', fp);
1171 break;
1172 case NPIPE:
1173 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001174 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001175 if (lp->next)
1176 fputs(" | ", fp);
1177 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001178 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001179 fputs(" &", fp);
1180 if (ind >= 0)
1181 putc('\n', fp);
1182 break;
1183 default:
1184 fprintf(fp, "<node type %d>", n->type);
1185 if (ind >= 0)
1186 putc('\n', fp);
1187 break;
1188 }
1189}
1190
1191static void
1192showtree(union node *n)
1193{
1194 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001195 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001196}
1197
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001198#endif /* DEBUG */
1199
1200
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001201/* ============ Parser data */
1202
1203/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001204 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1205 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001206struct strlist {
1207 struct strlist *next;
1208 char *text;
1209};
1210
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001211struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001212
Denis Vlasenkob012b102007-02-19 22:43:01 +00001213struct strpush {
1214 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001215 char *prev_string;
1216 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001217#if ENABLE_ASH_ALIAS
1218 struct alias *ap; /* if push was associated with an alias */
1219#endif
1220 char *string; /* remember the string since it may change */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001221
1222 /* Remember last two characters for pungetc. */
1223 int lastc[2];
1224
1225 /* Number of outstanding calls to pungetc. */
1226 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001227};
1228
1229struct parsefile {
1230 struct parsefile *prev; /* preceding file on stack */
1231 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001232 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001233 int left_in_line; /* number of chars left in this line */
1234 int left_in_buffer; /* number of chars left in this buffer past the line */
1235 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001236 char *buf; /* input buffer */
1237 struct strpush *strpush; /* for pushing strings at this level */
1238 struct strpush basestrpush; /* so pushing one is fast */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001239
1240 /* Remember last two characters for pungetc. */
1241 int lastc[2];
1242
1243 /* Number of outstanding calls to pungetc. */
1244 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001245};
1246
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001247static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001248static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001249static int startlinno; /* line # where last token started */
1250static char *commandname; /* currently executing command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001251
1252
1253/* ============ Message printing */
1254
1255static void
1256ash_vmsg(const char *msg, va_list ap)
1257{
1258 fprintf(stderr, "%s: ", arg0);
1259 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001260 if (strcmp(arg0, commandname))
1261 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001262 if (!iflag || g_parsefile->pf_fd > 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001263 fprintf(stderr, "line %d: ", startlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001264 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001265 vfprintf(stderr, msg, ap);
Denys Vlasenko9c541002015-10-07 15:44:36 +02001266 newline_and_flush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001267}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001268
1269/*
1270 * Exverror is called to raise the error exception. If the second argument
1271 * is not NULL then error prints an error message using printf style
1272 * formatting. It then raises the error exception.
1273 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001274static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001275static void
1276ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001277{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001278#if DEBUG
1279 if (msg) {
Denys Vlasenko474ed062016-10-30 18:30:29 +01001280 TRACE(("ash_vmsg_and_raise(%d):", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001281 TRACEV((msg, ap));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001282 } else
Denys Vlasenko474ed062016-10-30 18:30:29 +01001283 TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001284 if (msg)
1285#endif
1286 ash_vmsg(msg, ap);
1287
1288 flush_stdout_stderr();
1289 raise_exception(cond);
1290 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001291}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001292
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001293static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001294static void
1295ash_msg_and_raise_error(const char *msg, ...)
1296{
1297 va_list ap;
1298
Ron Yorstonea7d2f62017-01-03 11:18:23 +01001299 exitstatus = 2;
1300
Denis Vlasenkob012b102007-02-19 22:43:01 +00001301 va_start(ap, msg);
1302 ash_vmsg_and_raise(EXERROR, msg, ap);
1303 /* NOTREACHED */
1304 va_end(ap);
1305}
1306
Ron Yorstonbe366e52017-07-27 13:53:39 +01001307/*
1308 * Use '%m' to append error string on platforms that support it, '%s' and
1309 * strerror() on those that don't.
1310 *
1311 * 'fmt' must be a string literal.
1312 */
1313#ifdef HAVE_PRINTF_PERCENTM
1314#define ash_msg_and_raise_perror(fmt, ...) ash_msg_and_raise_error(fmt ": %m", ##__VA_ARGS__)
1315#else
1316#define ash_msg_and_raise_perror(fmt, ...) ash_msg_and_raise_error(fmt ": %s", ##__VA_ARGS__, strerror(errno))
1317#endif
1318
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001319static void raise_error_syntax(const char *) NORETURN;
1320static void
1321raise_error_syntax(const char *msg)
1322{
1323 ash_msg_and_raise_error("syntax error: %s", msg);
1324 /* NOTREACHED */
1325}
1326
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001327static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001328static void
1329ash_msg_and_raise(int cond, const char *msg, ...)
1330{
1331 va_list ap;
1332
1333 va_start(ap, msg);
1334 ash_vmsg_and_raise(cond, msg, ap);
1335 /* NOTREACHED */
1336 va_end(ap);
1337}
1338
1339/*
1340 * error/warning routines for external builtins
1341 */
1342static void
1343ash_msg(const char *fmt, ...)
1344{
1345 va_list ap;
1346
1347 va_start(ap, fmt);
1348 ash_vmsg(fmt, ap);
1349 va_end(ap);
1350}
1351
1352/*
1353 * Return a string describing an error. The returned string may be a
1354 * pointer to a static buffer that will be overwritten on the next call.
1355 * Action describes the operation that got the error.
1356 */
1357static const char *
1358errmsg(int e, const char *em)
1359{
1360 if (e == ENOENT || e == ENOTDIR) {
1361 return em;
1362 }
1363 return strerror(e);
1364}
1365
1366
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001367/* ============ Memory allocation */
1368
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001369#if 0
1370/* I consider these wrappers nearly useless:
1371 * ok, they return you to nearest exception handler, but
1372 * how much memory do you leak in the process, making
1373 * memory starvation worse?
1374 */
1375static void *
1376ckrealloc(void * p, size_t nbytes)
1377{
1378 p = realloc(p, nbytes);
1379 if (!p)
1380 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1381 return p;
1382}
1383
1384static void *
1385ckmalloc(size_t nbytes)
1386{
1387 return ckrealloc(NULL, nbytes);
1388}
1389
1390static void *
1391ckzalloc(size_t nbytes)
1392{
1393 return memset(ckmalloc(nbytes), 0, nbytes);
1394}
1395
1396static char *
1397ckstrdup(const char *s)
1398{
1399 char *p = strdup(s);
1400 if (!p)
1401 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1402 return p;
1403}
1404#else
1405/* Using bbox equivalents. They exit if out of memory */
1406# define ckrealloc xrealloc
1407# define ckmalloc xmalloc
1408# define ckzalloc xzalloc
1409# define ckstrdup xstrdup
1410#endif
1411
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001412/*
1413 * It appears that grabstackstr() will barf with such alignments
1414 * because stalloc() will return a string allocated in a new stackblock.
1415 */
1416#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1417enum {
1418 /* Most machines require the value returned from malloc to be aligned
1419 * in some way. The following macro will get this right
1420 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001421 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001422 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001423 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001424};
1425
1426struct stack_block {
1427 struct stack_block *prev;
1428 char space[MINSIZE];
1429};
1430
1431struct stackmark {
1432 struct stack_block *stackp;
1433 char *stacknxt;
1434 size_t stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001435};
1436
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001437
Denis Vlasenko01631112007-12-16 17:20:38 +00001438struct globals_memstack {
1439 struct stack_block *g_stackp; // = &stackbase;
Denis Vlasenko01631112007-12-16 17:20:38 +00001440 char *g_stacknxt; // = stackbase.space;
1441 char *sstrend; // = stackbase.space + MINSIZE;
1442 size_t g_stacknleft; // = MINSIZE;
Denis Vlasenko01631112007-12-16 17:20:38 +00001443 struct stack_block stackbase;
1444};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001445extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1446#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001447#define g_stackp (G_memstack.g_stackp )
Denis Vlasenko01631112007-12-16 17:20:38 +00001448#define g_stacknxt (G_memstack.g_stacknxt )
1449#define sstrend (G_memstack.sstrend )
1450#define g_stacknleft (G_memstack.g_stacknleft)
Denis Vlasenko01631112007-12-16 17:20:38 +00001451#define stackbase (G_memstack.stackbase )
1452#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001453 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1454 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001455 g_stackp = &stackbase; \
1456 g_stacknxt = stackbase.space; \
1457 g_stacknleft = MINSIZE; \
1458 sstrend = stackbase.space + MINSIZE; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001459} while (0)
1460
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001461
Denis Vlasenko01631112007-12-16 17:20:38 +00001462#define stackblock() ((void *)g_stacknxt)
1463#define stackblocksize() g_stacknleft
1464
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001465/*
1466 * Parse trees for commands are allocated in lifo order, so we use a stack
1467 * to make this more efficient, and also to avoid all sorts of exception
1468 * handling code to handle interrupts in the middle of a parse.
1469 *
1470 * The size 504 was chosen because the Ultrix malloc handles that size
1471 * well.
1472 */
1473static void *
1474stalloc(size_t nbytes)
1475{
1476 char *p;
1477 size_t aligned;
1478
1479 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001480 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001481 size_t len;
1482 size_t blocksize;
1483 struct stack_block *sp;
1484
1485 blocksize = aligned;
1486 if (blocksize < MINSIZE)
1487 blocksize = MINSIZE;
1488 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1489 if (len < blocksize)
1490 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1491 INT_OFF;
1492 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001493 sp->prev = g_stackp;
1494 g_stacknxt = sp->space;
1495 g_stacknleft = blocksize;
1496 sstrend = g_stacknxt + blocksize;
1497 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001498 INT_ON;
1499 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001500 p = g_stacknxt;
1501 g_stacknxt += aligned;
1502 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001503 return p;
1504}
1505
Denis Vlasenko597906c2008-02-20 16:38:54 +00001506static void *
1507stzalloc(size_t nbytes)
1508{
1509 return memset(stalloc(nbytes), 0, nbytes);
1510}
1511
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001512static void
1513stunalloc(void *p)
1514{
1515#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001516 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001517 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001518 abort();
1519 }
1520#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001521 g_stacknleft += g_stacknxt - (char *)p;
1522 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001523}
1524
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001525/*
1526 * Like strdup but works with the ash stack.
1527 */
1528static char *
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02001529sstrdup(const char *p)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001530{
1531 size_t len = strlen(p) + 1;
1532 return memcpy(stalloc(len), p, len);
1533}
1534
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001535static inline void
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001536grabstackblock(size_t len)
1537{
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001538 stalloc(len);
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001539}
1540
1541static void
1542pushstackmark(struct stackmark *mark, size_t len)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001543{
Denis Vlasenko01631112007-12-16 17:20:38 +00001544 mark->stackp = g_stackp;
1545 mark->stacknxt = g_stacknxt;
1546 mark->stacknleft = g_stacknleft;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001547 grabstackblock(len);
1548}
1549
1550static void
1551setstackmark(struct stackmark *mark)
1552{
1553 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001554}
1555
1556static void
1557popstackmark(struct stackmark *mark)
1558{
1559 struct stack_block *sp;
1560
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001561 if (!mark->stackp)
1562 return;
1563
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001564 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001565 while (g_stackp != mark->stackp) {
1566 sp = g_stackp;
1567 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001568 free(sp);
1569 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001570 g_stacknxt = mark->stacknxt;
1571 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001572 sstrend = mark->stacknxt + mark->stacknleft;
1573 INT_ON;
1574}
1575
1576/*
1577 * When the parser reads in a string, it wants to stick the string on the
1578 * stack and only adjust the stack pointer when it knows how big the
1579 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1580 * of space on top of the stack and stackblocklen returns the length of
1581 * this block. Growstackblock will grow this space by at least one byte,
1582 * possibly moving it (like realloc). Grabstackblock actually allocates the
1583 * part of the block that has been used.
1584 */
1585static void
1586growstackblock(void)
1587{
1588 size_t newlen;
1589
Denis Vlasenko01631112007-12-16 17:20:38 +00001590 newlen = g_stacknleft * 2;
1591 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001592 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1593 if (newlen < 128)
1594 newlen += 128;
1595
Denis Vlasenko01631112007-12-16 17:20:38 +00001596 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001597 struct stack_block *sp;
1598 struct stack_block *prevstackp;
1599 size_t grosslen;
1600
1601 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001602 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001603 prevstackp = sp->prev;
1604 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1605 sp = ckrealloc(sp, grosslen);
1606 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001607 g_stackp = sp;
1608 g_stacknxt = sp->space;
1609 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001610 sstrend = sp->space + newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001611 INT_ON;
1612 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001613 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001614 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001615 char *p = stalloc(newlen);
1616
1617 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001618 g_stacknxt = memcpy(p, oldspace, oldlen);
1619 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001620 }
1621}
1622
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001623/*
1624 * The following routines are somewhat easier to use than the above.
1625 * The user declares a variable of type STACKSTR, which may be declared
1626 * to be a register. The macro STARTSTACKSTR initializes things. Then
1627 * the user uses the macro STPUTC to add characters to the string. In
1628 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1629 * grown as necessary. When the user is done, she can just leave the
1630 * string there and refer to it using stackblock(). Or she can allocate
1631 * the space for it using grabstackstr(). If it is necessary to allow
1632 * someone else to use the stack temporarily and then continue to grow
1633 * the string, the user should use grabstack to allocate the space, and
1634 * then call ungrabstr(p) to return to the previous mode of operation.
1635 *
1636 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1637 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1638 * is space for at least one character.
1639 */
1640static void *
1641growstackstr(void)
1642{
1643 size_t len = stackblocksize();
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001644 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001645 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001646}
1647
1648/*
1649 * Called from CHECKSTRSPACE.
1650 */
1651static char *
1652makestrspace(size_t newlen, char *p)
1653{
Denis Vlasenko01631112007-12-16 17:20:38 +00001654 size_t len = p - g_stacknxt;
Denys Vlasenko53d6e032016-09-30 11:24:12 +02001655 size_t size;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001656
1657 for (;;) {
1658 size_t nleft;
1659
1660 size = stackblocksize();
1661 nleft = size - len;
1662 if (nleft >= newlen)
1663 break;
1664 growstackblock();
1665 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001666 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001667}
1668
1669static char *
1670stack_nputstr(const char *s, size_t n, char *p)
1671{
1672 p = makestrspace(n, p);
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02001673 p = (char *)mempcpy(p, s, n);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001674 return p;
1675}
1676
1677static char *
1678stack_putstr(const char *s, char *p)
1679{
1680 return stack_nputstr(s, strlen(s), p);
1681}
1682
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001683static char *
1684_STPUTC(int c, char *p)
1685{
1686 if (p == sstrend)
1687 p = growstackstr();
1688 *p++ = c;
1689 return p;
1690}
1691
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001692#define STARTSTACKSTR(p) ((p) = stackblock())
1693#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001694#define CHECKSTRSPACE(n, p) do { \
1695 char *q = (p); \
1696 size_t l = (n); \
1697 size_t m = sstrend - q; \
1698 if (l > m) \
1699 (p) = makestrspace(l, q); \
1700} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001701#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001702#define STACKSTRNUL(p) do { \
1703 if ((p) == sstrend) \
1704 (p) = growstackstr(); \
1705 *(p) = '\0'; \
1706} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001707#define STUNPUTC(p) (--(p))
1708#define STTOPC(p) ((p)[-1])
1709#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001710
1711#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001712#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001713#define stackstrend() ((void *)sstrend)
1714
1715
1716/* ============ String helpers */
1717
1718/*
1719 * prefix -- see if pfx is a prefix of string.
1720 */
1721static char *
1722prefix(const char *string, const char *pfx)
1723{
1724 while (*pfx) {
1725 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001726 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001727 }
1728 return (char *) string;
1729}
1730
1731/*
1732 * Check for a valid number. This should be elsewhere.
1733 */
1734static int
1735is_number(const char *p)
1736{
1737 do {
1738 if (!isdigit(*p))
1739 return 0;
1740 } while (*++p != '\0');
1741 return 1;
1742}
1743
1744/*
1745 * Convert a string of digits to an integer, printing an error message on
1746 * failure.
1747 */
1748static int
1749number(const char *s)
1750{
1751 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001752 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001753 return atoi(s);
1754}
1755
1756/*
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001757 * Produce a single quoted string suitable as input to the shell.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001758 * The return string is allocated on the stack.
1759 */
1760static char *
1761single_quote(const char *s)
1762{
1763 char *p;
1764
1765 STARTSTACKSTR(p);
1766
1767 do {
1768 char *q;
1769 size_t len;
1770
1771 len = strchrnul(s, '\'') - s;
1772
1773 q = p = makestrspace(len + 3, p);
1774
1775 *q++ = '\'';
Denys Vlasenko94af83e2017-07-23 21:55:40 +02001776 q = (char *)mempcpy(q, s, len);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001777 *q++ = '\'';
1778 s += len;
1779
1780 STADJUST(q - p, p);
1781
Denys Vlasenkocd716832009-11-28 22:14:02 +01001782 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001783 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001784 len = 0;
1785 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001786
1787 q = p = makestrspace(len + 3, p);
1788
1789 *q++ = '"';
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02001790 q = (char *)mempcpy(q, s - len, len);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001791 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001792
1793 STADJUST(q - p, p);
1794 } while (*s);
1795
Denys Vlasenkocd716832009-11-28 22:14:02 +01001796 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001797
1798 return stackblock();
1799}
1800
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001801/*
1802 * Produce a possibly single quoted string suitable as input to the shell.
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001803 * If quoting was done, the return string is allocated on the stack,
1804 * otherwise a pointer to the original string is returned.
1805 */
1806static const char *
1807maybe_single_quote(const char *s)
1808{
1809 const char *p = s;
1810
1811 while (*p) {
1812 /* Assuming ACSII */
1813 /* quote ctrl_chars space !"#$%&'()* */
1814 if (*p < '+')
1815 goto need_quoting;
1816 /* quote ;<=>? */
1817 if (*p >= ';' && *p <= '?')
1818 goto need_quoting;
1819 /* quote `[\ */
1820 if (*p == '`')
1821 goto need_quoting;
1822 if (*p == '[')
1823 goto need_quoting;
1824 if (*p == '\\')
1825 goto need_quoting;
1826 /* quote {|}~ DEL and high bytes */
1827 if (*p > 'z')
1828 goto need_quoting;
1829 /* Not quoting these: +,-./ 0-9 :@ A-Z ]^_ a-z */
1830 /* TODO: maybe avoid quoting % */
1831 p++;
1832 }
1833 return s;
1834
1835 need_quoting:
1836 return single_quote(s);
1837}
1838
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001839
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001840/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001841
1842static char **argptr; /* argument list for builtin commands */
1843static char *optionarg; /* set by nextopt (like getopt) */
1844static char *optptr; /* used by nextopt */
1845
1846/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001847 * XXX - should get rid of. Have all builtins use getopt(3).
1848 * The library getopt must have the BSD extension static variable
1849 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001850 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001851 * Standard option processing (a la getopt) for builtin routines.
1852 * The only argument that is passed to nextopt is the option string;
1853 * the other arguments are unnecessary. It returns the character,
1854 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001855 */
1856static int
1857nextopt(const char *optstring)
1858{
1859 char *p;
1860 const char *q;
1861 char c;
1862
1863 p = optptr;
1864 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001865 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001866 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001867 if (p == NULL)
1868 return '\0';
1869 if (*p != '-')
1870 return '\0';
1871 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001872 return '\0';
1873 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001874 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001875 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001876 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001877 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001878 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001879 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001880 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001881 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001882 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001883 if (*++q == ':')
1884 q++;
1885 }
1886 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001887 if (*p == '\0') {
1888 p = *argptr++;
1889 if (p == NULL)
1890 ash_msg_and_raise_error("no arg for -%c option", c);
1891 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001892 optionarg = p;
1893 p = NULL;
1894 }
1895 optptr = p;
1896 return c;
1897}
1898
1899
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001900/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001901
Denis Vlasenko01631112007-12-16 17:20:38 +00001902/*
1903 * The parsefile structure pointed to by the global variable parsefile
1904 * contains information about the current file being read.
1905 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001906struct shparam {
1907 int nparam; /* # of positional parameters (without $0) */
1908#if ENABLE_ASH_GETOPTS
1909 int optind; /* next parameter to be processed by getopts */
1910 int optoff; /* used by getopts */
1911#endif
1912 unsigned char malloced; /* if parameter list dynamically allocated */
1913 char **p; /* parameter list */
1914};
1915
1916/*
1917 * Free the list of positional parameters.
1918 */
1919static void
1920freeparam(volatile struct shparam *param)
1921{
Denis Vlasenko01631112007-12-16 17:20:38 +00001922 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001923 char **ap, **ap1;
1924 ap = ap1 = param->p;
1925 while (*ap)
1926 free(*ap++);
1927 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001928 }
1929}
1930
1931#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001932static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001933#endif
1934
1935struct var {
1936 struct var *next; /* next entry in hash list */
1937 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001938 const char *var_text; /* name=value */
1939 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001940 /* the variable gets set/unset */
1941};
1942
1943struct localvar {
1944 struct localvar *next; /* next local variable in list */
1945 struct var *vp; /* the variable that was made local */
1946 int flags; /* saved flags */
1947 const char *text; /* saved text */
1948};
1949
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001950/* flags */
1951#define VEXPORT 0x01 /* variable is exported */
1952#define VREADONLY 0x02 /* variable cannot be modified */
1953#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1954#define VTEXTFIXED 0x08 /* text is statically allocated */
1955#define VSTACK 0x10 /* text is allocated on the stack */
1956#define VUNSET 0x20 /* the variable is not set */
1957#define VNOFUNC 0x40 /* don't call the callback function */
1958#define VNOSET 0x80 /* do not set variable - just readonly test */
1959#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001960#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001961# define VDYNAMIC 0x200 /* dynamic variable */
1962#else
1963# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001964#endif
1965
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001966
Denis Vlasenko01631112007-12-16 17:20:38 +00001967/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001968#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001969static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001970change_lc_all(const char *value)
1971{
1972 if (value && *value != '\0')
1973 setlocale(LC_ALL, value);
1974}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001975static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001976change_lc_ctype(const char *value)
1977{
1978 if (value && *value != '\0')
1979 setlocale(LC_CTYPE, value);
1980}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001981#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001982#if ENABLE_ASH_MAIL
1983static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01001984static void changemail(const char *var_value) FAST_FUNC;
1985#else
1986# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001987#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001988static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001989#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001990static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001991#endif
1992
Denis Vlasenko01631112007-12-16 17:20:38 +00001993static const struct {
1994 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001995 const char *var_text;
1996 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00001997} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02001998 /*
1999 * Note: VEXPORT would not work correctly here for NOFORK applets:
2000 * some environment strings may be constant.
2001 */
Denis Vlasenko01631112007-12-16 17:20:38 +00002002 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002003#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002004 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
2005 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002006#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00002007 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
2008 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
2009 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
2010 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002011#if ENABLE_ASH_GETOPTS
Denys Vlasenkoe627ac92016-09-30 14:36:59 +02002012 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002013#endif
2014#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002015 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002016#endif
2017#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002018 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
2019 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002020#endif
2021#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002022 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002023#endif
2024};
2025
Denis Vlasenko0b769642008-07-24 07:54:57 +00002026struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00002027
2028struct globals_var {
2029 struct shparam shellparam; /* $@ current positional parameters */
2030 struct redirtab *redirlist;
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02002031 int preverrout_fd; /* stderr fd: usually 2, unless redirect moved it */
Denis Vlasenko01631112007-12-16 17:20:38 +00002032 struct var *vartab[VTABSIZE];
2033 struct var varinit[ARRAY_SIZE(varinit_data)];
2034};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00002035extern struct globals_var *const ash_ptr_to_globals_var;
2036#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00002037#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00002038//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00002039#define preverrout_fd (G_var.preverrout_fd)
2040#define vartab (G_var.vartab )
2041#define varinit (G_var.varinit )
2042#define INIT_G_var() do { \
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00002043 unsigned i; \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00002044 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
2045 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00002046 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002047 varinit[i].flags = varinit_data[i].flags; \
2048 varinit[i].var_text = varinit_data[i].var_text; \
2049 varinit[i].var_func = varinit_data[i].var_func; \
Denis Vlasenko01631112007-12-16 17:20:38 +00002050 } \
2051} while (0)
2052
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002053#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002054#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002055# define vmail (&vifs)[1]
2056# define vmpath (&vmail)[1]
2057# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002058#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002059# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002060#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002061#define vps1 (&vpath)[1]
2062#define vps2 (&vps1)[1]
2063#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002064#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002065# define voptind (&vps4)[1]
2066# if ENABLE_ASH_RANDOM_SUPPORT
2067# define vrandom (&voptind)[1]
2068# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002069#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002070# if ENABLE_ASH_RANDOM_SUPPORT
2071# define vrandom (&vps4)[1]
2072# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002073#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002074
2075/*
2076 * The following macros access the values of the above variables.
2077 * They have to skip over the name. They return the null string
2078 * for unset variables.
2079 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002080#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002081#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002082#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002083# define mailval() (vmail.var_text + 5)
2084# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002085# define mpathset() ((vmpath.flags & VUNSET) == 0)
2086#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002087#define pathval() (vpath.var_text + 5)
2088#define ps1val() (vps1.var_text + 4)
2089#define ps2val() (vps2.var_text + 4)
2090#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002091#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002092# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002093#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002094
Denis Vlasenko01631112007-12-16 17:20:38 +00002095#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002096static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002097getoptsreset(const char *value)
2098{
Denys Vlasenkoa513bf32016-10-26 02:03:37 +02002099 shellparam.optind = number(value) ?: 1;
Denis Vlasenko01631112007-12-16 17:20:38 +00002100 shellparam.optoff = -1;
2101}
2102#endif
2103
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002104/*
2105 * Compares two strings up to the first = or '\0'. The first
2106 * string must be terminated by '='; the second may be terminated by
2107 * either '=' or '\0'.
2108 */
2109static int
2110varcmp(const char *p, const char *q)
2111{
2112 int c, d;
2113
2114 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002115 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002116 goto out;
2117 p++;
2118 q++;
2119 }
2120 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002121 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002122 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002123 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002124 out:
2125 return c - d;
2126}
2127
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002128/*
2129 * Find the appropriate entry in the hash table from the name.
2130 */
2131static struct var **
2132hashvar(const char *p)
2133{
2134 unsigned hashval;
2135
2136 hashval = ((unsigned char) *p) << 4;
2137 while (*p && *p != '=')
2138 hashval += (unsigned char) *p++;
2139 return &vartab[hashval % VTABSIZE];
2140}
2141
2142static int
2143vpcmp(const void *a, const void *b)
2144{
2145 return varcmp(*(const char **)a, *(const char **)b);
2146}
2147
2148/*
2149 * This routine initializes the builtin variables.
2150 */
2151static void
2152initvar(void)
2153{
2154 struct var *vp;
2155 struct var *end;
2156 struct var **vpp;
2157
2158 /*
2159 * PS1 depends on uid
2160 */
2161#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002162 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002163#else
2164 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002165 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002166#endif
2167 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002168 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002169 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002170 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002171 vp->next = *vpp;
2172 *vpp = vp;
2173 } while (++vp < end);
2174}
2175
2176static struct var **
2177findvar(struct var **vpp, const char *name)
2178{
2179 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002180 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002181 break;
2182 }
2183 }
2184 return vpp;
2185}
2186
2187/*
2188 * Find the value of a variable. Returns NULL if not set.
2189 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002190static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002191lookupvar(const char *name)
2192{
2193 struct var *v;
2194
2195 v = *findvar(hashvar(name), name);
2196 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002197#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002198 /*
2199 * Dynamic variables are implemented roughly the same way they are
2200 * in bash. Namely, they're "special" so long as they aren't unset.
2201 * As soon as they're unset, they're no longer dynamic, and dynamic
2202 * lookup will no longer happen at that point. -- PFM.
2203 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002204 if (v->flags & VDYNAMIC)
2205 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002206#endif
2207 if (!(v->flags & VUNSET))
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002208 return var_end(v->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002209 }
2210 return NULL;
2211}
2212
Denys Vlasenko0b883582016-12-23 16:49:07 +01002213#if ENABLE_UNICODE_SUPPORT
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02002214static void
2215reinit_unicode_for_ash(void)
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002216{
2217 /* Unicode support should be activated even if LANG is set
2218 * _during_ shell execution, not only if it was set when
2219 * shell was started. Therefore, re-check LANG every time:
2220 */
2221 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2222 || ENABLE_UNICODE_USING_LOCALE
2223 ) {
2224 const char *s = lookupvar("LC_ALL");
2225 if (!s) s = lookupvar("LC_CTYPE");
2226 if (!s) s = lookupvar("LANG");
2227 reinit_unicode(s);
2228 }
2229}
Denys Vlasenko0b883582016-12-23 16:49:07 +01002230#else
2231# define reinit_unicode_for_ash() ((void)0)
2232#endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002233
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002234/*
2235 * Search the environment of a builtin command.
2236 */
Denys Vlasenko488e6092017-07-26 23:08:36 +02002237static ALWAYS_INLINE const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002238bltinlookup(const char *name)
2239{
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002240 return lookupvar(name);
2241}
2242
2243/*
2244 * Same as setvar except that the variable and value are passed in
2245 * the first argument as name=value. Since the first argument will
2246 * be actually stored in the table, it should not be a string that
2247 * will go away.
2248 * Called with interrupts off.
2249 */
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002250static struct var *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002251setvareq(char *s, int flags)
2252{
2253 struct var *vp, **vpp;
2254
2255 vpp = hashvar(s);
2256 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002257 vpp = findvar(vpp, s);
2258 vp = *vpp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002259 if (vp) {
2260 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2261 const char *n;
2262
2263 if (flags & VNOSAVE)
2264 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002265 n = vp->var_text;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02002266 exitstatus = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002267 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2268 }
2269
2270 if (flags & VNOSET)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002271 goto out;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002272
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002273 if (vp->var_func && !(flags & VNOFUNC))
2274 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002275
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002276 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2277 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002278
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002279 if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) {
2280 *vpp = vp->next;
2281 free(vp);
2282 out_free:
2283 if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE)
2284 free(s);
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002285 goto out;
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002286 }
2287
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002288 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2289 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002290 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002291 if (flags & VNOSET)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002292 goto out;
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002293 if ((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
2294 goto out_free;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002295 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002296 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002297 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002298 *vpp = vp;
2299 }
2300 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2301 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002302 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002303 vp->flags = flags;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002304
2305 out:
2306 return vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002307}
2308
2309/*
2310 * Set the value of a variable. The flags argument is ored with the
2311 * flags of the variable. If val is NULL, the variable is unset.
2312 */
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002313static struct var *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002314setvar(const char *name, const char *val, int flags)
2315{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002316 const char *q;
2317 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002318 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002319 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002320 size_t vallen;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002321 struct var *vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002322
2323 q = endofname(name);
2324 p = strchrnul(q, '=');
2325 namelen = p - name;
2326 if (!namelen || p != q)
2327 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2328 vallen = 0;
2329 if (val == NULL) {
2330 flags |= VUNSET;
2331 } else {
2332 vallen = strlen(val);
2333 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002334
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002335 INT_OFF;
2336 nameeq = ckmalloc(namelen + vallen + 2);
Denys Vlasenkoda2244f2017-07-21 18:51:29 +02002337 p = mempcpy(nameeq, name, namelen);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002338 if (val) {
2339 *p++ = '=';
Denys Vlasenkoda2244f2017-07-21 18:51:29 +02002340 p = mempcpy(p, val, vallen);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002341 }
2342 *p = '\0';
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002343 vp = setvareq(nameeq, flags | VNOSAVE);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002344 INT_ON;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002345
2346 return vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002347}
2348
Denys Vlasenko03dad222010-01-12 23:29:57 +01002349static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002350setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002351{
2352 setvar(name, val, 0);
2353}
2354
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002355/*
2356 * Unset the specified variable.
2357 */
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002358static void
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002359unsetvar(const char *s)
2360{
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02002361 setvar(s, NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002362}
2363
2364/*
2365 * Process a linked list of variable assignments.
2366 */
2367static void
2368listsetvar(struct strlist *list_set_var, int flags)
2369{
2370 struct strlist *lp = list_set_var;
2371
2372 if (!lp)
2373 return;
2374 INT_OFF;
2375 do {
2376 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002377 lp = lp->next;
2378 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002379 INT_ON;
2380}
2381
2382/*
2383 * Generate a list of variables satisfying the given conditions.
2384 */
2385static char **
2386listvars(int on, int off, char ***end)
2387{
2388 struct var **vpp;
2389 struct var *vp;
2390 char **ep;
2391 int mask;
2392
2393 STARTSTACKSTR(ep);
2394 vpp = vartab;
2395 mask = on | off;
2396 do {
2397 for (vp = *vpp; vp; vp = vp->next) {
2398 if ((vp->flags & mask) == on) {
2399 if (ep == stackstrend())
2400 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002401 *ep++ = (char*)vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002402 }
2403 }
2404 } while (++vpp < vartab + VTABSIZE);
2405 if (ep == stackstrend())
2406 ep = growstackstr();
2407 if (end)
2408 *end = ep;
2409 *ep++ = NULL;
2410 return grabstackstr(ep);
2411}
2412
2413
2414/* ============ Path search helper
2415 *
2416 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002417 * of the path before the first call; path_advance will update
2418 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002419 * the possible path expansions in sequence. If an option (indicated by
2420 * a percent sign) appears in the path entry then the global variable
2421 * pathopt will be set to point to it; otherwise pathopt will be set to
2422 * NULL.
2423 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002424static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002425
2426static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002427path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002428{
2429 const char *p;
2430 char *q;
2431 const char *start;
2432 size_t len;
2433
2434 if (*path == NULL)
2435 return NULL;
2436 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002437 for (p = start; *p && *p != ':' && *p != '%'; p++)
2438 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002439 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2440 while (stackblocksize() < len)
2441 growstackblock();
2442 q = stackblock();
2443 if (p != start) {
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02002444 q = mempcpy(q, start, p - start);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002445 *q++ = '/';
2446 }
2447 strcpy(q, name);
2448 pathopt = NULL;
2449 if (*p == '%') {
2450 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002451 while (*p && *p != ':')
2452 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002453 }
2454 if (*p == ':')
2455 *path = p + 1;
2456 else
2457 *path = NULL;
2458 return stalloc(len);
2459}
2460
2461
2462/* ============ Prompt */
2463
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002464static smallint doprompt; /* if set, prompt the user */
2465static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002466
2467#if ENABLE_FEATURE_EDITING
2468static line_input_t *line_input_state;
2469static const char *cmdedit_prompt;
2470static void
2471putprompt(const char *s)
2472{
2473 if (ENABLE_ASH_EXPAND_PRMT) {
2474 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002475 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002476 return;
2477 }
2478 cmdedit_prompt = s;
2479}
2480#else
2481static void
2482putprompt(const char *s)
2483{
2484 out2str(s);
2485}
2486#endif
2487
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002488/* expandstr() needs parsing machinery, so it is far away ahead... */
Denys Vlasenko46999802017-07-29 21:12:29 +02002489static const char *expandstr(const char *ps, int syntax_type);
2490/* Values for syntax param */
2491#define BASESYNTAX 0 /* not in quotes */
2492#define DQSYNTAX 1 /* in double quotes */
2493#define SQSYNTAX 2 /* in single quotes */
2494#define ARISYNTAX 3 /* in arithmetic */
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +02002495#if ENABLE_ASH_EXPAND_PRMT
2496# define PSSYNTAX 4 /* prompt. never passed to SIT() */
2497#endif
Denys Vlasenko46999802017-07-29 21:12:29 +02002498/* PSSYNTAX expansion is identical to DQSYNTAX, except keeping '\$' as '\$' */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002499
Denys Vlasenko46999802017-07-29 21:12:29 +02002500/*
2501 * called by editline -- any expansions to the prompt should be added here.
2502 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002503static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002504setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002505{
2506 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002507 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2508
2509 if (!do_set)
2510 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002511
2512 needprompt = 0;
2513
2514 switch (whichprompt) {
2515 case 1:
2516 prompt = ps1val();
2517 break;
2518 case 2:
2519 prompt = ps2val();
2520 break;
2521 default: /* 0 */
2522 prompt = nullstr;
2523 }
2524#if ENABLE_ASH_EXPAND_PRMT
Denys Vlasenko60ca8342016-09-30 11:21:21 +02002525 pushstackmark(&smark, stackblocksize());
Denys Vlasenko46999802017-07-29 21:12:29 +02002526 putprompt(expandstr(prompt, PSSYNTAX));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002527 popstackmark(&smark);
Denys Vlasenko48c803a2017-07-01 23:24:48 +02002528#else
2529 putprompt(prompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002530#endif
2531}
2532
2533
2534/* ============ The cd and pwd commands */
2535
2536#define CD_PHYSICAL 1
2537#define CD_PRINT 2
2538
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002539static int
2540cdopt(void)
2541{
2542 int flags = 0;
2543 int i, j;
2544
2545 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002546 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002547 if (i != j) {
2548 flags ^= CD_PHYSICAL;
2549 j = i;
2550 }
2551 }
2552
2553 return flags;
2554}
2555
2556/*
2557 * Update curdir (the name of the current directory) in response to a
2558 * cd command.
2559 */
2560static const char *
2561updatepwd(const char *dir)
2562{
2563 char *new;
2564 char *p;
2565 char *cdcomppath;
2566 const char *lim;
2567
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02002568 cdcomppath = sstrdup(dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002569 STARTSTACKSTR(new);
2570 if (*dir != '/') {
2571 if (curdir == nullstr)
2572 return 0;
2573 new = stack_putstr(curdir, new);
2574 }
2575 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002576 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002577 if (*dir != '/') {
2578 if (new[-1] != '/')
2579 USTPUTC('/', new);
2580 if (new > lim && *lim == '/')
2581 lim++;
2582 } else {
2583 USTPUTC('/', new);
2584 cdcomppath++;
2585 if (dir[1] == '/' && dir[2] != '/') {
2586 USTPUTC('/', new);
2587 cdcomppath++;
2588 lim++;
2589 }
2590 }
2591 p = strtok(cdcomppath, "/");
2592 while (p) {
2593 switch (*p) {
2594 case '.':
2595 if (p[1] == '.' && p[2] == '\0') {
2596 while (new > lim) {
2597 STUNPUTC(new);
2598 if (new[-1] == '/')
2599 break;
2600 }
2601 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002602 }
2603 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002604 break;
2605 /* fall through */
2606 default:
2607 new = stack_putstr(p, new);
2608 USTPUTC('/', new);
2609 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002610 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002611 }
2612 if (new > lim)
2613 STUNPUTC(new);
2614 *new = 0;
2615 return stackblock();
2616}
2617
2618/*
2619 * Find out what the current directory is. If we already know the current
2620 * directory, this routine returns immediately.
2621 */
2622static char *
2623getpwd(void)
2624{
Denis Vlasenko01631112007-12-16 17:20:38 +00002625 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002626 return dir ? dir : nullstr;
2627}
2628
2629static void
2630setpwd(const char *val, int setold)
2631{
2632 char *oldcur, *dir;
2633
2634 oldcur = dir = curdir;
2635
2636 if (setold) {
2637 setvar("OLDPWD", oldcur, VEXPORT);
2638 }
2639 INT_OFF;
2640 if (physdir != nullstr) {
2641 if (physdir != oldcur)
2642 free(physdir);
2643 physdir = nullstr;
2644 }
2645 if (oldcur == val || !val) {
2646 char *s = getpwd();
2647 physdir = s;
2648 if (!val)
2649 dir = s;
2650 } else
2651 dir = ckstrdup(val);
2652 if (oldcur != dir && oldcur != nullstr) {
2653 free(oldcur);
2654 }
2655 curdir = dir;
2656 INT_ON;
2657 setvar("PWD", dir, VEXPORT);
2658}
2659
2660static void hashcd(void);
2661
2662/*
Denys Vlasenko70392332016-10-27 02:31:55 +02002663 * Actually do the chdir. We also call hashcd to let other routines
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002664 * know that the current directory has changed.
2665 */
2666static int
2667docd(const char *dest, int flags)
2668{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002669 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002670 int err;
2671
2672 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2673
2674 INT_OFF;
2675 if (!(flags & CD_PHYSICAL)) {
2676 dir = updatepwd(dest);
2677 if (dir)
2678 dest = dir;
2679 }
2680 err = chdir(dest);
2681 if (err)
2682 goto out;
2683 setpwd(dir, 1);
2684 hashcd();
2685 out:
2686 INT_ON;
2687 return err;
2688}
2689
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002690static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002691cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002692{
2693 const char *dest;
2694 const char *path;
2695 const char *p;
2696 char c;
2697 struct stat statb;
2698 int flags;
2699
2700 flags = cdopt();
2701 dest = *argptr;
2702 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002703 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002704 else if (LONE_DASH(dest)) {
2705 dest = bltinlookup("OLDPWD");
2706 flags |= CD_PRINT;
2707 }
2708 if (!dest)
2709 dest = nullstr;
2710 if (*dest == '/')
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002711 goto step6;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002712 if (*dest == '.') {
2713 c = dest[1];
2714 dotdot:
2715 switch (c) {
2716 case '\0':
2717 case '/':
2718 goto step6;
2719 case '.':
2720 c = dest[2];
2721 if (c != '.')
2722 goto dotdot;
2723 }
2724 }
2725 if (!*dest)
2726 dest = ".";
2727 path = bltinlookup("CDPATH");
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002728 while (path) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002729 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002730 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002731 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2732 if (c && c != ':')
2733 flags |= CD_PRINT;
2734 docd:
2735 if (!docd(p, flags))
2736 goto out;
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002737 goto err;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002738 }
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002739 }
2740
2741 step6:
2742 p = dest;
2743 goto docd;
2744
2745 err:
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002746 ash_msg_and_raise_error("can't cd to %s", dest);
2747 /* NOTREACHED */
2748 out:
2749 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002750 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002751 return 0;
2752}
2753
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002754static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002755pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002756{
2757 int flags;
2758 const char *dir = curdir;
2759
2760 flags = cdopt();
2761 if (flags) {
2762 if (physdir == nullstr)
2763 setpwd(dir, 0);
2764 dir = physdir;
2765 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002766 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002767 return 0;
2768}
2769
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002770
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002771/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002772
Denis Vlasenko834dee72008-10-07 09:18:30 +00002773
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002774#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002775
Eric Andersenc470f442003-07-28 09:56:35 +00002776/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002777#define CWORD 0 /* character is nothing special */
2778#define CNL 1 /* newline character */
2779#define CBACK 2 /* a backslash character */
2780#define CSQUOTE 3 /* single quote */
2781#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002782#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002783#define CBQUOTE 6 /* backwards single quote */
2784#define CVAR 7 /* a dollar sign */
2785#define CENDVAR 8 /* a '}' character */
2786#define CLP 9 /* a left paren in arithmetic */
2787#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002788#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002789#define CCTL 12 /* like CWORD, except it must be escaped */
2790#define CSPCL 13 /* these terminate a word */
2791#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002792
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002793#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002794#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002795# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002796#endif
2797
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002798#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002799
Denys Vlasenko0b883582016-12-23 16:49:07 +01002800#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002801# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002802#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002803# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002804#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002805static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002806#if ENABLE_ASH_ALIAS
2807 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2808#endif
2809 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2810 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2811 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2812 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2813 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2814 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2815 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2816 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2817 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2818 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2819 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002820#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002821 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2822 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2823 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2824#endif
2825#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002826};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002827/* Constants below must match table above */
2828enum {
2829#if ENABLE_ASH_ALIAS
2830 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2831#endif
2832 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2833 CNL_CNL_CNL_CNL , /* 2 */
2834 CWORD_CCTL_CCTL_CWORD , /* 3 */
2835 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2836 CVAR_CVAR_CWORD_CVAR , /* 5 */
2837 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2838 CSPCL_CWORD_CWORD_CLP , /* 7 */
2839 CSPCL_CWORD_CWORD_CRP , /* 8 */
2840 CBACK_CBACK_CCTL_CBACK , /* 9 */
2841 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2842 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2843 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2844 CWORD_CWORD_CWORD_CWORD , /* 13 */
2845 CCTL_CCTL_CCTL_CCTL , /* 14 */
2846};
Eric Andersen2870d962001-07-02 17:27:21 +00002847
Denys Vlasenkocd716832009-11-28 22:14:02 +01002848/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2849 * caller must ensure proper cast on it if c is *char_ptr!
2850 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002851#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002852
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002853static int
2854SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002855{
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002856 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2857 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2858 /*
2859 * This causes '/' to be prepended with CTLESC in dquoted string,
2860 * making "./file"* treated incorrectly because we feed
2861 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2862 * The "homegrown" glob implementation is okay with that,
2863 * but glibc one isn't. With '/' always treated as CWORD,
2864 * both work fine.
2865 */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002866# if ENABLE_ASH_ALIAS
2867 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002868 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002869 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002870 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2871 11, 3 /* "}~" */
2872 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002873# else
2874 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002875 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002876 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002877 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2878 10, 2 /* "}~" */
2879 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002880# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002881 const char *s;
2882 int indx;
2883
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002884 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002885 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002886# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002887 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002888 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002889 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002890# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002891 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002892 /* Cast is purely for paranoia here,
2893 * just in case someone passed signed char to us */
2894 if ((unsigned char)c >= CTL_FIRST
2895 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002896 ) {
2897 return CCTL;
2898 }
2899 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002900 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002901 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002902 indx = syntax_index_table[s - spec_symbls];
2903 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002904 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002905}
2906
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002907#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002908
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002909static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002910 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002911 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2912 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2913 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2914 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2915 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2916 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2917 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2918 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2919 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2920 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2921 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2922 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2923 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2924 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2925 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2926 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2927 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2928 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2929 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2930 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2931 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2932 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2933 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2934 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2935 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2936 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2937 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2938 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2939 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2940 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2941 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2942 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2943 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2944 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2945 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2946 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2948 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2950 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2951 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2952 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2953 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2954 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2956 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2957 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002958/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
2959 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkocd716832009-11-28 22:14:02 +01002960 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2971 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2972 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2973 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2974 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2975 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2976 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2983 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2986 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2987 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2988 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2989 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2990 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2991 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2992 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2993 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2994 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2995 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2996 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2997 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2998 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2999 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
3000 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
3001 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
3002 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
3003 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
3004 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
3005 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
3006 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
3007 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
3008 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
3009 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
3010 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
3011 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
3012 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
3013 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
3014 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
3015 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
3016 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
3017 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
3018 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
3019 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
3020 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
3021 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
3022 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
3023 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
3024 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
3025 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
3026 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
3027 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
3028 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
3029 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
3030 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
3031 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
3032 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
3033 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
3034 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
3035 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
3036 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
3037 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3038 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
3039 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
3040 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
3042 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
3043 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
3044 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
3045 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
3046 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
3047 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
3048 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3049 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3112 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3113 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3114 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3115 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3116 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3117 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3118 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3119 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3120 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3121 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3122 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3123 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3124 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3125 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3126 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3127 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3128 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3129 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3130 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3131 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3132 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3133 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3134 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3135 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3136 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3137 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3138 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3139 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3140 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3141 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3142 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3143 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3144 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3145 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3146 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3147 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3148 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3149 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3150 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3151 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3152 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3153 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3154 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3155 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3156 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3157 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3158 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3159 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3160 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3161 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3162 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3163 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3164 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3165 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3166 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3167 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003168 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003169# if ENABLE_ASH_ALIAS
3170 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3171# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003172};
3173
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003174#if 1
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003175# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003176#else /* debug version, caught one signed char bug */
3177# define SIT(c, syntax) \
3178 ({ \
3179 if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3180 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
Denys Vlasenko0b883582016-12-23 16:49:07 +01003181 if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003182 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3183 ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3184 })
3185#endif
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003186
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003187#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003188
Eric Andersen2870d962001-07-02 17:27:21 +00003189
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003190/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003191
Denis Vlasenko131ae172007-02-18 13:00:19 +00003192#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003193
3194#define ALIASINUSE 1
3195#define ALIASDEAD 2
3196
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003197struct alias {
3198 struct alias *next;
3199 char *name;
3200 char *val;
3201 int flag;
3202};
3203
Denis Vlasenko01631112007-12-16 17:20:38 +00003204
3205static struct alias **atab; // [ATABSIZE];
3206#define INIT_G_alias() do { \
3207 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3208} while (0)
3209
Eric Andersen2870d962001-07-02 17:27:21 +00003210
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003211static struct alias **
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02003212__lookupalias(const char *name)
3213{
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003214 unsigned int hashval;
3215 struct alias **app;
3216 const char *p;
3217 unsigned int ch;
3218
3219 p = name;
3220
3221 ch = (unsigned char)*p;
3222 hashval = ch << 4;
3223 while (ch) {
3224 hashval += ch;
3225 ch = (unsigned char)*++p;
3226 }
3227 app = &atab[hashval % ATABSIZE];
3228
3229 for (; *app; app = &(*app)->next) {
3230 if (strcmp(name, (*app)->name) == 0) {
3231 break;
3232 }
3233 }
3234
3235 return app;
3236}
3237
3238static struct alias *
3239lookupalias(const char *name, int check)
3240{
3241 struct alias *ap = *__lookupalias(name);
3242
3243 if (check && ap && (ap->flag & ALIASINUSE))
3244 return NULL;
3245 return ap;
3246}
3247
3248static struct alias *
3249freealias(struct alias *ap)
3250{
3251 struct alias *next;
3252
3253 if (ap->flag & ALIASINUSE) {
3254 ap->flag |= ALIASDEAD;
3255 return ap;
3256 }
3257
3258 next = ap->next;
3259 free(ap->name);
3260 free(ap->val);
3261 free(ap);
3262 return next;
3263}
Eric Andersencb57d552001-06-28 07:25:16 +00003264
Eric Andersenc470f442003-07-28 09:56:35 +00003265static void
3266setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003267{
3268 struct alias *ap, **app;
3269
3270 app = __lookupalias(name);
3271 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003272 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003273 if (ap) {
3274 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003275 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003276 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003277 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003278 ap->flag &= ~ALIASDEAD;
3279 } else {
3280 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003281 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003282 ap->name = ckstrdup(name);
3283 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003284 /*ap->flag = 0; - ckzalloc did it */
3285 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003286 *app = ap;
3287 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003288 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003289}
3290
Eric Andersenc470f442003-07-28 09:56:35 +00003291static int
3292unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003293{
Eric Andersencb57d552001-06-28 07:25:16 +00003294 struct alias **app;
3295
3296 app = __lookupalias(name);
3297
3298 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003299 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003300 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003301 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003302 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003303 }
3304
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003305 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003306}
3307
Eric Andersenc470f442003-07-28 09:56:35 +00003308static void
3309rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003310{
Eric Andersencb57d552001-06-28 07:25:16 +00003311 struct alias *ap, **app;
3312 int i;
3313
Denis Vlasenkob012b102007-02-19 22:43:01 +00003314 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003315 for (i = 0; i < ATABSIZE; i++) {
3316 app = &atab[i];
3317 for (ap = *app; ap; ap = *app) {
3318 *app = freealias(*app);
3319 if (ap == *app) {
3320 app = &ap->next;
3321 }
3322 }
3323 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003324 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003325}
3326
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003327static void
3328printalias(const struct alias *ap)
3329{
3330 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3331}
3332
Eric Andersencb57d552001-06-28 07:25:16 +00003333/*
3334 * TODO - sort output
3335 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003336static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003337aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003338{
3339 char *n, *v;
3340 int ret = 0;
3341 struct alias *ap;
3342
Denis Vlasenko68404f12008-03-17 09:00:54 +00003343 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003344 int i;
3345
Denis Vlasenko68404f12008-03-17 09:00:54 +00003346 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003347 for (ap = atab[i]; ap; ap = ap->next) {
3348 printalias(ap);
3349 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003350 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003351 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003352 }
3353 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003354 v = strchr(n+1, '=');
3355 if (v == NULL) { /* n+1: funny ksh stuff */
3356 ap = *__lookupalias(n);
3357 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003358 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003359 ret = 1;
3360 } else
3361 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003362 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003363 *v++ = '\0';
3364 setalias(n, v);
3365 }
3366 }
3367
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003368 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003369}
3370
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003371static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003372unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003373{
3374 int i;
3375
Denys Vlasenko6c149f42017-04-12 21:31:32 +02003376 while (nextopt("a") != '\0') {
3377 rmaliases();
3378 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003379 }
3380 for (i = 0; *argptr; argptr++) {
3381 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003382 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003383 i = 1;
3384 }
3385 }
3386
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003387 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003388}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003389
Denis Vlasenko131ae172007-02-18 13:00:19 +00003390#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003391
Eric Andersenc470f442003-07-28 09:56:35 +00003392
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003393/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003394#define FORK_FG 0
3395#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003396#define FORK_NOJOB 2
3397
3398/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003399#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3400#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3401#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003402#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003403
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003404/*
3405 * A job structure contains information about a job. A job is either a
3406 * single process or a set of processes contained in a pipeline. In the
3407 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3408 * array of pids.
3409 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003410struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003411 pid_t ps_pid; /* process id */
3412 int ps_status; /* last process status from wait() */
3413 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003414};
3415
3416struct job {
3417 struct procstat ps0; /* status of process */
3418 struct procstat *ps; /* status or processes when more than one */
3419#if JOBS
3420 int stopstatus; /* status of a stopped job */
3421#endif
Denys Vlasenko4c179372017-01-11 18:44:15 +01003422 unsigned nprocs; /* number of processes */
3423
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003424#define JOBRUNNING 0 /* at least one proc running */
3425#define JOBSTOPPED 1 /* all procs are stopped */
3426#define JOBDONE 2 /* all procs are completed */
Denys Vlasenko4c179372017-01-11 18:44:15 +01003427 unsigned
3428 state: 8,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003429#if JOBS
3430 sigint: 1, /* job was killed by SIGINT */
3431 jobctl: 1, /* job running under job control */
3432#endif
3433 waited: 1, /* true if this entry has been waited for */
3434 used: 1, /* true if this entry is in used */
3435 changed: 1; /* true if status has changed */
3436 struct job *prev_job; /* previous job */
3437};
3438
Denis Vlasenko68404f12008-03-17 09:00:54 +00003439static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003440static int forkshell(struct job *, union node *, int);
3441static int waitforjob(struct job *);
3442
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003443#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003444enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003445#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003446#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003447static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003448static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003449#endif
3450
3451/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003452 * Ignore a signal.
3453 */
3454static void
3455ignoresig(int signo)
3456{
3457 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3458 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3459 /* No, need to do it */
3460 signal(signo, SIG_IGN);
3461 }
3462 sigmode[signo - 1] = S_HARD_IGN;
3463}
3464
3465/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003466 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003467 */
3468static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003469signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003470{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003471 if (signo == SIGCHLD) {
3472 got_sigchld = 1;
3473 if (!trap[SIGCHLD])
3474 return;
3475 }
3476
Denis Vlasenko4b875702009-03-19 13:30:04 +00003477 gotsig[signo - 1] = 1;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003478 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003479
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003480 if (signo == SIGINT && !trap[SIGINT]) {
3481 if (!suppress_int) {
3482 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003483 raise_interrupt(); /* does not return */
3484 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003485 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003486 }
3487}
3488
3489/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003490 * Set the signal handler for the specified signal. The routine figures
3491 * out what it should be set to.
3492 */
3493static void
3494setsignal(int signo)
3495{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003496 char *t;
3497 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003498 struct sigaction act;
3499
3500 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003501 new_act = S_DFL;
3502 if (t != NULL) { /* trap for this sig is set */
3503 new_act = S_CATCH;
3504 if (t[0] == '\0') /* trap is "": ignore this sig */
3505 new_act = S_IGN;
3506 }
3507
3508 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003509 switch (signo) {
3510 case SIGINT:
3511 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003512 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003513 break;
3514 case SIGQUIT:
3515#if DEBUG
3516 if (debug)
3517 break;
3518#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003519 /* man bash:
3520 * "In all cases, bash ignores SIGQUIT. Non-builtin
3521 * commands run by bash have signal handlers
3522 * set to the values inherited by the shell
3523 * from its parent". */
3524 new_act = S_IGN;
3525 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003526 case SIGTERM:
3527 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003528 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003529 break;
3530#if JOBS
3531 case SIGTSTP:
3532 case SIGTTOU:
3533 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003534 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003535 break;
3536#endif
3537 }
3538 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003539//TODO: if !rootshell, we reset SIGQUIT to DFL,
3540//whereas we have to restore it to what shell got on entry
3541//from the parent. See comment above
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003542
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003543 if (signo == SIGCHLD)
3544 new_act = S_CATCH;
3545
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003546 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003547 cur_act = *t;
3548 if (cur_act == 0) {
3549 /* current setting is not yet known */
3550 if (sigaction(signo, NULL, &act)) {
3551 /* pretend it worked; maybe we should give a warning,
3552 * but other shells don't. We don't alter sigmode,
3553 * so we retry every time.
3554 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003555 return;
3556 }
3557 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003558 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003559 if (mflag
3560 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3561 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003562 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003563 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003564 }
3565 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003566 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003567 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003568
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003569 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003570 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003571 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003572 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003573 break;
3574 case S_IGN:
3575 act.sa_handler = SIG_IGN;
3576 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003577 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003578
3579 /* flags and mask matter only if !DFL and !IGN, but we do it
3580 * for all cases for more deterministic behavior:
3581 */
3582 act.sa_flags = 0;
3583 sigfillset(&act.sa_mask);
3584
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003585 sigaction_set(signo, &act);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003586
3587 *t = new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003588}
3589
3590/* mode flags for set_curjob */
3591#define CUR_DELETE 2
3592#define CUR_RUNNING 1
3593#define CUR_STOPPED 0
3594
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003595#if JOBS
3596/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003597static int initialpgrp; //references:2
3598static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003599#endif
3600/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003601static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003602/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003603static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003604/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003605static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003606/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003607static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003608
Denys Vlasenko098b7132017-01-11 19:59:03 +01003609#if 0
3610/* Bash has a feature: it restores termios after a successful wait for
3611 * a foreground job which had at least one stopped or sigkilled member.
3612 * The probable rationale is that SIGSTOP and SIGKILL can preclude task from
3613 * properly restoring tty state. Should we do this too?
3614 * A reproducer: ^Z an interactive python:
3615 *
3616 * # python
3617 * Python 2.7.12 (...)
3618 * >>> ^Z
3619 * { python leaves tty in -icanon -echo state. We do survive that... }
3620 * [1]+ Stopped python
3621 * { ...however, next program (python #2) does not survive it well: }
3622 * # python
3623 * Python 2.7.12 (...)
3624 * >>> Traceback (most recent call last):
3625 * { above, I typed "qwerty<CR>", but -echo state is still in effect }
3626 * File "<stdin>", line 1, in <module>
3627 * NameError: name 'qwerty' is not defined
3628 *
3629 * The implementation below is modeled on bash code and seems to work.
3630 * However, I'm not sure we should do this. For one: what if I'd fg
3631 * the stopped python instead? It'll be confused by "restored" tty state.
3632 */
3633static struct termios shell_tty_info;
3634static void
3635get_tty_state(void)
3636{
3637 if (rootshell && ttyfd >= 0)
3638 tcgetattr(ttyfd, &shell_tty_info);
3639}
3640static void
3641set_tty_state(void)
3642{
3643 /* if (rootshell) - caller ensures this */
3644 if (ttyfd >= 0)
3645 tcsetattr(ttyfd, TCSADRAIN, &shell_tty_info);
3646}
3647static int
3648job_signal_status(struct job *jp)
3649{
3650 int status;
3651 unsigned i;
3652 struct procstat *ps = jp->ps;
3653 for (i = 0; i < jp->nprocs; i++) {
3654 status = ps[i].ps_status;
3655 if (WIFSIGNALED(status) || WIFSTOPPED(status))
3656 return status;
3657 }
3658 return 0;
3659}
3660static void
3661restore_tty_if_stopped_or_signaled(struct job *jp)
3662{
3663//TODO: check what happens if we come from waitforjob() in expbackq()
3664 if (rootshell) {
3665 int s = job_signal_status(jp);
3666 if (s) /* WIFSIGNALED(s) || WIFSTOPPED(s) */
3667 set_tty_state();
3668 }
3669}
3670#else
3671# define get_tty_state() ((void)0)
3672# define restore_tty_if_stopped_or_signaled(jp) ((void)0)
3673#endif
3674
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003675static void
3676set_curjob(struct job *jp, unsigned mode)
3677{
3678 struct job *jp1;
3679 struct job **jpp, **curp;
3680
3681 /* first remove from list */
3682 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003683 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003684 jp1 = *jpp;
3685 if (jp1 == jp)
3686 break;
3687 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003688 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003689 *jpp = jp1->prev_job;
3690
3691 /* Then re-insert in correct position */
3692 jpp = curp;
3693 switch (mode) {
3694 default:
3695#if DEBUG
3696 abort();
3697#endif
3698 case CUR_DELETE:
3699 /* job being deleted */
3700 break;
3701 case CUR_RUNNING:
3702 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003703 * put after all stopped jobs.
3704 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003705 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003706 jp1 = *jpp;
3707#if JOBS
3708 if (!jp1 || jp1->state != JOBSTOPPED)
3709#endif
3710 break;
3711 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003712 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003713 /* FALLTHROUGH */
3714#if JOBS
3715 case CUR_STOPPED:
3716#endif
3717 /* newly stopped job - becomes curjob */
3718 jp->prev_job = *jpp;
3719 *jpp = jp;
3720 break;
3721 }
3722}
3723
3724#if JOBS || DEBUG
3725static int
3726jobno(const struct job *jp)
3727{
3728 return jp - jobtab + 1;
3729}
3730#endif
3731
3732/*
3733 * Convert a job name to a job structure.
3734 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003735#if !JOBS
3736#define getjob(name, getctl) getjob(name)
3737#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003738static struct job *
3739getjob(const char *name, int getctl)
3740{
3741 struct job *jp;
3742 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003743 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003744 unsigned num;
3745 int c;
3746 const char *p;
3747 char *(*match)(const char *, const char *);
3748
3749 jp = curjob;
3750 p = name;
3751 if (!p)
3752 goto currentjob;
3753
3754 if (*p != '%')
3755 goto err;
3756
3757 c = *++p;
3758 if (!c)
3759 goto currentjob;
3760
3761 if (!p[1]) {
3762 if (c == '+' || c == '%') {
3763 currentjob:
3764 err_msg = "No current job";
3765 goto check;
3766 }
3767 if (c == '-') {
3768 if (jp)
3769 jp = jp->prev_job;
3770 err_msg = "No previous job";
3771 check:
3772 if (!jp)
3773 goto err;
3774 goto gotit;
3775 }
3776 }
3777
3778 if (is_number(p)) {
3779 num = atoi(p);
Denys Vlasenko46a45ce2016-09-29 01:10:08 +02003780 if (num > 0 && num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003781 jp = jobtab + num - 1;
3782 if (jp->used)
3783 goto gotit;
3784 goto err;
3785 }
3786 }
3787
3788 match = prefix;
3789 if (*p == '?') {
3790 match = strstr;
3791 p++;
3792 }
3793
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003794 found = NULL;
3795 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003796 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003797 if (found)
3798 goto err;
3799 found = jp;
3800 err_msg = "%s: ambiguous";
3801 }
3802 jp = jp->prev_job;
3803 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003804 if (!found)
3805 goto err;
3806 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003807
3808 gotit:
3809#if JOBS
3810 err_msg = "job %s not created under job control";
3811 if (getctl && jp->jobctl == 0)
3812 goto err;
3813#endif
3814 return jp;
3815 err:
3816 ash_msg_and_raise_error(err_msg, name);
3817}
3818
3819/*
3820 * Mark a job structure as unused.
3821 */
3822static void
3823freejob(struct job *jp)
3824{
3825 struct procstat *ps;
3826 int i;
3827
3828 INT_OFF;
3829 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003830 if (ps->ps_cmd != nullstr)
3831 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003832 }
3833 if (jp->ps != &jp->ps0)
3834 free(jp->ps);
3835 jp->used = 0;
3836 set_curjob(jp, CUR_DELETE);
3837 INT_ON;
3838}
3839
3840#if JOBS
3841static void
3842xtcsetpgrp(int fd, pid_t pgrp)
3843{
3844 if (tcsetpgrp(fd, pgrp))
Ron Yorstonbe366e52017-07-27 13:53:39 +01003845 ash_msg_and_raise_perror("can't set tty process group");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003846}
3847
3848/*
3849 * Turn job control on and off.
3850 *
3851 * Note: This code assumes that the third arg to ioctl is a character
3852 * pointer, which is true on Berkeley systems but not System V. Since
3853 * System V doesn't have job control yet, this isn't a problem now.
3854 *
3855 * Called with interrupts off.
3856 */
3857static void
3858setjobctl(int on)
3859{
3860 int fd;
3861 int pgrp;
3862
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003863 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003864 return;
3865 if (on) {
3866 int ofd;
3867 ofd = fd = open(_PATH_TTY, O_RDWR);
3868 if (fd < 0) {
3869 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3870 * That sometimes helps to acquire controlling tty.
3871 * Obviously, a workaround for bugs when someone
3872 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003873 fd = 2;
3874 while (!isatty(fd))
3875 if (--fd < 0)
3876 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003877 }
Denys Vlasenko64774602016-10-26 15:24:30 +02003878 /* fd is a tty at this point */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003879 fd = fcntl(fd, F_DUPFD, 10);
Denys Vlasenko10ad6222017-04-17 16:13:32 +02003880 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, don't */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003881 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003882 if (fd < 0)
Denys Vlasenko64774602016-10-26 15:24:30 +02003883 goto out; /* F_DUPFD failed */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003884 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003885 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003886 pgrp = tcgetpgrp(fd);
3887 if (pgrp < 0) {
3888 out:
3889 ash_msg("can't access tty; job control turned off");
3890 mflag = on = 0;
3891 goto close;
3892 }
3893 if (pgrp == getpgrp())
3894 break;
3895 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003896 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003897 initialpgrp = pgrp;
3898
3899 setsignal(SIGTSTP);
3900 setsignal(SIGTTOU);
3901 setsignal(SIGTTIN);
3902 pgrp = rootpid;
3903 setpgid(0, pgrp);
3904 xtcsetpgrp(fd, pgrp);
3905 } else {
3906 /* turning job control off */
3907 fd = ttyfd;
3908 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003909 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003910 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003911 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003912 setpgid(0, pgrp);
3913 setsignal(SIGTSTP);
3914 setsignal(SIGTTOU);
3915 setsignal(SIGTTIN);
3916 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003917 if (fd >= 0)
3918 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003919 fd = -1;
3920 }
3921 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003922 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003923}
3924
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003925static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003926killcmd(int argc, char **argv)
3927{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003928 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003929 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003930 do {
3931 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003932 /*
3933 * "kill %N" - job kill
3934 * Converting to pgrp / pid kill
3935 */
3936 struct job *jp;
3937 char *dst;
3938 int j, n;
3939
3940 jp = getjob(argv[i], 0);
3941 /*
3942 * In jobs started under job control, we signal
3943 * entire process group by kill -PGRP_ID.
3944 * This happens, f.e., in interactive shell.
3945 *
3946 * Otherwise, we signal each child via
3947 * kill PID1 PID2 PID3.
3948 * Testcases:
3949 * sh -c 'sleep 1|sleep 1 & kill %1'
3950 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3951 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3952 */
3953 n = jp->nprocs; /* can't be 0 (I hope) */
3954 if (jp->jobctl)
3955 n = 1;
3956 dst = alloca(n * sizeof(int)*4);
3957 argv[i] = dst;
3958 for (j = 0; j < n; j++) {
3959 struct procstat *ps = &jp->ps[j];
3960 /* Skip non-running and not-stopped members
3961 * (i.e. dead members) of the job
3962 */
3963 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3964 continue;
3965 /*
3966 * kill_main has matching code to expect
3967 * leading space. Needed to not confuse
3968 * negative pids with "kill -SIGNAL_NO" syntax
3969 */
3970 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3971 }
3972 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003973 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003974 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003975 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003976 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003977}
3978
3979static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01003980showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003981{
Denys Vlasenko285ad152009-12-04 23:02:27 +01003982 struct procstat *ps;
3983 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003984
Denys Vlasenko285ad152009-12-04 23:02:27 +01003985 psend = jp->ps + jp->nprocs;
3986 for (ps = jp->ps + 1; ps < psend; ps++)
3987 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003988 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003989 flush_stdout_stderr();
3990}
3991
3992
3993static int
3994restartjob(struct job *jp, int mode)
3995{
3996 struct procstat *ps;
3997 int i;
3998 int status;
3999 pid_t pgid;
4000
4001 INT_OFF;
4002 if (jp->state == JOBDONE)
4003 goto out;
4004 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004005 pgid = jp->ps[0].ps_pid;
Denys Vlasenko098b7132017-01-11 19:59:03 +01004006 if (mode == FORK_FG) {
4007 get_tty_state();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004008 xtcsetpgrp(ttyfd, pgid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01004009 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004010 killpg(pgid, SIGCONT);
4011 ps = jp->ps;
4012 i = jp->nprocs;
4013 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004014 if (WIFSTOPPED(ps->ps_status)) {
4015 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004016 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004017 ps++;
4018 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004019 out:
4020 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
4021 INT_ON;
4022 return status;
4023}
4024
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004025static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004026fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004027{
4028 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004029 int mode;
4030 int retval;
4031
4032 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
4033 nextopt(nullstr);
4034 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004035 do {
4036 jp = getjob(*argv, 1);
4037 if (mode == FORK_BG) {
4038 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004039 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004040 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004041 out1str(jp->ps[0].ps_cmd);
4042 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004043 retval = restartjob(jp, mode);
4044 } while (*argv && *++argv);
4045 return retval;
4046}
4047#endif
4048
4049static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02004050sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004051{
4052 int col;
4053 int st;
4054
4055 col = 0;
4056 if (!WIFEXITED(status)) {
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004057#if JOBS
4058 if (WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004059 st = WSTOPSIG(status);
4060 else
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004061#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004062 st = WTERMSIG(status);
4063 if (sigonly) {
4064 if (st == SIGINT || st == SIGPIPE)
4065 goto out;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004066#if JOBS
4067 if (WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004068 goto out;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004069#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004070 }
4071 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01004072//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004073 col = fmtstr(s, 32, strsignal(st));
4074 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004075 strcpy(s + col, " (core dumped)");
4076 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004077 }
4078 } else if (!sigonly) {
4079 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004080 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004081 }
4082 out:
4083 return col;
4084}
4085
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004086static int
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004087wait_block_or_sig(int *status)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004088{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004089 int pid;
4090
4091 do {
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004092 sigset_t mask;
4093
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004094 /* Poll all children for changes in their state */
4095 got_sigchld = 0;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004096 /* if job control is active, accept stopped processes too */
4097 pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004098 if (pid != 0)
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004099 break; /* Error (e.g. EINTR, ECHILD) or pid */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004100
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004101 /* Children exist, but none are ready. Sleep until interesting signal */
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004102#if 1
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004103 sigfillset(&mask);
4104 sigprocmask(SIG_SETMASK, &mask, &mask);
4105 while (!got_sigchld && !pending_sig)
4106 sigsuspend(&mask);
4107 sigprocmask(SIG_SETMASK, &mask, NULL);
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004108#else /* unsafe: a signal can set pending_sig after check, but before pause() */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004109 while (!got_sigchld && !pending_sig)
4110 pause();
4111#endif
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004112
4113 /* If it was SIGCHLD, poll children again */
4114 } while (got_sigchld);
4115
4116 return pid;
4117}
4118
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004119#define DOWAIT_NONBLOCK 0
4120#define DOWAIT_BLOCK 1
4121#define DOWAIT_BLOCK_OR_SIG 2
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004122
4123static int
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004124dowait(int block, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004125{
4126 int pid;
4127 int status;
4128 struct job *jp;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004129 struct job *thisjob = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004130
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004131 TRACE(("dowait(0x%x) called\n", block));
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00004132
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004133 /* It's wrong to call waitpid() outside of INT_OFF region:
4134 * signal can arrive just after syscall return and handler can
4135 * longjmp away, losing stop/exit notification processing.
4136 * Thus, for "jobs" builtin, and for waiting for a fg job,
4137 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4138 *
4139 * However, for "wait" builtin it is wrong to simply call waitpid()
4140 * in INT_OFF region: "wait" needs to wait for any running job
4141 * to change state, but should exit on any trap too.
4142 * In INT_OFF region, a signal just before syscall entry can set
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004143 * pending_sig variables, but we can't check them, and we would
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004144 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004145 *
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004146 * Because of this, we run inside INT_OFF, but use a special routine
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004147 * which combines waitpid() and sigsuspend().
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004148 * This is the reason why we need to have a handler for SIGCHLD:
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004149 * SIG_DFL handler does not wake sigsuspend().
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004150 */
4151 INT_OFF;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004152 if (block == DOWAIT_BLOCK_OR_SIG) {
4153 pid = wait_block_or_sig(&status);
4154 } else {
4155 int wait_flags = 0;
4156 if (block == DOWAIT_NONBLOCK)
4157 wait_flags = WNOHANG;
4158 /* if job control is active, accept stopped processes too */
4159 if (doing_jobctl)
4160 wait_flags |= WUNTRACED;
4161 /* NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004162 pid = waitpid(-1, &status, wait_flags);
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004163 }
Denis Vlasenkob21f3792009-03-19 23:09:58 +00004164 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4165 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004166 if (pid <= 0)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004167 goto out;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004168
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004169 thisjob = NULL;
4170 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004171 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004172 struct procstat *ps;
4173 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004174 if (jp->state == JOBDONE)
4175 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004176 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004177 ps = jp->ps;
4178 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004179 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004180 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004181 TRACE(("Job %d: changing status of proc %d "
4182 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01004183 jobno(jp), pid, ps->ps_status, status));
4184 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004185 thisjob = jp;
4186 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004187 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004188 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004189#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004190 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004191 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004192 if (WIFSTOPPED(ps->ps_status)) {
4193 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004194 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004195 }
4196#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004197 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004198 if (!thisjob)
4199 continue;
4200
4201 /* Found the job where one of its processes changed its state.
4202 * Is there at least one live and running process in this job? */
4203 if (jobstate != JOBRUNNING) {
4204 /* No. All live processes in the job are stopped
4205 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4206 */
4207 thisjob->changed = 1;
4208 if (thisjob->state != jobstate) {
4209 TRACE(("Job %d: changing state from %d to %d\n",
4210 jobno(thisjob), thisjob->state, jobstate));
4211 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004212#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004213 if (jobstate == JOBSTOPPED)
4214 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004215#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004216 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004217 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004218 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004219 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004220 /* The process wasn't found in job list */
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004221#if JOBS
4222 if (!WIFSTOPPED(status))
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004223 jobless--;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004224#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004225 out:
4226 INT_ON;
4227
4228 if (thisjob && thisjob == job) {
4229 char s[48 + 1];
4230 int len;
4231
Denys Vlasenko9c541002015-10-07 15:44:36 +02004232 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004233 if (len) {
4234 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004235 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004236 out2str(s);
4237 }
4238 }
4239 return pid;
4240}
4241
4242#if JOBS
4243static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004244showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004245{
4246 struct procstat *ps;
4247 struct procstat *psend;
4248 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004249 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004250 char s[16 + 16 + 48];
4251 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004252
4253 ps = jp->ps;
4254
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004255 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004256 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004257 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004258 return;
4259 }
4260
4261 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004262 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004263
4264 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004265 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004266 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004267 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004268
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004269 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004270 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004271
4272 psend = ps + jp->nprocs;
4273
4274 if (jp->state == JOBRUNNING) {
4275 strcpy(s + col, "Running");
4276 col += sizeof("Running") - 1;
4277 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004278 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004279 if (jp->state == JOBSTOPPED)
4280 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004281 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004282 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004283 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004284
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004285 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4286 * or prints several "PID | <cmdN>" lines,
4287 * depending on SHOW_PIDS bit.
4288 * We do not print status of individual processes
4289 * between PID and <cmdN>. bash does it, but not very well:
4290 * first line shows overall job status, not process status,
4291 * making it impossible to know 1st process status.
4292 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004293 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004294 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004295 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004296 s[0] = '\0';
4297 col = 33;
4298 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004299 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004300 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004301 fprintf(out, "%s%*c%s%s",
4302 s,
4303 33 - col >= 0 ? 33 - col : 0, ' ',
4304 ps == jp->ps ? "" : "| ",
4305 ps->ps_cmd
4306 );
4307 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004308 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004309
4310 jp->changed = 0;
4311
4312 if (jp->state == JOBDONE) {
4313 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4314 freejob(jp);
4315 }
4316}
4317
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004318/*
4319 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4320 * statuses have changed since the last call to showjobs.
4321 */
4322static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004323showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004324{
4325 struct job *jp;
4326
Denys Vlasenko883cea42009-07-11 15:31:59 +02004327 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004328
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004329 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004330 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004331 continue;
4332
4333 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004334 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004335 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004336 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004337 }
4338}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004339
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004340static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004341jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004342{
4343 int mode, m;
4344
4345 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004346 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004347 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004348 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004349 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004350 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004351 }
4352
4353 argv = argptr;
4354 if (*argv) {
4355 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004356 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004357 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004358 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004359 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004360 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004361
4362 return 0;
4363}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004364#endif /* JOBS */
4365
Michael Abbott359da5e2009-12-04 23:03:29 +01004366/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004367static int
4368getstatus(struct job *job)
4369{
4370 int status;
4371 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004372 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004373
Michael Abbott359da5e2009-12-04 23:03:29 +01004374 /* Fetch last member's status */
4375 ps = job->ps + job->nprocs - 1;
4376 status = ps->ps_status;
4377 if (pipefail) {
4378 /* "set -o pipefail" mode: use last _nonzero_ status */
4379 while (status == 0 && --ps >= job->ps)
4380 status = ps->ps_status;
4381 }
4382
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004383 retval = WEXITSTATUS(status);
4384 if (!WIFEXITED(status)) {
4385#if JOBS
4386 retval = WSTOPSIG(status);
4387 if (!WIFSTOPPED(status))
4388#endif
4389 {
4390 /* XXX: limits number of signals */
4391 retval = WTERMSIG(status);
4392#if JOBS
4393 if (retval == SIGINT)
4394 job->sigint = 1;
4395#endif
4396 }
4397 retval += 128;
4398 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004399 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004400 jobno(job), job->nprocs, status, retval));
4401 return retval;
4402}
4403
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004404static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004405waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004406{
4407 struct job *job;
4408 int retval;
4409 struct job *jp;
4410
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004411 nextopt(nullstr);
4412 retval = 0;
4413
4414 argv = argptr;
4415 if (!*argv) {
4416 /* wait for all jobs */
4417 for (;;) {
4418 jp = curjob;
4419 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004420 if (!jp) /* no running procs */
4421 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004422 if (jp->state == JOBRUNNING)
4423 break;
4424 jp->waited = 1;
4425 jp = jp->prev_job;
4426 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004427 /* man bash:
4428 * "When bash is waiting for an asynchronous command via
4429 * the wait builtin, the reception of a signal for which a trap
4430 * has been set will cause the wait builtin to return immediately
4431 * with an exit status greater than 128, immediately after which
4432 * the trap is executed."
Denys Vlasenko69188112016-10-27 20:18:18 +02004433 */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004434 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004435 /* if child sends us a signal *and immediately exits*,
4436 * dowait() returns pid > 0. Check this case,
4437 * not "if (dowait() < 0)"!
4438 */
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004439 if (pending_sig)
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004440 goto sigout;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004441 }
4442 }
4443
4444 retval = 127;
4445 do {
4446 if (**argv != '%') {
4447 pid_t pid = number(*argv);
4448 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004449 while (1) {
4450 if (!job)
4451 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004452 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004453 break;
4454 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004455 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004456 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004457 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004458 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004459 /* loop until process terminated or stopped */
Denys Vlasenko69188112016-10-27 20:18:18 +02004460 while (job->state == JOBRUNNING) {
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004461 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004462 if (pending_sig)
4463 goto sigout;
Denys Vlasenko69188112016-10-27 20:18:18 +02004464 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004465 job->waited = 1;
4466 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004467 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004468 } while (*++argv);
4469
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004470 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004471 return retval;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004472 sigout:
4473 retval = 128 + pending_sig;
4474 return retval;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004475}
4476
4477static struct job *
4478growjobtab(void)
4479{
4480 size_t len;
4481 ptrdiff_t offset;
4482 struct job *jp, *jq;
4483
4484 len = njobs * sizeof(*jp);
4485 jq = jobtab;
4486 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4487
4488 offset = (char *)jp - (char *)jq;
4489 if (offset) {
4490 /* Relocate pointers */
4491 size_t l = len;
4492
4493 jq = (struct job *)((char *)jq + l);
4494 while (l) {
4495 l -= sizeof(*jp);
4496 jq--;
4497#define joff(p) ((struct job *)((char *)(p) + l))
4498#define jmove(p) (p) = (void *)((char *)(p) + offset)
4499 if (joff(jp)->ps == &jq->ps0)
4500 jmove(joff(jp)->ps);
4501 if (joff(jp)->prev_job)
4502 jmove(joff(jp)->prev_job);
4503 }
4504 if (curjob)
4505 jmove(curjob);
4506#undef joff
4507#undef jmove
4508 }
4509
4510 njobs += 4;
4511 jobtab = jp;
4512 jp = (struct job *)((char *)jp + len);
4513 jq = jp + 3;
4514 do {
4515 jq->used = 0;
4516 } while (--jq >= jp);
4517 return jp;
4518}
4519
4520/*
4521 * Return a new job structure.
4522 * Called with interrupts off.
4523 */
4524static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004525makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004526{
4527 int i;
4528 struct job *jp;
4529
4530 for (i = njobs, jp = jobtab; ; jp++) {
4531 if (--i < 0) {
4532 jp = growjobtab();
4533 break;
4534 }
4535 if (jp->used == 0)
4536 break;
4537 if (jp->state != JOBDONE || !jp->waited)
4538 continue;
4539#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004540 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004541 continue;
4542#endif
4543 freejob(jp);
4544 break;
4545 }
4546 memset(jp, 0, sizeof(*jp));
4547#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004548 /* jp->jobctl is a bitfield.
Denys Vlasenko098b7132017-01-11 19:59:03 +01004549 * "jp->jobctl |= doing_jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004550 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004551 jp->jobctl = 1;
4552#endif
4553 jp->prev_job = curjob;
4554 curjob = jp;
4555 jp->used = 1;
4556 jp->ps = &jp->ps0;
4557 if (nprocs > 1) {
4558 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4559 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004560 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004561 jobno(jp)));
4562 return jp;
4563}
4564
4565#if JOBS
4566/*
4567 * Return a string identifying a command (to be printed by the
4568 * jobs command).
4569 */
4570static char *cmdnextc;
4571
4572static void
4573cmdputs(const char *s)
4574{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004575 static const char vstype[VSTYPE + 1][3] = {
4576 "", "}", "-", "+", "?", "=",
4577 "%", "%%", "#", "##"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004578 IF_BASH_SUBSTR(, ":")
4579 IF_BASH_PATTERN_SUBST(, "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004580 };
4581
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004582 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004583 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004584 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004585 unsigned char c;
4586 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004587 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004588
Denys Vlasenko46a14772009-12-10 21:27:13 +01004589 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004590 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4591 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004592 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004593 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004594 switch (c) {
4595 case CTLESC:
4596 c = *p++;
4597 break;
4598 case CTLVAR:
4599 subtype = *p++;
4600 if ((subtype & VSTYPE) == VSLENGTH)
4601 str = "${#";
4602 else
4603 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004604 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004605 case CTLENDVAR:
4606 str = "\"}" + !(quoted & 1);
4607 quoted >>= 1;
4608 subtype = 0;
4609 goto dostr;
4610 case CTLBACKQ:
4611 str = "$(...)";
4612 goto dostr;
Denys Vlasenko0b883582016-12-23 16:49:07 +01004613#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004614 case CTLARI:
4615 str = "$((";
4616 goto dostr;
4617 case CTLENDARI:
4618 str = "))";
4619 goto dostr;
4620#endif
4621 case CTLQUOTEMARK:
4622 quoted ^= 1;
4623 c = '"';
4624 break;
4625 case '=':
4626 if (subtype == 0)
4627 break;
4628 if ((subtype & VSTYPE) != VSNORMAL)
4629 quoted <<= 1;
4630 str = vstype[subtype & VSTYPE];
4631 if (subtype & VSNUL)
4632 c = ':';
4633 else
4634 goto checkstr;
4635 break;
4636 case '\'':
4637 case '\\':
4638 case '"':
4639 case '$':
4640 /* These can only happen inside quotes */
4641 cc[0] = c;
4642 str = cc;
Denys Vlasenkod0fff912017-07-31 14:32:18 +02004643//FIXME:
4644// $ true $$ &
4645// $ <cr>
4646// [1]+ Done true ${\$} <<=== BUG: ${\$} is not a valid way to write $$ (${$} would be ok)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004647 c = '\\';
4648 break;
4649 default:
4650 break;
4651 }
4652 USTPUTC(c, nextc);
4653 checkstr:
4654 if (!str)
4655 continue;
4656 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004657 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004658 USTPUTC(c, nextc);
4659 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004660 } /* while *p++ not NUL */
4661
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004662 if (quoted & 1) {
4663 USTPUTC('"', nextc);
4664 }
4665 *nextc = 0;
4666 cmdnextc = nextc;
4667}
4668
4669/* cmdtxt() and cmdlist() call each other */
4670static void cmdtxt(union node *n);
4671
4672static void
4673cmdlist(union node *np, int sep)
4674{
4675 for (; np; np = np->narg.next) {
4676 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004677 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004678 cmdtxt(np);
4679 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004680 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004681 }
4682}
4683
4684static void
4685cmdtxt(union node *n)
4686{
4687 union node *np;
4688 struct nodelist *lp;
4689 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004690
4691 if (!n)
4692 return;
4693 switch (n->type) {
4694 default:
4695#if DEBUG
4696 abort();
4697#endif
4698 case NPIPE:
4699 lp = n->npipe.cmdlist;
4700 for (;;) {
4701 cmdtxt(lp->n);
4702 lp = lp->next;
4703 if (!lp)
4704 break;
4705 cmdputs(" | ");
4706 }
4707 break;
4708 case NSEMI:
4709 p = "; ";
4710 goto binop;
4711 case NAND:
4712 p = " && ";
4713 goto binop;
4714 case NOR:
4715 p = " || ";
4716 binop:
4717 cmdtxt(n->nbinary.ch1);
4718 cmdputs(p);
4719 n = n->nbinary.ch2;
4720 goto donode;
4721 case NREDIR:
4722 case NBACKGND:
4723 n = n->nredir.n;
4724 goto donode;
4725 case NNOT:
4726 cmdputs("!");
4727 n = n->nnot.com;
4728 donode:
4729 cmdtxt(n);
4730 break;
4731 case NIF:
4732 cmdputs("if ");
4733 cmdtxt(n->nif.test);
4734 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004735 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004736 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004737 cmdputs("; else ");
4738 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004739 } else {
4740 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004741 }
4742 p = "; fi";
4743 goto dotail;
4744 case NSUBSHELL:
4745 cmdputs("(");
4746 n = n->nredir.n;
4747 p = ")";
4748 goto dotail;
4749 case NWHILE:
4750 p = "while ";
4751 goto until;
4752 case NUNTIL:
4753 p = "until ";
4754 until:
4755 cmdputs(p);
4756 cmdtxt(n->nbinary.ch1);
4757 n = n->nbinary.ch2;
4758 p = "; done";
4759 dodo:
4760 cmdputs("; do ");
4761 dotail:
4762 cmdtxt(n);
4763 goto dotail2;
4764 case NFOR:
4765 cmdputs("for ");
4766 cmdputs(n->nfor.var);
4767 cmdputs(" in ");
4768 cmdlist(n->nfor.args, 1);
4769 n = n->nfor.body;
4770 p = "; done";
4771 goto dodo;
4772 case NDEFUN:
4773 cmdputs(n->narg.text);
4774 p = "() { ... }";
4775 goto dotail2;
4776 case NCMD:
4777 cmdlist(n->ncmd.args, 1);
4778 cmdlist(n->ncmd.redirect, 0);
4779 break;
4780 case NARG:
4781 p = n->narg.text;
4782 dotail2:
4783 cmdputs(p);
4784 break;
4785 case NHERE:
4786 case NXHERE:
4787 p = "<<...";
4788 goto dotail2;
4789 case NCASE:
4790 cmdputs("case ");
4791 cmdputs(n->ncase.expr->narg.text);
4792 cmdputs(" in ");
4793 for (np = n->ncase.cases; np; np = np->nclist.next) {
4794 cmdtxt(np->nclist.pattern);
4795 cmdputs(") ");
4796 cmdtxt(np->nclist.body);
4797 cmdputs(";; ");
4798 }
4799 p = "esac";
4800 goto dotail2;
4801 case NTO:
4802 p = ">";
4803 goto redir;
4804 case NCLOBBER:
4805 p = ">|";
4806 goto redir;
4807 case NAPPEND:
4808 p = ">>";
4809 goto redir;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004810#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00004811 case NTO2:
4812#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004813 case NTOFD:
4814 p = ">&";
4815 goto redir;
4816 case NFROM:
4817 p = "<";
4818 goto redir;
4819 case NFROMFD:
4820 p = "<&";
4821 goto redir;
4822 case NFROMTO:
4823 p = "<>";
4824 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004825 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004826 cmdputs(p);
4827 if (n->type == NTOFD || n->type == NFROMFD) {
Denys Vlasenkod0fff912017-07-31 14:32:18 +02004828 if (n->ndup.dupfd >= 0)
4829 cmdputs(utoa(n->ndup.dupfd));
4830 else
4831 cmdputs("-");
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004832 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004833 }
4834 n = n->nfile.fname;
4835 goto donode;
4836 }
4837}
4838
4839static char *
4840commandtext(union node *n)
4841{
4842 char *name;
4843
4844 STARTSTACKSTR(cmdnextc);
4845 cmdtxt(n);
4846 name = stackblock();
Denys Vlasenko6a94cee2016-10-25 17:40:25 +02004847 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004848 return ckstrdup(name);
4849}
4850#endif /* JOBS */
4851
4852/*
4853 * Fork off a subshell. If we are doing job control, give the subshell its
4854 * own process group. Jp is a job structure that the job is to be added to.
4855 * N is the command that will be evaluated by the child. Both jp and n may
4856 * be NULL. The mode parameter can be one of the following:
4857 * FORK_FG - Fork off a foreground process.
4858 * FORK_BG - Fork off a background process.
4859 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4860 * process group even if job control is on.
4861 *
4862 * When job control is turned off, background processes have their standard
4863 * input redirected to /dev/null (except for the second and later processes
4864 * in a pipeline).
4865 *
4866 * Called with interrupts off.
4867 */
4868/*
4869 * Clear traps on a fork.
4870 */
4871static void
4872clear_traps(void)
4873{
4874 char **tp;
4875
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004876 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004877 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004878 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004879 if (trap_ptr == trap)
4880 free(*tp);
4881 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004882 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004883 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004884 setsignal(tp - trap);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004885 }
4886 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004887 may_have_traps = 0;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004888 INT_ON;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004889}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004890
4891/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004892static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004893
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004894/* Called after fork(), in child */
Denys Vlasenko70392332016-10-27 02:31:55 +02004895/* jp and n are NULL when called by openhere() for heredoc support */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004896static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004897forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004898{
4899 int oldlvl;
4900
4901 TRACE(("Child shell %d\n", getpid()));
4902 oldlvl = shlvl;
4903 shlvl++;
4904
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004905 /* man bash: "Non-builtin commands run by bash have signal handlers
4906 * set to the values inherited by the shell from its parent".
4907 * Do we do it correctly? */
4908
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004909 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004910
4911 if (mode == FORK_NOJOB /* is it `xxx` ? */
4912 && n && n->type == NCMD /* is it single cmd? */
4913 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004914 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004915 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4916 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4917 ) {
4918 TRACE(("Trap hack\n"));
4919 /* Awful hack for `trap` or $(trap).
4920 *
4921 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4922 * contains an example where "trap" is executed in a subshell:
4923 *
4924 * save_traps=$(trap)
4925 * ...
4926 * eval "$save_traps"
4927 *
4928 * Standard does not say that "trap" in subshell shall print
4929 * parent shell's traps. It only says that its output
4930 * must have suitable form, but then, in the above example
4931 * (which is not supposed to be normative), it implies that.
4932 *
4933 * bash (and probably other shell) does implement it
4934 * (traps are reset to defaults, but "trap" still shows them),
4935 * but as a result, "trap" logic is hopelessly messed up:
4936 *
4937 * # trap
4938 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4939 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4940 * # true | trap <--- trap is in subshell - no output (ditto)
4941 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4942 * trap -- 'echo Ho' SIGWINCH
4943 * # echo `(trap)` <--- in subshell in subshell - output
4944 * trap -- 'echo Ho' SIGWINCH
4945 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4946 * trap -- 'echo Ho' SIGWINCH
4947 *
4948 * The rules when to forget and when to not forget traps
4949 * get really complex and nonsensical.
4950 *
4951 * Our solution: ONLY bare $(trap) or `trap` is special.
4952 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004953 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02004954 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004955 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004956 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004957 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004958#if JOBS
4959 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004960 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004961 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004962 pid_t pgrp;
4963
4964 if (jp->nprocs == 0)
4965 pgrp = getpid();
4966 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004967 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004968 /* this can fail because we are doing it in the parent also */
4969 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004970 if (mode == FORK_FG)
4971 xtcsetpgrp(ttyfd, pgrp);
4972 setsignal(SIGTSTP);
4973 setsignal(SIGTTOU);
4974 } else
4975#endif
4976 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004977 /* man bash: "When job control is not in effect,
4978 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004979 ignoresig(SIGINT);
4980 ignoresig(SIGQUIT);
4981 if (jp->nprocs == 0) {
4982 close(0);
4983 if (open(bb_dev_null, O_RDONLY) != 0)
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00004984 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004985 }
4986 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004987 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004988 if (iflag) { /* why if iflag only? */
4989 setsignal(SIGINT);
4990 setsignal(SIGTERM);
4991 }
4992 /* man bash:
4993 * "In all cases, bash ignores SIGQUIT. Non-builtin
4994 * commands run by bash have signal handlers
4995 * set to the values inherited by the shell
4996 * from its parent".
4997 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004998 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004999 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005000#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02005001 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01005002 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02005003 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005004 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02005005 /* "jobs": we do not want to clear job list for it,
5006 * instead we remove only _its_ own_ job from job list.
5007 * This makes "jobs .... | cat" more useful.
5008 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005009 freejob(curjob);
5010 return;
5011 }
5012#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005013 for (jp = curjob; jp; jp = jp->prev_job)
5014 freejob(jp);
5015 jobless = 0;
5016}
5017
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00005018/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00005019#if !JOBS
5020#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
5021#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005022static void
5023forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5024{
5025 TRACE(("In parent shell: child = %d\n", pid));
5026 if (!jp) {
Denys Vlasenko70392332016-10-27 02:31:55 +02005027 /* jp is NULL when called by openhere() for heredoc support */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00005028 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
5029 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005030 jobless++;
5031 return;
5032 }
5033#if JOBS
5034 if (mode != FORK_NOJOB && jp->jobctl) {
5035 int pgrp;
5036
5037 if (jp->nprocs == 0)
5038 pgrp = pid;
5039 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01005040 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005041 /* This can fail because we are doing it in the child also */
5042 setpgid(pid, pgrp);
5043 }
5044#endif
5045 if (mode == FORK_BG) {
5046 backgndpid = pid; /* set $! */
5047 set_curjob(jp, CUR_RUNNING);
5048 }
5049 if (jp) {
5050 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01005051 ps->ps_pid = pid;
5052 ps->ps_status = -1;
5053 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005054#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005055 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01005056 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005057#endif
5058 }
5059}
5060
Denys Vlasenko70392332016-10-27 02:31:55 +02005061/* jp and n are NULL when called by openhere() for heredoc support */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005062static int
5063forkshell(struct job *jp, union node *n, int mode)
5064{
5065 int pid;
5066
5067 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5068 pid = fork();
5069 if (pid < 0) {
5070 TRACE(("Fork failed, errno=%d", errno));
5071 if (jp)
5072 freejob(jp);
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +00005073 ash_msg_and_raise_error("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005074 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02005075 if (pid == 0) {
5076 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005077 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005078 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005079 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005080 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005081 return pid;
5082}
5083
5084/*
5085 * Wait for job to finish.
5086 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005087 * Under job control we have the problem that while a child process
5088 * is running interrupts generated by the user are sent to the child
5089 * but not to the shell. This means that an infinite loop started by
5090 * an interactive user may be hard to kill. With job control turned off,
5091 * an interactive user may place an interactive program inside a loop.
5092 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005093 * these interrupts to also abort the loop. The approach we take here
5094 * is to have the shell ignore interrupt signals while waiting for a
5095 * foreground process to terminate, and then send itself an interrupt
5096 * signal if the child process was terminated by an interrupt signal.
5097 * Unfortunately, some programs want to do a bit of cleanup and then
5098 * exit on interrupt; unless these processes terminate themselves by
5099 * sending a signal to themselves (instead of calling exit) they will
5100 * confuse this approach.
5101 *
5102 * Called with interrupts off.
5103 */
5104static int
5105waitforjob(struct job *jp)
5106{
5107 int st;
5108
5109 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005110
5111 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005112 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005113 /* In non-interactive shells, we _can_ get
5114 * a keyboard signal here and be EINTRed,
5115 * but we just loop back, waiting for command to complete.
5116 *
5117 * man bash:
5118 * "If bash is waiting for a command to complete and receives
5119 * a signal for which a trap has been set, the trap
5120 * will not be executed until the command completes."
5121 *
5122 * Reality is that even if trap is not set, bash
5123 * will not act on the signal until command completes.
5124 * Try this. sleep5intoff.c:
5125 * #include <signal.h>
5126 * #include <unistd.h>
5127 * int main() {
5128 * sigset_t set;
5129 * sigemptyset(&set);
5130 * sigaddset(&set, SIGINT);
5131 * sigaddset(&set, SIGQUIT);
5132 * sigprocmask(SIG_BLOCK, &set, NULL);
5133 * sleep(5);
5134 * return 0;
5135 * }
5136 * $ bash -c './sleep5intoff; echo hi'
5137 * ^C^C^C^C <--- pressing ^C once a second
5138 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005139 * $ bash -c './sleep5intoff; echo hi'
5140 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5141 * $ _
5142 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005143 dowait(DOWAIT_BLOCK, jp);
5144 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005145 INT_ON;
5146
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005147 st = getstatus(jp);
5148#if JOBS
5149 if (jp->jobctl) {
5150 xtcsetpgrp(ttyfd, rootpid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01005151 restore_tty_if_stopped_or_signaled(jp);
5152
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005153 /*
5154 * This is truly gross.
5155 * If we're doing job control, then we did a TIOCSPGRP which
5156 * caused us (the shell) to no longer be in the controlling
5157 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
5158 * intuit from the subprocess exit status whether a SIGINT
5159 * occurred, and if so interrupt ourselves. Yuck. - mycroft
5160 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00005161 if (jp->sigint) /* TODO: do the same with all signals */
5162 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005163 }
5164 if (jp->state == JOBDONE)
5165#endif
5166 freejob(jp);
5167 return st;
5168}
5169
5170/*
5171 * return 1 if there are stopped jobs, otherwise 0
5172 */
5173static int
5174stoppedjobs(void)
5175{
5176 struct job *jp;
5177 int retval;
5178
5179 retval = 0;
5180 if (job_warning)
5181 goto out;
5182 jp = curjob;
5183 if (jp && jp->state == JOBSTOPPED) {
5184 out2str("You have stopped jobs.\n");
5185 job_warning = 2;
5186 retval++;
5187 }
5188 out:
5189 return retval;
5190}
5191
5192
Denys Vlasenko70392332016-10-27 02:31:55 +02005193/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005194 * Code for dealing with input/output redirection.
5195 */
5196
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005197#undef EMPTY
5198#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005199#define EMPTY -2 /* marks an unused slot in redirtab */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005200#define CLOSED -1 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005201
5202/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005203 * Handle here documents. Normally we fork off a process to write the
5204 * data to a pipe. If the document is short, we can stuff the data in
5205 * the pipe without forking.
5206 */
5207/* openhere needs this forward reference */
5208static void expandhere(union node *arg, int fd);
5209static int
5210openhere(union node *redir)
5211{
5212 int pip[2];
5213 size_t len = 0;
5214
5215 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005216 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005217 if (redir->type == NHERE) {
5218 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005219 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005220 full_write(pip[1], redir->nhere.doc->narg.text, len);
5221 goto out;
5222 }
5223 }
5224 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005225 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005226 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005227 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5228 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5229 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5230 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005231 signal(SIGPIPE, SIG_DFL);
5232 if (redir->type == NHERE)
5233 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005234 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005235 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005236 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005237 }
5238 out:
5239 close(pip[1]);
5240 return pip[0];
5241}
5242
5243static int
5244openredirect(union node *redir)
5245{
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005246 struct stat sb;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005247 char *fname;
5248 int f;
5249
5250 switch (redir->nfile.type) {
Denys Vlasenko557482c2016-09-25 21:24:04 +02005251/* Can't happen, our single caller does this itself */
5252// case NTOFD:
5253// case NFROMFD:
5254// return -1;
5255 case NHERE:
5256 case NXHERE:
5257 return openhere(redir);
5258 }
5259
5260 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5261 * allocated space. Do it only when we know it is safe.
5262 */
5263 fname = redir->nfile.expfname;
5264
5265 switch (redir->nfile.type) {
5266 default:
5267#if DEBUG
5268 abort();
5269#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005270 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005271 f = open(fname, O_RDONLY);
5272 if (f < 0)
5273 goto eopen;
5274 break;
5275 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005276 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005277 if (f < 0)
5278 goto ecreate;
5279 break;
5280 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005281#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005282 case NTO2:
5283#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005284 /* Take care of noclobber mode. */
5285 if (Cflag) {
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005286 if (stat(fname, &sb) < 0) {
5287 f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5288 if (f < 0)
5289 goto ecreate;
5290 } else if (!S_ISREG(sb.st_mode)) {
5291 f = open(fname, O_WRONLY, 0666);
5292 if (f < 0)
5293 goto ecreate;
5294 if (fstat(f, &sb) < 0 && S_ISREG(sb.st_mode)) {
5295 close(f);
5296 errno = EEXIST;
5297 goto ecreate;
5298 }
5299 } else {
5300 errno = EEXIST;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005301 goto ecreate;
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005302 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005303 break;
5304 }
5305 /* FALLTHROUGH */
5306 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005307 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5308 if (f < 0)
5309 goto ecreate;
5310 break;
5311 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005312 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5313 if (f < 0)
5314 goto ecreate;
5315 break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005316 }
5317
5318 return f;
5319 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005320 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005321 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005322 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005323}
5324
5325/*
Denys Vlasenko64774602016-10-26 15:24:30 +02005326 * Copy a file descriptor to be >= 10. Throws exception on error.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005327 */
5328static int
Denys Vlasenko64774602016-10-26 15:24:30 +02005329savefd(int from)
5330{
5331 int newfd;
5332 int err;
5333
5334 newfd = fcntl(from, F_DUPFD, 10);
5335 err = newfd < 0 ? errno : 0;
5336 if (err != EBADF) {
5337 if (err)
Ron Yorstonbe366e52017-07-27 13:53:39 +01005338 ash_msg_and_raise_perror("%d", from);
Denys Vlasenko64774602016-10-26 15:24:30 +02005339 close(from);
5340 fcntl(newfd, F_SETFD, FD_CLOEXEC);
5341 }
5342
5343 return newfd;
5344}
5345static int
5346dup2_or_raise(int from, int to)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005347{
5348 int newfd;
5349
Denys Vlasenko64774602016-10-26 15:24:30 +02005350 newfd = (from != to) ? dup2(from, to) : to;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005351 if (newfd < 0) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005352 /* Happens when source fd is not open: try "echo >&99" */
Ron Yorstonbe366e52017-07-27 13:53:39 +01005353 ash_msg_and_raise_perror("%d", from);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005354 }
5355 return newfd;
5356}
Denys Vlasenko035486c2017-07-31 04:09:19 +02005357static int
5358fcntl_F_DUPFD(int fd, int avoid_fd)
5359{
5360 int newfd;
5361 repeat:
5362 newfd = fcntl(fd, F_DUPFD, avoid_fd + 1);
5363 if (newfd < 0) {
5364 if (errno == EBUSY)
5365 goto repeat;
5366 if (errno == EINTR)
5367 goto repeat;
5368 }
5369 return newfd;
5370}
5371static int
5372xdup_CLOEXEC_and_close(int fd, int avoid_fd)
5373{
5374 int newfd;
5375 repeat:
5376 newfd = fcntl(fd, F_DUPFD, avoid_fd + 1);
5377 if (newfd < 0) {
5378 if (errno == EBUSY)
5379 goto repeat;
5380 if (errno == EINTR)
5381 goto repeat;
5382 /* fd was not open? */
5383 if (errno == EBADF)
5384 return fd;
5385 ash_msg_and_raise_perror("%d", newfd);
5386 }
5387 fcntl(newfd, F_SETFD, FD_CLOEXEC);
5388 close(fd);
5389 return newfd;
5390}
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005391
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005392/* Struct def and variable are moved down to the first usage site */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005393struct squirrel {
5394 int orig_fd;
5395 int moved_to;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005396};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005397struct redirtab {
5398 struct redirtab *next;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005399 int pair_count;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005400 struct squirrel two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005401};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005402#define redirlist (G_var.redirlist)
Denis Vlasenko0b769642008-07-24 07:54:57 +00005403
Denys Vlasenko035486c2017-07-31 04:09:19 +02005404static void
5405add_squirrel_closed(struct redirtab *sq, int fd)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005406{
5407 int i;
5408
Denys Vlasenko035486c2017-07-31 04:09:19 +02005409 if (!sq)
5410 return;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005411
Denys Vlasenko035486c2017-07-31 04:09:19 +02005412 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5413 /* If we collide with an already moved fd... */
5414 if (fd == sq->two_fd[i].orig_fd) {
5415 /* Examples:
5416 * "echo 3>FILE 3>&- 3>FILE"
5417 * "echo 3>&- 3>FILE"
5418 * No need for last redirect to insert
5419 * another "need to close 3" indicator.
5420 */
5421 TRACE(("redirect_fd %d: already moved or closed\n", fd));
5422 return;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005423 }
5424 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005425 TRACE(("redirect_fd %d: previous fd was closed\n", fd));
5426 sq->two_fd[i].orig_fd = fd;
5427 sq->two_fd[i].moved_to = CLOSED;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005428}
5429
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005430static int
Denys Vlasenko035486c2017-07-31 04:09:19 +02005431save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005432{
Denys Vlasenko035486c2017-07-31 04:09:19 +02005433 int i, new_fd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005434
Denys Vlasenko035486c2017-07-31 04:09:19 +02005435 if (avoid_fd < 9) /* the important case here is that it can be -1 */
5436 avoid_fd = 9;
5437
5438#if JOBS
5439 if (fd == ttyfd) {
5440 /* Testcase: "ls -l /proc/$$/fd 10>&-" should work */
5441 ttyfd = xdup_CLOEXEC_and_close(ttyfd, avoid_fd);
5442 TRACE(("redirect_fd %d: matches ttyfd, moving it to %d\n", fd, ttyfd));
5443 return 1; /* "we closed fd" */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005444 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005445#endif
5446 /* Are we called from redirect(0)? E.g. redirect
5447 * in a forked child. No need to save fds,
5448 * we aren't going to use them anymore, ok to trash.
5449 */
5450 if (!sq)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005451 return 0;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005452
5453 /* If this one of script's fds? */
5454 if (fd != 0) {
5455 struct parsefile *pf = g_parsefile;
5456 while (pf) {
5457 /* We skip fd == 0 case because of the following:
5458 * $ ash # running ash interactively
5459 * $ . ./script.sh
5460 * and in script.sh: "exec 9>&0".
5461 * Even though top-level pf_fd _is_ 0,
5462 * it's still ok to use it: "read" builtin uses it,
5463 * why should we cripple "exec" builtin?
5464 */
5465 if (fd == pf->pf_fd) {
5466 pf->pf_fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
5467 return 1; /* "we closed fd" */
5468 }
5469 pf = pf->prev;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005470 }
5471 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005472
5473 /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */
5474
5475 /* First: do we collide with some already moved fds? */
5476 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5477 /* If we collide with an already moved fd... */
5478 if (fd == sq->two_fd[i].moved_to) {
5479 new_fd = fcntl_F_DUPFD(fd, avoid_fd);
5480 sq->two_fd[i].moved_to = new_fd;
5481 TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd));
5482 if (new_fd < 0) /* what? */
5483 xfunc_die();
5484 return 0; /* "we did not close fd" */
5485 }
5486 if (fd == sq->two_fd[i].orig_fd) {
5487 /* Example: echo Hello >/dev/null 1>&2 */
5488 TRACE(("redirect_fd %d: already moved\n", fd));
5489 return 0; /* "we did not close fd" */
5490 }
5491 }
5492
5493 /* If this fd is open, we move and remember it; if it's closed, new_fd = CLOSED (-1) */
5494 new_fd = fcntl_F_DUPFD(fd, avoid_fd);
5495 TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd));
5496 if (new_fd < 0) {
5497 if (errno != EBADF)
5498 xfunc_die();
5499 /* new_fd = CLOSED; - already is -1 */
5500 }
5501 sq->two_fd[i].moved_to = new_fd;
5502 sq->two_fd[i].orig_fd = fd;
5503
5504 /* if we move stderr, let "set -x" code know */
5505 if (fd == preverrout_fd)
5506 preverrout_fd = new_fd;
5507
5508 return 0; /* "we did not close fd" */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005509}
5510
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02005511static int
5512internally_opened_fd(int fd, struct redirtab *sq)
5513{
5514 int i;
5515#if JOBS
5516 if (fd == ttyfd)
5517 return 1;
5518#endif
5519 /* If this one of script's fds? */
5520 if (fd != 0) {
5521 struct parsefile *pf = g_parsefile;
5522 while (pf) {
5523 if (fd == pf->pf_fd)
5524 return 1;
5525 pf = pf->prev;
5526 }
5527 }
5528
5529 if (sq) for (i = 0; i < sq->pair_count && sq->two_fd[i].orig_fd != EMPTY; i++) {
5530 if (fd == sq->two_fd[i].moved_to)
5531 return 1;
5532 }
5533 return 0;
5534}
5535
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005536/*
5537 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5538 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005539 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005540 */
5541/* flags passed to redirect */
5542#define REDIR_PUSH 01 /* save previous values of file descriptors */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005543static void
5544redirect(union node *redir, int flags)
5545{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005546 struct redirtab *sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005547 int sv_pos;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005548
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005549 if (!redir)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005550 return;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005551
5552 sv_pos = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005553 sv = NULL;
5554 INT_OFF;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005555 if (flags & REDIR_PUSH)
5556 sv = redirlist;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005557 do {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005558 int fd;
5559 int newfd;
5560 int close_fd;
5561 int closed;
5562
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005563 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005564 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005565 //bb_error_msg("doing %d > %d", fd, newfd);
5566 newfd = redir->ndup.dupfd;
5567 close_fd = -1;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005568 } else {
5569 newfd = openredirect(redir); /* always >= 0 */
5570 if (fd == newfd) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005571 /* open() gave us precisely the fd we wanted.
5572 * This means that this fd was not busy
5573 * (not opened to anywhere).
5574 * Remember to close it on restore:
5575 */
5576 add_squirrel_closed(sv, fd);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005577 continue;
5578 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005579 close_fd = newfd;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005580 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005581
5582 if (fd == newfd)
5583 continue;
5584
5585 /* if "N>FILE": move newfd to fd */
5586 /* if "N>&M": dup newfd to fd */
5587 /* if "N>&-": close fd (newfd is -1) */
5588
5589 IF_BASH_REDIR_OUTPUT(redirect_more:)
5590
5591 closed = save_fd_on_redirect(fd, /*avoid:*/ newfd, sv);
5592 if (newfd == -1) {
5593 /* "N>&-" means "close me" */
5594 if (!closed) {
5595 /* ^^^ optimization: saving may already
5596 * have closed it. If not... */
5597 close(fd);
Denis Vlasenko22f74142008-07-24 22:34:43 +00005598 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005599 } else {
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02005600 /* if newfd is a script fd or saved fd, simulate EBADF */
5601 if (internally_opened_fd(newfd, sv)) {
5602 errno = EBADF;
5603 ash_msg_and_raise_perror("%d", newfd);
5604 }
Denys Vlasenko64774602016-10-26 15:24:30 +02005605 dup2_or_raise(newfd, fd);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005606 if (close_fd >= 0) /* "N>FILE" or ">&FILE" or heredoc? */
5607 close(close_fd);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005608#if BASH_REDIR_OUTPUT
Denys Vlasenko035486c2017-07-31 04:09:19 +02005609 if (redir->nfile.type == NTO2 && fd == 1) {
5610 /* ">&FILE". we already redirected to 1, now copy 1 to 2 */
5611 fd = 2;
5612 newfd = 1;
5613 close_fd = -1;
5614 goto redirect_more;
5615 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005616#endif
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005617 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005618 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005619 INT_ON;
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005620
5621//dash:#define REDIR_SAVEFD2 03 /* set preverrout */
5622#define REDIR_SAVEFD2 0
5623 // dash has a bug: since REDIR_SAVEFD2=3 and REDIR_PUSH=1, this test
5624 // triggers for pure REDIR_PUSH too. Thus, this is done almost always,
5625 // not only for calls with flags containing REDIR_SAVEFD2.
Denys Vlasenko035486c2017-07-31 04:09:19 +02005626 // We do this unconditionally (see save_fd_on_redirect()).
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005627 //if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5628 // preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005629}
5630
Denys Vlasenko170f93e2017-07-29 18:54:53 +02005631static int
5632redirectsafe(union node *redir, int flags)
5633{
5634 int err;
5635 volatile int saveint;
5636 struct jmploc *volatile savehandler = exception_handler;
5637 struct jmploc jmploc;
5638
5639 SAVE_INT(saveint);
5640 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005641 err = setjmp(jmploc.loc); /* was = setjmp(jmploc.loc) * 2; */
Denys Vlasenko170f93e2017-07-29 18:54:53 +02005642 if (!err) {
5643 exception_handler = &jmploc;
5644 redirect(redir, flags);
5645 }
5646 exception_handler = savehandler;
5647 if (err && exception_type != EXERROR)
5648 longjmp(exception_handler->loc, 1);
5649 RESTORE_INT(saveint);
5650 return err;
5651}
5652
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005653static struct redirtab*
5654pushredir(union node *redir)
5655{
5656 struct redirtab *sv;
5657 int i;
5658
5659 if (!redir)
5660 return redirlist;
5661
5662 i = 0;
5663 do {
5664 i++;
5665#if BASH_REDIR_OUTPUT
5666 if (redir->nfile.type == NTO2)
5667 i++;
5668#endif
5669 redir = redir->nfile.next;
5670 } while (redir);
5671
5672 sv = ckzalloc(sizeof(*sv) + i * sizeof(sv->two_fd[0]));
5673 sv->pair_count = i;
5674 while (--i >= 0)
Denys Vlasenko035486c2017-07-31 04:09:19 +02005675 sv->two_fd[i].orig_fd = sv->two_fd[i].moved_to = EMPTY;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005676 sv->next = redirlist;
5677 redirlist = sv;
5678 return sv->next;
5679}
5680
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005681/*
5682 * Undo the effects of the last redirection.
5683 */
5684static void
Denys Vlasenko035486c2017-07-31 04:09:19 +02005685popredir(int drop)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005686{
5687 struct redirtab *rp;
5688 int i;
5689
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02005690 if (redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005691 return;
5692 INT_OFF;
5693 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005694 for (i = 0; i < rp->pair_count; i++) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005695 int fd = rp->two_fd[i].orig_fd;
5696 int copy = rp->two_fd[i].moved_to;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005697 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005698 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005699 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005700 continue;
5701 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005702 if (copy != EMPTY) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005703 if (!drop) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005704 /*close(fd);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02005705 dup2_or_raise(copy, fd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005706 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005707 close(copy);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005708 }
5709 }
5710 redirlist = rp->next;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005711 free(rp);
5712 INT_ON;
5713}
5714
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005715static void
5716unwindredir(struct redirtab *stop)
5717{
5718 while (redirlist != stop)
Denys Vlasenko035486c2017-07-31 04:09:19 +02005719 popredir(/*drop:*/ 0);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005720}
5721
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005722
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005723/* ============ Routines to expand arguments to commands
5724 *
5725 * We have to deal with backquotes, shell variables, and file metacharacters.
5726 */
5727
Denys Vlasenko0b883582016-12-23 16:49:07 +01005728#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005729static arith_t
5730ash_arith(const char *s)
5731{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005732 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005733 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005734
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005735 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005736 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005737 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005738
5739 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005740 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005741 if (math_state.errmsg)
5742 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005743 INT_ON;
5744
5745 return result;
5746}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005747#endif
5748
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005749/*
5750 * expandarg flags
5751 */
5752#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5753#define EXP_TILDE 0x2 /* do normal tilde expansion */
5754#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5755#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
Denys Vlasenkodb74c6c2016-10-24 21:12:33 +02005756/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5757 * POSIX says for this case:
5758 * Pathname expansion shall not be performed on the word by a
5759 * non-interactive shell; an interactive shell may perform it, but shall
5760 * do so only when the expansion would result in one word.
5761 * Currently, our code complies to the above rule by never globbing
5762 * redirection filenames.
5763 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5764 * (this means that on a typical Linux distro, bash almost always
5765 * performs globbing, and thus diverges from what we do).
5766 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005767#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Ron Yorston549deab2015-05-18 09:57:51 +02005768#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005769#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5770#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005771#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005772/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005773 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005774 */
5775#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5776#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005777#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5778#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Ron Yorston417622c2015-05-18 09:59:14 +02005779#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005780
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005781/* Add CTLESC when necessary. */
Denys Vlasenko2990aa42017-07-25 17:37:57 +02005782#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005783/* Do not skip NUL characters. */
5784#define QUOTES_KEEPNUL EXP_TILDE
5785
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005786/*
5787 * Structure specifying which parts of the string should be searched
5788 * for IFS characters.
5789 */
5790struct ifsregion {
5791 struct ifsregion *next; /* next region in list */
5792 int begoff; /* offset of start of region */
5793 int endoff; /* offset of end of region */
5794 int nulonly; /* search for nul bytes only */
5795};
5796
5797struct arglist {
5798 struct strlist *list;
5799 struct strlist **lastp;
5800};
5801
5802/* output of current string */
5803static char *expdest;
5804/* list of back quote expressions */
5805static struct nodelist *argbackq;
5806/* first struct in list of ifs regions */
5807static struct ifsregion ifsfirst;
5808/* last struct in list */
5809static struct ifsregion *ifslastp;
5810/* holds expanded arg list */
5811static struct arglist exparg;
5812
5813/*
5814 * Our own itoa().
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02005815 * cvtnum() is used even if math support is off (to prepare $? values and such).
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005816 */
5817static int
5818cvtnum(arith_t num)
5819{
5820 int len;
5821
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02005822 /* 32-bit and wider ints require buffer size of bytes*3 (or less) */
5823 len = sizeof(arith_t) * 3;
5824 /* If narrower: worst case, 1-byte ints: need 5 bytes: "-127<NUL>" */
5825 if (sizeof(arith_t) < 4) len += 2;
5826
5827 expdest = makestrspace(len, expdest);
5828 len = fmtstr(expdest, len, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005829 STADJUST(len, expdest);
5830 return len;
5831}
5832
Denys Vlasenko455e4222016-10-27 14:45:13 +02005833/*
5834 * Break the argument string into pieces based upon IFS and add the
5835 * strings to the argument list. The regions of the string to be
5836 * searched for IFS characters have been stored by recordregion.
5837 */
5838static void
5839ifsbreakup(char *string, struct arglist *arglist)
5840{
5841 struct ifsregion *ifsp;
5842 struct strlist *sp;
5843 char *start;
5844 char *p;
5845 char *q;
5846 const char *ifs, *realifs;
5847 int ifsspc;
5848 int nulonly;
5849
5850 start = string;
5851 if (ifslastp != NULL) {
5852 ifsspc = 0;
5853 nulonly = 0;
5854 realifs = ifsset() ? ifsval() : defifs;
5855 ifsp = &ifsfirst;
5856 do {
5857 p = string + ifsp->begoff;
5858 nulonly = ifsp->nulonly;
5859 ifs = nulonly ? nullstr : realifs;
5860 ifsspc = 0;
5861 while (p < string + ifsp->endoff) {
5862 q = p;
5863 if ((unsigned char)*p == CTLESC)
5864 p++;
5865 if (!strchr(ifs, *p)) {
5866 p++;
5867 continue;
5868 }
5869 if (!nulonly)
5870 ifsspc = (strchr(defifs, *p) != NULL);
5871 /* Ignore IFS whitespace at start */
5872 if (q == start && ifsspc) {
5873 p++;
5874 start = p;
5875 continue;
5876 }
5877 *q = '\0';
5878 sp = stzalloc(sizeof(*sp));
5879 sp->text = start;
5880 *arglist->lastp = sp;
5881 arglist->lastp = &sp->next;
5882 p++;
5883 if (!nulonly) {
5884 for (;;) {
5885 if (p >= string + ifsp->endoff) {
5886 break;
5887 }
5888 q = p;
5889 if ((unsigned char)*p == CTLESC)
5890 p++;
5891 if (strchr(ifs, *p) == NULL) {
5892 p = q;
5893 break;
5894 }
5895 if (strchr(defifs, *p) == NULL) {
5896 if (ifsspc) {
5897 p++;
5898 ifsspc = 0;
5899 } else {
5900 p = q;
5901 break;
5902 }
5903 } else
5904 p++;
5905 }
5906 }
5907 start = p;
5908 } /* while */
5909 ifsp = ifsp->next;
5910 } while (ifsp != NULL);
5911 if (nulonly)
5912 goto add;
5913 }
5914
5915 if (!*start)
5916 return;
5917
5918 add:
5919 sp = stzalloc(sizeof(*sp));
5920 sp->text = start;
5921 *arglist->lastp = sp;
5922 arglist->lastp = &sp->next;
5923}
5924
5925static void
5926ifsfree(void)
5927{
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005928 struct ifsregion *p = ifsfirst.next;
5929
5930 if (!p)
5931 goto out;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005932
5933 INT_OFF;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005934 do {
5935 struct ifsregion *ifsp;
5936 ifsp = p->next;
5937 free(p);
5938 p = ifsp;
5939 } while (p);
Denys Vlasenko455e4222016-10-27 14:45:13 +02005940 ifsfirst.next = NULL;
5941 INT_ON;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005942 out:
5943 ifslastp = NULL;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005944}
5945
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005946static size_t
5947esclen(const char *start, const char *p)
5948{
5949 size_t esc = 0;
5950
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005951 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005952 esc++;
5953 }
5954 return esc;
5955}
5956
5957/*
5958 * Remove any CTLESC characters from a string.
5959 */
5960static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005961rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005962{
Ron Yorston417622c2015-05-18 09:59:14 +02005963 static const char qchars[] ALIGN1 = {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005964 IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005965
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005966 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005967 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005968 unsigned protect_against_glob;
5969 unsigned globbing;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005970 IF_BASH_PATTERN_SUBST(unsigned slash = flag & RMESCAPE_SLASH;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005971
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005972 p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005973 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005974 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005975
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005976 q = p;
5977 r = str;
5978 if (flag & RMESCAPE_ALLOC) {
5979 size_t len = p - str;
5980 size_t fulllen = len + strlen(p) + 1;
5981
5982 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005983 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005984 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005985 /* p and str may be invalidated by makestrspace */
5986 str = (char *)stackblock() + strloc;
5987 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005988 } else if (flag & RMESCAPE_HEAP) {
5989 r = ckmalloc(fulllen);
5990 } else {
5991 r = stalloc(fulllen);
5992 }
5993 q = r;
5994 if (len > 0) {
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02005995 q = (char *)mempcpy(q, str, len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005996 }
5997 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005998
Ron Yorston549deab2015-05-18 09:57:51 +02005999 inquotes = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006000 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006001 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006002 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006003 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006004// Note: both inquotes and protect_against_glob only affect whether
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006005// CTLESC,<ch> gets converted to <ch> or to \<ch>
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006006 inquotes = ~inquotes;
6007 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006008 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006009 continue;
6010 }
Ron Yorston549deab2015-05-18 09:57:51 +02006011 if ((unsigned char)*p == CTLESC) {
6012 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02006013#if DEBUG
6014 if (*p == '\0')
6015 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
6016#endif
Ron Yorston549deab2015-05-18 09:57:51 +02006017 if (protect_against_glob) {
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006018 /*
6019 * We used to trust glob() and fnmatch() to eat
6020 * superfluous escapes (\z where z has no
6021 * special meaning anyway). But this causes
6022 * bugs such as string of one greek letter rho
Denys Vlasenkoed79a632017-07-05 19:20:43 +02006023 * (unicode-encoded as two bytes "cf,81")
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006024 * getting encoded as "cf,CTLESC,81"
6025 * and here, converted to "cf,\,81" -
6026 * which does not go well with some flavors
Denys Vlasenko92b8d9c2017-07-05 19:13:44 +02006027 * of fnmatch() in unicode locales
6028 * (for example, glibc <= 2.22).
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006029 *
6030 * Lets add "\" only on the chars which need it.
Denys Vlasenko4142f012017-07-05 22:19:28 +02006031 * Testcases for less obvious chars are shown.
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006032 */
6033 if (*p == '*'
6034 || *p == '?'
6035 || *p == '['
Denys Vlasenko4142f012017-07-05 22:19:28 +02006036 || *p == '\\' /* case '\' in \\ ) echo ok;; *) echo WRONG;; esac */
6037 || *p == ']' /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */
6038 || *p == '-' /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */
6039 || *p == '!' /* case '!' in [\!] ) echo ok;; *) echo WRONG;; esac */
6040 /* Some libc support [^negate], that's why "^" also needs love */
6041 || *p == '^' /* case '^' in [\^] ) echo ok;; *) echo WRONG;; esac */
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006042 ) {
6043 *q++ = '\\';
6044 }
Ron Yorston549deab2015-05-18 09:57:51 +02006045 }
6046 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006047 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006048 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006049 goto copy;
6050 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006051#if BASH_PATTERN_SUBST
Ron Yorston417622c2015-05-18 09:59:14 +02006052 else if (*p == '/' && slash) {
6053 /* stop handling globbing and mark location of slash */
6054 globbing = slash = 0;
6055 *p = CTLESC;
6056 }
6057#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006058 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006059 copy:
6060 *q++ = *p++;
6061 }
6062 *q = '\0';
6063 if (flag & RMESCAPE_GROW) {
6064 expdest = r;
6065 STADJUST(q - r + 1, expdest);
6066 }
6067 return r;
6068}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006069#define pmatch(a, b) !fnmatch((a), (b), 0)
6070
6071/*
6072 * Prepare a pattern for a expmeta (internal glob(3)) call.
6073 *
6074 * Returns an stalloced string.
6075 */
6076static char *
Ron Yorston549deab2015-05-18 09:57:51 +02006077preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006078{
Ron Yorston549deab2015-05-18 09:57:51 +02006079 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006080}
6081
6082/*
6083 * Put a string on the stack.
6084 */
6085static void
6086memtodest(const char *p, size_t len, int syntax, int quotes)
6087{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006088 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006089
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006090 if (!len)
6091 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006092
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006093 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
6094
6095 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006096 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006097 if (c) {
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01006098 if (quotes & QUOTES_ESC) {
6099 int n = SIT(c, syntax);
6100 if (n == CCTL
6101 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
6102 && n == CBACK
6103 )
6104 ) {
6105 USTPUTC(CTLESC, q);
6106 }
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006107 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006108 } else if (!(quotes & QUOTES_KEEPNUL))
6109 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006110 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006111 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006112
6113 expdest = q;
6114}
6115
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006116static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006117strtodest(const char *p, int syntax, int quotes)
6118{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006119 size_t len = strlen(p);
6120 memtodest(p, len, syntax, quotes);
6121 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006122}
6123
6124/*
6125 * Record the fact that we have to scan this region of the
6126 * string for IFS characters.
6127 */
6128static void
6129recordregion(int start, int end, int nulonly)
6130{
6131 struct ifsregion *ifsp;
6132
6133 if (ifslastp == NULL) {
6134 ifsp = &ifsfirst;
6135 } else {
6136 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00006137 ifsp = ckzalloc(sizeof(*ifsp));
6138 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006139 ifslastp->next = ifsp;
6140 INT_ON;
6141 }
6142 ifslastp = ifsp;
6143 ifslastp->begoff = start;
6144 ifslastp->endoff = end;
6145 ifslastp->nulonly = nulonly;
6146}
6147
6148static void
6149removerecordregions(int endoff)
6150{
6151 if (ifslastp == NULL)
6152 return;
6153
6154 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006155 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006156 struct ifsregion *ifsp;
6157 INT_OFF;
6158 ifsp = ifsfirst.next->next;
6159 free(ifsfirst.next);
6160 ifsfirst.next = ifsp;
6161 INT_ON;
6162 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006163 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006164 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006165 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006166 ifslastp = &ifsfirst;
6167 ifsfirst.endoff = endoff;
6168 }
6169 return;
6170 }
6171
6172 ifslastp = &ifsfirst;
6173 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006174 ifslastp = ifslastp->next;
6175 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006176 struct ifsregion *ifsp;
6177 INT_OFF;
6178 ifsp = ifslastp->next->next;
6179 free(ifslastp->next);
6180 ifslastp->next = ifsp;
6181 INT_ON;
6182 }
6183 if (ifslastp->endoff > endoff)
6184 ifslastp->endoff = endoff;
6185}
6186
6187static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006188exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006189{
Denys Vlasenkocd716832009-11-28 22:14:02 +01006190 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006191 char *name;
6192 struct passwd *pw;
6193 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006194 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006195
6196 name = p + 1;
6197
6198 while ((c = *++p) != '\0') {
6199 switch (c) {
6200 case CTLESC:
6201 return startp;
6202 case CTLQUOTEMARK:
6203 return startp;
6204 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006205 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006206 goto done;
6207 break;
6208 case '/':
6209 case CTLENDVAR:
6210 goto done;
6211 }
6212 }
6213 done:
6214 *p = '\0';
6215 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02006216 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006217 } else {
6218 pw = getpwnam(name);
6219 if (pw == NULL)
6220 goto lose;
6221 home = pw->pw_dir;
6222 }
6223 if (!home || !*home)
6224 goto lose;
6225 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006226 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006227 return p;
6228 lose:
6229 *p = c;
6230 return startp;
6231}
6232
6233/*
6234 * Execute a command inside back quotes. If it's a builtin command, we
6235 * want to save its output in a block obtained from malloc. Otherwise
6236 * we fork off a subprocess and get the output of the command via a pipe.
6237 * Should be called with interrupts off.
6238 */
6239struct backcmd { /* result of evalbackcmd */
6240 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006241 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00006242 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006243 struct job *jp; /* job structure for command */
6244};
6245
6246/* These forward decls are needed to use "eval" code for backticks handling: */
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +02006247/* flags in argument to evaltree */
6248#define EV_EXIT 01 /* exit after evaluating tree */
6249#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02006250static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006251
Denys Vlasenko619d9b52017-07-28 15:28:33 +02006252/* An evaltree() which is known to never return.
6253 * Used to use an alias:
6254 * static int evaltreenr(union node *, int) __attribute__((alias("evaltree"),__noreturn__));
6255 * but clang was reported to "transfer" noreturn-ness to evaltree() as well.
6256 */
6257static ALWAYS_INLINE NORETURN void
6258evaltreenr(union node *n, int flags)
6259{
6260 evaltree(n, flags);
6261 bb_unreachable(abort());
6262 /* NOTREACHED */
6263}
6264
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02006265static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006266evalbackcmd(union node *n, struct backcmd *result)
6267{
Denys Vlasenko579ad102016-10-25 21:10:20 +02006268 int pip[2];
6269 struct job *jp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006270
6271 result->fd = -1;
6272 result->buf = NULL;
6273 result->nleft = 0;
6274 result->jp = NULL;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006275 if (n == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006276 goto out;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006277 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006278
Denys Vlasenko579ad102016-10-25 21:10:20 +02006279 if (pipe(pip) < 0)
6280 ash_msg_and_raise_error("pipe call failed");
6281 jp = makejob(/*n,*/ 1);
6282 if (forkshell(jp, n, FORK_NOJOB) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02006283 /* child */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006284 FORCE_INT_ON;
6285 close(pip[0]);
6286 if (pip[1] != 1) {
6287 /*close(1);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02006288 dup2_or_raise(pip[1], 1);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006289 close(pip[1]);
6290 }
Denys Vlasenko960ca382016-10-25 18:12:15 +02006291/* TODO: eflag clearing makes the following not abort:
6292 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6293 * which is what bash does (unless it is in POSIX mode).
6294 * dash deleted "eflag = 0" line in the commit
6295 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6296 * [EVAL] Don't clear eflag in evalbackcmd
6297 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6298 */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006299 eflag = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006300 ifsfree();
Denys Vlasenko619d9b52017-07-28 15:28:33 +02006301 evaltreenr(n, EV_EXIT);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006302 /* NOTREACHED */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006303 }
Denys Vlasenko70392332016-10-27 02:31:55 +02006304 /* parent */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006305 close(pip[1]);
6306 result->fd = pip[0];
6307 result->jp = jp;
6308
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006309 out:
6310 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6311 result->fd, result->buf, result->nleft, result->jp));
6312}
6313
6314/*
6315 * Expand stuff in backwards quotes.
6316 */
6317static void
Ron Yorston549deab2015-05-18 09:57:51 +02006318expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006319{
6320 struct backcmd in;
6321 int i;
6322 char buf[128];
6323 char *p;
6324 char *dest;
6325 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02006326 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006327 struct stackmark smark;
6328
6329 INT_OFF;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02006330 startloc = expdest - (char *)stackblock();
6331 pushstackmark(&smark, startloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006332 evalbackcmd(cmd, &in);
6333 popstackmark(&smark);
6334
6335 p = in.buf;
6336 i = in.nleft;
6337 if (i == 0)
6338 goto read;
6339 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02006340 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006341 read:
6342 if (in.fd < 0)
6343 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01006344 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006345 TRACE(("expbackq: read returns %d\n", i));
6346 if (i <= 0)
6347 break;
6348 p = buf;
6349 }
6350
Denis Vlasenko60818682007-09-28 22:07:23 +00006351 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006352 if (in.fd >= 0) {
6353 close(in.fd);
6354 back_exitstatus = waitforjob(in.jp);
6355 }
6356 INT_ON;
6357
6358 /* Eat all trailing newlines */
6359 dest = expdest;
6360 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6361 STUNPUTC(dest);
6362 expdest = dest;
6363
Ron Yorston549deab2015-05-18 09:57:51 +02006364 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006365 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006366 TRACE(("evalbackq: size:%d:'%.*s'\n",
6367 (int)((dest - (char *)stackblock()) - startloc),
6368 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006369 stackblock() + startloc));
6370}
6371
Denys Vlasenko0b883582016-12-23 16:49:07 +01006372#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006373/*
6374 * Expand arithmetic expression. Backup to start of expression,
6375 * evaluate, place result in (backed up) result, adjust string position.
6376 */
6377static void
Ron Yorston549deab2015-05-18 09:57:51 +02006378expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006379{
6380 char *p, *start;
6381 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006382 int len;
6383
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006384 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006385
6386 /*
6387 * This routine is slightly over-complicated for
6388 * efficiency. Next we scan backwards looking for the
6389 * start of arithmetic.
6390 */
6391 start = stackblock();
6392 p = expdest - 1;
6393 *p = '\0';
6394 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006395 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006396 int esc;
6397
Denys Vlasenkocd716832009-11-28 22:14:02 +01006398 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006399 p--;
6400#if DEBUG
6401 if (p < start) {
6402 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6403 }
6404#endif
6405 }
6406
6407 esc = esclen(start, p);
6408 if (!(esc % 2)) {
6409 break;
6410 }
6411
6412 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006413 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006414
6415 begoff = p - start;
6416
6417 removerecordregions(begoff);
6418
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006419 expdest = p;
6420
Ron Yorston549deab2015-05-18 09:57:51 +02006421 if (flag & QUOTES_ESC)
6422 rmescapes(p + 1, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006423
Ron Yorston549deab2015-05-18 09:57:51 +02006424 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006425
Ron Yorston549deab2015-05-18 09:57:51 +02006426 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006427 recordregion(begoff, begoff + len, 0);
6428}
6429#endif
6430
6431/* argstr needs it */
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006432static char *evalvar(char *p, int flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006433
6434/*
6435 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6436 * characters to allow for further processing. Otherwise treat
6437 * $@ like $* since no splitting will be performed.
6438 */
6439static void
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006440argstr(char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006441{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006442 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006443 '=',
6444 ':',
6445 CTLQUOTEMARK,
6446 CTLENDVAR,
6447 CTLESC,
6448 CTLVAR,
6449 CTLBACKQ,
Denys Vlasenko0b883582016-12-23 16:49:07 +01006450#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006451 CTLENDARI,
6452#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006453 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006454 };
6455 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006456 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006457 int inquotes;
6458 size_t length;
6459 int startloc;
6460
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006461 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006462 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006463 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006464 reject++;
6465 }
6466 inquotes = 0;
6467 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006468 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006469 char *q;
6470
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006471 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006472 tilde:
6473 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006474 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006475 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006476 }
6477 start:
6478 startloc = expdest - (char *)stackblock();
6479 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006480 unsigned char c;
6481
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006482 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006483 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006484 if (c) {
6485 if (!(c & 0x80)
Denys Vlasenko0b883582016-12-23 16:49:07 +01006486 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006487 ) {
6488 /* c == '=' || c == ':' || c == CTLENDARI */
6489 length++;
6490 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006491 }
6492 if (length > 0) {
6493 int newloc;
6494 expdest = stack_nputstr(p, length, expdest);
6495 newloc = expdest - (char *)stackblock();
6496 if (breakall && !inquotes && newloc > startloc) {
6497 recordregion(startloc, newloc, 0);
6498 }
6499 startloc = newloc;
6500 }
6501 p += length + 1;
6502 length = 0;
6503
6504 switch (c) {
6505 case '\0':
6506 goto breakloop;
6507 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006508 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006509 p--;
6510 continue;
6511 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006512 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006513 reject++;
6514 /* fall through */
6515 case ':':
6516 /*
6517 * sort of a hack - expand tildes in variable
6518 * assignments (after the first '=' and after ':'s).
6519 */
6520 if (*--p == '~') {
6521 goto tilde;
6522 }
6523 continue;
6524 }
6525
6526 switch (c) {
6527 case CTLENDVAR: /* ??? */
6528 goto breakloop;
6529 case CTLQUOTEMARK:
Ron Yorston549deab2015-05-18 09:57:51 +02006530 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006531 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006532 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006533 p = evalvar(p + 1, flags | inquotes) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006534 goto start;
6535 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006536 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006537 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006538 p--;
6539 length++;
6540 startloc++;
6541 }
6542 break;
6543 case CTLESC:
6544 startloc++;
6545 length++;
Ron Yorston549deab2015-05-18 09:57:51 +02006546
6547 /*
6548 * Quoted parameter expansion pattern: remove quote
6549 * unless inside inner quotes or we have a literal
6550 * backslash.
6551 */
6552 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6553 EXP_QPAT && *p != '\\')
6554 break;
6555
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006556 goto addquote;
6557 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006558 TRACE(("argstr: evalvar('%s')\n", p));
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006559 p = evalvar(p, flags | inquotes);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006560 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006561 goto start;
6562 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006563 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006564 argbackq = argbackq->next;
6565 goto start;
Denys Vlasenko0b883582016-12-23 16:49:07 +01006566#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006567 case CTLENDARI:
6568 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006569 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006570 goto start;
6571#endif
6572 }
6573 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006574 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006575}
6576
6577static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006578scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6579 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006580{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006581 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006582 char c;
6583
6584 loc = startp;
6585 loc2 = rmesc;
6586 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006587 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006588 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006589
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006590 c = *loc2;
6591 if (zero) {
6592 *loc2 = '\0';
6593 s = rmesc;
6594 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006595 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006596
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006597 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006598 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006599 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006600 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006601 loc++;
6602 loc++;
6603 loc2++;
6604 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006605 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006606}
6607
6608static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006609scanright(char *startp, char *rmesc, char *rmescend,
6610 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006611{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006612#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6613 int try2optimize = match_at_start;
6614#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006615 int esc = 0;
6616 char *loc;
6617 char *loc2;
6618
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006619 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6620 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6621 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6622 * Logic:
6623 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6624 * and on each iteration they go back two/one char until they reach the beginning.
6625 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6626 */
6627 /* TODO: document in what other circumstances we are called. */
6628
6629 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006630 int match;
6631 char c = *loc2;
6632 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006633 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006634 *loc2 = '\0';
6635 s = rmesc;
6636 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006637 match = pmatch(pattern, s);
6638 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006639 *loc2 = c;
6640 if (match)
6641 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006642#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6643 if (try2optimize) {
6644 /* Maybe we can optimize this:
6645 * if pattern ends with unescaped *, we can avoid checking
Denys Vlasenko10ad6222017-04-17 16:13:32 +02006646 * shorter strings: if "foo*" doesn't match "raw_value_of_v",
6647 * it won't match truncated "raw_value_of_" strings too.
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006648 */
6649 unsigned plen = strlen(pattern);
6650 /* Does it end with "*"? */
6651 if (plen != 0 && pattern[--plen] == '*') {
6652 /* "xxxx*" is not escaped */
6653 /* "xxx\*" is escaped */
6654 /* "xx\\*" is not escaped */
6655 /* "x\\\*" is escaped */
6656 int slashes = 0;
6657 while (plen != 0 && pattern[--plen] == '\\')
6658 slashes++;
6659 if (!(slashes & 1))
6660 break; /* ends with unescaped "*" */
6661 }
6662 try2optimize = 0;
6663 }
6664#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006665 loc--;
6666 if (quotes) {
6667 if (--esc < 0) {
6668 esc = esclen(startp, loc);
6669 }
6670 if (esc % 2) {
6671 esc--;
6672 loc--;
6673 }
6674 }
6675 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006676 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006677}
6678
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006679static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006680static void
6681varunset(const char *end, const char *var, const char *umsg, int varflags)
6682{
6683 const char *msg;
6684 const char *tail;
6685
6686 tail = nullstr;
6687 msg = "parameter not set";
6688 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006689 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006690 if (varflags & VSNUL)
6691 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006692 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006693 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006694 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006695 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006696 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006697}
6698
6699static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006700subevalvar(char *p, char *varname, int strloc, int subtype,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006701 int startloc, int varflags, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006702{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006703 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006704 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006705 char *startp;
6706 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006707 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006708 char *str;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006709 int amount, resetloc;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006710 IF_BASH_PATTERN_SUBST(int workloc;)
6711 IF_BASH_PATTERN_SUBST(char *repl = NULL;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006712 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006713 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006714
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006715 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6716 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006717
Ron Yorstoneb6b48b2015-05-18 09:51:35 +02006718 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006719 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0)
6720 );
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006721 STPUTC('\0', expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006722 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006723 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006724
6725 switch (subtype) {
6726 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006727 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006728 amount = startp - expdest;
6729 STADJUST(amount, expdest);
6730 return startp;
6731
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006732 case VSQUESTION:
6733 varunset(p, varname, startp, varflags);
6734 /* NOTREACHED */
6735
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006736#if BASH_SUBSTR
Denys Vlasenko826360f2017-07-17 17:49:11 +02006737 case VSSUBSTR: {
6738 int pos, len, orig_len;
6739 char *colon;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006740
Denys Vlasenko826360f2017-07-17 17:49:11 +02006741 loc = str = stackblock() + strloc;
6742
6743# if !ENABLE_FEATURE_SH_MATH
6744# define ash_arith number
6745# endif
6746 /* Read POS in ${var:POS:LEN} */
6747 colon = strchr(loc, ':');
6748 if (colon) *colon = '\0';
6749 pos = ash_arith(loc);
6750 if (colon) *colon = ':';
6751
6752 /* Read LEN in ${var:POS:LEN} */
6753 len = str - startp - 1;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006754 /* *loc != '\0', guaranteed by parser */
6755 if (quotes) {
6756 char *ptr;
6757
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006758 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006759 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006760 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006761 len--;
6762 ptr++;
6763 }
6764 }
6765 }
6766 orig_len = len;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006767 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006768 /* ${var::LEN} */
Denys Vlasenko826360f2017-07-17 17:49:11 +02006769 len = ash_arith(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006770 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006771 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006772 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006773 while (*loc && *loc != ':') {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006774 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006775 }
6776 if (*loc++ == ':') {
Denys Vlasenko826360f2017-07-17 17:49:11 +02006777 len = ash_arith(loc);
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006778 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006779 }
Denys Vlasenko826360f2017-07-17 17:49:11 +02006780# undef ash_arith
6781
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006782 if (pos < 0) {
6783 /* ${VAR:$((-n)):l} starts n chars from the end */
6784 pos = orig_len + pos;
6785 }
6786 if ((unsigned)pos >= orig_len) {
6787 /* apart from obvious ${VAR:999999:l},
6788 * covers ${VAR:$((-9999999)):l} - result is ""
Denys Vlasenko826360f2017-07-17 17:49:11 +02006789 * (bash compat)
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006790 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006791 pos = 0;
6792 len = 0;
6793 }
Denys Vlasenko826360f2017-07-17 17:49:11 +02006794 if (len < 0) {
6795 /* ${VAR:N:-M} sets LEN to strlen()-M */
6796 len = (orig_len - pos) + len;
6797 }
6798 if ((unsigned)len > (orig_len - pos))
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006799 len = orig_len - pos;
6800
6801 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006802 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006803 str++;
6804 }
6805 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006806 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006807 *loc++ = *str++;
6808 *loc++ = *str++;
6809 }
6810 *loc = '\0';
6811 amount = loc - expdest;
6812 STADJUST(amount, expdest);
6813 return loc;
Denys Vlasenko826360f2017-07-17 17:49:11 +02006814 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006815#endif /* BASH_SUBSTR */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006816 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006817
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006818 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006819
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006820#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006821 /* We'll comeback here if we grow the stack while handling
6822 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6823 * stack will need rebasing, and we'll need to remove our work
6824 * areas each time
6825 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006826 restart:
6827#endif
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006828
6829 amount = expdest - ((char *)stackblock() + resetloc);
6830 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006831 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006832
6833 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006834 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006835 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006836 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006837 if (rmesc != startp) {
6838 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006839 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006840 }
6841 }
6842 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006843 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02006844 /*
6845 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6846 * The result is a_\_z_c (not a\_\_z_c)!
6847 *
6848 * The search pattern and replace string treat backslashes differently!
6849 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6850 * and string. It's only used on the first call.
6851 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006852 preglob(str, IF_BASH_PATTERN_SUBST(
Ron Yorston417622c2015-05-18 09:59:14 +02006853 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006854 RMESCAPE_SLASH : ) 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006855
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006856#if BASH_PATTERN_SUBST
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006857 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006858 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenko826360f2017-07-17 17:49:11 +02006859 int len;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006860 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006861
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006862 if (!repl) {
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006863 repl = strchr(str, CTLESC);
6864 if (repl)
Ron Yorston417622c2015-05-18 09:59:14 +02006865 *repl++ = '\0';
6866 else
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006867 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006868 }
Ron Yorston417622c2015-05-18 09:59:14 +02006869 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006870
6871 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006872 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006873 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006874
6875 len = 0;
6876 idx = startp;
6877 end = str - 1;
6878 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006879 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006880 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006881 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006882 if (!loc) {
6883 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006884 char *restart_detect = stackblock();
6885 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006886 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006887 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006888 idx++;
6889 len++;
6890 STPUTC(*idx, expdest);
6891 }
6892 if (stackblock() != restart_detect)
6893 goto restart;
6894 idx++;
6895 len++;
6896 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006897 /* continue; - prone to quadratic behavior, smarter code: */
6898 if (idx >= end)
6899 break;
6900 if (str[0] == '*') {
6901 /* Pattern is "*foo". If "*foo" does not match "long_string",
6902 * it would never match "ong_string" etc, no point in trying.
6903 */
6904 goto skip_matching;
6905 }
6906 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006907 }
6908
6909 if (subtype == VSREPLACEALL) {
6910 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006911 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006912 idx++;
6913 idx++;
6914 rmesc++;
6915 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006916 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006917 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006918 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006919
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006920 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006921 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006922 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006923 if (quotes && *loc == '\\') {
6924 STPUTC(CTLESC, expdest);
6925 len++;
6926 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006927 STPUTC(*loc, expdest);
6928 if (stackblock() != restart_detect)
6929 goto restart;
6930 len++;
6931 }
6932
6933 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006934 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006935 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006936 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006937 STPUTC(*idx, expdest);
6938 if (stackblock() != restart_detect)
6939 goto restart;
6940 len++;
6941 idx++;
6942 }
6943 break;
6944 }
6945 }
6946
6947 /* We've put the replaced text into a buffer at workloc, now
6948 * move it to the right place and adjust the stack.
6949 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006950 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006951 startp = (char *)stackblock() + startloc;
6952 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006953 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006954 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006955 STADJUST(-amount, expdest);
6956 return startp;
6957 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006958#endif /* BASH_PATTERN_SUBST */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006959
6960 subtype -= VSTRIMRIGHT;
6961#if DEBUG
6962 if (subtype < 0 || subtype > 7)
6963 abort();
6964#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006965 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006966 zero = subtype >> 1;
6967 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6968 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6969
6970 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6971 if (loc) {
6972 if (zero) {
6973 memmove(startp, loc, str - loc);
6974 loc = startp + (str - loc) - 1;
6975 }
6976 *loc = '\0';
6977 amount = loc - expdest;
6978 STADJUST(amount, expdest);
6979 }
6980 return loc;
6981}
6982
6983/*
6984 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006985 * name parameter (examples):
6986 * ash -c 'echo $1' name:'1='
6987 * ash -c 'echo $qwe' name:'qwe='
6988 * ash -c 'echo $$' name:'$='
6989 * ash -c 'echo ${$}' name:'$='
6990 * ash -c 'echo ${$##q}' name:'$=q'
6991 * ash -c 'echo ${#$}' name:'$='
6992 * note: examples with bad shell syntax:
6993 * ash -c 'echo ${#$1}' name:'$=1'
6994 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006995 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02006996static NOINLINE ssize_t
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006997varvalue(char *name, int varflags, int flags, int *quotedp)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006998{
Mike Frysinger98c52642009-04-02 10:02:37 +00006999 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007000 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007001 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007002 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007003 int sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007004 int quoted = *quotedp;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007005 int subtype = varflags & VSTYPE;
7006 int discard = subtype == VSPLUS || subtype == VSLENGTH;
7007 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007008 int syntax;
7009
7010 sep = (flags & EXP_FULL) << CHAR_BIT;
7011 syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007012
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007013 switch (*name) {
7014 case '$':
7015 num = rootpid;
7016 goto numvar;
7017 case '?':
7018 num = exitstatus;
7019 goto numvar;
7020 case '#':
7021 num = shellparam.nparam;
7022 goto numvar;
7023 case '!':
7024 num = backgndpid;
7025 if (num == 0)
7026 return -1;
7027 numvar:
7028 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007029 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007030 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00007031 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007032 for (i = NOPTS - 1; i >= 0; i--) {
7033 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00007034 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007035 len++;
7036 }
7037 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007038 check_1char_name:
7039#if 0
7040 /* handles cases similar to ${#$1} */
7041 if (name[2] != '\0')
7042 raise_error_syntax("bad substitution");
7043#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007044 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007045 case '@':
7046 if (quoted && sep)
7047 goto param;
7048 /* fall through */
7049 case '*': {
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007050 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007051 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007052
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007053 if (quoted)
7054 sep = 0;
7055 sep |= ifsset() ? ifsval()[0] : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007056 param:
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007057 sepc = sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007058 *quotedp = !sepc;
7059 ap = shellparam.p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007060 if (!ap)
7061 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007062 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007063 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007064
7065 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007066 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007067 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007068 }
7069 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007070 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007071 } /* case '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007072 case '0':
7073 case '1':
7074 case '2':
7075 case '3':
7076 case '4':
7077 case '5':
7078 case '6':
7079 case '7':
7080 case '8':
7081 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02007082 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007083 if (num < 0 || num > shellparam.nparam)
7084 return -1;
7085 p = num ? shellparam.p[num - 1] : arg0;
7086 goto value;
7087 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007088 /* NB: name has form "VAR=..." */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007089 p = lookupvar(name);
7090 value:
7091 if (!p)
7092 return -1;
7093
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007094 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007095#if ENABLE_UNICODE_SUPPORT
7096 if (subtype == VSLENGTH && len > 0) {
7097 reinit_unicode_for_ash();
7098 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00007099 STADJUST(-len, expdest);
7100 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007101 len = unicode_strlen(p);
7102 }
7103 }
7104#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007105 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007106 }
7107
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007108 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007109 STADJUST(-len, expdest);
7110 return len;
7111}
7112
7113/*
7114 * Expand a variable, and return a pointer to the next character in the
7115 * input string.
7116 */
7117static char *
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007118evalvar(char *p, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007119{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007120 char varflags;
7121 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02007122 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007123 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007124 char *var;
7125 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007126 int startloc;
7127 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007128
Denys Vlasenkob0d63382009-09-16 16:18:32 +02007129 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007130 subtype = varflags & VSTYPE;
Denys Vlasenko88e15702016-10-26 01:55:56 +02007131
7132 if (!subtype)
7133 raise_error_syntax("bad substitution");
7134
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007135 quoted = flag & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007136 var = p;
7137 easy = (!quoted || (*var == '@' && shellparam.nparam));
7138 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02007139 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007140
7141 again:
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007142 varlen = varvalue(var, varflags, flag, &quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007143 if (varflags & VSNUL)
7144 varlen--;
7145
7146 if (subtype == VSPLUS) {
7147 varlen = -1 - varlen;
7148 goto vsplus;
7149 }
7150
7151 if (subtype == VSMINUS) {
7152 vsplus:
7153 if (varlen < 0) {
7154 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02007155 p,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007156 flag | EXP_TILDE | EXP_WORD
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007157 );
7158 goto end;
7159 }
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007160 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007161 }
7162
7163 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007164 if (varlen >= 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007165 goto record;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007166
7167 subevalvar(p, var, 0, subtype, startloc, varflags,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007168 flag & ~QUOTES_ESC);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007169 varflags &= ~VSNUL;
7170 /*
7171 * Remove any recorded regions beyond
7172 * start of variable
7173 */
7174 removerecordregions(startloc);
7175 goto again;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007176 }
7177
7178 if (varlen < 0 && uflag)
7179 varunset(p, var, 0, 0);
7180
7181 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007182 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007183 goto record;
7184 }
7185
7186 if (subtype == VSNORMAL) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007187 record:
7188 if (!easy)
7189 goto end;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007190 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007191 goto end;
7192 }
7193
7194#if DEBUG
7195 switch (subtype) {
7196 case VSTRIMLEFT:
7197 case VSTRIMLEFTMAX:
7198 case VSTRIMRIGHT:
7199 case VSTRIMRIGHTMAX:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007200#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007201 case VSSUBSTR:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007202#endif
7203#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007204 case VSREPLACE:
7205 case VSREPLACEALL:
7206#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007207 break;
7208 default:
7209 abort();
7210 }
7211#endif
7212
7213 if (varlen >= 0) {
7214 /*
7215 * Terminate the string and start recording the pattern
7216 * right after it
7217 */
7218 STPUTC('\0', expdest);
7219 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007220 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007221 startloc, varflags, flag)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007222 int amount = expdest - (
7223 (char *)stackblock() + patloc - 1
7224 );
7225 STADJUST(-amount, expdest);
7226 }
7227 /* Remove any recorded regions beyond start of variable */
7228 removerecordregions(startloc);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007229 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007230 }
7231
7232 end:
7233 if (subtype != VSNORMAL) { /* skip to end of alternative */
7234 int nesting = 1;
7235 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007236 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007237 if (c == CTLESC)
7238 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02007239 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007240 if (varlen >= 0)
7241 argbackq = argbackq->next;
7242 } else if (c == CTLVAR) {
7243 if ((*p++ & VSTYPE) != VSNORMAL)
7244 nesting++;
7245 } else if (c == CTLENDVAR) {
7246 if (--nesting == 0)
7247 break;
7248 }
7249 }
7250 }
7251 return p;
7252}
7253
7254/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007255 * Add a file name to the list.
7256 */
7257static void
7258addfname(const char *name)
7259{
7260 struct strlist *sp;
7261
Denis Vlasenko597906c2008-02-20 16:38:54 +00007262 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02007263 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007264 *exparg.lastp = sp;
7265 exparg.lastp = &sp->next;
7266}
7267
Felix Fietkaub5b21122017-01-31 21:58:55 +01007268/* Avoid glob() (and thus, stat() et al) for words like "echo" */
7269static int
7270hasmeta(const char *p)
7271{
7272 static const char chars[] ALIGN1 = {
7273 '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
7274 };
7275
7276 for (;;) {
7277 p = strpbrk(p, chars);
7278 if (!p)
7279 break;
7280 switch ((unsigned char) *p) {
7281 case CTLQUOTEMARK:
7282 for (;;) {
7283 p++;
7284 if (*p == CTLQUOTEMARK)
7285 break;
7286 if (*p == CTLESC)
7287 p++;
7288 if (*p == '\0') /* huh? */
7289 return 0;
7290 }
7291 break;
7292 case '\\':
7293 case CTLESC:
7294 p++;
7295 if (*p == '\0')
7296 return 0;
7297 break;
7298 case '[':
7299 if (!strchr(p + 1, ']')) {
7300 /* It's not a properly closed [] pattern,
7301 * but other metas may follow. Continue checking.
7302 * my[file* _is_ globbed by bash
7303 * and matches filenames like "my[file1".
7304 */
7305 break;
7306 }
7307 /* fallthrough */
7308 default:
7309 /* case '*': */
7310 /* case '?': */
7311 return 1;
7312 }
7313 p++;
7314 }
7315
7316 return 0;
7317}
7318
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007319/* If we want to use glob() from libc... */
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007320#if !ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007321
7322/* Add the result of glob() to the list */
7323static void
7324addglob(const glob_t *pglob)
7325{
7326 char **p = pglob->gl_pathv;
7327
7328 do {
7329 addfname(*p);
7330 } while (*++p);
7331}
7332static void
7333expandmeta(struct strlist *str /*, int flag*/)
7334{
7335 /* TODO - EXP_REDIR */
7336
7337 while (str) {
7338 char *p;
7339 glob_t pglob;
7340 int i;
7341
7342 if (fflag)
7343 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007344
Felix Fietkaub5b21122017-01-31 21:58:55 +01007345 if (!hasmeta(str->text))
7346 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007347
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007348 INT_OFF;
7349 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007350// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7351// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7352//
7353// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7354// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7355// Which means you need to unescape the string, right? Not so fast:
7356// if there _is_ a file named "file\?" (with backslash), it is returned
7357// as "file\?" too (whichever pattern you used to find it, say, "file*").
Denys Vlasenko10ad6222017-04-17 16:13:32 +02007358// You DON'T KNOW by looking at the result whether you need to unescape it.
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007359//
7360// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7361// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7362// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7363// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7364// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7365// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7366 i = glob(p, 0, NULL, &pglob);
7367 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007368 if (p != str->text)
7369 free(p);
7370 switch (i) {
7371 case 0:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007372#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007373 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7374 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7375 goto nometa2;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007376#endif
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007377 addglob(&pglob);
7378 globfree(&pglob);
7379 INT_ON;
7380 break;
7381 case GLOB_NOMATCH:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007382 //nometa2:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007383 globfree(&pglob);
7384 INT_ON;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007385 nometa:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007386 *exparg.lastp = str;
7387 rmescapes(str->text, 0);
7388 exparg.lastp = &str->next;
7389 break;
7390 default: /* GLOB_NOSPACE */
7391 globfree(&pglob);
7392 INT_ON;
7393 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7394 }
7395 str = str->next;
7396 }
7397}
7398
7399#else
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007400/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007401
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007402/*
7403 * Do metacharacter (i.e. *, ?, [...]) expansion.
7404 */
7405static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007406expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007407{
7408 char *p;
7409 const char *cp;
7410 char *start;
7411 char *endname;
7412 int metaflag;
7413 struct stat statb;
7414 DIR *dirp;
7415 struct dirent *dp;
7416 int atend;
7417 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007418 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007419
7420 metaflag = 0;
7421 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007422 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007423 if (*p == '*' || *p == '?')
7424 metaflag = 1;
7425 else if (*p == '[') {
7426 char *q = p + 1;
7427 if (*q == '!')
7428 q++;
7429 for (;;) {
7430 if (*q == '\\')
7431 q++;
7432 if (*q == '/' || *q == '\0')
7433 break;
7434 if (*++q == ']') {
7435 metaflag = 1;
7436 break;
7437 }
7438 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007439 } else {
7440 if (*p == '\\')
7441 esc++;
7442 if (p[esc] == '/') {
7443 if (metaflag)
7444 break;
7445 start = p + esc + 1;
7446 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007447 }
7448 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007449 if (metaflag == 0) { /* we've reached the end of the file name */
7450 if (enddir != expdir)
7451 metaflag++;
7452 p = name;
7453 do {
7454 if (*p == '\\')
7455 p++;
7456 *enddir++ = *p;
7457 } while (*p++);
7458 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7459 addfname(expdir);
7460 return;
7461 }
7462 endname = p;
7463 if (name < start) {
7464 p = name;
7465 do {
7466 if (*p == '\\')
7467 p++;
7468 *enddir++ = *p++;
7469 } while (p < start);
7470 }
7471 if (enddir == expdir) {
7472 cp = ".";
7473 } else if (enddir == expdir + 1 && *expdir == '/') {
7474 cp = "/";
7475 } else {
7476 cp = expdir;
7477 enddir[-1] = '\0';
7478 }
7479 dirp = opendir(cp);
7480 if (dirp == NULL)
7481 return;
7482 if (enddir != expdir)
7483 enddir[-1] = '/';
7484 if (*endname == 0) {
7485 atend = 1;
7486 } else {
7487 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007488 *endname = '\0';
7489 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007490 }
7491 matchdot = 0;
7492 p = start;
7493 if (*p == '\\')
7494 p++;
7495 if (*p == '.')
7496 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007497 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007498 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007499 continue;
7500 if (pmatch(start, dp->d_name)) {
7501 if (atend) {
7502 strcpy(enddir, dp->d_name);
7503 addfname(expdir);
7504 } else {
7505 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7506 continue;
7507 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007508 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007509 }
7510 }
7511 }
7512 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007513 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007514 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007515}
7516
7517static struct strlist *
7518msort(struct strlist *list, int len)
7519{
7520 struct strlist *p, *q = NULL;
7521 struct strlist **lpp;
7522 int half;
7523 int n;
7524
7525 if (len <= 1)
7526 return list;
7527 half = len >> 1;
7528 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007529 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007530 q = p;
7531 p = p->next;
7532 }
7533 q->next = NULL; /* terminate first half of list */
7534 q = msort(list, half); /* sort first half of list */
7535 p = msort(p, len - half); /* sort second half */
7536 lpp = &list;
7537 for (;;) {
7538#if ENABLE_LOCALE_SUPPORT
7539 if (strcoll(p->text, q->text) < 0)
7540#else
7541 if (strcmp(p->text, q->text) < 0)
7542#endif
7543 {
7544 *lpp = p;
7545 lpp = &p->next;
7546 p = *lpp;
7547 if (p == NULL) {
7548 *lpp = q;
7549 break;
7550 }
7551 } else {
7552 *lpp = q;
7553 lpp = &q->next;
7554 q = *lpp;
7555 if (q == NULL) {
7556 *lpp = p;
7557 break;
7558 }
7559 }
7560 }
7561 return list;
7562}
7563
7564/*
7565 * Sort the results of file name expansion. It calculates the number of
7566 * strings to sort and then calls msort (short for merge sort) to do the
7567 * work.
7568 */
7569static struct strlist *
7570expsort(struct strlist *str)
7571{
7572 int len;
7573 struct strlist *sp;
7574
7575 len = 0;
7576 for (sp = str; sp; sp = sp->next)
7577 len++;
7578 return msort(str, len);
7579}
7580
7581static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007582expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007583{
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007584 /* TODO - EXP_REDIR */
7585
7586 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007587 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007588 struct strlist **savelastp;
7589 struct strlist *sp;
7590 char *p;
7591
7592 if (fflag)
7593 goto nometa;
Felix Fietkaub5b21122017-01-31 21:58:55 +01007594 if (!hasmeta(str->text))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007595 goto nometa;
7596 savelastp = exparg.lastp;
7597
7598 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007599 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007600 {
7601 int i = strlen(str->text);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007602//BUGGY estimation of how long expanded name can be
7603 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007604 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007605 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007606 free(expdir);
7607 if (p != str->text)
7608 free(p);
7609 INT_ON;
7610 if (exparg.lastp == savelastp) {
7611 /*
7612 * no matches
7613 */
7614 nometa:
7615 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007616 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007617 exparg.lastp = &str->next;
7618 } else {
7619 *exparg.lastp = NULL;
7620 *savelastp = sp = expsort(*savelastp);
7621 while (sp->next != NULL)
7622 sp = sp->next;
7623 exparg.lastp = &sp->next;
7624 }
7625 str = str->next;
7626 }
7627}
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007628#endif /* ENABLE_ASH_INTERNAL_GLOB */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007629
7630/*
7631 * Perform variable substitution and command substitution on an argument,
7632 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7633 * perform splitting and file name expansion. When arglist is NULL, perform
7634 * here document expansion.
7635 */
7636static void
7637expandarg(union node *arg, struct arglist *arglist, int flag)
7638{
7639 struct strlist *sp;
7640 char *p;
7641
7642 argbackq = arg->narg.backquote;
7643 STARTSTACKSTR(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007644 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007645 argstr(arg->narg.text, flag);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007646 p = _STPUTC('\0', expdest);
7647 expdest = p - 1;
7648 if (arglist == NULL) {
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007649 /* here document expanded */
7650 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007651 }
7652 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007653 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007654 exparg.lastp = &exparg.list;
7655 /*
7656 * TODO - EXP_REDIR
7657 */
7658 if (flag & EXP_FULL) {
7659 ifsbreakup(p, &exparg);
7660 *exparg.lastp = NULL;
7661 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007662 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007663 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +00007664 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007665 sp->text = p;
7666 *exparg.lastp = sp;
7667 exparg.lastp = &sp->next;
7668 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007669 *exparg.lastp = NULL;
7670 if (exparg.list) {
7671 *arglist->lastp = exparg.list;
7672 arglist->lastp = exparg.lastp;
7673 }
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007674
7675 out:
7676 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007677}
7678
7679/*
7680 * Expand shell variables and backquotes inside a here document.
7681 */
7682static void
7683expandhere(union node *arg, int fd)
7684{
Ron Yorston549deab2015-05-18 09:57:51 +02007685 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007686 full_write(fd, stackblock(), expdest - (char *)stackblock());
7687}
7688
7689/*
7690 * Returns true if the pattern matches the string.
7691 */
7692static int
7693patmatch(char *pattern, const char *string)
7694{
Denys Vlasenkobd43c672017-07-05 23:12:15 +02007695 char *p = preglob(pattern, 0);
7696 //bb_error_msg("fnmatch(pattern:'%s',str:'%s')", p, string);
7697 return pmatch(p, string);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007698}
7699
7700/*
7701 * See if a pattern matches in a case statement.
7702 */
7703static int
7704casematch(union node *pattern, char *val)
7705{
7706 struct stackmark smark;
7707 int result;
7708
7709 setstackmark(&smark);
7710 argbackq = pattern->narg.backquote;
7711 STARTSTACKSTR(expdest);
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007712 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007713 STACKSTRNUL(expdest);
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007714 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007715 result = patmatch(stackblock(), val);
7716 popstackmark(&smark);
7717 return result;
7718}
7719
7720
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007721/* ============ find_command */
7722
7723struct builtincmd {
7724 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007725 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007726 /* unsigned flags; */
7727};
7728#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007729/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007730 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007731#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007732#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007733
7734struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007735 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007736 union param {
7737 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007738 /* index >= 0 for commands without path (slashes) */
7739 /* (TODO: what exactly does the value mean? PATH position?) */
7740 /* index == -1 for commands with slashes */
7741 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007742 const struct builtincmd *cmd;
7743 struct funcnode *func;
7744 } u;
7745};
7746/* values of cmdtype */
7747#define CMDUNKNOWN -1 /* no entry in table for command */
7748#define CMDNORMAL 0 /* command is an executable program */
7749#define CMDFUNCTION 1 /* command is a shell function */
7750#define CMDBUILTIN 2 /* command is a shell builtin */
7751
7752/* action to find_command() */
7753#define DO_ERR 0x01 /* prints errors */
7754#define DO_ABS 0x02 /* checks absolute paths */
7755#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7756#define DO_ALTPATH 0x08 /* using alternate path */
7757#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7758
7759static void find_command(char *, struct cmdentry *, int, const char *);
7760
7761
7762/* ============ Hashing commands */
7763
7764/*
7765 * When commands are first encountered, they are entered in a hash table.
7766 * This ensures that a full path search will not have to be done for them
7767 * on each invocation.
7768 *
7769 * We should investigate converting to a linear search, even though that
7770 * would make the command name "hash" a misnomer.
7771 */
7772
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007773struct tblentry {
7774 struct tblentry *next; /* next entry in hash chain */
7775 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007776 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007777 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007778 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007779};
7780
Denis Vlasenko01631112007-12-16 17:20:38 +00007781static struct tblentry **cmdtable;
7782#define INIT_G_cmdtable() do { \
7783 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7784} while (0)
7785
7786static int builtinloc = -1; /* index in path of %builtin, or -1 */
7787
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007788
7789static void
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02007790tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007791{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007792#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007793 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007794 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007795 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007796 while (*envp)
7797 putenv(*envp++);
Denys Vlasenko035486c2017-07-31 04:09:19 +02007798 popredir(/*drop:*/ 1);
Denys Vlasenko69a5ec92017-07-07 19:08:56 +02007799 run_applet_no_and_exit(applet_no, cmd, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007800 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007801 /* re-exec ourselves with the new arguments */
7802 execve(bb_busybox_exec_path, argv, envp);
7803 /* If they called chroot or otherwise made the binary no longer
7804 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007805 }
7806#endif
7807
7808 repeat:
7809#ifdef SYSV
7810 do {
7811 execve(cmd, argv, envp);
7812 } while (errno == EINTR);
7813#else
7814 execve(cmd, argv, envp);
7815#endif
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02007816 if (cmd != bb_busybox_exec_path && errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007817 /* Run "cmd" as a shell script:
7818 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7819 * "If the execve() function fails with ENOEXEC, the shell
7820 * shall execute a command equivalent to having a shell invoked
7821 * with the command name as its first operand,
7822 * with any remaining arguments passed to the new shell"
7823 *
7824 * That is, do not use $SHELL, user's shell, or /bin/sh;
7825 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007826 *
7827 * Note that bash reads ~80 chars of the file, and if it sees
7828 * a zero byte before it sees newline, it doesn't try to
7829 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007830 * message and exit code 126. For one, this prevents attempts
7831 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007832 */
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02007833 argv[0] = (char*) cmd;
7834 cmd = bb_busybox_exec_path;
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007835 /* NB: this is only possible because all callers of shellexec()
7836 * ensure that the argv[-1] slot exists!
7837 */
7838 argv--;
7839 argv[0] = (char*) "ash";
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007840 goto repeat;
7841 }
7842}
7843
7844/*
7845 * Exec a program. Never returns. If you change this routine, you may
7846 * have to change the find_command routine as well.
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007847 * argv[-1] must exist and be writable! See tryexec() for why.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007848 */
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007849static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN;
7850static void shellexec(char *prog, char **argv, const char *path, int idx)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007851{
7852 char *cmdname;
7853 int e;
7854 char **envp;
7855 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007856 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007857
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007858 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007859 if (strchr(prog, '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007860#if ENABLE_FEATURE_SH_STANDALONE
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007861 || (applet_no = find_applet_by_name(prog)) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007862#endif
7863 ) {
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007864 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007865 if (applet_no >= 0) {
7866 /* We tried execing ourself, but it didn't work.
7867 * Maybe /proc/self/exe doesn't exist?
7868 * Try $PATH search.
7869 */
7870 goto try_PATH;
7871 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007872 e = errno;
7873 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007874 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007875 e = ENOENT;
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007876 while ((cmdname = path_advance(&path, prog)) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007877 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007878 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007879 if (errno != ENOENT && errno != ENOTDIR)
7880 e = errno;
7881 }
7882 stunalloc(cmdname);
7883 }
7884 }
7885
7886 /* Map to POSIX errors */
7887 switch (e) {
7888 case EACCES:
7889 exerrno = 126;
7890 break;
7891 case ENOENT:
7892 exerrno = 127;
7893 break;
7894 default:
7895 exerrno = 2;
7896 break;
7897 }
7898 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007899 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007900 prog, e, suppress_int));
7901 ash_msg_and_raise(EXEXIT, "%s: %s", prog, errmsg(e, "not found"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007902 /* NOTREACHED */
7903}
7904
7905static void
7906printentry(struct tblentry *cmdp)
7907{
7908 int idx;
7909 const char *path;
7910 char *name;
7911
7912 idx = cmdp->param.index;
7913 path = pathval();
7914 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007915 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007916 stunalloc(name);
7917 } while (--idx >= 0);
7918 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7919}
7920
7921/*
7922 * Clear out command entries. The argument specifies the first entry in
7923 * PATH which has changed.
7924 */
7925static void
7926clearcmdentry(int firstchange)
7927{
7928 struct tblentry **tblp;
7929 struct tblentry **pp;
7930 struct tblentry *cmdp;
7931
7932 INT_OFF;
7933 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7934 pp = tblp;
7935 while ((cmdp = *pp) != NULL) {
7936 if ((cmdp->cmdtype == CMDNORMAL &&
7937 cmdp->param.index >= firstchange)
7938 || (cmdp->cmdtype == CMDBUILTIN &&
7939 builtinloc >= firstchange)
7940 ) {
7941 *pp = cmdp->next;
7942 free(cmdp);
7943 } else {
7944 pp = &cmdp->next;
7945 }
7946 }
7947 }
7948 INT_ON;
7949}
7950
7951/*
7952 * Locate a command in the command hash table. If "add" is nonzero,
7953 * add the command to the table if it is not already present. The
7954 * variable "lastcmdentry" is set to point to the address of the link
7955 * pointing to the entry, so that delete_cmd_entry can delete the
7956 * entry.
7957 *
7958 * Interrupts must be off if called with add != 0.
7959 */
7960static struct tblentry **lastcmdentry;
7961
7962static struct tblentry *
7963cmdlookup(const char *name, int add)
7964{
7965 unsigned int hashval;
7966 const char *p;
7967 struct tblentry *cmdp;
7968 struct tblentry **pp;
7969
7970 p = name;
7971 hashval = (unsigned char)*p << 4;
7972 while (*p)
7973 hashval += (unsigned char)*p++;
7974 hashval &= 0x7FFF;
7975 pp = &cmdtable[hashval % CMDTABLESIZE];
7976 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7977 if (strcmp(cmdp->cmdname, name) == 0)
7978 break;
7979 pp = &cmdp->next;
7980 }
7981 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007982 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7983 + strlen(name)
7984 /* + 1 - already done because
7985 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007986 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007987 cmdp->cmdtype = CMDUNKNOWN;
7988 strcpy(cmdp->cmdname, name);
7989 }
7990 lastcmdentry = pp;
7991 return cmdp;
7992}
7993
7994/*
7995 * Delete the command entry returned on the last lookup.
7996 */
7997static void
7998delete_cmd_entry(void)
7999{
8000 struct tblentry *cmdp;
8001
8002 INT_OFF;
8003 cmdp = *lastcmdentry;
8004 *lastcmdentry = cmdp->next;
8005 if (cmdp->cmdtype == CMDFUNCTION)
8006 freefunc(cmdp->param.func);
8007 free(cmdp);
8008 INT_ON;
8009}
8010
8011/*
8012 * Add a new command entry, replacing any existing command entry for
8013 * the same name - except special builtins.
8014 */
8015static void
8016addcmdentry(char *name, struct cmdentry *entry)
8017{
8018 struct tblentry *cmdp;
8019
8020 cmdp = cmdlookup(name, 1);
8021 if (cmdp->cmdtype == CMDFUNCTION) {
8022 freefunc(cmdp->param.func);
8023 }
8024 cmdp->cmdtype = entry->cmdtype;
8025 cmdp->param = entry->u;
8026 cmdp->rehash = 0;
8027}
8028
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008029static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008030hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008031{
8032 struct tblentry **pp;
8033 struct tblentry *cmdp;
8034 int c;
8035 struct cmdentry entry;
8036 char *name;
8037
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008038 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008039 clearcmdentry(0);
8040 return 0;
8041 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008042
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008043 if (*argptr == NULL) {
8044 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8045 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8046 if (cmdp->cmdtype == CMDNORMAL)
8047 printentry(cmdp);
8048 }
8049 }
8050 return 0;
8051 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008052
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008053 c = 0;
8054 while ((name = *argptr) != NULL) {
8055 cmdp = cmdlookup(name, 0);
8056 if (cmdp != NULL
8057 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008058 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
8059 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008060 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008061 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008062 find_command(name, &entry, DO_ERR, pathval());
8063 if (entry.cmdtype == CMDUNKNOWN)
8064 c = 1;
8065 argptr++;
8066 }
8067 return c;
8068}
8069
8070/*
8071 * Called when a cd is done. Marks all commands so the next time they
8072 * are executed they will be rehashed.
8073 */
8074static void
8075hashcd(void)
8076{
8077 struct tblentry **pp;
8078 struct tblentry *cmdp;
8079
8080 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8081 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008082 if (cmdp->cmdtype == CMDNORMAL
8083 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02008084 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008085 && builtinloc > 0)
8086 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008087 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008088 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008089 }
8090 }
8091}
8092
8093/*
8094 * Fix command hash table when PATH changed.
8095 * Called before PATH is changed. The argument is the new value of PATH;
8096 * pathval() still returns the old value at this point.
8097 * Called with interrupts off.
8098 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008099static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008100changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008101{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008102 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008103 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008104 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008105 int idx_bltin;
8106
8107 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008108 firstchange = 9999; /* assume no change */
8109 idx = 0;
8110 idx_bltin = -1;
8111 for (;;) {
8112 if (*old != *new) {
8113 firstchange = idx;
8114 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008115 || (*old == ':' && *new == '\0')
8116 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008117 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008118 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008119 old = new; /* ignore subsequent differences */
8120 }
8121 if (*new == '\0')
8122 break;
8123 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
8124 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008125 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008126 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008127 new++;
8128 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008129 }
8130 if (builtinloc < 0 && idx_bltin >= 0)
8131 builtinloc = idx_bltin; /* zap builtins */
8132 if (builtinloc >= 0 && idx_bltin < 0)
8133 firstchange = 0;
8134 clearcmdentry(firstchange);
8135 builtinloc = idx_bltin;
8136}
Ron Yorston95ebcf72015-11-03 09:42:23 +00008137enum {
8138 TEOF,
8139 TNL,
8140 TREDIR,
8141 TWORD,
8142 TSEMI,
8143 TBACKGND,
8144 TAND,
8145 TOR,
8146 TPIPE,
8147 TLP,
8148 TRP,
8149 TENDCASE,
8150 TENDBQUOTE,
8151 TNOT,
8152 TCASE,
8153 TDO,
8154 TDONE,
8155 TELIF,
8156 TELSE,
8157 TESAC,
8158 TFI,
8159 TFOR,
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008160#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +00008161 TFUNCTION,
8162#endif
8163 TIF,
8164 TIN,
8165 TTHEN,
8166 TUNTIL,
8167 TWHILE,
8168 TBEGIN,
8169 TEND
8170};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008171typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008172
Denys Vlasenko888527c2016-10-02 16:54:17 +02008173/* Nth bit indicates if token marks the end of a list */
8174enum {
8175 tokendlist = 0
8176 /* 0 */ | (1u << TEOF)
8177 /* 1 */ | (0u << TNL)
8178 /* 2 */ | (0u << TREDIR)
8179 /* 3 */ | (0u << TWORD)
8180 /* 4 */ | (0u << TSEMI)
8181 /* 5 */ | (0u << TBACKGND)
8182 /* 6 */ | (0u << TAND)
8183 /* 7 */ | (0u << TOR)
8184 /* 8 */ | (0u << TPIPE)
8185 /* 9 */ | (0u << TLP)
8186 /* 10 */ | (1u << TRP)
8187 /* 11 */ | (1u << TENDCASE)
8188 /* 12 */ | (1u << TENDBQUOTE)
8189 /* 13 */ | (0u << TNOT)
8190 /* 14 */ | (0u << TCASE)
8191 /* 15 */ | (1u << TDO)
8192 /* 16 */ | (1u << TDONE)
8193 /* 17 */ | (1u << TELIF)
8194 /* 18 */ | (1u << TELSE)
8195 /* 19 */ | (1u << TESAC)
8196 /* 20 */ | (1u << TFI)
8197 /* 21 */ | (0u << TFOR)
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008198#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008199 /* 22 */ | (0u << TFUNCTION)
Denys Vlasenko80729a42016-10-02 22:33:15 +02008200#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008201 /* 23 */ | (0u << TIF)
8202 /* 24 */ | (0u << TIN)
8203 /* 25 */ | (1u << TTHEN)
8204 /* 26 */ | (0u << TUNTIL)
8205 /* 27 */ | (0u << TWHILE)
8206 /* 28 */ | (0u << TBEGIN)
8207 /* 29 */ | (1u << TEND)
8208 , /* thus far 29 bits used */
8209};
8210
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008211static const char *const tokname_array[] = {
Denys Vlasenko888527c2016-10-02 16:54:17 +02008212 "end of file",
8213 "newline",
8214 "redirection",
8215 "word",
8216 ";",
8217 "&",
8218 "&&",
8219 "||",
8220 "|",
8221 "(",
8222 ")",
8223 ";;",
8224 "`",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008225#define KWDOFFSET 13
8226 /* the following are keywords */
Denys Vlasenko888527c2016-10-02 16:54:17 +02008227 "!",
8228 "case",
8229 "do",
8230 "done",
8231 "elif",
8232 "else",
8233 "esac",
8234 "fi",
8235 "for",
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008236#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008237 "function",
Ron Yorston95ebcf72015-11-03 09:42:23 +00008238#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008239 "if",
8240 "in",
8241 "then",
8242 "until",
8243 "while",
8244 "{",
8245 "}",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008246};
8247
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008248/* Wrapper around strcmp for qsort/bsearch/... */
8249static int
8250pstrcmp(const void *a, const void *b)
8251{
Denys Vlasenko888527c2016-10-02 16:54:17 +02008252 return strcmp((char*)a, *(char**)b);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008253}
8254
8255static const char *const *
8256findkwd(const char *s)
8257{
8258 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00008259 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8260 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008261}
8262
8263/*
8264 * Locate and print what a word is...
8265 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008266static int
Ron Yorston3f221112015-08-03 13:47:33 +01008267describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008268{
8269 struct cmdentry entry;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008270#if ENABLE_ASH_ALIAS
8271 const struct alias *ap;
8272#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008273
8274 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008275
8276 if (describe_command_verbose) {
8277 out1str(command);
8278 }
8279
8280 /* First look at the keywords */
8281 if (findkwd(command)) {
8282 out1str(describe_command_verbose ? " is a shell keyword" : command);
8283 goto out;
8284 }
8285
8286#if ENABLE_ASH_ALIAS
8287 /* Then look at the aliases */
8288 ap = lookupalias(command, 0);
8289 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008290 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008291 out1str("alias ");
8292 printalias(ap);
8293 return 0;
8294 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00008295 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008296 goto out;
8297 }
8298#endif
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008299 /* Brute force */
8300 find_command(command, &entry, DO_ABS, path);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008301
8302 switch (entry.cmdtype) {
8303 case CMDNORMAL: {
8304 int j = entry.u.index;
8305 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008306 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008307 p = command;
8308 } else {
8309 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008310 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008311 stunalloc(p);
8312 } while (--j >= 0);
8313 }
8314 if (describe_command_verbose) {
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008315 out1fmt(" is %s", p);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008316 } else {
8317 out1str(p);
8318 }
8319 break;
8320 }
8321
8322 case CMDFUNCTION:
8323 if (describe_command_verbose) {
8324 out1str(" is a shell function");
8325 } else {
8326 out1str(command);
8327 }
8328 break;
8329
8330 case CMDBUILTIN:
8331 if (describe_command_verbose) {
8332 out1fmt(" is a %sshell builtin",
8333 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8334 "special " : nullstr
8335 );
8336 } else {
8337 out1str(command);
8338 }
8339 break;
8340
8341 default:
8342 if (describe_command_verbose) {
8343 out1str(": not found\n");
8344 }
8345 return 127;
8346 }
8347 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008348 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008349 return 0;
8350}
8351
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008352static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008353typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008354{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008355 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008356 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008357 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008358
Denis Vlasenko46846e22007-05-20 13:08:31 +00008359 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008360 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008361 i++;
8362 verbose = 0;
8363 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008364 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008365 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008366 }
8367 return err;
8368}
8369
8370#if ENABLE_ASH_CMDCMD
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008371/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8372static char **
8373parse_command_args(char **argv, const char **path)
8374{
8375 char *cp, c;
8376
8377 for (;;) {
8378 cp = *++argv;
8379 if (!cp)
8380 return NULL;
8381 if (*cp++ != '-')
8382 break;
8383 c = *cp++;
8384 if (!c)
8385 break;
8386 if (c == '-' && !*cp) {
8387 if (!*++argv)
8388 return NULL;
8389 break;
8390 }
8391 do {
8392 switch (c) {
8393 case 'p':
8394 *path = bb_default_path;
8395 break;
8396 default:
8397 /* run 'typecmd' for other options */
8398 return NULL;
8399 }
8400 c = *cp++;
8401 } while (c);
8402 }
8403 return argv;
8404}
8405
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008406static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008407commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008408{
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008409 char *cmd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008410 int c;
8411 enum {
8412 VERIFY_BRIEF = 1,
8413 VERIFY_VERBOSE = 2,
8414 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008415 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008416
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008417 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8418 * never reaches this function.
8419 */
8420
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008421 while ((c = nextopt("pvV")) != '\0')
8422 if (c == 'V')
8423 verify |= VERIFY_VERBOSE;
8424 else if (c == 'v')
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008425 /*verify |= VERIFY_BRIEF*/;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008426#if DEBUG
8427 else if (c != 'p')
8428 abort();
8429#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008430 else
8431 path = bb_default_path;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008432
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008433 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008434 cmd = *argptr;
8435 if (/*verify && */ cmd)
8436 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008437
8438 return 0;
8439}
8440#endif
8441
8442
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008443/*static int funcblocksize; // size of structures in function */
8444/*static int funcstringsize; // size of strings in node */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008445static void *funcblock; /* block to allocate function from */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008446static char *funcstring_end; /* end of block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008447
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008448static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008449 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8450 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8451 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8452 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8453 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8454 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8455 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8456 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8457 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8458 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8459 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8460 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8461 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8462 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8463 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8464 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8465 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008466#if BASH_REDIR_OUTPUT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008467 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008468#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008469 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8470 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8471 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8472 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8473 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8474 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8475 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8476 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8477 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008478};
8479
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008480static int calcsize(int funcblocksize, union node *n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008481
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008482static int
8483sizenodelist(int funcblocksize, struct nodelist *lp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008484{
8485 while (lp) {
8486 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008487 funcblocksize = calcsize(funcblocksize, lp->n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008488 lp = lp->next;
8489 }
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008490 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008491}
8492
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008493static int
8494calcsize(int funcblocksize, union node *n)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008495{
8496 if (n == NULL)
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008497 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008498 funcblocksize += nodesize[n->type];
8499 switch (n->type) {
8500 case NCMD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008501 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8502 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8503 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008504 break;
8505 case NPIPE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008506 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008507 break;
8508 case NREDIR:
8509 case NBACKGND:
8510 case NSUBSHELL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008511 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8512 funcblocksize = calcsize(funcblocksize, n->nredir.n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008513 break;
8514 case NAND:
8515 case NOR:
8516 case NSEMI:
8517 case NWHILE:
8518 case NUNTIL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008519 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8520 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008521 break;
8522 case NIF:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008523 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8524 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8525 funcblocksize = calcsize(funcblocksize, n->nif.test);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008526 break;
8527 case NFOR:
Denys Vlasenko561639a2016-10-07 04:28:33 +02008528 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008529 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8530 funcblocksize = calcsize(funcblocksize, n->nfor.args);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008531 break;
8532 case NCASE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008533 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8534 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008535 break;
8536 case NCLIST:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008537 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8538 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8539 funcblocksize = calcsize(funcblocksize, n->nclist.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008540 break;
8541 case NDEFUN:
8542 case NARG:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008543 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
Denys Vlasenko561639a2016-10-07 04:28:33 +02008544 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008545 funcblocksize = calcsize(funcblocksize, n->narg.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008546 break;
8547 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008548#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008549 case NTO2:
8550#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008551 case NCLOBBER:
8552 case NFROM:
8553 case NFROMTO:
8554 case NAPPEND:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008555 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8556 funcblocksize = calcsize(funcblocksize, n->nfile.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008557 break;
8558 case NTOFD:
8559 case NFROMFD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008560 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8561 funcblocksize = calcsize(funcblocksize, n->ndup.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008562 break;
8563 case NHERE:
8564 case NXHERE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008565 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8566 funcblocksize = calcsize(funcblocksize, n->nhere.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008567 break;
8568 case NNOT:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008569 funcblocksize = calcsize(funcblocksize, n->nnot.com);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008570 break;
8571 };
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008572 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008573}
8574
8575static char *
8576nodeckstrdup(char *s)
8577{
Denys Vlasenko561639a2016-10-07 04:28:33 +02008578 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008579 return strcpy(funcstring_end, s);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008580}
8581
8582static union node *copynode(union node *);
8583
8584static struct nodelist *
8585copynodelist(struct nodelist *lp)
8586{
8587 struct nodelist *start;
8588 struct nodelist **lpp;
8589
8590 lpp = &start;
8591 while (lp) {
8592 *lpp = funcblock;
8593 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8594 (*lpp)->n = copynode(lp->n);
8595 lp = lp->next;
8596 lpp = &(*lpp)->next;
8597 }
8598 *lpp = NULL;
8599 return start;
8600}
8601
8602static union node *
8603copynode(union node *n)
8604{
8605 union node *new;
8606
8607 if (n == NULL)
8608 return NULL;
8609 new = funcblock;
8610 funcblock = (char *) funcblock + nodesize[n->type];
8611
8612 switch (n->type) {
8613 case NCMD:
8614 new->ncmd.redirect = copynode(n->ncmd.redirect);
8615 new->ncmd.args = copynode(n->ncmd.args);
8616 new->ncmd.assign = copynode(n->ncmd.assign);
8617 break;
8618 case NPIPE:
8619 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008620 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008621 break;
8622 case NREDIR:
8623 case NBACKGND:
8624 case NSUBSHELL:
8625 new->nredir.redirect = copynode(n->nredir.redirect);
8626 new->nredir.n = copynode(n->nredir.n);
8627 break;
8628 case NAND:
8629 case NOR:
8630 case NSEMI:
8631 case NWHILE:
8632 case NUNTIL:
8633 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8634 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8635 break;
8636 case NIF:
8637 new->nif.elsepart = copynode(n->nif.elsepart);
8638 new->nif.ifpart = copynode(n->nif.ifpart);
8639 new->nif.test = copynode(n->nif.test);
8640 break;
8641 case NFOR:
8642 new->nfor.var = nodeckstrdup(n->nfor.var);
8643 new->nfor.body = copynode(n->nfor.body);
8644 new->nfor.args = copynode(n->nfor.args);
8645 break;
8646 case NCASE:
8647 new->ncase.cases = copynode(n->ncase.cases);
8648 new->ncase.expr = copynode(n->ncase.expr);
8649 break;
8650 case NCLIST:
8651 new->nclist.body = copynode(n->nclist.body);
8652 new->nclist.pattern = copynode(n->nclist.pattern);
8653 new->nclist.next = copynode(n->nclist.next);
8654 break;
8655 case NDEFUN:
8656 case NARG:
8657 new->narg.backquote = copynodelist(n->narg.backquote);
8658 new->narg.text = nodeckstrdup(n->narg.text);
8659 new->narg.next = copynode(n->narg.next);
8660 break;
8661 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008662#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008663 case NTO2:
8664#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008665 case NCLOBBER:
8666 case NFROM:
8667 case NFROMTO:
8668 case NAPPEND:
8669 new->nfile.fname = copynode(n->nfile.fname);
8670 new->nfile.fd = n->nfile.fd;
8671 new->nfile.next = copynode(n->nfile.next);
8672 break;
8673 case NTOFD:
8674 case NFROMFD:
8675 new->ndup.vname = copynode(n->ndup.vname);
8676 new->ndup.dupfd = n->ndup.dupfd;
8677 new->ndup.fd = n->ndup.fd;
8678 new->ndup.next = copynode(n->ndup.next);
8679 break;
8680 case NHERE:
8681 case NXHERE:
8682 new->nhere.doc = copynode(n->nhere.doc);
8683 new->nhere.fd = n->nhere.fd;
8684 new->nhere.next = copynode(n->nhere.next);
8685 break;
8686 case NNOT:
8687 new->nnot.com = copynode(n->nnot.com);
8688 break;
8689 };
8690 new->type = n->type;
8691 return new;
8692}
8693
8694/*
8695 * Make a copy of a parse tree.
8696 */
8697static struct funcnode *
8698copyfunc(union node *n)
8699{
8700 struct funcnode *f;
8701 size_t blocksize;
8702
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008703 /*funcstringsize = 0;*/
8704 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8705 f = ckzalloc(blocksize /* + funcstringsize */);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008706 funcblock = (char *) f + offsetof(struct funcnode, n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008707 funcstring_end = (char *) f + blocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008708 copynode(n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008709 /* f->count = 0; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008710 return f;
8711}
8712
8713/*
8714 * Define a shell function.
8715 */
8716static void
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008717defun(union node *func)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008718{
8719 struct cmdentry entry;
8720
8721 INT_OFF;
8722 entry.cmdtype = CMDFUNCTION;
8723 entry.u.func = copyfunc(func);
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008724 addcmdentry(func->narg.text, &entry);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008725 INT_ON;
8726}
8727
Denis Vlasenko4b875702009-03-19 13:30:04 +00008728/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008729#define SKIPBREAK (1 << 0)
8730#define SKIPCONT (1 << 1)
8731#define SKIPFUNC (1 << 2)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008732static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008733static int skipcount; /* number of levels to skip */
8734static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008735static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008736
Denis Vlasenko4b875702009-03-19 13:30:04 +00008737/* Forward decl way out to parsing code - dotrap needs it */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008738static int evalstring(char *s, int flags);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008739
Denis Vlasenko4b875702009-03-19 13:30:04 +00008740/* Called to execute a trap.
8741 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008742 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008743 *
8744 * Perhaps we should avoid entering new trap handlers
8745 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008746 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008747static void
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008748dotrap(void)
8749{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008750 uint8_t *g;
8751 int sig;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008752 uint8_t last_status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008753
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008754 if (!pending_sig)
8755 return;
8756
8757 last_status = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008758 pending_sig = 0;
Denys Vlasenkode892052016-10-02 01:49:13 +02008759 barrier();
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008760
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008761 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008762 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008763 char *p;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008764
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008765 if (!*g)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008766 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008767
8768 if (evalskip) {
8769 pending_sig = sig;
8770 break;
8771 }
8772
8773 p = trap[sig];
Denis Vlasenko4b875702009-03-19 13:30:04 +00008774 /* non-trapped SIGINT is handled separately by raise_interrupt,
8775 * don't upset it by resetting gotsig[SIGINT-1] */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008776 if (sig == SIGINT && !p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008777 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008778
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008779 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008780 *g = 0;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008781 if (!p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008782 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008783 evalstring(p, 0);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008784 }
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008785 exitstatus = last_status;
8786 TRACE(("dotrap returns\n"));
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008787}
8788
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008789/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008790static int evalloop(union node *, int);
8791static int evalfor(union node *, int);
8792static int evalcase(union node *, int);
8793static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008794static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008795static int evalpipe(union node *, int);
8796static int evalcommand(union node *, int);
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008797static int evalbltin(const struct builtincmd *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008798static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008799
Eric Andersen62483552001-07-10 06:09:16 +00008800/*
Eric Andersenc470f442003-07-28 09:56:35 +00008801 * Evaluate a parse tree. The value is left in the global variable
8802 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008803 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008804static int
Eric Andersenc470f442003-07-28 09:56:35 +00008805evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008806{
Eric Andersenc470f442003-07-28 09:56:35 +00008807 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008808 int (*evalfn)(union node *, int);
8809 int status = 0;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008810
Eric Andersenc470f442003-07-28 09:56:35 +00008811 if (n == NULL) {
8812 TRACE(("evaltree(NULL) called\n"));
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02008813 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00008814 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008815 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008816
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008817 dotrap();
8818
Eric Andersenc470f442003-07-28 09:56:35 +00008819 switch (n->type) {
8820 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008821#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008822 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008823 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008824 break;
8825#endif
8826 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008827 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008828 goto setstatus;
8829 case NREDIR:
8830 expredir(n->nredir.redirect);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02008831 pushredir(n->nredir.redirect);
Eric Andersenc470f442003-07-28 09:56:35 +00008832 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8833 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008834 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008835 }
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02008836 if (n->nredir.redirect)
Denys Vlasenko035486c2017-07-31 04:09:19 +02008837 popredir(/*drop:*/ 0);
Eric Andersenc470f442003-07-28 09:56:35 +00008838 goto setstatus;
8839 case NCMD:
8840 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008841 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008842 if (eflag && !(flags & EV_TESTED))
8843 checkexit = ~0;
8844 goto calleval;
8845 case NFOR:
8846 evalfn = evalfor;
8847 goto calleval;
8848 case NWHILE:
8849 case NUNTIL:
8850 evalfn = evalloop;
8851 goto calleval;
8852 case NSUBSHELL:
8853 case NBACKGND:
8854 evalfn = evalsubshell;
Denys Vlasenkocf98b0c2016-10-25 18:19:39 +02008855 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00008856 case NPIPE:
8857 evalfn = evalpipe;
8858 goto checkexit;
8859 case NCASE:
8860 evalfn = evalcase;
8861 goto calleval;
8862 case NAND:
8863 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008864 case NSEMI: {
8865
Eric Andersenc470f442003-07-28 09:56:35 +00008866#if NAND + 1 != NOR
8867#error NAND + 1 != NOR
8868#endif
8869#if NOR + 1 != NSEMI
8870#error NOR + 1 != NSEMI
8871#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008872 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008873 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00008874 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008875 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008876 );
Denys Vlasenkobc1a0082016-10-02 15:31:33 +02008877 if ((!status) == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00008878 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008879 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008880 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008881 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008882 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008883 status = evalfn(n, flags);
8884 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008885 }
Eric Andersenc470f442003-07-28 09:56:35 +00008886 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008887 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008888 if (evalskip)
8889 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008890 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00008891 n = n->nif.ifpart;
8892 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008893 }
8894 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008895 n = n->nif.elsepart;
8896 goto evaln;
8897 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008898 status = 0;
8899 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00008900 case NDEFUN:
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008901 defun(n);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008902 /* Not necessary. To test it:
8903 * "false; f() { qwerty; }; echo $?" should print 0.
8904 */
8905 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008906 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00008907 exitstatus = status;
8908 break;
8909 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008910 out:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008911 /* Order of checks below is important:
8912 * signal handlers trigger before exit caused by "set -e".
8913 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008914 dotrap();
8915
8916 if (checkexit & status)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008917 raise_exception(EXEXIT);
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008918 if (flags & EV_EXIT)
8919 raise_exception(EXEXIT);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008920
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008921 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008922 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00008923}
8924
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02008925static int
8926skiploop(void)
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008927{
8928 int skip = evalskip;
8929
8930 switch (skip) {
8931 case 0:
8932 break;
8933 case SKIPBREAK:
8934 case SKIPCONT:
8935 if (--skipcount <= 0) {
8936 evalskip = 0;
8937 break;
8938 }
8939 skip = SKIPBREAK;
8940 break;
8941 }
8942 return skip;
8943}
8944
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008945static int
Eric Andersenc470f442003-07-28 09:56:35 +00008946evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008947{
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008948 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00008949 int status;
8950
8951 loopnest++;
8952 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008953 flags &= EV_TESTED;
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008954 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008955 int i;
8956
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008957 i = evaltree(n->nbinary.ch1, EV_TESTED);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008958 skip = skiploop();
8959 if (skip == SKIPFUNC)
8960 status = i;
8961 if (skip)
8962 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00008963 if (n->type != NWHILE)
8964 i = !i;
8965 if (i != 0)
8966 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008967 status = evaltree(n->nbinary.ch2, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008968 skip = skiploop();
8969 } while (!(skip & ~SKIPCONT));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008970 loopnest--;
8971
8972 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008973}
8974
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008975static int
Eric Andersenc470f442003-07-28 09:56:35 +00008976evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008977{
8978 struct arglist arglist;
8979 union node *argp;
8980 struct strlist *sp;
8981 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008982 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008983
8984 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008985 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008986 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008987 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02008988 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersencb57d552001-06-28 07:25:16 +00008989 }
8990 *arglist.lastp = NULL;
8991
Eric Andersencb57d552001-06-28 07:25:16 +00008992 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008993 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008994 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008995 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008996 status = evaltree(n->nfor.body, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008997 if (skiploop() & ~SKIPCONT)
Eric Andersencb57d552001-06-28 07:25:16 +00008998 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008999 }
9000 loopnest--;
Eric Andersencb57d552001-06-28 07:25:16 +00009001 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009002
9003 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009004}
9005
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009006static int
Eric Andersenc470f442003-07-28 09:56:35 +00009007evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009008{
9009 union node *cp;
9010 union node *patp;
9011 struct arglist arglist;
9012 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009013 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009014
9015 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009016 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00009017 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00009018 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009019 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
9020 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00009021 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009022 /* Ensure body is non-empty as otherwise
9023 * EV_EXIT may prevent us from setting the
9024 * exit status.
9025 */
9026 if (evalskip == 0 && cp->nclist.body) {
9027 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00009028 }
9029 goto out;
9030 }
9031 }
9032 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009033 out:
Eric Andersencb57d552001-06-28 07:25:16 +00009034 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009035
9036 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009037}
9038
Eric Andersenc470f442003-07-28 09:56:35 +00009039/*
9040 * Kick off a subshell to evaluate a tree.
9041 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009042static int
Eric Andersenc470f442003-07-28 09:56:35 +00009043evalsubshell(union node *n, int flags)
9044{
9045 struct job *jp;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009046 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
Eric Andersenc470f442003-07-28 09:56:35 +00009047 int status;
9048
9049 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02009050 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00009051 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009052 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009053 if (backgnd == FORK_FG)
9054 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009055 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009056 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009057 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009058 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009059 flags |= EV_EXIT;
9060 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02009061 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00009062 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00009063 redirect(n->nredir.redirect, 0);
9064 evaltreenr(n->nredir.n, flags);
9065 /* never returns */
9066 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009067 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00009068 status = 0;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009069 if (backgnd == FORK_FG)
Eric Andersenc470f442003-07-28 09:56:35 +00009070 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009071 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009072 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009073}
9074
Eric Andersenc470f442003-07-28 09:56:35 +00009075/*
9076 * Compute the names of the files in a redirection list.
9077 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009078static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00009079static void
9080expredir(union node *n)
9081{
9082 union node *redir;
9083
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009084 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009085 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009086
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009087 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009088 fn.lastp = &fn.list;
9089 switch (redir->type) {
9090 case NFROMTO:
9091 case NFROM:
9092 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009093#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009094 case NTO2:
9095#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009096 case NCLOBBER:
9097 case NAPPEND:
9098 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02009099 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009100#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009101 store_expfname:
9102#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009103#if 0
9104// By the design of stack allocator, the loop of this kind:
9105// while true; do while true; do break; done </dev/null; done
9106// will look like a memory leak: ash plans to free expfname's
9107// of "/dev/null" as soon as it finishes running the loop
9108// (in this case, never).
9109// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01009110 if (redir->nfile.expfname)
9111 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009112// It results in corrupted state of stacked allocations.
9113#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009114 redir->nfile.expfname = fn.list->text;
9115 break;
9116 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00009117 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00009118 if (redir->ndup.vname) {
9119 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009120 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009121 ash_msg_and_raise_error("redir error");
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009122#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009123//FIXME: we used expandarg with different args!
9124 if (!isdigit_str9(fn.list->text)) {
9125 /* >&file, not >&fd */
9126 if (redir->nfile.fd != 1) /* 123>&file - BAD */
9127 ash_msg_and_raise_error("redir error");
9128 redir->type = NTO2;
9129 goto store_expfname;
9130 }
9131#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009132 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009133 }
9134 break;
9135 }
9136 }
9137}
9138
Eric Andersencb57d552001-06-28 07:25:16 +00009139/*
Eric Andersencb57d552001-06-28 07:25:16 +00009140 * Evaluate a pipeline. All the processes in the pipeline are children
9141 * of the process creating the pipeline. (This differs from some versions
9142 * of the shell, which make the last process in a pipeline the parent
9143 * of all the rest.)
9144 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009145static int
Eric Andersenc470f442003-07-28 09:56:35 +00009146evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009147{
9148 struct job *jp;
9149 struct nodelist *lp;
9150 int pipelen;
9151 int prevfd;
9152 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009153 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009154
Eric Andersenc470f442003-07-28 09:56:35 +00009155 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00009156 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009157 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00009158 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009159 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009160 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009161 if (n->npipe.pipe_backgnd == 0)
9162 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009163 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00009164 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009165 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009166 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00009167 pip[1] = -1;
9168 if (lp->next) {
9169 if (pipe(pip) < 0) {
9170 close(prevfd);
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00009171 ash_msg_and_raise_error("pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00009172 }
9173 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009174 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02009175 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009176 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00009177 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009178 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00009179 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009180 if (prevfd > 0) {
9181 dup2(prevfd, 0);
9182 close(prevfd);
9183 }
9184 if (pip[1] > 1) {
9185 dup2(pip[1], 1);
9186 close(pip[1]);
9187 }
Eric Andersenc470f442003-07-28 09:56:35 +00009188 evaltreenr(lp->n, flags);
9189 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00009190 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009191 /* parent */
Eric Andersencb57d552001-06-28 07:25:16 +00009192 if (prevfd >= 0)
9193 close(prevfd);
9194 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00009195 /* Don't want to trigger debugging */
9196 if (pip[1] != -1)
9197 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009198 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009199 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009200 status = waitforjob(jp);
9201 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00009202 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009203 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009204
9205 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009206}
9207
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009208/*
9209 * Controls whether the shell is interactive or not.
9210 */
9211static void
9212setinteractive(int on)
9213{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009214 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009215
9216 if (++on == is_interactive)
9217 return;
9218 is_interactive = on;
9219 setsignal(SIGINT);
9220 setsignal(SIGQUIT);
9221 setsignal(SIGTERM);
9222#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9223 if (is_interactive > 1) {
9224 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009225 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009226
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009227 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009228 /* note: ash and hush share this string */
9229 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009230 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9231 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009232 bb_banner,
9233 "built-in shell (ash)"
9234 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009235 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009236 }
9237 }
9238#endif
9239}
9240
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009241static void
9242optschanged(void)
9243{
9244#if DEBUG
9245 opentrace();
9246#endif
9247 setinteractive(iflag);
9248 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009249#if ENABLE_FEATURE_EDITING_VI
9250 if (viflag)
9251 line_input_state->flags |= VI_MODE;
9252 else
9253 line_input_state->flags &= ~VI_MODE;
9254#else
9255 viflag = 0; /* forcibly keep the option off */
9256#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009257}
9258
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009259struct localvar_list {
9260 struct localvar_list *next;
9261 struct localvar *lv;
9262};
9263
9264static struct localvar_list *localvar_stack;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009265
9266/*
9267 * Called after a function returns.
9268 * Interrupts must be off.
9269 */
9270static void
Denys Vlasenko981a0562017-07-26 19:53:11 +02009271poplocalvars(int keep)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009272{
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009273 struct localvar_list *ll;
9274 struct localvar *lvp, *next;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009275 struct var *vp;
9276
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009277 INT_OFF;
9278 ll = localvar_stack;
9279 localvar_stack = ll->next;
9280
9281 next = ll->lv;
9282 free(ll);
9283
9284 while ((lvp = next) != NULL) {
9285 next = lvp->next;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009286 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02009287 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denys Vlasenko981a0562017-07-26 19:53:11 +02009288 if (keep) {
9289 int bits = VSTRFIXED;
9290
9291 if (lvp->flags != VUNSET) {
9292 if (vp->var_text == lvp->text)
9293 bits |= VTEXTFIXED;
9294 else if (!(lvp->flags & (VTEXTFIXED|VSTACK)))
9295 free((char*)lvp->text);
9296 }
9297
9298 vp->flags &= ~bits;
9299 vp->flags |= (lvp->flags & bits);
9300
9301 if ((vp->flags &
9302 (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
9303 unsetvar(vp->var_text);
9304 } else if (vp == NULL) { /* $- saved */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009305 memcpy(optlist, lvp->text, sizeof(optlist));
9306 free((char*)lvp->text);
9307 optschanged();
Denys Vlasenkod5b500c2017-07-26 19:25:40 +02009308 } else if (lvp->flags == VUNSET) {
9309 vp->flags &= ~(VSTRFIXED|VREADONLY);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009310 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009311 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009312 if (vp->var_func)
9313 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009314 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009315 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009316 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009317 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009318 }
9319 free(lvp);
9320 }
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009321 INT_ON;
9322}
9323
9324/*
9325 * Create a new localvar environment.
9326 */
Denys Vlasenko484fc202017-07-26 19:55:31 +02009327static struct localvar_list *
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009328pushlocalvars(void)
9329{
9330 struct localvar_list *ll;
9331
9332 INT_OFF;
9333 ll = ckzalloc(sizeof(*ll));
9334 /*ll->lv = NULL; - zalloc did it */
9335 ll->next = localvar_stack;
9336 localvar_stack = ll;
9337 INT_ON;
Denys Vlasenko484fc202017-07-26 19:55:31 +02009338
9339 return ll->next;
9340}
9341
9342static void
9343unwindlocalvars(struct localvar_list *stop)
9344{
9345 while (localvar_stack != stop)
9346 poplocalvars(0);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009347}
9348
9349static int
9350evalfun(struct funcnode *func, int argc, char **argv, int flags)
9351{
9352 volatile struct shparam saveparam;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009353 struct jmploc *volatile savehandler;
9354 struct jmploc jmploc;
9355 int e;
9356
9357 saveparam = shellparam;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009358 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009359 e = setjmp(jmploc.loc);
9360 if (e) {
9361 goto funcdone;
9362 }
9363 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009364 exception_handler = &jmploc;
Denis Vlasenko01631112007-12-16 17:20:38 +00009365 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009366 func->count++;
9367 funcnest++;
9368 INT_ON;
9369 shellparam.nparam = argc - 1;
9370 shellparam.p = argv + 1;
9371#if ENABLE_ASH_GETOPTS
9372 shellparam.optind = 1;
9373 shellparam.optoff = -1;
9374#endif
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009375 pushlocalvars();
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009376 evaltree(func->n.narg.next, flags & EV_TESTED);
Denys Vlasenko981a0562017-07-26 19:53:11 +02009377 poplocalvars(0);
Denis Vlasenko01631112007-12-16 17:20:38 +00009378 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009379 INT_OFF;
9380 funcnest--;
9381 freefunc(func);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009382 freeparam(&shellparam);
9383 shellparam = saveparam;
9384 exception_handler = savehandler;
9385 INT_ON;
9386 evalskip &= ~SKIPFUNC;
9387 return e;
9388}
9389
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009390/*
9391 * Make a variable a local variable. When a variable is made local, it's
9392 * value and flags are saved in a localvar structure. The saved values
9393 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009394 * "-" as a special case: it makes changes to "set +-options" local
9395 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009396 */
9397static void
9398mklocal(char *name)
9399{
9400 struct localvar *lvp;
9401 struct var **vpp;
9402 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009403 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009404
9405 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009406 /* Cater for duplicate "local". Examples:
9407 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9408 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9409 */
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009410 lvp = localvar_stack->lv;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009411 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009412 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009413 if (eq)
9414 setvareq(name, 0);
9415 /* else:
9416 * it's a duplicate "local VAR" declaration, do nothing
9417 */
Denys Vlasenko06b11492016-11-04 16:43:18 +01009418 goto ret;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009419 }
9420 lvp = lvp->next;
9421 }
9422
9423 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009424 if (LONE_DASH(name)) {
9425 char *p;
9426 p = ckmalloc(sizeof(optlist));
9427 lvp->text = memcpy(p, optlist, sizeof(optlist));
9428 vp = NULL;
9429 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009430 vpp = hashvar(name);
9431 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009432 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009433 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009434 if (eq)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02009435 vp = setvareq(name, VSTRFIXED);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009436 else
Denys Vlasenkod04fc712017-07-26 20:06:48 +02009437 vp = setvar(name, NULL, VSTRFIXED);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009438 lvp->flags = VUNSET;
9439 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009440 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009441 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009442 /* make sure neither "struct var" nor string gets freed
9443 * during (un)setting:
9444 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009445 vp->flags |= VSTRFIXED|VTEXTFIXED;
9446 if (eq)
9447 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009448 else
9449 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009450 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009451 }
9452 }
9453 lvp->vp = vp;
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009454 lvp->next = localvar_stack->lv;
9455 localvar_stack->lv = lvp;
Denys Vlasenko06b11492016-11-04 16:43:18 +01009456 ret:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009457 INT_ON;
9458}
9459
9460/*
9461 * The "local" command.
9462 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009463static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009464localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009465{
9466 char *name;
9467
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009468 if (!localvar_stack)
Ron Yorstonef2386b2015-10-29 16:19:14 +00009469 ash_msg_and_raise_error("not in a function");
9470
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009471 argv = argptr;
9472 while ((name = *argv++) != NULL) {
9473 mklocal(name);
9474 }
9475 return 0;
9476}
9477
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009478static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009479falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009480{
9481 return 1;
9482}
9483
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009484static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009485truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009486{
9487 return 0;
9488}
9489
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009490static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009491execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009492{
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009493 optionarg = NULL;
9494 while (nextopt("a:") != '\0')
9495 /* nextopt() sets optionarg to "-a ARGV0" */;
9496
9497 argv = argptr;
9498 if (argv[0]) {
9499 char *prog;
9500
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009501 iflag = 0; /* exit on error */
9502 mflag = 0;
9503 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009504 /* We should set up signals for "exec CMD"
9505 * the same way as for "CMD" without "exec".
9506 * But optschanged->setinteractive->setsignal
9507 * still thought we are a root shell. Therefore, for example,
9508 * SIGQUIT is still set to IGN. Fix it:
9509 */
9510 shlvl++;
9511 setsignal(SIGQUIT);
9512 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9513 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9514 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9515
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009516 prog = argv[0];
9517 if (optionarg)
9518 argv[0] = optionarg;
9519 shellexec(prog, argv, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009520 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009521 }
9522 return 0;
9523}
9524
9525/*
9526 * The return command.
9527 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009528static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009529returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009530{
9531 /*
9532 * If called outside a function, do what ksh does;
9533 * skip the rest of the file.
9534 */
Denys Vlasenko6a0710e2016-09-30 14:18:34 +02009535 evalskip = SKIPFUNC;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009536 return argv[1] ? number(argv[1]) : exitstatus;
9537}
9538
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009539/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009540static int breakcmd(int, char **) FAST_FUNC;
9541static int dotcmd(int, char **) FAST_FUNC;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009542static int evalcmd(int, char **, int) FAST_FUNC;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009543static int exitcmd(int, char **) FAST_FUNC;
9544static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009545#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009546static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009547#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009548#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009549static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009550#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009551#if MAX_HISTORY
9552static int historycmd(int, char **) FAST_FUNC;
9553#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009554#if ENABLE_FEATURE_SH_MATH
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009555static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009556#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009557static int readcmd(int, char **) FAST_FUNC;
9558static int setcmd(int, char **) FAST_FUNC;
9559static int shiftcmd(int, char **) FAST_FUNC;
9560static int timescmd(int, char **) FAST_FUNC;
9561static int trapcmd(int, char **) FAST_FUNC;
9562static int umaskcmd(int, char **) FAST_FUNC;
9563static int unsetcmd(int, char **) FAST_FUNC;
9564static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009565
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009566#define BUILTIN_NOSPEC "0"
9567#define BUILTIN_SPECIAL "1"
9568#define BUILTIN_REGULAR "2"
9569#define BUILTIN_SPEC_REG "3"
9570#define BUILTIN_ASSIGN "4"
9571#define BUILTIN_SPEC_ASSG "5"
9572#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009573#define BUILTIN_SPEC_REG_ASSG "7"
9574
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009575/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko265062d2017-01-10 15:13:30 +01009576#if ENABLE_ASH_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009577static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009578#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009579#if ENABLE_ASH_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009580static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009581#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009582#if ENABLE_ASH_TEST || BASH_TEST2
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009583static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009584#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009585
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009586/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009587static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009588 { BUILTIN_SPEC_REG "." , dotcmd },
9589 { BUILTIN_SPEC_REG ":" , truecmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009590#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009591 { BUILTIN_REGULAR "[" , testcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009592#endif
9593#if BASH_TEST2
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009594 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009595#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009596#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009597 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009598#endif
9599#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009600 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009601#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009602 { BUILTIN_SPEC_REG "break" , breakcmd },
9603 { BUILTIN_REGULAR "cd" , cdcmd },
9604 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009605#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009606 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009607#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009608 { BUILTIN_SPEC_REG "continue", breakcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009609#if ENABLE_ASH_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009610 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009611#endif
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009612 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009613 { BUILTIN_SPEC_REG "exec" , execcmd },
9614 { BUILTIN_SPEC_REG "exit" , exitcmd },
9615 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9616 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009617#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009618 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009619#endif
9620#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009621 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009622#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009623 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009624#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009625 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009626#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009627#if MAX_HISTORY
9628 { BUILTIN_NOSPEC "history" , historycmd },
9629#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009630#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009631 { BUILTIN_REGULAR "jobs" , jobscmd },
9632 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009633#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009634#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009635 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009636#endif
Denys Vlasenko85241c72017-07-26 20:00:08 +02009637 { BUILTIN_SPEC_REG_ASSG "local" , localcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009638#if ENABLE_ASH_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009639 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009640#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009641 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9642 { BUILTIN_REGULAR "read" , readcmd },
9643 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9644 { BUILTIN_SPEC_REG "return" , returncmd },
9645 { BUILTIN_SPEC_REG "set" , setcmd },
9646 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009647#if BASH_SOURCE
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009648 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009649#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009650#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009651 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009652#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009653 { BUILTIN_SPEC_REG "times" , timescmd },
9654 { BUILTIN_SPEC_REG "trap" , trapcmd },
9655 { BUILTIN_REGULAR "true" , truecmd },
9656 { BUILTIN_NOSPEC "type" , typecmd },
9657 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9658 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009659#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009660 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009661#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009662 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9663 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009664};
9665
Denis Vlasenko80591b02008-03-25 07:49:43 +00009666/* Should match the above table! */
9667#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009668 /* . : */ 2 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009669 /* [ */ 1 * ENABLE_ASH_TEST + \
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009670 /* [[ */ 1 * BASH_TEST2 + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009671 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9672 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9673 /* break cd cddir */ 3)
9674#define EVALCMD (COMMANDCMD + \
9675 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9676 /* continue */ 1 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009677 /* echo */ 1 * ENABLE_ASH_ECHO + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009678 0)
9679#define EXECCMD (EVALCMD + \
9680 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009681
9682/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009683 * Search the table of builtin commands.
9684 */
Denys Vlasenko888527c2016-10-02 16:54:17 +02009685static int
9686pstrcmp1(const void *a, const void *b)
9687{
9688 return strcmp((char*)a, *(char**)b + 1);
9689}
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009690static struct builtincmd *
9691find_builtin(const char *name)
9692{
9693 struct builtincmd *bp;
9694
9695 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009696 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denys Vlasenko888527c2016-10-02 16:54:17 +02009697 pstrcmp1
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009698 );
9699 return bp;
9700}
9701
9702/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009703 * Execute a simple command.
9704 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009705static int
9706isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009707{
9708 const char *q = endofname(p);
9709 if (p == q)
9710 return 0;
9711 return *q == '=';
9712}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009713static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009714bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009715{
9716 /* Preserve exitstatus of a previous possible redirection
9717 * as POSIX mandates */
9718 return back_exitstatus;
9719}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009720static int
Eric Andersenc470f442003-07-28 09:56:35 +00009721evalcommand(union node *cmd, int flags)
9722{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009723 static const struct builtincmd null_bltin = {
9724 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009725 };
Denys Vlasenko484fc202017-07-26 19:55:31 +02009726 struct localvar_list *localvar_stop;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02009727 struct redirtab *redir_stop;
Eric Andersenc470f442003-07-28 09:56:35 +00009728 struct stackmark smark;
9729 union node *argp;
9730 struct arglist arglist;
9731 struct arglist varlist;
9732 char **argv;
9733 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009734 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009735 struct cmdentry cmdentry;
9736 struct job *jp;
9737 char *lastarg;
9738 const char *path;
9739 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009740 int status;
9741 char **nargv;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009742 smallint cmd_is_exec;
Eric Andersenc470f442003-07-28 09:56:35 +00009743
9744 /* First expand the arguments. */
9745 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9746 setstackmark(&smark);
Denys Vlasenko484fc202017-07-26 19:55:31 +02009747 localvar_stop = pushlocalvars();
Eric Andersenc470f442003-07-28 09:56:35 +00009748 back_exitstatus = 0;
9749
9750 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009751 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009752 varlist.lastp = &varlist.list;
9753 *varlist.lastp = NULL;
9754 arglist.lastp = &arglist.list;
9755 *arglist.lastp = NULL;
9756
9757 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009758 if (cmd->ncmd.args) {
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009759 struct builtincmd *bcmd;
9760 smallint pseudovarflag;
9761
Paul Foxc3850c82005-07-20 18:23:39 +00009762 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9763 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Paul Foxc3850c82005-07-20 18:23:39 +00009764
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009765 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9766 struct strlist **spp;
Eric Andersenc470f442003-07-28 09:56:35 +00009767
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009768 spp = arglist.lastp;
9769 if (pseudovarflag && isassignment(argp->narg.text))
9770 expandarg(argp, &arglist, EXP_VARTILDE);
9771 else
9772 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Paul Foxc3850c82005-07-20 18:23:39 +00009773
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009774 for (sp = *spp; sp; sp = sp->next)
9775 argc++;
9776 }
Eric Andersenc470f442003-07-28 09:56:35 +00009777 }
9778
Denys Vlasenko65a8b852016-10-26 22:29:11 +02009779 /* Reserve one extra spot at the front for shellexec. */
9780 nargv = stalloc(sizeof(char *) * (argc + 2));
9781 argv = ++nargv;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009782 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009783 TRACE(("evalcommand arg: %s\n", sp->text));
9784 *nargv++ = sp->text;
9785 }
9786 *nargv = NULL;
9787
9788 lastarg = NULL;
9789 if (iflag && funcnest == 0 && argc > 0)
9790 lastarg = nargv[-1];
9791
9792 expredir(cmd->ncmd.redirect);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02009793 redir_stop = pushredir(cmd->ncmd.redirect);
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009794 preverrout_fd = 2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009795 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009796
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009797 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009798 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9799 struct strlist **spp;
9800 char *p;
9801
9802 spp = varlist.lastp;
9803 expandarg(argp, &varlist, EXP_VARTILDE);
9804
Denys Vlasenko981a0562017-07-26 19:53:11 +02009805 mklocal((*spp)->text);
9806
Eric Andersenc470f442003-07-28 09:56:35 +00009807 /*
9808 * Modify the command lookup path, if a PATH= assignment
9809 * is present
9810 */
9811 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009812 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009813 path = p;
9814 }
9815
9816 /* Print the command if xflag is set. */
9817 if (xflag) {
Denys Vlasenko42ba7572017-07-21 13:20:14 +02009818 const char *pfx = "";
Eric Andersenc470f442003-07-28 09:56:35 +00009819
Denys Vlasenko46999802017-07-29 21:12:29 +02009820 fdprintf(preverrout_fd, "%s", expandstr(ps4val(), DQSYNTAX));
Denys Vlasenko42ba7572017-07-21 13:20:14 +02009821
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009822 sp = varlist.list;
Denys Vlasenko42ba7572017-07-21 13:20:14 +02009823 while (sp) {
9824 char *varval = sp->text;
9825 char *eq = strchrnul(varval, '=');
9826 if (*eq)
9827 eq++;
9828 fdprintf(preverrout_fd, "%s%.*s%s",
9829 pfx,
9830 (int)(eq - varval), varval,
9831 maybe_single_quote(eq)
9832 );
9833 sp = sp->next;
9834 pfx = " ";
9835 }
9836
9837 sp = arglist.list;
9838 while (sp) {
9839 fdprintf(preverrout_fd, "%s%s",
9840 pfx,
9841 /* always quote if matches reserved word: */
9842 findkwd(sp->text)
9843 ? single_quote(sp->text)
9844 : maybe_single_quote(sp->text)
9845 );
9846 sp = sp->next;
9847 pfx = " ";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009848 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009849 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009850 }
9851
9852 cmd_is_exec = 0;
9853 spclbltin = -1;
9854
9855 /* Now locate the command. */
9856 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009857 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02009858#if ENABLE_ASH_CMDCMD
9859 const char *oldpath = path + 5;
9860#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009861 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009862 for (;;) {
9863 find_command(argv[0], &cmdentry, cmd_flag, path);
9864 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009865 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009866 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009867 goto bail;
9868 }
9869
9870 /* implement bltin and command here */
9871 if (cmdentry.cmdtype != CMDBUILTIN)
9872 break;
9873 if (spclbltin < 0)
9874 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9875 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009876 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009877#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009878 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009879 path = oldpath;
9880 nargv = parse_command_args(argv, &path);
9881 if (!nargv)
9882 break;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02009883 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
9884 * nargv => "PROG". path is updated if -p.
9885 */
Eric Andersenc470f442003-07-28 09:56:35 +00009886 argc -= nargv - argv;
9887 argv = nargv;
9888 cmd_flag |= DO_NOFUNC;
9889 } else
9890#endif
9891 break;
9892 }
9893 }
9894
9895 if (status) {
Ron Yorstonea7d2f62017-01-03 11:18:23 +01009896 bail:
9897 exitstatus = status;
9898
Eric Andersenc470f442003-07-28 09:56:35 +00009899 /* We have a redirection error. */
9900 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009901 raise_exception(EXERROR);
Ron Yorstonea7d2f62017-01-03 11:18:23 +01009902
Eric Andersenc470f442003-07-28 09:56:35 +00009903 goto out;
9904 }
9905
9906 /* Execute the command. */
9907 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009908 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009909
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009910#if ENABLE_FEATURE_SH_NOFORK
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009911/* (1) BUG: if variables are set, we need to fork, or save/restore them
9912 * around run_nofork_applet() call.
9913 * (2) Should this check also be done in forkshell()?
9914 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9915 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009916 /* find_command() encodes applet_no as (-2 - applet_no) */
9917 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009918 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009919 listsetvar(varlist.list, VEXPORT|VSTACK);
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009920 /* run <applet>_main() */
Ron Yorston5ccb0e92016-10-20 12:24:02 +01009921 status = run_nofork_applet(applet_no, argv);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009922 break;
9923 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009924#endif
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009925 /* Can we avoid forking off? For example, very last command
9926 * in a script or a subshell does not need forking,
9927 * we can just exec it.
9928 */
Denys Vlasenko238bf182010-05-18 15:49:07 +02009929 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009930 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009931 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009932 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009933 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009934 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009935 /* parent */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009936 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009937 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009938 TRACE(("forked child exited with %d\n", status));
Eric Andersenc470f442003-07-28 09:56:35 +00009939 break;
9940 }
Denys Vlasenko238bf182010-05-18 15:49:07 +02009941 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009942 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +02009943 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +00009944 }
9945 listsetvar(varlist.list, VEXPORT|VSTACK);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02009946 shellexec(argv[0], argv, path, cmdentry.u.index);
Eric Andersenc470f442003-07-28 09:56:35 +00009947 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009948 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +00009949 case CMDBUILTIN:
Denys Vlasenko85241c72017-07-26 20:00:08 +02009950 if (spclbltin > 0 || argc == 0) {
9951 poplocalvars(1);
9952 if (cmd_is_exec && argc > 1)
9953 listsetvar(varlist.list, VEXPORT);
9954 }
Denys Vlasenko981a0562017-07-26 19:53:11 +02009955
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009956 /* Tight loop with builtins only:
9957 * "while kill -0 $child; do true; done"
9958 * will never exit even if $child died, unless we do this
9959 * to reap the zombie and make kill detect that it's gone: */
9960 dowait(DOWAIT_NONBLOCK, NULL);
9961
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009962 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009963 if (exception_type == EXERROR && spclbltin <= 0) {
9964 FORCE_INT_ON;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02009965 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009966 }
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009967 raise:
9968 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009969 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009970 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009971
9972 case CMDFUNCTION:
Denys Vlasenko981a0562017-07-26 19:53:11 +02009973 poplocalvars(1);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009974 /* See above for the rationale */
9975 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009976 if (evalfun(cmdentry.u.func, argc, argv, flags))
9977 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009978 readstatus:
9979 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009980 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009981 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +00009982
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009983 out:
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02009984 if (cmd->ncmd.redirect)
Denys Vlasenko035486c2017-07-31 04:09:19 +02009985 popredir(/*drop:*/ cmd_is_exec);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02009986 unwindredir(redir_stop);
Denys Vlasenko484fc202017-07-26 19:55:31 +02009987 unwindlocalvars(localvar_stop);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009988 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +00009989 /* dsl: I think this is intended to be used to support
9990 * '_' in 'vi' command mode during line editing...
9991 * However I implemented that within libedit itself.
9992 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009993 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009994 }
Eric Andersenc470f442003-07-28 09:56:35 +00009995 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009996
9997 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009998}
9999
10000static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010001evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010002{
Eric Andersenc470f442003-07-28 09:56:35 +000010003 char *volatile savecmdname;
10004 struct jmploc *volatile savehandler;
10005 struct jmploc jmploc;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010006 int status;
Eric Andersenc470f442003-07-28 09:56:35 +000010007 int i;
10008
10009 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +020010010 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010011 i = setjmp(jmploc.loc);
10012 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +000010013 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010014 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +000010015 commandname = argv[0];
10016 argptr = argv + 1;
10017 optptr = NULL; /* initialize nextopt */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010018 if (cmd == EVALCMD)
10019 status = evalcmd(argc, argv, flags);
10020 else
10021 status = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010022 flush_stdout_stderr();
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010023 status |= ferror(stdout);
10024 exitstatus = status;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010025 cmddone:
Rob Landleyf296f0b2006-07-06 01:09:21 +000010026 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000010027 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010028 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010029
10030 return i;
10031}
10032
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010033static int
10034goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010035{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +020010036 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010037}
10038
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010039
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010040/*
10041 * Search for a command. This is called before we fork so that the
10042 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010043 * the child. The check for "goodname" is an overly conservative
10044 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010045 */
Eric Andersenc470f442003-07-28 09:56:35 +000010046static void
10047prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010048{
10049 struct cmdentry entry;
10050
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010051 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
10052 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010053}
10054
Eric Andersencb57d552001-06-28 07:25:16 +000010055
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000010056/* ============ Builtin commands
10057 *
10058 * Builtin commands whose functions are closely tied to evaluation
10059 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +000010060 */
10061
10062/*
Eric Andersencb57d552001-06-28 07:25:16 +000010063 * Handle break and continue commands. Break, continue, and return are
10064 * all handled by setting the evalskip flag. The evaluation routines
10065 * above all check this flag, and if it is set they start skipping
10066 * commands rather than executing them. The variable skipcount is
10067 * the number of loops to break/continue, or the number of function
10068 * levels to return. (The latter is always 1.) It should probably
10069 * be an error to break out of more loops than exist, but it isn't
10070 * in the standard shell so we don't make it one here.
10071 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010072static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010073breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010074{
Denis Vlasenko68404f12008-03-17 09:00:54 +000010075 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010076
Aaron Lehmann2aef3a62001-12-31 06:03:12 +000010077 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +020010078 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +000010079 if (n > loopnest)
10080 n = loopnest;
10081 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000010082 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +000010083 skipcount = n;
10084 }
10085 return 0;
10086}
10087
Eric Andersenc470f442003-07-28 09:56:35 +000010088
Denys Vlasenko70392332016-10-27 02:31:55 +020010089/*
Eric Andersen90898442003-08-06 11:20:52 +000010090 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +000010091 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010092
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010093enum {
10094 INPUT_PUSH_FILE = 1,
10095 INPUT_NOFILE_OK = 2,
10096};
Eric Andersencb57d552001-06-28 07:25:16 +000010097
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010098static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010099/* values of checkkwd variable */
10100#define CHKALIAS 0x1
10101#define CHKKWD 0x2
10102#define CHKNL 0x4
Denys Vlasenkoa7328982017-07-29 19:57:28 +020010103#define CHKEOFMARK 0x8
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010104
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010105/*
10106 * Push a string back onto the input at this current parsefile level.
10107 * We handle aliases this way.
10108 */
10109#if !ENABLE_ASH_ALIAS
10110#define pushstring(s, ap) pushstring(s)
10111#endif
10112static void
10113pushstring(char *s, struct alias *ap)
10114{
10115 struct strpush *sp;
10116 int len;
10117
10118 len = strlen(s);
10119 INT_OFF;
10120 if (g_parsefile->strpush) {
10121 sp = ckzalloc(sizeof(*sp));
10122 sp->prev = g_parsefile->strpush;
10123 } else {
10124 sp = &(g_parsefile->basestrpush);
10125 }
10126 g_parsefile->strpush = sp;
10127 sp->prev_string = g_parsefile->next_to_pgetc;
10128 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010129 sp->unget = g_parsefile->unget;
10130 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010131#if ENABLE_ASH_ALIAS
10132 sp->ap = ap;
10133 if (ap) {
10134 ap->flag |= ALIASINUSE;
10135 sp->string = s;
10136 }
10137#endif
10138 g_parsefile->next_to_pgetc = s;
10139 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010140 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010141 INT_ON;
10142}
10143
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010144static void
10145popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010146{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010147 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +000010148
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010149 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010150#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010151 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010152 if (g_parsefile->next_to_pgetc[-1] == ' '
10153 || g_parsefile->next_to_pgetc[-1] == '\t'
10154 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010155 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010156 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010157 if (sp->string != sp->ap->val) {
10158 free(sp->string);
10159 }
10160 sp->ap->flag &= ~ALIASINUSE;
10161 if (sp->ap->flag & ALIASDEAD) {
10162 unalias(sp->ap->name);
10163 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010164 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010165#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010166 g_parsefile->next_to_pgetc = sp->prev_string;
10167 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010168 g_parsefile->unget = sp->unget;
10169 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010170 g_parsefile->strpush = sp->prev;
10171 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010172 free(sp);
10173 INT_ON;
10174}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010175
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010176static int
10177preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010178{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010179 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +000010180 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010181
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010182 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +000010183#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +000010184 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010185 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +010010186 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010187 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010188# if ENABLE_ASH_IDLE_TIMEOUT
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010189 int timeout = -1;
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010190 if (iflag) {
10191 const char *tmout_var = lookupvar("TMOUT");
10192 if (tmout_var) {
10193 timeout = atoi(tmout_var) * 1000;
10194 if (timeout <= 0)
10195 timeout = -1;
10196 }
10197 }
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010198 line_input_state->timeout = timeout;
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010199# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010200# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010201 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010202# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +020010203 reinit_unicode_for_ash();
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010204 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010205 if (nr == 0) {
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010206 /* ^C pressed, "convert" to SIGINT */
10207 write(STDOUT_FILENO, "^C", 2);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010208 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010209 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010210 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010211 raise(SIGINT);
10212 return 1;
10213 }
Denys Vlasenko8660aeb2016-11-24 17:44:02 +010010214 exitstatus = 128 + SIGINT;
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010215 bb_putchar('\n');
Eric Andersenc470f442003-07-28 09:56:35 +000010216 goto retry;
10217 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010218 if (nr < 0) {
10219 if (errno == 0) {
10220 /* Ctrl+D pressed */
10221 nr = 0;
10222 }
10223# if ENABLE_ASH_IDLE_TIMEOUT
10224 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +020010225 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010226 exitshell();
10227 }
10228# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010229 }
Eric Andersencb57d552001-06-28 07:25:16 +000010230 }
10231#else
Ron Yorston61d6ae22015-04-19 10:50:25 +010010232 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +000010233#endif
10234
Denys Vlasenko80c5b682011-05-08 21:21:10 +020010235#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +000010236 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010237 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +000010238 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +000010239 if (flags >= 0 && (flags & O_NONBLOCK)) {
10240 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +000010241 if (fcntl(0, F_SETFL, flags) >= 0) {
10242 out2str("sh: turning off NDELAY mode\n");
10243 goto retry;
10244 }
10245 }
10246 }
10247 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +000010248#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010249 return nr;
10250}
10251
10252/*
10253 * Refill the input buffer and return the next input character:
10254 *
10255 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010256 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
10257 * or we are reading from a string so we can't refill the buffer,
10258 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +020010259 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +000010260 * 4) Process input up to the next newline, deleting nul characters.
10261 */
Denis Vlasenko727752d2008-11-28 03:41:47 +000010262//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
10263#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010264static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010265static int
Eric Andersenc470f442003-07-28 09:56:35 +000010266preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010267{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010268 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010269 int more;
Eric Andersencb57d552001-06-28 07:25:16 +000010270
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010271 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000010272#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010273 if (g_parsefile->left_in_line == -1
10274 && g_parsefile->strpush->ap
10275 && g_parsefile->next_to_pgetc[-1] != ' '
10276 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +000010277 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010278 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +000010279 return PEOA;
10280 }
Eric Andersen2870d962001-07-02 17:27:21 +000010281#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010282 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010283 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010284 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010285 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010286 * "pgetc" needs refilling.
10287 */
10288
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010289 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010290 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010291 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010292 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010293 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010294 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010295 /* even in failure keep left_in_line and next_to_pgetc
10296 * in lock step, for correct multi-layer pungetc.
10297 * left_in_line was decremented before preadbuffer(),
10298 * must inc next_to_pgetc: */
10299 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010300 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010301 }
Eric Andersencb57d552001-06-28 07:25:16 +000010302
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010303 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010304 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010305 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010306 again:
10307 more = preadfd();
10308 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010309 /* don't try reading again */
10310 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010311 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010312 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010313 return PEOF;
10314 }
10315 }
10316
Denis Vlasenko727752d2008-11-28 03:41:47 +000010317 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010318 * Set g_parsefile->left_in_line
10319 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010320 * NUL chars are deleted.
10321 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010322 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010323 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010324 char c;
Eric Andersencb57d552001-06-28 07:25:16 +000010325
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010326 more--;
Eric Andersenc470f442003-07-28 09:56:35 +000010327
Denis Vlasenko727752d2008-11-28 03:41:47 +000010328 c = *q;
10329 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010330 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010331 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010332 q++;
10333 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010334 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010335 break;
10336 }
Eric Andersencb57d552001-06-28 07:25:16 +000010337 }
10338
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010339 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010340 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10341 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010342 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010343 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010344 }
10345 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010346 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +000010347
Eric Andersencb57d552001-06-28 07:25:16 +000010348 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010349 char save = *q;
10350 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010351 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010352 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +000010353 }
10354
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010355 pgetc_debug("preadbuffer at %d:%p'%s'",
10356 g_parsefile->left_in_line,
10357 g_parsefile->next_to_pgetc,
10358 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +010010359 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010360}
10361
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010362static void
10363nlprompt(void)
10364{
10365 g_parsefile->linno++;
10366 setprompt_if(doprompt, 2);
10367}
10368static void
10369nlnoprompt(void)
10370{
10371 g_parsefile->linno++;
10372 needprompt = doprompt;
10373}
10374
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010375static int
10376pgetc(void)
10377{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010378 int c;
10379
10380 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010381 g_parsefile->left_in_line,
10382 g_parsefile->next_to_pgetc,
10383 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010384 if (g_parsefile->unget)
10385 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010386
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010387 if (--g_parsefile->left_in_line >= 0)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +010010388 c = (unsigned char)*g_parsefile->next_to_pgetc++;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010389 else
10390 c = preadbuffer();
10391
10392 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10393 g_parsefile->lastc[0] = c;
10394
10395 return c;
10396}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010397
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010398#if ENABLE_ASH_ALIAS
10399static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010400pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010401{
10402 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010403 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010404 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010405 g_parsefile->left_in_line,
10406 g_parsefile->next_to_pgetc,
10407 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010408 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010409 } while (c == PEOA);
10410 return c;
10411}
10412#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010413# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010414#endif
10415
10416/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010417 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010418 * PEOF may be pushed back.
10419 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010420static void
Eric Andersenc470f442003-07-28 09:56:35 +000010421pungetc(void)
10422{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010423 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010424}
10425
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010426/* This one eats backslash+newline */
10427static int
10428pgetc_eatbnl(void)
10429{
10430 int c;
10431
10432 while ((c = pgetc()) == '\\') {
10433 if (pgetc() != '\n') {
10434 pungetc();
10435 break;
10436 }
10437
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010438 nlprompt();
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010439 }
10440
10441 return c;
10442}
10443
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010444/*
10445 * To handle the "." command, a stack of input files is used. Pushfile
10446 * adds a new entry to the stack and popfile restores the previous level.
10447 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010448static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010449pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010450{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010451 struct parsefile *pf;
10452
Denis Vlasenko597906c2008-02-20 16:38:54 +000010453 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010454 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010455 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010456 /*pf->strpush = NULL; - ckzalloc did it */
10457 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010458 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010459 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010460}
10461
10462static void
10463popfile(void)
10464{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010465 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010466
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010010467 if (pf == &basepf)
10468 return;
10469
Denis Vlasenkob012b102007-02-19 22:43:01 +000010470 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010471 if (pf->pf_fd >= 0)
10472 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010473 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010474 while (pf->strpush)
10475 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010476 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010477 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010478 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010479}
10480
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010481/*
10482 * Return to top level.
10483 */
10484static void
10485popallfiles(void)
10486{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010487 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010488 popfile();
10489}
10490
10491/*
10492 * Close the file(s) that the shell is reading commands from. Called
10493 * after a fork is done.
10494 */
10495static void
10496closescript(void)
10497{
10498 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010499 if (g_parsefile->pf_fd > 0) {
10500 close(g_parsefile->pf_fd);
10501 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010502 }
10503}
10504
10505/*
10506 * Like setinputfile, but takes an open file descriptor. Call this with
10507 * interrupts off.
10508 */
10509static void
10510setinputfd(int fd, int push)
10511{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010512 if (push) {
10513 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010514 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010515 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010516 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010517 if (g_parsefile->buf == NULL)
10518 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010519 g_parsefile->left_in_buffer = 0;
10520 g_parsefile->left_in_line = 0;
10521 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010522}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010523
Eric Andersenc470f442003-07-28 09:56:35 +000010524/*
10525 * Set the input to take input from a file. If push is set, push the
10526 * old input onto the stack first.
10527 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010528static int
10529setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010530{
10531 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010532
Denis Vlasenkob012b102007-02-19 22:43:01 +000010533 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010534 fd = open(fname, O_RDONLY);
10535 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010536 if (flags & INPUT_NOFILE_OK)
10537 goto out;
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010538 exitstatus = 127;
Denis Vlasenko9604e1b2009-03-03 18:47:56 +000010539 ash_msg_and_raise_error("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010540 }
Denys Vlasenko64774602016-10-26 15:24:30 +020010541 if (fd < 10)
10542 fd = savefd(fd);
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020010543 else
10544 close_on_exec_on(fd);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010545 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010546 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010547 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010548 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010549}
10550
Eric Andersencb57d552001-06-28 07:25:16 +000010551/*
10552 * Like setinputfile, but takes input from a string.
10553 */
Eric Andersenc470f442003-07-28 09:56:35 +000010554static void
10555setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010556{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010557 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010558 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010559 g_parsefile->next_to_pgetc = string;
10560 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010561 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010562 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010563 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010564}
10565
10566
Denys Vlasenko70392332016-10-27 02:31:55 +020010567/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010568 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010569 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010570
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010571#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010572
Denys Vlasenko23841622015-10-09 15:52:03 +020010573/* Hash of mtimes of mailboxes */
10574static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010575/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010576static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010577
Eric Andersencb57d552001-06-28 07:25:16 +000010578/*
Eric Andersenc470f442003-07-28 09:56:35 +000010579 * Print appropriate message(s) if mail has arrived.
10580 * If mail_var_path_changed is set,
10581 * then the value of MAIL has mail_var_path_changed,
10582 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010583 */
Eric Andersenc470f442003-07-28 09:56:35 +000010584static void
10585chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010586{
Eric Andersencb57d552001-06-28 07:25:16 +000010587 const char *mpath;
10588 char *p;
10589 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010590 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010591 struct stackmark smark;
10592 struct stat statb;
10593
Eric Andersencb57d552001-06-28 07:25:16 +000010594 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010595 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010596 new_hash = 0;
10597 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010598 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010599 if (p == NULL)
10600 break;
10601 if (*p == '\0')
10602 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010603 for (q = p; *q; q++)
10604 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010605#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010606 if (q[-1] != '/')
10607 abort();
10608#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010609 q[-1] = '\0'; /* delete trailing '/' */
10610 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010611 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010612 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010613 /* Very simplistic "hash": just a sum of all mtimes */
10614 new_hash += (unsigned)statb.st_mtime;
10615 }
10616 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010617 if (mailtime_hash != 0)
10618 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010619 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010620 }
Eric Andersenc470f442003-07-28 09:56:35 +000010621 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010622 popstackmark(&smark);
10623}
Eric Andersencb57d552001-06-28 07:25:16 +000010624
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010625static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010626changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010627{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010628 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010629}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010630
Denis Vlasenko131ae172007-02-18 13:00:19 +000010631#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010632
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010633
10634/* ============ ??? */
10635
Eric Andersencb57d552001-06-28 07:25:16 +000010636/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010637 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010638 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010639static void
10640setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010641{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010642 char **newparam;
10643 char **ap;
10644 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010645
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010646 for (nparam = 0; argv[nparam]; nparam++)
10647 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010648 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10649 while (*argv) {
10650 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010651 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010652 *ap = NULL;
10653 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010654 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010655 shellparam.nparam = nparam;
10656 shellparam.p = newparam;
10657#if ENABLE_ASH_GETOPTS
10658 shellparam.optind = 1;
10659 shellparam.optoff = -1;
10660#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010661}
10662
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010663/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010664 * Process shell options. The global variable argptr contains a pointer
10665 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010666 *
10667 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10668 * For a non-interactive shell, an error condition encountered
10669 * by a special built-in ... shall cause the shell to write a diagnostic message
10670 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010671 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010672 * ...
10673 * Utility syntax error (option or operand error) Shall exit
10674 * ...
10675 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10676 * we see that bash does not do that (set "finishes" with error code 1 instead,
10677 * and shell continues), and people rely on this behavior!
10678 * Testcase:
10679 * set -o barfoo 2>/dev/null
10680 * echo $?
10681 *
10682 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010683 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010684static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010685plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010686{
10687 int i;
10688
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010689 if (name) {
10690 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010691 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010692 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010693 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010694 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010695 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010696 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010697 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010698 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010699 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010700 if (val) {
10701 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10702 } else {
10703 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10704 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010705 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010706 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010707}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010708static void
10709setoption(int flag, int val)
10710{
10711 int i;
10712
10713 for (i = 0; i < NOPTS; i++) {
10714 if (optletters(i) == flag) {
10715 optlist[i] = val;
10716 return;
10717 }
10718 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010719 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010720 /* NOTREACHED */
10721}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010722static int
Denys Vlasenkoec05df12017-07-31 19:43:47 +020010723options(int cmdline, int *login_sh)
Eric Andersencb57d552001-06-28 07:25:16 +000010724{
10725 char *p;
10726 int val;
10727 int c;
10728
10729 if (cmdline)
10730 minusc = NULL;
10731 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010732 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010733 if (c != '-' && c != '+')
10734 break;
10735 argptr++;
10736 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010737 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010738 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010739 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010740 if (!cmdline) {
10741 /* "-" means turn off -x and -v */
10742 if (p[0] == '\0')
10743 xflag = vflag = 0;
10744 /* "--" means reset params */
10745 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010746 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010747 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010748 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010749 }
Eric Andersencb57d552001-06-28 07:25:16 +000010750 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010751 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010752 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010753 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010754 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010755 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010756 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010757 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010758 /* it already printed err message */
10759 return 1; /* error */
10760 }
Eric Andersencb57d552001-06-28 07:25:16 +000010761 if (*argptr)
10762 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010763 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020010764 if (login_sh)
10765 *login_sh = 1;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010766 /* bash does not accept +-login, we also won't */
10767 } else if (cmdline && val && (c == '-')) { /* long options */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020010768 if (strcmp(p, "login") == 0) {
10769 if (login_sh)
10770 *login_sh = 1;
10771 }
Robert Griebl64f70cc2002-05-14 23:22:06 +000010772 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010773 } else {
10774 setoption(c, val);
10775 }
10776 }
10777 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010778 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010779}
10780
Eric Andersencb57d552001-06-28 07:25:16 +000010781/*
Eric Andersencb57d552001-06-28 07:25:16 +000010782 * The shift builtin command.
10783 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010784static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010785shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010786{
10787 int n;
10788 char **ap1, **ap2;
10789
10790 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010791 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010792 n = number(argv[1]);
10793 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010794 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010795 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010796 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010797 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010798 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010799 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010800 }
10801 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010802 while ((*ap2++ = *ap1++) != NULL)
10803 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010804#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010805 shellparam.optind = 1;
10806 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010807#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010808 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010809 return 0;
10810}
10811
Eric Andersencb57d552001-06-28 07:25:16 +000010812/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010813 * POSIX requires that 'set' (but not export or readonly) output the
10814 * variables in lexicographic order - by the locale's collating order (sigh).
10815 * Maybe we could keep them in an ordered balanced binary tree
10816 * instead of hashed lists.
10817 * For now just roll 'em through qsort for printing...
10818 */
10819static int
10820showvars(const char *sep_prefix, int on, int off)
10821{
10822 const char *sep;
10823 char **ep, **epend;
10824
10825 ep = listvars(on, off, &epend);
10826 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10827
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010828 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010829
10830 for (; ep < epend; ep++) {
10831 const char *p;
10832 const char *q;
10833
10834 p = strchrnul(*ep, '=');
10835 q = nullstr;
10836 if (*p)
10837 q = single_quote(++p);
10838 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10839 }
10840 return 0;
10841}
10842
10843/*
Eric Andersencb57d552001-06-28 07:25:16 +000010844 * The set command builtin.
10845 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010846static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010847setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010848{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010849 int retval;
10850
Denis Vlasenko68404f12008-03-17 09:00:54 +000010851 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010852 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010853
Denis Vlasenkob012b102007-02-19 22:43:01 +000010854 INT_OFF;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020010855 retval = options(/*cmdline:*/ 0, NULL);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010856 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010857 optschanged();
10858 if (*argptr != NULL) {
10859 setparam(argptr);
10860 }
Eric Andersencb57d552001-06-28 07:25:16 +000010861 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010862 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010863 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010864}
10865
Denis Vlasenko131ae172007-02-18 13:00:19 +000010866#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010867static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010868change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010869{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010870 uint32_t t;
10871
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010872 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010873 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010874 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010875 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010876 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010877 vrandom.flags &= ~VNOFUNC;
10878 } else {
10879 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010880 t = strtoul(value, NULL, 10);
10881 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010882 }
Eric Andersenef02f822004-03-11 13:34:24 +000010883}
Eric Andersen16767e22004-03-16 05:14:10 +000010884#endif
10885
Denis Vlasenko131ae172007-02-18 13:00:19 +000010886#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010887static int
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010888getopts(char *optstr, char *optvar, char **optfirst)
Eric Andersencb57d552001-06-28 07:25:16 +000010889{
10890 char *p, *q;
10891 char c = '?';
10892 int done = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010893 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000010894 char **optnext;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010895 int ind = shellparam.optind;
10896 int off = shellparam.optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010897
Denys Vlasenko9c541002015-10-07 15:44:36 +020010898 sbuf[1] = '\0';
10899
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010900 shellparam.optind = -1;
10901 optnext = optfirst + ind - 1;
Eric Andersena48b0a32003-10-22 10:56:47 +000010902
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010903 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
Eric Andersencb57d552001-06-28 07:25:16 +000010904 p = NULL;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010905 else
10906 p = optnext[-1] + off;
Eric Andersencb57d552001-06-28 07:25:16 +000010907 if (p == NULL || *p == '\0') {
10908 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010909 p = *optnext;
10910 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010911 atend:
Eric Andersencb57d552001-06-28 07:25:16 +000010912 p = NULL;
10913 done = 1;
10914 goto out;
10915 }
10916 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010917 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010918 goto atend;
10919 }
10920
10921 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010922 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010923 if (*q == '\0') {
10924 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010925 sbuf[0] = c;
10926 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010927 setvar0("OPTARG", sbuf);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010928 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010929 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010930 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010931 }
10932 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010933 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010934 }
10935 if (*++q == ':')
10936 q++;
10937 }
10938
10939 if (*++q == ':') {
10940 if (*p == '\0' && (p = *optnext) == NULL) {
10941 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010942 sbuf[0] = c;
10943 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010944 setvar0("OPTARG", sbuf);
Eric Andersencb57d552001-06-28 07:25:16 +000010945 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010946 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010947 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010948 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010949 c = '?';
10950 }
Eric Andersenc470f442003-07-28 09:56:35 +000010951 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010952 }
10953
10954 if (p == *optnext)
10955 optnext++;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010956 setvar0("OPTARG", p);
Eric Andersencb57d552001-06-28 07:25:16 +000010957 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010958 } else
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010959 setvar0("OPTARG", nullstr);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010960 out:
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010961 ind = optnext - optfirst + 1;
10962 setvar("OPTIND", itoa(ind), VNOFUNC);
Denys Vlasenko9c541002015-10-07 15:44:36 +020010963 sbuf[0] = c;
10964 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010965 setvar0(optvar, sbuf);
10966
10967 shellparam.optoff = p ? p - *(optnext - 1) : -1;
10968 shellparam.optind = ind;
10969
Eric Andersencb57d552001-06-28 07:25:16 +000010970 return done;
10971}
Eric Andersenc470f442003-07-28 09:56:35 +000010972
10973/*
10974 * The getopts builtin. Shellparam.optnext points to the next argument
10975 * to be processed. Shellparam.optptr points to the next character to
10976 * be processed in the current argument. If shellparam.optnext is NULL,
10977 * then it's the first time getopts has been called.
10978 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010979static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000010980getoptscmd(int argc, char **argv)
10981{
10982 char **optbase;
10983
10984 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010985 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010986 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000010987 optbase = shellparam.p;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010988 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
Eric Andersenc470f442003-07-28 09:56:35 +000010989 shellparam.optind = 1;
10990 shellparam.optoff = -1;
10991 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010992 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010993 optbase = &argv[3];
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010994 if ((unsigned)shellparam.optind > argc - 2) {
Eric Andersenc470f442003-07-28 09:56:35 +000010995 shellparam.optind = 1;
10996 shellparam.optoff = -1;
10997 }
10998 }
10999
Denys Vlasenko35c2a132016-10-26 17:34:26 +020011000 return getopts(argv[1], argv[2], optbase);
Eric Andersenc470f442003-07-28 09:56:35 +000011001}
Denis Vlasenko131ae172007-02-18 13:00:19 +000011002#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000011003
Eric Andersencb57d552001-06-28 07:25:16 +000011004
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011005/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000011006
Denis Vlasenkob07a4962008-06-22 13:16:23 +000011007struct heredoc {
11008 struct heredoc *next; /* next here document in list */
11009 union node *here; /* redirection node */
11010 char *eofmark; /* string indicating end of input */
11011 smallint striptabs; /* if set, strip leading tabs */
11012};
11013
11014static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000011015static smallint quoteflag; /* set if (part of) last token was quoted */
11016static token_id_t lasttoken; /* last token read (integer id Txxx) */
11017static struct heredoc *heredoclist; /* list of here documents to read */
11018static char *wordtext; /* text of last word returned by readtoken */
11019static struct nodelist *backquotelist;
11020static union node *redirnode;
11021static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000011022
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011023static const char *
11024tokname(char *buf, int tok)
11025{
11026 if (tok < TSEMI)
Denys Vlasenko888527c2016-10-02 16:54:17 +020011027 return tokname_array[tok];
11028 sprintf(buf, "\"%s\"", tokname_array[tok]);
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011029 return buf;
11030}
11031
11032/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011033 * Called when an unexpected token is read during the parse. The argument
11034 * is the token that is expected, or -1 if more than one type of token can
11035 * occur at this point.
11036 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011037static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011038static void
11039raise_error_unexpected_syntax(int token)
11040{
11041 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011042 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011043 int l;
11044
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011045 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011046 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011047 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011048 raise_error_syntax(msg);
11049 /* NOTREACHED */
11050}
Eric Andersencb57d552001-06-28 07:25:16 +000011051
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011052/* parsing is heavily cross-recursive, need these forward decls */
11053static union node *andor(void);
11054static union node *pipeline(void);
11055static union node *parse_command(void);
11056static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000011057static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011058static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000011059
Eric Andersenc470f442003-07-28 09:56:35 +000011060static union node *
11061list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000011062{
11063 union node *n1, *n2, *n3;
11064 int tok;
11065
Eric Andersencb57d552001-06-28 07:25:16 +000011066 n1 = NULL;
11067 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011068 switch (peektoken()) {
11069 case TNL:
11070 if (!(nlflag & 1))
11071 break;
11072 parseheredoc();
11073 return n1;
11074
11075 case TEOF:
11076 if (!n1 && (nlflag & 1))
11077 n1 = NODE_EOF;
11078 parseheredoc();
11079 return n1;
11080 }
11081
11082 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko888527c2016-10-02 16:54:17 +020011083 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
Ron Yorstonc0e00762015-10-29 11:30:55 +000011084 return n1;
11085 nlflag |= 2;
11086
Eric Andersencb57d552001-06-28 07:25:16 +000011087 n2 = andor();
11088 tok = readtoken();
11089 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000011090 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011091 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011092 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011093 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011094 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000011095 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011096 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011097 n2 = n3;
11098 }
11099 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000011100 }
11101 }
11102 if (n1 == NULL) {
11103 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011104 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011105 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011106 n3->type = NSEMI;
11107 n3->nbinary.ch1 = n1;
11108 n3->nbinary.ch2 = n2;
11109 n1 = n3;
11110 }
11111 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011112 case TNL:
11113 case TEOF:
11114 tokpushback = 1;
11115 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000011116 case TBACKGND:
11117 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000011118 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011119 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000011120 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011121 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011122 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011123 return n1;
11124 }
11125 }
11126}
11127
Eric Andersenc470f442003-07-28 09:56:35 +000011128static union node *
11129andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011130{
Eric Andersencb57d552001-06-28 07:25:16 +000011131 union node *n1, *n2, *n3;
11132 int t;
11133
Eric Andersencb57d552001-06-28 07:25:16 +000011134 n1 = pipeline();
11135 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011136 t = readtoken();
11137 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000011138 t = NAND;
11139 } else if (t == TOR) {
11140 t = NOR;
11141 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011142 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011143 return n1;
11144 }
Eric Andersenc470f442003-07-28 09:56:35 +000011145 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011146 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011147 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011148 n3->type = t;
11149 n3->nbinary.ch1 = n1;
11150 n3->nbinary.ch2 = n2;
11151 n1 = n3;
11152 }
11153}
11154
Eric Andersenc470f442003-07-28 09:56:35 +000011155static union node *
11156pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011157{
Eric Andersencb57d552001-06-28 07:25:16 +000011158 union node *n1, *n2, *pipenode;
11159 struct nodelist *lp, *prev;
11160 int negate;
11161
11162 negate = 0;
11163 TRACE(("pipeline: entered\n"));
11164 if (readtoken() == TNOT) {
11165 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000011166 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011167 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011168 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011169 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011170 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011171 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000011172 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011173 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011174 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000011175 pipenode->npipe.cmdlist = lp;
11176 lp->n = n1;
11177 do {
11178 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011179 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000011180 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011181 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011182 prev->next = lp;
11183 } while (readtoken() == TPIPE);
11184 lp->next = NULL;
11185 n1 = pipenode;
11186 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011187 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011188 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011189 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000011190 n2->type = NNOT;
11191 n2->nnot.com = n1;
11192 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011193 }
11194 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000011195}
11196
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011197static union node *
11198makename(void)
11199{
11200 union node *n;
11201
Denis Vlasenko597906c2008-02-20 16:38:54 +000011202 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011203 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011204 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011205 n->narg.text = wordtext;
11206 n->narg.backquote = backquotelist;
11207 return n;
11208}
11209
11210static void
11211fixredir(union node *n, const char *text, int err)
11212{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011213 int fd;
11214
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011215 TRACE(("Fix redir %s %d\n", text, err));
11216 if (!err)
11217 n->ndup.vname = NULL;
11218
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011219 fd = bb_strtou(text, NULL, 10);
11220 if (!errno && fd >= 0)
11221 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011222 else if (LONE_DASH(text))
11223 n->ndup.dupfd = -1;
11224 else {
11225 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011226 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011227 n->ndup.vname = makename();
11228 }
11229}
11230
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011231static void
11232parsefname(void)
11233{
11234 union node *n = redirnode;
11235
Denys Vlasenkoa7328982017-07-29 19:57:28 +020011236 if (n->type == NHERE)
11237 checkkwd = CHKEOFMARK;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011238 if (readtoken() != TWORD)
11239 raise_error_unexpected_syntax(-1);
11240 if (n->type == NHERE) {
11241 struct heredoc *here = heredoc;
11242 struct heredoc *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011243
11244 if (quoteflag == 0)
11245 n->type = NXHERE;
11246 TRACE(("Here document %d\n", n->type));
Denys Vlasenkob6c84342009-08-29 20:23:20 +020011247 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011248 here->eofmark = wordtext;
11249 here->next = NULL;
11250 if (heredoclist == NULL)
11251 heredoclist = here;
11252 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011253 for (p = heredoclist; p->next; p = p->next)
11254 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011255 p->next = here;
11256 }
11257 } else if (n->type == NTOFD || n->type == NFROMFD) {
11258 fixredir(n, wordtext, 0);
11259 } else {
11260 n->nfile.fname = makename();
11261 }
11262}
Eric Andersencb57d552001-06-28 07:25:16 +000011263
Eric Andersenc470f442003-07-28 09:56:35 +000011264static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011265simplecmd(void)
11266{
11267 union node *args, **app;
11268 union node *n = NULL;
11269 union node *vars, **vpp;
11270 union node **rpp, *redir;
11271 int savecheckkwd;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011272#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011273 smallint double_brackets_flag = 0;
11274#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011275 IF_BASH_FUNCTION(smallint function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011276
11277 args = NULL;
11278 app = &args;
11279 vars = NULL;
11280 vpp = &vars;
11281 redir = NULL;
11282 rpp = &redir;
11283
11284 savecheckkwd = CHKALIAS;
11285 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000011286 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011287 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011288 t = readtoken();
11289 switch (t) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011290#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011291 case TFUNCTION:
11292 if (peektoken() != TWORD)
11293 raise_error_unexpected_syntax(TWORD);
11294 function_flag = 1;
11295 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011296#endif
11297#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011298 case TAND: /* "&&" */
11299 case TOR: /* "||" */
11300 if (!double_brackets_flag) {
11301 tokpushback = 1;
11302 goto out;
11303 }
11304 wordtext = (char *) (t == TAND ? "-a" : "-o");
11305#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011306 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011307 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011308 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011309 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011310 n->narg.text = wordtext;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011311#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011312 if (strcmp("[[", wordtext) == 0)
11313 double_brackets_flag = 1;
11314 else if (strcmp("]]", wordtext) == 0)
11315 double_brackets_flag = 0;
11316#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011317 n->narg.backquote = backquotelist;
11318 if (savecheckkwd && isassignment(wordtext)) {
11319 *vpp = n;
11320 vpp = &n->narg.next;
11321 } else {
11322 *app = n;
11323 app = &n->narg.next;
11324 savecheckkwd = 0;
11325 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011326#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011327 if (function_flag) {
11328 checkkwd = CHKNL | CHKKWD;
11329 switch (peektoken()) {
11330 case TBEGIN:
11331 case TIF:
11332 case TCASE:
11333 case TUNTIL:
11334 case TWHILE:
11335 case TFOR:
11336 goto do_func;
11337 case TLP:
11338 function_flag = 0;
11339 break;
11340 case TWORD:
11341 if (strcmp("[[", wordtext) == 0)
11342 goto do_func;
11343 /* fall through */
11344 default:
11345 raise_error_unexpected_syntax(-1);
11346 }
11347 }
11348#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011349 break;
11350 case TREDIR:
11351 *rpp = n = redirnode;
11352 rpp = &n->nfile.next;
11353 parsefname(); /* read name of redirection file */
11354 break;
11355 case TLP:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011356 IF_BASH_FUNCTION(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011357 if (args && app == &args->narg.next
11358 && !vars && !redir
11359 ) {
11360 struct builtincmd *bcmd;
11361 const char *name;
11362
11363 /* We have a function */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011364 if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011365 raise_error_unexpected_syntax(TRP);
11366 name = n->narg.text;
11367 if (!goodname(name)
11368 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11369 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011370 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011371 }
11372 n->type = NDEFUN;
11373 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11374 n->narg.next = parse_command();
11375 return n;
11376 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011377 IF_BASH_FUNCTION(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011378 /* fall through */
11379 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011380 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011381 goto out;
11382 }
11383 }
11384 out:
11385 *app = NULL;
11386 *vpp = NULL;
11387 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011388 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011389 n->type = NCMD;
11390 n->ncmd.args = args;
11391 n->ncmd.assign = vars;
11392 n->ncmd.redirect = redir;
11393 return n;
11394}
11395
11396static union node *
11397parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011398{
Eric Andersencb57d552001-06-28 07:25:16 +000011399 union node *n1, *n2;
11400 union node *ap, **app;
11401 union node *cp, **cpp;
11402 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011403 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011404 int t;
11405
11406 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011407 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011408
Eric Andersencb57d552001-06-28 07:25:16 +000011409 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011410 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011411 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011412 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011413 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011414 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011415 n1->type = NIF;
11416 n1->nif.test = list(0);
11417 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011418 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011419 n1->nif.ifpart = list(0);
11420 n2 = n1;
11421 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011422 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011423 n2 = n2->nif.elsepart;
11424 n2->type = NIF;
11425 n2->nif.test = list(0);
11426 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011427 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011428 n2->nif.ifpart = list(0);
11429 }
11430 if (lasttoken == TELSE)
11431 n2->nif.elsepart = list(0);
11432 else {
11433 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011434 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011435 }
Eric Andersenc470f442003-07-28 09:56:35 +000011436 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011437 break;
11438 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011439 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011440 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011441 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011442 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011443 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011444 got = readtoken();
11445 if (got != TDO) {
Denys Vlasenko888527c2016-10-02 16:54:17 +020011446 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
Denis Vlasenko131ae172007-02-18 13:00:19 +000011447 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011448 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011449 }
11450 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011451 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011452 break;
11453 }
11454 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011455 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011456 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011457 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011458 n1->type = NFOR;
11459 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011460 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011461 if (readtoken() == TIN) {
11462 app = &ap;
11463 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011464 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011465 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011466 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011467 n2->narg.text = wordtext;
11468 n2->narg.backquote = backquotelist;
11469 *app = n2;
11470 app = &n2->narg.next;
11471 }
11472 *app = NULL;
11473 n1->nfor.args = ap;
11474 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011475 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011476 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011477 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011478 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011479 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011480 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011481 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011482 n1->nfor.args = n2;
11483 /*
11484 * Newline or semicolon here is optional (but note
11485 * that the original Bourne shell only allowed NL).
11486 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011487 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011488 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011489 }
Eric Andersenc470f442003-07-28 09:56:35 +000011490 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011491 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011492 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011493 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011494 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011495 break;
11496 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011497 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011498 n1->type = NCASE;
11499 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011500 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011501 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011502 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011503 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011504 n2->narg.text = wordtext;
11505 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011506 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11507 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011508 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011509 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011510 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011511 checkkwd = CHKNL | CHKKWD;
11512 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011513 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011514 if (lasttoken == TLP)
11515 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011516 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011517 cp->type = NCLIST;
11518 app = &cp->nclist.pattern;
11519 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011520 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011521 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011522 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011523 ap->narg.text = wordtext;
11524 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011525 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011526 break;
11527 app = &ap->narg.next;
11528 readtoken();
11529 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011530 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011531 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011532 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011533 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011534
Eric Andersenc470f442003-07-28 09:56:35 +000011535 cpp = &cp->nclist.next;
11536
11537 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011538 t = readtoken();
11539 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011540 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011541 raise_error_unexpected_syntax(TENDCASE);
11542 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011543 }
Eric Andersenc470f442003-07-28 09:56:35 +000011544 }
Eric Andersencb57d552001-06-28 07:25:16 +000011545 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011546 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011547 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011548 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011549 n1->type = NSUBSHELL;
11550 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011551 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011552 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011553 break;
11554 case TBEGIN:
11555 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011556 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011557 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011558 IF_BASH_FUNCTION(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011559 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011560 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011561 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011562 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011563 }
11564
Eric Andersenc470f442003-07-28 09:56:35 +000011565 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011566 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011567
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011568 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011569 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011570 checkkwd = CHKKWD | CHKALIAS;
11571 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011572 while (readtoken() == TREDIR) {
11573 *rpp = n2 = redirnode;
11574 rpp = &n2->nfile.next;
11575 parsefname();
11576 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011577 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011578 *rpp = NULL;
11579 if (redir) {
11580 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011581 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011582 n2->type = NREDIR;
11583 n2->nredir.n = n1;
11584 n1 = n2;
11585 }
11586 n1->nredir.redirect = redir;
11587 }
Eric Andersencb57d552001-06-28 07:25:16 +000011588 return n1;
11589}
11590
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011591#if BASH_DOLLAR_SQUOTE
Denys Vlasenko37dc08b2016-10-02 04:38:07 +020011592static int
11593decode_dollar_squote(void)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011594{
11595 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11596 int c, cnt;
11597 char *p;
11598 char buf[4];
11599
11600 c = pgetc();
11601 p = strchr(C_escapes, c);
11602 if (p) {
11603 buf[0] = c;
11604 p = buf;
11605 cnt = 3;
11606 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11607 do {
11608 c = pgetc();
11609 *++p = c;
11610 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11611 pungetc();
11612 } else if (c == 'x') { /* \xHH */
11613 do {
11614 c = pgetc();
11615 *++p = c;
11616 } while (isxdigit(c) && --cnt);
11617 pungetc();
11618 if (cnt == 3) { /* \x but next char is "bad" */
11619 c = 'x';
11620 goto unrecognized;
11621 }
11622 } else { /* simple seq like \\ or \t */
11623 p++;
11624 }
11625 *p = '\0';
11626 p = buf;
11627 c = bb_process_escape_sequence((void*)&p);
11628 } else { /* unrecognized "\z": print both chars unless ' or " */
11629 if (c != '\'' && c != '"') {
11630 unrecognized:
11631 c |= 0x100; /* "please encode \, then me" */
11632 }
11633 }
11634 return c;
11635}
11636#endif
11637
Denys Vlasenko46999802017-07-29 21:12:29 +020011638/* Used by expandstr to get here-doc like behaviour. */
11639#define FAKEEOFMARK ((char*)(uintptr_t)1)
11640
11641static ALWAYS_INLINE int
11642realeofmark(const char *eofmark)
11643{
11644 return eofmark && eofmark != FAKEEOFMARK;
11645}
11646
Eric Andersencb57d552001-06-28 07:25:16 +000011647/*
11648 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11649 * is not NULL, read a here document. In the latter case, eofmark is the
11650 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011651 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011652 * is the first character of the input token or document.
11653 *
11654 * Because C does not have internal subroutines, I have simulated them
11655 * using goto's to implement the subroutine linkage. The following macros
11656 * will run code that appears at the end of readtoken1.
11657 */
Eric Andersen2870d962001-07-02 17:27:21 +000011658#define CHECKEND() {goto checkend; checkend_return:;}
11659#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11660#define PARSESUB() {goto parsesub; parsesub_return:;}
11661#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11662#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11663#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011664static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011665readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011666{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011667 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011668 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011669 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020011670 size_t len;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011671 struct nodelist *bqlist;
11672 smallint quotef;
11673 smallint dblquote;
11674 smallint oldstyle;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011675 IF_FEATURE_SH_MATH(smallint prevsyntax;) /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011676 smallint pssyntax; /* we are expanding a prompt string */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011677 int varnest; /* levels of variables expansion */
Denys Vlasenko0b883582016-12-23 16:49:07 +010011678 IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */
11679 IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011680 int dqvarnest; /* levels of variables expansion within double quotes */
11681
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011682 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011683
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011684 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011685 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011686 quotef = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011687 IF_FEATURE_SH_MATH(prevsyntax = 0;)
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020011688#if ENABLE_ASH_EXPAND_PRMT
Denis Vlasenko46a53062007-09-24 18:30:02 +000011689 pssyntax = (syntax == PSSYNTAX);
11690 if (pssyntax)
11691 syntax = DQSYNTAX;
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020011692#else
11693 pssyntax = 0; /* constant */
11694#endif
Denis Vlasenko46a53062007-09-24 18:30:02 +000011695 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011696 varnest = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011697 IF_FEATURE_SH_MATH(arinest = 0;)
11698 IF_FEATURE_SH_MATH(parenlevel = 0;)
Eric Andersencb57d552001-06-28 07:25:16 +000011699 dqvarnest = 0;
11700
11701 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011702 loop:
11703 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011704 CHECKEND(); /* set c to PEOF if at end of here document */
11705 for (;;) { /* until end of line or end of word */
11706 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11707 switch (SIT(c, syntax)) {
11708 case CNL: /* '\n' */
11709 if (syntax == BASESYNTAX)
11710 goto endword; /* exit outer loop */
11711 USTPUTC(c, out);
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011712 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011713 c = pgetc();
11714 goto loop; /* continue outer loop */
11715 case CWORD:
11716 USTPUTC(c, out);
11717 break;
11718 case CCTL:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011719#if BASH_DOLLAR_SQUOTE
Denys Vlasenko958581a2010-09-12 15:04:27 +020011720 if (c == '\\' && bash_dollar_squote) {
11721 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020011722 if (c == '\0') {
11723 /* skip $'\000', $'\x00' (like bash) */
11724 break;
11725 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011726 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020011727 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011728 c = (unsigned char)c;
Denys Vlasenko13f20912016-09-25 20:54:25 +020011729 if (eofmark == NULL || dblquote)
11730 USTPUTC(CTLESC, out);
11731 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011732 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011733 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011734#endif
Denys Vlasenko13f20912016-09-25 20:54:25 +020011735 if (eofmark == NULL || dblquote)
11736 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011737 USTPUTC(c, out);
11738 break;
11739 case CBACK: /* backslash */
11740 c = pgetc_without_PEOA();
11741 if (c == PEOF) {
11742 USTPUTC(CTLESC, out);
11743 USTPUTC('\\', out);
11744 pungetc();
11745 } else if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011746 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011747 } else {
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020011748 if (pssyntax && c == '$') {
Eric Andersenc470f442003-07-28 09:56:35 +000011749 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011750 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011751 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011752 /* Backslash is retained if we are in "str" and next char isn't special */
11753 if (dblquote
11754 && c != '\\'
11755 && c != '`'
11756 && c != '$'
11757 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011758 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011759 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011760 }
Ron Yorston549deab2015-05-18 09:57:51 +020011761 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011762 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011763 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011764 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011765 break;
11766 case CSQUOTE:
11767 syntax = SQSYNTAX;
11768 quotemark:
11769 if (eofmark == NULL) {
11770 USTPUTC(CTLQUOTEMARK, out);
11771 }
11772 break;
11773 case CDQUOTE:
11774 syntax = DQSYNTAX;
11775 dblquote = 1;
11776 goto quotemark;
11777 case CENDQUOTE:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011778 IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020011779 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011780 USTPUTC(c, out);
11781 } else {
11782 if (dqvarnest == 0) {
11783 syntax = BASESYNTAX;
11784 dblquote = 0;
11785 }
11786 quotef = 1;
11787 goto quotemark;
11788 }
11789 break;
11790 case CVAR: /* '$' */
11791 PARSESUB(); /* parse substitution */
11792 break;
11793 case CENDVAR: /* '}' */
11794 if (varnest > 0) {
11795 varnest--;
11796 if (dqvarnest > 0) {
11797 dqvarnest--;
11798 }
11799 c = CTLENDVAR;
11800 }
11801 USTPUTC(c, out);
11802 break;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011803#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko958581a2010-09-12 15:04:27 +020011804 case CLP: /* '(' in arithmetic */
11805 parenlevel++;
11806 USTPUTC(c, out);
11807 break;
11808 case CRP: /* ')' in arithmetic */
11809 if (parenlevel > 0) {
11810 parenlevel--;
11811 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011812 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020011813 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011814 if (--arinest == 0) {
11815 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011816 }
11817 } else {
11818 /*
11819 * unbalanced parens
11820 * (don't 2nd guess - no error)
11821 */
11822 pungetc();
11823 }
11824 }
11825 USTPUTC(c, out);
11826 break;
11827#endif
11828 case CBQUOTE: /* '`' */
11829 PARSEBACKQOLD();
11830 break;
11831 case CENDFILE:
11832 goto endword; /* exit outer loop */
11833 case CIGN:
11834 break;
11835 default:
11836 if (varnest == 0) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011837#if BASH_REDIR_OUTPUT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011838 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011839//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020011840 if (pgetc() == '>')
11841 c = 0x100 + '>'; /* flag &> */
11842 pungetc();
11843 }
11844#endif
11845 goto endword; /* exit outer loop */
11846 }
11847 IF_ASH_ALIAS(if (c != PEOA))
11848 USTPUTC(c, out);
11849 }
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020011850 c = pgetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011851 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011852 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011853
Denys Vlasenko0b883582016-12-23 16:49:07 +010011854#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000011855 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011856 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011857#endif
Ron Yorston0e056f72015-07-01 16:45:40 +010011858 if (syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011859 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011860 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011861 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011862 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011863 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011864 }
11865 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011866 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011867 out = stackblock();
11868 if (eofmark == NULL) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011869 if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011870 && quotef == 0
11871 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011872 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011873 PARSEREDIR(); /* passed as params: out, c */
11874 lasttoken = TREDIR;
11875 return lasttoken;
11876 }
11877 /* else: non-number X seen, interpret it
11878 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011879 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011880 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011881 }
11882 quoteflag = quotef;
11883 backquotelist = bqlist;
11884 grabstackblock(len);
11885 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011886 lasttoken = TWORD;
11887 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011888/* end of readtoken routine */
11889
Eric Andersencb57d552001-06-28 07:25:16 +000011890/*
11891 * Check to see whether we are at the end of the here document. When this
11892 * is called, c is set to the first character of the next input line. If
11893 * we are at the end of the here document, this routine sets the c to PEOF.
11894 */
Eric Andersenc470f442003-07-28 09:56:35 +000011895checkend: {
Denys Vlasenko46999802017-07-29 21:12:29 +020011896 if (realeofmark(eofmark)) {
Denys Vlasenkoa7328982017-07-29 19:57:28 +020011897 int markloc;
11898 char *p;
11899
Denis Vlasenko131ae172007-02-18 13:00:19 +000011900#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011901 if (c == PEOA)
11902 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011903#endif
11904 if (striptabs) {
11905 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011906 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011907 }
Eric Andersenc470f442003-07-28 09:56:35 +000011908 }
Eric Andersencb57d552001-06-28 07:25:16 +000011909
Denys Vlasenkoa7328982017-07-29 19:57:28 +020011910 markloc = out - (char *)stackblock();
11911 for (p = eofmark; STPUTC(c, out), *p; p++) {
11912 if (c != *p)
11913 goto more_heredoc;
11914
11915 c = pgetc_without_PEOA();
11916 }
11917
11918 if (c == '\n' || c == PEOF) {
11919 c = PEOF;
11920 g_parsefile->linno++;
11921 needprompt = doprompt;
11922 } else {
11923 int len_here;
11924
11925 more_heredoc:
11926 p = (char *)stackblock() + markloc + 1;
11927 len_here = out - p;
11928
11929 if (len_here) {
11930 len_here -= (c >= PEOF);
11931 c = p[-1];
11932
11933 if (len_here) {
11934 char *str;
11935
11936 str = alloca(len_here + 1);
11937 *(char *)mempcpy(str, p, len_here) = '\0';
11938
11939 pushstring(str, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011940 }
11941 }
11942 }
Denys Vlasenkoa7328982017-07-29 19:57:28 +020011943
11944 STADJUST((char *)stackblock() + markloc - out, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011945 }
Eric Andersenc470f442003-07-28 09:56:35 +000011946 goto checkend_return;
11947}
Eric Andersencb57d552001-06-28 07:25:16 +000011948
Eric Andersencb57d552001-06-28 07:25:16 +000011949/*
11950 * Parse a redirection operator. The variable "out" points to a string
11951 * specifying the fd to be redirected. The variable "c" contains the
11952 * first character of the redirection operator.
11953 */
Eric Andersenc470f442003-07-28 09:56:35 +000011954parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011955 /* out is already checked to be a valid number or "" */
11956 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000011957 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000011958
Denis Vlasenko597906c2008-02-20 16:38:54 +000011959 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000011960 if (c == '>') {
11961 np->nfile.fd = 1;
11962 c = pgetc();
11963 if (c == '>')
11964 np->type = NAPPEND;
11965 else if (c == '|')
11966 np->type = NCLOBBER;
11967 else if (c == '&')
11968 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011969 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000011970 else {
11971 np->type = NTO;
11972 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011973 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000011974 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011975#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000011976 else if (c == 0x100 + '>') { /* this flags &> redirection */
11977 np->nfile.fd = 1;
11978 pgetc(); /* this is '>', no need to check */
11979 np->type = NTO2;
11980 }
11981#endif
11982 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000011983 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011984 c = pgetc();
11985 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000011986 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011987 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011988 np = stzalloc(sizeof(struct nhere));
11989 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011990 }
11991 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011992 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000011993 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011994 c = pgetc();
11995 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000011996 heredoc->striptabs = 1;
11997 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011998 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011999 pungetc();
12000 }
12001 break;
12002
12003 case '&':
12004 np->type = NFROMFD;
12005 break;
12006
12007 case '>':
12008 np->type = NFROMTO;
12009 break;
12010
12011 default:
12012 np->type = NFROM;
12013 pungetc();
12014 break;
12015 }
Eric Andersencb57d552001-06-28 07:25:16 +000012016 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012017 if (fd >= 0)
12018 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000012019 redirnode = np;
12020 goto parseredir_return;
12021}
Eric Andersencb57d552001-06-28 07:25:16 +000012022
Eric Andersencb57d552001-06-28 07:25:16 +000012023/*
12024 * Parse a substitution. At this point, we have read the dollar sign
12025 * and nothing else.
12026 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012027
12028/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
12029 * (assuming ascii char codes, as the original implementation did) */
12030#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012031 (((unsigned)(c) - 33 < 32) \
12032 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000012033parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010012034 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012035 int typeloc;
Eric Andersencb57d552001-06-28 07:25:16 +000012036
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012037 c = pgetc_eatbnl();
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012038 if ((checkkwd & CHKEOFMARK)
12039 || c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012040 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000012041 ) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012042#if BASH_DOLLAR_SQUOTE
Ron Yorston84ba50c2016-04-03 22:43:14 +010012043 if (syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012044 bash_dollar_squote = 1;
12045 else
12046#endif
12047 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000012048 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012049 } else if (c == '(') {
12050 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012051 if (pgetc_eatbnl() == '(') {
Denys Vlasenko0b883582016-12-23 16:49:07 +010012052#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000012053 PARSEARITH();
12054#else
Denys Vlasenko4f8079d2017-07-17 17:11:48 +020012055 raise_error_syntax("support for $((arith)) is disabled");
Eric Andersenc470f442003-07-28 09:56:35 +000012056#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012057 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012058 pungetc();
12059 PARSEBACKQNEW();
12060 }
12061 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012062 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000012063 USTPUTC(CTLVAR, out);
12064 typeloc = out - (char *)stackblock();
Denys Vlasenko3df14102016-10-26 16:41:13 +020012065 STADJUST(1, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012066 subtype = VSNORMAL;
12067 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012068 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012069 subtype = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000012070 }
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012071 varname:
Denys Vlasenko3df14102016-10-26 16:41:13 +020012072 if (is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012073 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000012074 do {
12075 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012076 c = pgetc_eatbnl();
Denys Vlasenko3df14102016-10-26 16:41:13 +020012077 } while (is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012078 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012079 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000012080 do {
12081 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012082 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012083 } while (isdigit(c));
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012084 } else if (is_special(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012085 /* $[{[#]]<specialchar>[}] */
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012086 int cc = c;
12087
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012088 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012089 if (!subtype && cc == '#') {
12090 subtype = VSLENGTH;
12091 if (c == '_' || isalnum(c))
12092 goto varname;
12093 cc = c;
12094 c = pgetc_eatbnl();
12095 if (cc == '}' || c != '}') {
12096 pungetc();
12097 subtype = 0;
12098 c = cc;
12099 cc = '#';
12100 }
12101 }
12102 USTPUTC(cc, out);
Denis Vlasenko559691a2008-10-05 18:39:31 +000012103 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020012104 goto badsub;
Denis Vlasenko559691a2008-10-05 18:39:31 +000012105 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012106 if (c != '}' && subtype == VSLENGTH) {
12107 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020012108 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012109 }
Eric Andersencb57d552001-06-28 07:25:16 +000012110
Eric Andersenc470f442003-07-28 09:56:35 +000012111 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012112 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012113 /* ${VAR...} but not $VAR or ${#VAR} */
12114 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000012115 switch (c) {
12116 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012117 c = pgetc_eatbnl();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012118#if BASH_SUBSTR
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012119 /* This check is only needed to not misinterpret
12120 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
12121 * constructs.
12122 */
12123 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012124 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012125 pungetc();
Denys Vlasenko88e15702016-10-26 01:55:56 +020012126 break; /* "goto badsub" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012127 }
12128#endif
Denys Vlasenko3df14102016-10-26 16:41:13 +020012129 subtype = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000012130 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012131 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012132 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000012133 if (p == NULL)
Denys Vlasenko88e15702016-10-26 01:55:56 +020012134 break;
Denys Vlasenko3df14102016-10-26 16:41:13 +020012135 subtype |= p - types + VSNORMAL;
Eric Andersenc470f442003-07-28 09:56:35 +000012136 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012137 }
Eric Andersenc470f442003-07-28 09:56:35 +000012138 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012139 case '#': {
12140 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012141 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012142 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012143 if (c != cc)
Denys Vlasenko88e15702016-10-26 01:55:56 +020012144 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012145 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012146 break;
12147 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012148#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012149 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020012150 /* ${v/[/]pattern/repl} */
12151//TODO: encode pattern and repl separately.
12152// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012153 subtype = VSREPLACE;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012154 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012155 if (c != '/')
Denys Vlasenko88e15702016-10-26 01:55:56 +020012156 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012157 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012158 break;
12159#endif
Eric Andersencb57d552001-06-28 07:25:16 +000012160 }
Eric Andersenc470f442003-07-28 09:56:35 +000012161 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020012162 badsub:
Eric Andersenc470f442003-07-28 09:56:35 +000012163 pungetc();
12164 }
Denys Vlasenko3df14102016-10-26 16:41:13 +020012165 ((unsigned char *)stackblock())[typeloc] = subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012166 if (subtype != VSNORMAL) {
12167 varnest++;
Denys Vlasenko3df14102016-10-26 16:41:13 +020012168 if (dblquote)
Eric Andersenc470f442003-07-28 09:56:35 +000012169 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000012170 }
Denys Vlasenko88e15702016-10-26 01:55:56 +020012171 STPUTC('=', out);
Eric Andersencb57d552001-06-28 07:25:16 +000012172 }
Eric Andersenc470f442003-07-28 09:56:35 +000012173 goto parsesub_return;
12174}
Eric Andersencb57d552001-06-28 07:25:16 +000012175
Eric Andersencb57d552001-06-28 07:25:16 +000012176/*
12177 * Called to parse command substitutions. Newstyle is set if the command
12178 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
12179 * list of commands (passed by reference), and savelen is the number of
12180 * characters on the top of the stack which must be preserved.
12181 */
Eric Andersenc470f442003-07-28 09:56:35 +000012182parsebackq: {
12183 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012184 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010012185 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000012186 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012187 smallint saveprompt = 0;
12188
Eric Andersenc470f442003-07-28 09:56:35 +000012189 str = NULL;
12190 savelen = out - (char *)stackblock();
12191 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012192 /*
12193 * FIXME: this can allocate very large block on stack and SEGV.
12194 * Example:
12195 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020012196 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012197 * a hundred command substitutions stack overflows.
12198 * With larger prepended string, SEGV happens sooner.
12199 */
Ron Yorston072fc602015-07-01 16:46:18 +010012200 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000012201 memcpy(str, stackblock(), savelen);
12202 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012203
Eric Andersenc470f442003-07-28 09:56:35 +000012204 if (oldstyle) {
12205 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010012206 * treatment to some slashes, and then push the string and
12207 * reread it as input, interpreting it normally.
12208 */
Eric Andersenc470f442003-07-28 09:56:35 +000012209 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000012210 size_t psavelen;
12211 char *pstr;
12212
Eric Andersenc470f442003-07-28 09:56:35 +000012213 STARTSTACKSTR(pout);
12214 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012215 int pc;
12216
12217 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012218 pc = pgetc();
12219 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000012220 case '`':
12221 goto done;
12222
12223 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012224 pc = pgetc();
12225 if (pc == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012226 nlprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012227 /*
12228 * If eating a newline, avoid putting
12229 * the newline into the new character
12230 * stream (via the STPUTC after the
12231 * switch).
12232 */
12233 continue;
12234 }
12235 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012236 && (!dblquote || pc != '"')
12237 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000012238 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012239 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010012240 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000012241 break;
12242 }
12243 /* fall through */
12244
12245 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012246 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012247 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012248 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000012249
12250 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012251 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012252 break;
12253
12254 default:
12255 break;
12256 }
12257 STPUTC(pc, pout);
12258 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012259 done:
Eric Andersenc470f442003-07-28 09:56:35 +000012260 STPUTC('\0', pout);
12261 psavelen = pout - (char *)stackblock();
12262 if (psavelen > 0) {
12263 pstr = grabstackstr(pout);
12264 setinputstring(pstr);
12265 }
12266 }
12267 nlpp = &bqlist;
12268 while (*nlpp)
12269 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012270 *nlpp = stzalloc(sizeof(**nlpp));
12271 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012272
12273 if (oldstyle) {
12274 saveprompt = doprompt;
12275 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012276 }
12277
Eric Andersenc470f442003-07-28 09:56:35 +000012278 n = list(2);
12279
12280 if (oldstyle)
12281 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012282 else if (readtoken() != TRP)
12283 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000012284
12285 (*nlpp)->n = n;
12286 if (oldstyle) {
12287 /*
12288 * Start reading from old file again, ignoring any pushed back
12289 * tokens left from the backquote parsing
12290 */
12291 popfile();
12292 tokpushback = 0;
12293 }
12294 while (stackblocksize() <= savelen)
12295 growstackblock();
12296 STARTSTACKSTR(out);
12297 if (str) {
12298 memcpy(out, str, savelen);
12299 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012300 }
Ron Yorston549deab2015-05-18 09:57:51 +020012301 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012302 if (oldstyle)
12303 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012304 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000012305}
12306
Denys Vlasenko0b883582016-12-23 16:49:07 +010012307#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000012308/*
12309 * Parse an arithmetic expansion (indicate start of one and set state)
12310 */
Eric Andersenc470f442003-07-28 09:56:35 +000012311parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000012312 if (++arinest == 1) {
12313 prevsyntax = syntax;
12314 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000012315 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020012316 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012317 goto parsearith_return;
12318}
12319#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012320} /* end of readtoken */
12321
Eric Andersencb57d552001-06-28 07:25:16 +000012322/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012323 * Read the next input token.
12324 * If the token is a word, we set backquotelist to the list of cmds in
12325 * backquotes. We set quoteflag to true if any part of the word was
12326 * quoted.
12327 * If the token is TREDIR, then we set redirnode to a structure containing
12328 * the redirection.
12329 * In all cases, the variable startlinno is set to the number of the line
12330 * on which the token starts.
12331 *
12332 * [Change comment: here documents and internal procedures]
12333 * [Readtoken shouldn't have any arguments. Perhaps we should make the
12334 * word parsing code into a separate routine. In this case, readtoken
12335 * doesn't need to have any internal procedures, but parseword does.
12336 * We could also make parseoperator in essence the main routine, and
12337 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000012338 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012339#define NEW_xxreadtoken
12340#ifdef NEW_xxreadtoken
12341/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012342static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000012343 '\n', '(', ')', /* singles */
12344 '&', '|', ';', /* doubles */
12345 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012346};
Eric Andersencb57d552001-06-28 07:25:16 +000012347
Denis Vlasenko834dee72008-10-07 09:18:30 +000012348#define xxreadtoken_singles 3
12349#define xxreadtoken_doubles 3
12350
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012351static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012352 TNL, TLP, TRP, /* only single occurrence allowed */
12353 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12354 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012355 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012356};
12357
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012358static int
12359xxreadtoken(void)
12360{
12361 int c;
12362
12363 if (tokpushback) {
12364 tokpushback = 0;
12365 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012366 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012367 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012368 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012369 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012370 c = pgetc();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000012371 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012372 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012373
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012374 if (c == '#') {
12375 while ((c = pgetc()) != '\n' && c != PEOF)
12376 continue;
12377 pungetc();
12378 } else if (c == '\\') {
12379 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012380 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012381 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012382 }
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012383 nlprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012384 } else {
12385 const char *p;
12386
12387 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12388 if (c != PEOF) {
12389 if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012390 nlnoprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012391 }
12392
12393 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000012394 if (p == NULL)
12395 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012396
Denis Vlasenko834dee72008-10-07 09:18:30 +000012397 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12398 int cc = pgetc();
12399 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012400 p += xxreadtoken_doubles + 1;
12401 } else {
12402 pungetc();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012403#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012404 if (c == '&' && cc == '>') /* &> */
12405 break; /* return readtoken1(...) */
12406#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012407 }
12408 }
12409 }
12410 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12411 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012412 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012413 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012414
12415 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012416}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012417#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012418#define RETURN(token) return lasttoken = token
12419static int
12420xxreadtoken(void)
12421{
12422 int c;
12423
12424 if (tokpushback) {
12425 tokpushback = 0;
12426 return lasttoken;
12427 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012428 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012429 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012430 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012431 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012432 switch (c) {
12433 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012434 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012435 continue;
12436 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012437 while ((c = pgetc()) != '\n' && c != PEOF)
12438 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012439 pungetc();
12440 continue;
12441 case '\\':
12442 if (pgetc() == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012443 nlprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012444 continue;
12445 }
12446 pungetc();
12447 goto breakloop;
12448 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012449 nlnoprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012450 RETURN(TNL);
12451 case PEOF:
12452 RETURN(TEOF);
12453 case '&':
12454 if (pgetc() == '&')
12455 RETURN(TAND);
12456 pungetc();
12457 RETURN(TBACKGND);
12458 case '|':
12459 if (pgetc() == '|')
12460 RETURN(TOR);
12461 pungetc();
12462 RETURN(TPIPE);
12463 case ';':
12464 if (pgetc() == ';')
12465 RETURN(TENDCASE);
12466 pungetc();
12467 RETURN(TSEMI);
12468 case '(':
12469 RETURN(TLP);
12470 case ')':
12471 RETURN(TRP);
12472 default:
12473 goto breakloop;
12474 }
12475 }
12476 breakloop:
12477 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12478#undef RETURN
12479}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012480#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012481
12482static int
12483readtoken(void)
12484{
12485 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012486 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012487#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012488 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012489#endif
12490
12491#if ENABLE_ASH_ALIAS
12492 top:
12493#endif
12494
12495 t = xxreadtoken();
12496
12497 /*
12498 * eat newlines
12499 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012500 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012501 while (t == TNL) {
12502 parseheredoc();
12503 t = xxreadtoken();
12504 }
12505 }
12506
12507 if (t != TWORD || quoteflag) {
12508 goto out;
12509 }
12510
12511 /*
12512 * check for keywords
12513 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012514 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012515 const char *const *pp;
12516
12517 pp = findkwd(wordtext);
12518 if (pp) {
12519 lasttoken = t = pp - tokname_array;
Denys Vlasenko888527c2016-10-02 16:54:17 +020012520 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012521 goto out;
12522 }
12523 }
12524
12525 if (checkkwd & CHKALIAS) {
12526#if ENABLE_ASH_ALIAS
12527 struct alias *ap;
12528 ap = lookupalias(wordtext, 1);
12529 if (ap != NULL) {
12530 if (*ap->val) {
12531 pushstring(ap->val, ap);
12532 }
12533 goto top;
12534 }
12535#endif
12536 }
12537 out:
12538 checkkwd = 0;
12539#if DEBUG
12540 if (!alreadyseen)
Denys Vlasenko888527c2016-10-02 16:54:17 +020012541 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012542 else
Denys Vlasenko888527c2016-10-02 16:54:17 +020012543 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012544#endif
12545 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012546}
12547
Ron Yorstonc0e00762015-10-29 11:30:55 +000012548static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012549peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012550{
12551 int t;
12552
12553 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012554 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012555 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012556}
Eric Andersencb57d552001-06-28 07:25:16 +000012557
12558/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012559 * Read and parse a command. Returns NODE_EOF on end of file.
12560 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012561 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012562static union node *
12563parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012564{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012565 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012566 checkkwd = 0;
12567 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012568 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012569 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012570 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012571 return list(1);
12572}
12573
12574/*
12575 * Input any here documents.
12576 */
12577static void
12578parseheredoc(void)
12579{
12580 struct heredoc *here;
12581 union node *n;
12582
12583 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012584 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012585
12586 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012587 setprompt_if(needprompt, 2);
12588 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012589 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012590 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012591 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012592 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012593 n->narg.text = wordtext;
12594 n->narg.backquote = backquotelist;
12595 here->here->nhere.doc = n;
12596 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012597 }
Eric Andersencb57d552001-06-28 07:25:16 +000012598}
12599
12600
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012601static const char *
Denys Vlasenko46999802017-07-29 21:12:29 +020012602expandstr(const char *ps, int syntax_type)
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012603{
12604 union node n;
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012605 int saveprompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012606
Denys Vlasenko46999802017-07-29 21:12:29 +020012607 /* XXX Fix (char *) cast. */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012608 setinputstring((char *)ps);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012609
12610 saveprompt = doprompt;
12611 doprompt = 0;
Denys Vlasenko46999802017-07-29 21:12:29 +020012612 readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012613 doprompt = saveprompt;
12614
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012615 popfile();
12616
12617 n.narg.type = NARG;
12618 n.narg.next = NULL;
12619 n.narg.text = wordtext;
12620 n.narg.backquote = backquotelist;
12621
Ron Yorston549deab2015-05-18 09:57:51 +020012622 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012623 return stackblock();
12624}
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012625
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020012626static inline int
12627parser_eof(void)
12628{
12629 return tokpushback && lasttoken == TEOF;
12630}
12631
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012632/*
12633 * Execute a command or commands contained in a string.
12634 */
12635static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012636evalstring(char *s, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000012637{
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012638 struct jmploc *volatile savehandler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012639 struct jmploc jmploc;
12640 int ex;
12641
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012642 union node *n;
12643 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012644 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012645
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012646 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012647 setinputstring(s);
12648 setstackmark(&smark);
12649
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012650 status = 0;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012651 /* On exception inside execution loop, we must popfile().
12652 * Try interactively:
12653 * readonly a=a
12654 * command eval "a=b" # throws "is read only" error
12655 * "command BLTIN" is not supposed to abort (even in non-interactive use).
12656 * But if we skip popfile(), we hit EOF in eval's string, and exit.
12657 */
12658 savehandler = exception_handler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012659 ex = setjmp(jmploc.loc);
12660 if (ex)
12661 goto out;
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012662 exception_handler = &jmploc;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012663
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012664 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012665 int i;
12666
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020012667 i = evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT));
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012668 if (n)
12669 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012670 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012671 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012672 break;
12673 }
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012674 out:
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012675 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012676 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012677 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012678
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012679 exception_handler = savehandler;
12680 if (ex)
12681 longjmp(exception_handler->loc, ex);
12682
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012683 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000012684}
12685
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012686/*
12687 * The eval command.
12688 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012689static int FAST_FUNC
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012690evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012691{
12692 char *p;
12693 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012694
Denis Vlasenko68404f12008-03-17 09:00:54 +000012695 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012696 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012697 argv += 2;
12698 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012699 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012700 for (;;) {
12701 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012702 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012703 if (p == NULL)
12704 break;
12705 STPUTC(' ', concat);
12706 }
12707 STPUTC('\0', concat);
12708 p = grabstackstr(concat);
12709 }
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012710 return evalstring(p, flags & EV_TESTED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012711 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012712 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012713}
12714
12715/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012716 * Read and execute commands.
12717 * "Top" is nonzero for the top level command loop;
12718 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012719 */
12720static int
12721cmdloop(int top)
12722{
12723 union node *n;
12724 struct stackmark smark;
12725 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012726 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012727 int numeof = 0;
12728
12729 TRACE(("cmdloop(%d) called\n", top));
12730 for (;;) {
12731 int skip;
12732
12733 setstackmark(&smark);
12734#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012735 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020012736 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012737#endif
12738 inter = 0;
12739 if (iflag && top) {
12740 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012741 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012742 }
12743 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012744#if DEBUG
12745 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012746 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012747#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012748 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012749 if (!top || numeof >= 50)
12750 break;
12751 if (!stoppedjobs()) {
12752 if (!Iflag)
12753 break;
12754 out2str("\nUse \"exit\" to leave shell.\n");
12755 }
12756 numeof++;
12757 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012758 int i;
12759
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012760 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12761 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012762 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012763 i = evaltree(n, 0);
12764 if (n)
12765 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012766 }
12767 popstackmark(&smark);
12768 skip = evalskip;
12769
12770 if (skip) {
Denys Vlasenko6a0710e2016-09-30 14:18:34 +020012771 evalskip &= ~SKIPFUNC;
Denys Vlasenko0840c912016-10-01 15:27:44 +020012772 break;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012773 }
12774 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012775 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012776}
12777
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012778/*
12779 * Take commands from a file. To be compatible we should do a path
12780 * search for the file, which is necessary to find sub-commands.
12781 */
12782static char *
12783find_dot_file(char *name)
12784{
12785 char *fullname;
12786 const char *path = pathval();
12787 struct stat statb;
12788
12789 /* don't try this for absolute or relative paths */
12790 if (strchr(name, '/'))
12791 return name;
12792
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012793 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012794 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12795 /*
12796 * Don't bother freeing here, since it will
12797 * be freed by the caller.
12798 */
12799 return fullname;
12800 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012801 if (fullname != name)
12802 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012803 }
12804
12805 /* not found in the PATH */
12806 ash_msg_and_raise_error("%s: not found", name);
12807 /* NOTREACHED */
12808}
12809
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012810static int FAST_FUNC
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012811dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012812{
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012813 /* "false; . empty_file; echo $?" should print 0, not 1: */
12814 int status = 0;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012815 char *fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012816 char **argv;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012817 char *args_need_save;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012818 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012819
Denys Vlasenko981a0562017-07-26 19:53:11 +020012820//???
12821// struct strlist *sp;
12822// for (sp = cmdenviron; sp; sp = sp->next)
12823// setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012824
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012825 nextopt(nullstr); /* handle possible "--" */
12826 argv = argptr;
12827
12828 if (!argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012829 /* bash says: "bash: .: filename argument required" */
12830 return 2; /* bash compat */
12831 }
12832
Denys Vlasenko091f8312013-03-17 14:25:22 +010012833 /* This aborts if file isn't found, which is POSIXly correct.
12834 * bash returns exitcode 1 instead.
12835 */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012836 fullname = find_dot_file(argv[0]);
12837 argv++;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012838 args_need_save = argv[0];
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010012839 if (args_need_save) { /* ". FILE ARGS", and ARGS are not empty */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012840 int argc;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012841 saveparam = shellparam;
12842 shellparam.malloced = 0;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012843 argc = 1;
12844 while (argv[argc])
12845 argc++;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012846 shellparam.nparam = argc;
12847 shellparam.p = argv;
12848 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012849
Denys Vlasenko091f8312013-03-17 14:25:22 +010012850 /* This aborts if file can't be opened, which is POSIXly correct.
12851 * bash returns exitcode 1 instead.
12852 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012853 setinputfile(fullname, INPUT_PUSH_FILE);
12854 commandname = fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012855 status = cmdloop(0);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012856 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012857
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012858 if (args_need_save) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012859 freeparam(&shellparam);
12860 shellparam = saveparam;
12861 };
12862
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012863 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012864}
12865
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012866static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012867exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012868{
12869 if (stoppedjobs())
12870 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012871 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012872 exitstatus = number(argv[1]);
12873 raise_exception(EXEXIT);
12874 /* NOTREACHED */
12875}
12876
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012877/*
12878 * Read a file containing shell functions.
12879 */
12880static void
12881readcmdfile(char *name)
12882{
12883 setinputfile(name, INPUT_PUSH_FILE);
12884 cmdloop(0);
12885 popfile();
12886}
12887
12888
Denis Vlasenkocc571512007-02-23 21:10:35 +000012889/* ============ find_command inplementation */
12890
12891/*
12892 * Resolve a command name. If you change this routine, you may have to
12893 * change the shellexec routine as well.
12894 */
12895static void
12896find_command(char *name, struct cmdentry *entry, int act, const char *path)
12897{
12898 struct tblentry *cmdp;
12899 int idx;
12900 int prev;
12901 char *fullname;
12902 struct stat statb;
12903 int e;
12904 int updatetbl;
12905 struct builtincmd *bcmd;
12906
12907 /* If name contains a slash, don't use PATH or hash table */
12908 if (strchr(name, '/') != NULL) {
12909 entry->u.index = -1;
12910 if (act & DO_ABS) {
12911 while (stat(name, &statb) < 0) {
12912#ifdef SYSV
12913 if (errno == EINTR)
12914 continue;
12915#endif
12916 entry->cmdtype = CMDUNKNOWN;
12917 return;
12918 }
12919 }
12920 entry->cmdtype = CMDNORMAL;
12921 return;
12922 }
12923
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012924/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012925
12926 updatetbl = (path == pathval());
12927 if (!updatetbl) {
12928 act |= DO_ALTPATH;
12929 if (strstr(path, "%builtin") != NULL)
12930 act |= DO_ALTBLTIN;
12931 }
12932
12933 /* If name is in the table, check answer will be ok */
12934 cmdp = cmdlookup(name, 0);
12935 if (cmdp != NULL) {
12936 int bit;
12937
12938 switch (cmdp->cmdtype) {
12939 default:
12940#if DEBUG
12941 abort();
12942#endif
12943 case CMDNORMAL:
12944 bit = DO_ALTPATH;
12945 break;
12946 case CMDFUNCTION:
12947 bit = DO_NOFUNC;
12948 break;
12949 case CMDBUILTIN:
12950 bit = DO_ALTBLTIN;
12951 break;
12952 }
12953 if (act & bit) {
12954 updatetbl = 0;
12955 cmdp = NULL;
12956 } else if (cmdp->rehash == 0)
12957 /* if not invalidated by cd, we're done */
12958 goto success;
12959 }
12960
12961 /* If %builtin not in path, check for builtin next */
12962 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012963 if (bcmd) {
12964 if (IS_BUILTIN_REGULAR(bcmd))
12965 goto builtin_success;
12966 if (act & DO_ALTPATH) {
12967 if (!(act & DO_ALTBLTIN))
12968 goto builtin_success;
12969 } else if (builtinloc <= 0) {
12970 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000012971 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012972 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000012973
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012974#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000012975 {
12976 int applet_no = find_applet_by_name(name);
12977 if (applet_no >= 0) {
12978 entry->cmdtype = CMDNORMAL;
12979 entry->u.index = -2 - applet_no;
12980 return;
12981 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012982 }
12983#endif
12984
Denis Vlasenkocc571512007-02-23 21:10:35 +000012985 /* We have to search path. */
12986 prev = -1; /* where to start */
12987 if (cmdp && cmdp->rehash) { /* doing a rehash */
12988 if (cmdp->cmdtype == CMDBUILTIN)
12989 prev = builtinloc;
12990 else
12991 prev = cmdp->param.index;
12992 }
12993
12994 e = ENOENT;
12995 idx = -1;
12996 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012997 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000012998 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012999 /* NB: code below will still use fullname
13000 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013001 idx++;
13002 if (pathopt) {
13003 if (prefix(pathopt, "builtin")) {
13004 if (bcmd)
13005 goto builtin_success;
13006 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000013007 }
13008 if ((act & DO_NOFUNC)
13009 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020013010 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013011 continue;
13012 }
13013 }
13014 /* if rehash, don't redo absolute path names */
13015 if (fullname[0] == '/' && idx <= prev) {
13016 if (idx < prev)
13017 continue;
13018 TRACE(("searchexec \"%s\": no change\n", name));
13019 goto success;
13020 }
13021 while (stat(fullname, &statb) < 0) {
13022#ifdef SYSV
13023 if (errno == EINTR)
13024 continue;
13025#endif
13026 if (errno != ENOENT && errno != ENOTDIR)
13027 e = errno;
13028 goto loop;
13029 }
13030 e = EACCES; /* if we fail, this will be the error */
13031 if (!S_ISREG(statb.st_mode))
13032 continue;
13033 if (pathopt) { /* this is a %func directory */
13034 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000013035 /* NB: stalloc will return space pointed by fullname
13036 * (because we don't have any intervening allocations
13037 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013038 readcmdfile(fullname);
13039 cmdp = cmdlookup(name, 0);
13040 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
13041 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
13042 stunalloc(fullname);
13043 goto success;
13044 }
13045 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
13046 if (!updatetbl) {
13047 entry->cmdtype = CMDNORMAL;
13048 entry->u.index = idx;
13049 return;
13050 }
13051 INT_OFF;
13052 cmdp = cmdlookup(name, 1);
13053 cmdp->cmdtype = CMDNORMAL;
13054 cmdp->param.index = idx;
13055 INT_ON;
13056 goto success;
13057 }
13058
13059 /* We failed. If there was an entry for this command, delete it */
13060 if (cmdp && updatetbl)
13061 delete_cmd_entry();
13062 if (act & DO_ERR)
13063 ash_msg("%s: %s", name, errmsg(e, "not found"));
13064 entry->cmdtype = CMDUNKNOWN;
13065 return;
13066
13067 builtin_success:
13068 if (!updatetbl) {
13069 entry->cmdtype = CMDBUILTIN;
13070 entry->u.cmd = bcmd;
13071 return;
13072 }
13073 INT_OFF;
13074 cmdp = cmdlookup(name, 1);
13075 cmdp->cmdtype = CMDBUILTIN;
13076 cmdp->param.cmd = bcmd;
13077 INT_ON;
13078 success:
13079 cmdp->rehash = 0;
13080 entry->cmdtype = cmdp->cmdtype;
13081 entry->u = cmdp->param;
13082}
13083
13084
Eric Andersencb57d552001-06-28 07:25:16 +000013085/*
Eric Andersencb57d552001-06-28 07:25:16 +000013086 * The trap builtin.
13087 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013088static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013089trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013090{
13091 char *action;
13092 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013093 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013094
Eric Andersenc470f442003-07-28 09:56:35 +000013095 nextopt(nullstr);
13096 ap = argptr;
13097 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013098 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013099 char *tr = trap_ptr[signo];
13100 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013101 /* note: bash adds "SIG", but only if invoked
13102 * as "bash". If called as "sh", or if set -o posix,
13103 * then it prints short signal names.
13104 * We are printing short names: */
13105 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013106 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013107 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013108 /* trap_ptr != trap only if we are in special-cased `trap` code.
13109 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013110 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013111 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000013112 }
13113 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013114 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013115 if (trap_ptr != trap) {
13116 free(trap_ptr);
13117 trap_ptr = trap;
13118 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013119 */
Eric Andersencb57d552001-06-28 07:25:16 +000013120 return 0;
13121 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013122
Denys Vlasenko86981e32017-07-25 20:06:17 +020013123 /* Why the second check?
13124 * "trap NUM [sig2]..." is the same as "trap - NUM [sig2]..."
13125 * In this case, NUM is signal no, not an action.
13126 */
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013127 action = NULL;
Denys Vlasenko86981e32017-07-25 20:06:17 +020013128 if (ap[1] && !is_number(ap[0]))
Eric Andersencb57d552001-06-28 07:25:16 +000013129 action = *ap++;
Denys Vlasenko86981e32017-07-25 20:06:17 +020013130
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013131 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013132 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000013133 signo = get_signum(*ap);
Denys Vlasenko86981e32017-07-25 20:06:17 +020013134 if (signo < 0) {
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013135 /* Mimic bash message exactly */
13136 ash_msg("%s: invalid signal specification", *ap);
13137 exitcode = 1;
13138 goto next;
13139 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000013140 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000013141 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000013142 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000013143 action = NULL;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013144 else {
13145 if (action[0]) /* not NULL and not "" and not "-" */
13146 may_have_traps = 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013147 action = ckstrdup(action);
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013148 }
Eric Andersencb57d552001-06-28 07:25:16 +000013149 }
Denis Vlasenko60818682007-09-28 22:07:23 +000013150 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000013151 trap[signo] = action;
13152 if (signo != 0)
13153 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013154 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013155 next:
Eric Andersencb57d552001-06-28 07:25:16 +000013156 ap++;
13157 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013158 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013159}
13160
Eric Andersenc470f442003-07-28 09:56:35 +000013161
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013162/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000013163
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013164#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013165static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013166helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013167{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000013168 unsigned col;
13169 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000013170
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020013171 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000013172 "Built-in commands:\n"
13173 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000013174 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013175 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000013176 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013177 if (col > 60) {
13178 out1fmt("\n");
13179 col = 0;
13180 }
13181 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013182# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000013183 {
13184 const char *a = applet_names;
13185 while (*a) {
13186 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
13187 if (col > 60) {
13188 out1fmt("\n");
13189 col = 0;
13190 }
Ron Yorston2b919582016-04-08 11:57:20 +010013191 while (*a++ != '\0')
13192 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013193 }
13194 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013195# endif
Denys Vlasenkoebedb942016-10-02 18:45:09 +020013196 newline_and_flush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000013197 return EXIT_SUCCESS;
13198}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013199#endif
Eric Andersenc470f442003-07-28 09:56:35 +000013200
Flemming Madsend96ffda2013-04-07 18:47:24 +020013201#if MAX_HISTORY
13202static int FAST_FUNC
13203historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13204{
13205 show_history(line_input_state);
13206 return EXIT_SUCCESS;
13207}
13208#endif
13209
Eric Andersencb57d552001-06-28 07:25:16 +000013210/*
Eric Andersencb57d552001-06-28 07:25:16 +000013211 * The export and readonly commands.
13212 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013213static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013214exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000013215{
13216 struct var *vp;
13217 char *name;
13218 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000013219 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020013220 char opt;
13221 int flag;
13222 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000013223
Denys Vlasenkod5275882012-10-01 13:41:17 +020013224 /* "readonly" in bash accepts, but ignores -n.
13225 * We do the same: it saves a conditional in nextopt's param.
13226 */
13227 flag_off = 0;
13228 while ((opt = nextopt("np")) != '\0') {
13229 if (opt == 'n')
13230 flag_off = VEXPORT;
13231 }
13232 flag = VEXPORT;
13233 if (argv[0][0] == 'r') {
13234 flag = VREADONLY;
13235 flag_off = 0; /* readonly ignores -n */
13236 }
13237 flag_off = ~flag_off;
13238
Denys Vlasenko10ad6222017-04-17 16:13:32 +020013239 /*if (opt_p_not_specified) - bash doesn't check this. Try "export -p NAME" */
Denys Vlasenkod5275882012-10-01 13:41:17 +020013240 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013241 aptr = argptr;
13242 name = *aptr;
13243 if (name) {
13244 do {
13245 p = strchr(name, '=');
13246 if (p != NULL) {
13247 p++;
13248 } else {
13249 vp = *findvar(hashvar(name), name);
13250 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020013251 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013252 continue;
13253 }
Eric Andersencb57d552001-06-28 07:25:16 +000013254 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013255 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013256 } while ((name = *++aptr) != NULL);
13257 return 0;
13258 }
Eric Andersencb57d552001-06-28 07:25:16 +000013259 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013260
13261 /* No arguments. Show the list of exported or readonly vars.
13262 * -n is ignored.
13263 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013264 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000013265 return 0;
13266}
13267
Eric Andersencb57d552001-06-28 07:25:16 +000013268/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013269 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000013270 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013271static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013272unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000013273{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013274 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000013275
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013276 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013277 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013278 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000013279}
13280
Eric Andersencb57d552001-06-28 07:25:16 +000013281/*
Eric Andersencb57d552001-06-28 07:25:16 +000013282 * The unset builtin command. We unset the function before we unset the
13283 * variable to allow a function to be unset when there is a readonly variable
13284 * with the same name.
13285 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013286static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013287unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013288{
13289 char **ap;
13290 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013291 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013292
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013293 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000013294 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000013295 }
Eric Andersencb57d552001-06-28 07:25:16 +000013296
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013297 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013298 if (flag != 'f') {
Denys Vlasenkob28d4c32017-07-25 16:29:36 +020013299 unsetvar(*ap);
13300 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013301 }
13302 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000013303 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000013304 }
Denys Vlasenkob28d4c32017-07-25 16:29:36 +020013305 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013306}
13307
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000013308static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013309 ' ', offsetof(struct tms, tms_utime),
13310 '\n', offsetof(struct tms, tms_stime),
13311 ' ', offsetof(struct tms, tms_cutime),
13312 '\n', offsetof(struct tms, tms_cstime),
13313 0
13314};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013315static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013316timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013317{
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020013318 unsigned long clk_tck, s, t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013319 const unsigned char *p;
13320 struct tms buf;
13321
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020013322 clk_tck = bb_clk_tck();
Eric Andersencb57d552001-06-28 07:25:16 +000013323 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013324
13325 p = timescmd_str;
13326 do {
13327 t = *(clock_t *)(((char *) &buf) + p[1]);
13328 s = t / clk_tck;
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020013329 t = t % clk_tck;
13330 out1fmt("%lum%lu.%03lus%c",
13331 s / 60, s % 60,
13332 (t * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013333 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013334 p += 2;
13335 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013336
Eric Andersencb57d552001-06-28 07:25:16 +000013337 return 0;
13338}
13339
Denys Vlasenko0b883582016-12-23 16:49:07 +010013340#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000013341/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013342 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013343 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000013344 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013345 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000013346 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013347static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013348letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013349{
Denis Vlasenko68404f12008-03-17 09:00:54 +000013350 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000013351
Denis Vlasenko68404f12008-03-17 09:00:54 +000013352 argv++;
13353 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000013354 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000013355 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013356 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013357 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013358
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000013359 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000013360}
Eric Andersenc470f442003-07-28 09:56:35 +000013361#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013362
Eric Andersenc470f442003-07-28 09:56:35 +000013363/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013364 * The read builtin. Options:
13365 * -r Do not interpret '\' specially
13366 * -s Turn off echo (tty only)
13367 * -n NCHARS Read NCHARS max
13368 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13369 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13370 * -u FD Read from given FD instead of fd 0
Eric Andersenc470f442003-07-28 09:56:35 +000013371 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013372 * TODO: bash also has:
13373 * -a ARRAY Read into array[0],[1],etc
13374 * -d DELIM End on DELIM char, not newline
13375 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000013376 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013377static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013378readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013379{
Denys Vlasenko73067272010-01-12 22:11:24 +010013380 char *opt_n = NULL;
13381 char *opt_p = NULL;
13382 char *opt_t = NULL;
13383 char *opt_u = NULL;
13384 int read_flags = 0;
13385 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000013386 int i;
13387
Denys Vlasenko73067272010-01-12 22:11:24 +010013388 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000013389 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000013390 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010013391 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013392 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013393 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010013394 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013395 break;
13396 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010013397 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000013398 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013399 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010013400 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013401 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013402 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010013403 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000013404 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013405 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010013406 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013407 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013408 default:
13409 break;
13410 }
Eric Andersenc470f442003-07-28 09:56:35 +000013411 }
Paul Fox02eb9342005-09-07 16:56:02 +000013412
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013413 /* "read -s" needs to save/restore termios, can't allow ^C
13414 * to jump out of it.
13415 */
Denys Vlasenkof5470412017-05-22 19:34:45 +020013416 again:
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013417 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013418 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010013419 argptr,
13420 bltinlookup("IFS"), /* can be NULL */
13421 read_flags,
13422 opt_n,
13423 opt_p,
13424 opt_t,
13425 opt_u
13426 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013427 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000013428
Denys Vlasenkof5470412017-05-22 19:34:45 +020013429 if ((uintptr_t)r == 1 && errno == EINTR) {
13430 /* to get SIGCHLD: sleep 1 & read x; echo $x */
13431 if (pending_sig == 0)
13432 goto again;
13433 }
13434
Denys Vlasenko73067272010-01-12 22:11:24 +010013435 if ((uintptr_t)r > 1)
13436 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000013437
Denys Vlasenko73067272010-01-12 22:11:24 +010013438 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000013439}
13440
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013441static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020013442umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013443{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013444 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000013445
Eric Andersenc470f442003-07-28 09:56:35 +000013446 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000013447 int symbolic_mode = 0;
13448
13449 while (nextopt("S") != '\0') {
13450 symbolic_mode = 1;
13451 }
13452
Denis Vlasenkob012b102007-02-19 22:43:01 +000013453 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013454 mask = umask(0);
13455 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013456 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013457
Denys Vlasenko6283f982015-10-07 16:56:20 +020013458 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013459 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013460 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013461 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013462 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013463
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013464 i = 2;
13465 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013466 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013467 *p++ = permuser[i];
13468 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013469 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013470 if (!(mask & 0400)) *p++ = 'r';
13471 if (!(mask & 0200)) *p++ = 'w';
13472 if (!(mask & 0100)) *p++ = 'x';
13473 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013474 if (--i < 0)
13475 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013476 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013477 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013478 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013479 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013480 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013481 }
13482 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013483 char *modestr = *argptr;
13484 /* numeric umasks are taken as-is */
13485 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
13486 if (!isdigit(modestr[0]))
13487 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013488 mask = bb_parse_mode(modestr, mask);
13489 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013490 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013491 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013492 if (!isdigit(modestr[0]))
13493 mask ^= 0777;
13494 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013495 }
13496 return 0;
13497}
13498
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013499static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013500ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013501{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013502 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013503}
13504
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013505/* ============ main() and helpers */
13506
13507/*
13508 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013509 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013510static void
13511exitshell(void)
13512{
13513 struct jmploc loc;
13514 char *p;
13515 int status;
13516
Denys Vlasenkobede2152011-09-04 16:12:33 +020013517#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13518 save_history(line_input_state);
13519#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013520 status = exitstatus;
13521 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13522 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013523 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013524 status = exitstatus;
13525 goto out;
13526 }
13527 exception_handler = &loc;
13528 p = trap[0];
13529 if (p) {
13530 trap[0] = NULL;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013531 evalskip = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013532 evalstring(p, 0);
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013533 /*free(p); - we'll exit soon */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013534 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013535 out:
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013536 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13537 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13538 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013539 setjobctl(0);
Denys Vlasenkocaee80c2016-10-25 20:49:53 +020013540 flush_stdout_stderr();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013541 _exit(status);
13542 /* NOTREACHED */
13543}
13544
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013545static void
13546init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013547{
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013548 /* we will never free this */
13549 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013550
Denys Vlasenko458c1f22016-10-27 23:51:19 +020013551 sigmode[SIGCHLD - 1] = S_DFL;
13552 setsignal(SIGCHLD);
13553
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013554 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13555 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13556 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013557 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013558
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013559 {
13560 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013561 const char *p;
13562 struct stat st1, st2;
13563
13564 initvar();
13565 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenkob6838b52016-09-30 11:33:47 +020013566 p = endofname(*envp);
13567 if (p != *envp && *p == '=') {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013568 setvareq(*envp, VEXPORT|VTEXTFIXED);
13569 }
13570 }
13571
Denys Vlasenkoe627ac92016-09-30 14:36:59 +020013572 setvareq((char*)defoptindvar, VTEXTFIXED);
13573
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013574 setvar0("PPID", utoa(getppid()));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013575#if BASH_SHLVL_VAR
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013576 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013577 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013578#endif
13579#if BASH_HOSTNAME_VAR
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013580 if (!lookupvar("HOSTNAME")) {
13581 struct utsname uts;
13582 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013583 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013584 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013585#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013586 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013587 if (p) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013588 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013589 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13590 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013591 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013592 }
13593 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013594 setpwd(p, 0);
13595 }
13596}
13597
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013598
13599//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013600//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013601//usage:#define ash_full_usage "\n\n"
13602//usage: "Unix shell interpreter"
13603
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013604/*
13605 * Process the shell command line arguments.
13606 */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013607static int
Denis Vlasenko68404f12008-03-17 09:00:54 +000013608procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013609{
13610 int i;
13611 const char *xminusc;
13612 char **xargv;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013613 int login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013614
13615 xargv = argv;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013616 login_sh = xargv[0] && xargv[0][0] == '-';
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013617 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013618 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013619 xargv++;
13620 for (i = 0; i < NOPTS; i++)
13621 optlist[i] = 2;
13622 argptr = xargv;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013623 if (options(/*cmdline:*/ 1, &login_sh)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013624 /* it already printed err message */
13625 raise_exception(EXERROR);
13626 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013627 xargv = argptr;
13628 xminusc = minusc;
13629 if (*xargv == NULL) {
13630 if (xminusc)
13631 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13632 sflag = 1;
13633 }
13634 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13635 iflag = 1;
13636 if (mflag == 2)
13637 mflag = iflag;
13638 for (i = 0; i < NOPTS; i++)
13639 if (optlist[i] == 2)
13640 optlist[i] = 0;
13641#if DEBUG == 2
13642 debug = 1;
13643#endif
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013644 /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013645 if (xminusc) {
13646 minusc = *xargv++;
13647 if (*xargv)
13648 goto setarg0;
13649 } else if (!sflag) {
13650 setinputfile(*xargv, 0);
13651 setarg0:
13652 arg0 = *xargv++;
13653 commandname = arg0;
13654 }
13655
13656 shellparam.p = xargv;
13657#if ENABLE_ASH_GETOPTS
13658 shellparam.optind = 1;
13659 shellparam.optoff = -1;
13660#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013661 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013662 while (*xargv) {
13663 shellparam.nparam++;
13664 xargv++;
13665 }
13666 optschanged();
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013667
13668 return login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013669}
13670
13671/*
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013672 * Read /etc/profile, ~/.profile, $ENV.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013673 */
13674static void
13675read_profile(const char *name)
13676{
Denys Vlasenko46999802017-07-29 21:12:29 +020013677 name = expandstr(name, DQSYNTAX);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013678 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13679 return;
Denys Vlasenko0840c912016-10-01 15:27:44 +020013680 cmdloop(0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013681 popfile();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013682}
13683
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013684/*
13685 * This routine is called when an error or an interrupt occurs in an
13686 * interactive shell and control is returned to the main command loop.
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013687 * (In dash, this function is auto-generated by build machinery).
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013688 */
13689static void
13690reset(void)
13691{
13692 /* from eval.c: */
13693 evalskip = 0;
13694 loopnest = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013695
13696 /* from expand.c: */
13697 ifsfree();
13698
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013699 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013700 g_parsefile->left_in_buffer = 0;
13701 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013702 popallfiles();
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013703
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013704 /* from redir.c: */
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020013705 unwindredir(NULL);
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +020013706
13707 /* from var.c: */
Denys Vlasenko484fc202017-07-26 19:55:31 +020013708 unwindlocalvars(NULL);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013709}
13710
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013711#if PROFILE
13712static short profile_buf[16384];
13713extern int etext();
13714#endif
13715
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013716/*
13717 * Main routine. We initialize things, parse the arguments, execute
13718 * profiles if we're a login shell, and then call cmdloop to execute
13719 * commands. The setjmp call sets up the location to jump to when an
13720 * exception occurs. When an exception occurs the variable "state"
13721 * is used to figure out how far we had gotten.
13722 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013723int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013724int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013725{
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013726 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013727 struct jmploc jmploc;
13728 struct stackmark smark;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013729 int login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013730
Denis Vlasenko01631112007-12-16 17:20:38 +000013731 /* Initialize global data */
13732 INIT_G_misc();
13733 INIT_G_memstack();
13734 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013735#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013736 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013737#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013738 INIT_G_cmdtable();
13739
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013740#if PROFILE
13741 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13742#endif
13743
13744#if ENABLE_FEATURE_EDITING
13745 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13746#endif
13747 state = 0;
13748 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013749 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013750 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013751
13752 reset();
13753
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013754 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013755 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013756 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013757 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013758 }
13759 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020013760 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013761 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013762
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013763 popstackmark(&smark);
13764 FORCE_INT_ON; /* enable interrupts */
13765 if (s == 1)
13766 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013767 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013768 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013769 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013770 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013771 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013772 }
13773 exception_handler = &jmploc;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013774 rootpid = getpid();
13775
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013776 init();
13777 setstackmark(&smark);
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013778 login_sh = procargs(argv);
Denys Vlasenko474ed062016-10-30 18:30:29 +010013779#if DEBUG
13780 TRACE(("Shell args: "));
13781 trace_puts_args(argv);
13782#endif
Denis Vlasenko68404f12008-03-17 09:00:54 +000013783
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013784 if (login_sh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013785 const char *hp;
13786
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013787 state = 1;
13788 read_profile("/etc/profile");
13789 state1:
13790 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013791 hp = lookupvar("HOME");
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013792 if (hp)
13793 read_profile("$HOME/.profile");
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013794 }
13795 state2:
13796 state = 3;
13797 if (
13798#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013799 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013800#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013801 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013802 ) {
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013803 const char *shinit = lookupvar("ENV");
13804 if (shinit != NULL && *shinit != '\0')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013805 read_profile(shinit);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013806 }
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013807 popstackmark(&smark);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013808 state3:
13809 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013810 if (minusc) {
13811 /* evalstring pushes parsefile stack.
13812 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013813 * is one of stacked source fds.
13814 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013815 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013816 // ^^ not necessary since now we special-case fd 0
Denys Vlasenko035486c2017-07-31 04:09:19 +020013817 // in save_fd_on_redirect()
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020013818 evalstring(minusc, sflag ? 0 : EV_EXIT);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013819 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013820
13821 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020013822#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013823 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013824 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013825 if (!hp) {
13826 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013827 if (hp) {
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013828 INT_OFF;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013829 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013830 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013831 free((char*)hp);
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013832 INT_ON;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013833 hp = lookupvar("HISTFILE");
13834 }
13835 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013836 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013837 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013838# if ENABLE_FEATURE_SH_HISTFILESIZE
13839 hp = lookupvar("HISTFILESIZE");
13840 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13841# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013842 }
13843#endif
13844 state4: /* XXX ??? - why isn't this before the "if" statement */
13845 cmdloop(1);
13846 }
13847#if PROFILE
13848 monitor(0);
13849#endif
13850#ifdef GPROF
13851 {
13852 extern void _mcleanup(void);
13853 _mcleanup();
13854 }
13855#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013856 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013857 exitshell();
13858 /* NOTREACHED */
13859}
13860
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013861
Eric Andersendf82f612001-06-28 07:46:40 +000013862/*-
13863 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013864 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013865 *
13866 * This code is derived from software contributed to Berkeley by
13867 * Kenneth Almquist.
13868 *
13869 * Redistribution and use in source and binary forms, with or without
13870 * modification, are permitted provided that the following conditions
13871 * are met:
13872 * 1. Redistributions of source code must retain the above copyright
13873 * notice, this list of conditions and the following disclaimer.
13874 * 2. Redistributions in binary form must reproduce the above copyright
13875 * notice, this list of conditions and the following disclaimer in the
13876 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013877 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013878 * may be used to endorse or promote products derived from this software
13879 * without specific prior written permission.
13880 *
Denys Vlasenko95f79532017-08-02 14:26:33 +020013881 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
Eric Andersendf82f612001-06-28 07:46:40 +000013882 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13883 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13884 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13885 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13886 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13887 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13888 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13889 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13890 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13891 * SUCH DAMAGE.
13892 */