blob: c8b2adf4e7119477cc59ea0b6f70b1dbde1c32bd [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"
217#endif
218#if ENABLE_ASH_RANDOM_SUPPORT
219# include "random.h"
220#else
221# define CLEAR_RANDOM_T(rnd) ((void)0)
222#endif
223
224#include "NUM_APPLETS.h"
225#if NUM_APPLETS == 1
226/* STANDALONE does not make sense, and won't compile */
227# undef CONFIG_FEATURE_SH_STANDALONE
228# undef ENABLE_FEATURE_SH_STANDALONE
229# undef IF_FEATURE_SH_STANDALONE
230# undef IF_NOT_FEATURE_SH_STANDALONE
231# define ENABLE_FEATURE_SH_STANDALONE 0
232# define IF_FEATURE_SH_STANDALONE(...)
233# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
234#endif
235
236#ifndef PIPE_BUF
237# define PIPE_BUF 4096 /* amount of buffering in a pipe */
238#endif
239
240#if !BB_MMU
241# error "Do not even bother, ash will not run on NOMMU machine"
242#endif
243
Denis Vlasenkob012b102007-02-19 22:43:01 +0000244
Denis Vlasenko01631112007-12-16 17:20:38 +0000245/* ============ Hash table sizes. Configurable. */
246
247#define VTABSIZE 39
248#define ATABSIZE 39
249#define CMDTABLESIZE 31 /* should be prime */
250
251
Denis Vlasenkob012b102007-02-19 22:43:01 +0000252/* ============ Shell options */
253
254static const char *const optletters_optnames[] = {
255 "e" "errexit",
256 "f" "noglob",
257 "I" "ignoreeof",
258 "i" "interactive",
259 "m" "monitor",
260 "n" "noexec",
261 "s" "stdin",
262 "x" "xtrace",
263 "v" "verbose",
264 "C" "noclobber",
265 "a" "allexport",
266 "b" "notify",
267 "u" "nounset",
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100268 "\0" "vi"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100269#if BASH_PIPEFAIL
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100270 ,"\0" "pipefail"
Michael Abbott359da5e2009-12-04 23:03:29 +0100271#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000272#if DEBUG
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000273 ,"\0" "nolog"
274 ,"\0" "debug"
Denis Vlasenkob012b102007-02-19 22:43:01 +0000275#endif
276};
277
Denys Vlasenko285ad152009-12-04 23:02:27 +0100278#define optletters(n) optletters_optnames[n][0]
279#define optnames(n) (optletters_optnames[n] + 1)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000280
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000281enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
Denis Vlasenkob012b102007-02-19 22:43:01 +0000282
Eric Andersenc470f442003-07-28 09:56:35 +0000283
Denis Vlasenkob012b102007-02-19 22:43:01 +0000284/* ============ Misc data */
Eric Andersenc470f442003-07-28 09:56:35 +0000285
Denys Vlasenkoea8b2522010-06-02 12:57:26 +0200286#define msg_illnum "Illegal number: %s"
Denis Vlasenkoaa744452007-02-23 01:04:22 +0000287
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +0000288/*
Eric Andersenc470f442003-07-28 09:56:35 +0000289 * We enclose jmp_buf in a structure so that we can declare pointers to
290 * jump locations. The global variable handler contains the location to
Denis Vlasenkof1733952009-03-19 23:21:55 +0000291 * jump to when an exception occurs, and the global variable exception_type
Eric Andersenaff114c2004-04-14 17:51:38 +0000292 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000293 * exception handlers, the user should save the value of handler on entry
294 * to an inner scope, set handler to point to a jmploc structure for the
295 * inner scope, and restore handler on exit from the scope.
296 */
Eric Andersenc470f442003-07-28 09:56:35 +0000297struct jmploc {
298 jmp_buf loc;
299};
Denis Vlasenko01631112007-12-16 17:20:38 +0000300
301struct globals_misc {
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200302 uint8_t exitstatus; /* exit status of last command */
303 uint8_t back_exitstatus;/* exit status of backquoted command */
304 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
305 int rootpid; /* pid of main shell */
Denis Vlasenko01631112007-12-16 17:20:38 +0000306 /* shell level: 0 for the main shell, 1 for its children, and so on */
307 int shlvl;
308#define rootshell (!shlvl)
309 char *minusc; /* argument to -c option */
310
311 char *curdir; // = nullstr; /* current working directory */
312 char *physdir; // = nullstr; /* physical working directory */
313
314 char *arg0; /* value of $0 */
315
316 struct jmploc *exception_handler;
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000317
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200318 volatile int suppress_int; /* counter */
319 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200320 volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +0200321 volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000322 smallint exception_type; /* kind of exception (0..5) */
Denis Vlasenko01631112007-12-16 17:20:38 +0000323 /* exceptions */
Eric Andersenc470f442003-07-28 09:56:35 +0000324#define EXINT 0 /* SIGINT received */
325#define EXERROR 1 /* a generic error */
Eric Andersenc470f442003-07-28 09:56:35 +0000326#define EXEXIT 4 /* exit the shell */
Eric Andersen2870d962001-07-02 17:27:21 +0000327
Denis Vlasenko01631112007-12-16 17:20:38 +0000328 smallint isloginsh;
Denis Vlasenkob07a4962008-06-22 13:16:23 +0000329 char nullstr[1]; /* zero length string */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000330
331 char optlist[NOPTS];
332#define eflag optlist[0]
333#define fflag optlist[1]
334#define Iflag optlist[2]
335#define iflag optlist[3]
336#define mflag optlist[4]
337#define nflag optlist[5]
338#define sflag optlist[6]
339#define xflag optlist[7]
340#define vflag optlist[8]
341#define Cflag optlist[9]
342#define aflag optlist[10]
343#define bflag optlist[11]
344#define uflag optlist[12]
345#define viflag optlist[13]
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100346#if BASH_PIPEFAIL
Michael Abbott359da5e2009-12-04 23:03:29 +0100347# define pipefail optlist[14]
348#else
349# define pipefail 0
350#endif
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000351#if DEBUG
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100352# define nolog optlist[14 + BASH_PIPEFAIL]
353# define debug optlist[15 + BASH_PIPEFAIL]
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000354#endif
355
356 /* trap handler commands */
Denis Vlasenko01631112007-12-16 17:20:38 +0000357 /*
358 * Sigmode records the current value of the signal handlers for the various
359 * modes. A value of zero means that the current handler is not known.
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000360 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
Denis Vlasenko01631112007-12-16 17:20:38 +0000361 */
362 char sigmode[NSIG - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000363#define S_DFL 1 /* default signal handling (SIG_DFL) */
364#define S_CATCH 2 /* signal is caught */
365#define S_IGN 3 /* signal is ignored (SIG_IGN) */
Denys Vlasenkoe5814a52016-07-16 18:33:55 +0200366#define S_HARD_IGN 4 /* signal is ignored permanently */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000367
Denis Vlasenko01631112007-12-16 17:20:38 +0000368 /* indicates specified signal received */
Denis Vlasenko4b875702009-03-19 13:30:04 +0000369 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
Denys Vlasenko238bf182010-05-18 15:49:07 +0200370 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000371 char *trap[NSIG];
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200372 char **trap_ptr; /* used only by "trap hack" */
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000373
374 /* Rarely referenced stuff */
375#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200376 random_t random_gen;
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000377#endif
378 pid_t backgndpid; /* pid of last background process */
Denis Vlasenko01631112007-12-16 17:20:38 +0000379};
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000380extern struct globals_misc *const ash_ptr_to_globals_misc;
381#define G_misc (*ash_ptr_to_globals_misc)
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200382#define exitstatus (G_misc.exitstatus )
383#define back_exitstatus (G_misc.back_exitstatus )
384#define job_warning (G_misc.job_warning)
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000385#define rootpid (G_misc.rootpid )
386#define shlvl (G_misc.shlvl )
387#define minusc (G_misc.minusc )
388#define curdir (G_misc.curdir )
389#define physdir (G_misc.physdir )
390#define arg0 (G_misc.arg0 )
Denis Vlasenko01631112007-12-16 17:20:38 +0000391#define exception_handler (G_misc.exception_handler)
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000392#define exception_type (G_misc.exception_type )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200393#define suppress_int (G_misc.suppress_int )
394#define pending_int (G_misc.pending_int )
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200395#define got_sigchld (G_misc.got_sigchld )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200396#define pending_sig (G_misc.pending_sig )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000397#define isloginsh (G_misc.isloginsh )
398#define nullstr (G_misc.nullstr )
399#define optlist (G_misc.optlist )
400#define sigmode (G_misc.sigmode )
401#define gotsig (G_misc.gotsig )
Denys Vlasenko238bf182010-05-18 15:49:07 +0200402#define may_have_traps (G_misc.may_have_traps )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000403#define trap (G_misc.trap )
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200404#define trap_ptr (G_misc.trap_ptr )
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200405#define random_gen (G_misc.random_gen )
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000406#define backgndpid (G_misc.backgndpid )
Denis Vlasenko01631112007-12-16 17:20:38 +0000407#define INIT_G_misc() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000408 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
409 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +0000410 curdir = nullstr; \
411 physdir = nullstr; \
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200412 trap_ptr = trap; \
Denis Vlasenko01631112007-12-16 17:20:38 +0000413} while (0)
414
415
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000416/* ============ DEBUG */
417#if DEBUG
418static void trace_printf(const char *fmt, ...);
419static void trace_vprintf(const char *fmt, va_list va);
420# define TRACE(param) trace_printf param
421# define TRACEV(param) trace_vprintf param
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000422# define close(fd) do { \
423 int dfd = (fd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000424 if (close(dfd) < 0) \
Denys Vlasenko883cea42009-07-11 15:31:59 +0200425 bb_error_msg("bug on %d: closing %d(0x%x)", \
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000426 __LINE__, dfd, dfd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000427} while (0)
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000428#else
429# define TRACE(param)
430# define TRACEV(param)
431#endif
432
433
Denis Vlasenko559691a2008-10-05 18:39:31 +0000434/* ============ Utility functions */
Denys Vlasenko1961aea2013-02-26 00:36:53 +0100435#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
436#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
437
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200438static int
439isdigit_str9(const char *str)
Denis Vlasenko559691a2008-10-05 18:39:31 +0000440{
441 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
442 while (--maxlen && isdigit(*str))
443 str++;
444 return (*str == '\0');
445}
Denis Vlasenko01631112007-12-16 17:20:38 +0000446
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200447static const char *
448var_end(const char *var)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +0200449{
450 while (*var)
451 if (*var++ == '=')
452 break;
453 return var;
454}
455
Denis Vlasenko559691a2008-10-05 18:39:31 +0000456
457/* ============ Interrupts / exceptions */
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100458
459static void exitshell(void) NORETURN;
460
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000461/*
Eric Andersen2870d962001-07-02 17:27:21 +0000462 * These macros allow the user to suspend the handling of interrupt signals
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000463 * over a period of time. This is similar to SIGHOLD or to sigblock, but
Eric Andersen2870d962001-07-02 17:27:21 +0000464 * much more efficient and portable. (But hacking the kernel is so much
465 * more fun than worrying about efficiency and portability. :-))
466 */
Denys Vlasenko06b11492016-11-04 16:43:18 +0100467#if DEBUG_INTONOFF
468# define INT_OFF do { \
469 TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200470 suppress_int++; \
Denys Vlasenkode892052016-10-02 01:49:13 +0200471 barrier(); \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000472} while (0)
Denys Vlasenko06b11492016-11-04 16:43:18 +0100473#else
474# define INT_OFF do { \
475 suppress_int++; \
476 barrier(); \
477} while (0)
478#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000479
480/*
481 * Called to raise an exception. Since C doesn't include exceptions, we
482 * just do a longjmp to the exception handler. The type of exception is
Denis Vlasenko4b875702009-03-19 13:30:04 +0000483 * stored in the global variable "exception_type".
Denis Vlasenkob012b102007-02-19 22:43:01 +0000484 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000485static void raise_exception(int) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000486static void
487raise_exception(int e)
488{
489#if DEBUG
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000490 if (exception_handler == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000491 abort();
492#endif
493 INT_OFF;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000494 exception_type = e;
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000495 longjmp(exception_handler->loc, 1);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000496}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000497#if DEBUG
498#define raise_exception(e) do { \
499 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
500 raise_exception(e); \
501} while (0)
502#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000503
504/*
Denys Vlasenkof37e1152016-10-07 03:17:28 +0200505 * Called when a SIGINT is received. (If the user specifies
Denis Vlasenkob012b102007-02-19 22:43:01 +0000506 * that SIGINT is to be trapped or ignored using the trap builtin, then
507 * this routine is not called.) Suppressint is nonzero when interrupts
508 * are held using the INT_OFF macro. (The test for iflag is just
509 * defensive programming.)
510 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000511static void raise_interrupt(void) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000512static void
513raise_interrupt(void)
514{
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200515 pending_int = 0;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000516 /* Signal is not automatically unmasked after it is raised,
517 * do it ourself - unmask all signals */
Denis Vlasenko3f165fa2008-03-17 08:29:08 +0000518 sigprocmask_allsigs(SIG_UNBLOCK);
Denys Vlasenko238bf182010-05-18 15:49:07 +0200519 /* pending_sig = 0; - now done in signal_handler() */
Denis Vlasenko7c139b42007-03-21 20:17:27 +0000520
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200521 if (!(rootshell && iflag)) {
522 /* Kill ourself with SIGINT */
523 signal(SIGINT, SIG_DFL);
524 raise(SIGINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000525 }
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200526 /* bash: ^C even on empty command line sets $? */
527 exitstatus = SIGINT + 128;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200528 raise_exception(EXINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000529 /* NOTREACHED */
530}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000531#if DEBUG
532#define raise_interrupt() do { \
533 TRACE(("raising interrupt on line %d\n", __LINE__)); \
534 raise_interrupt(); \
535} while (0)
536#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000537
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000538static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000539int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000540{
Denys Vlasenkode892052016-10-02 01:49:13 +0200541 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200542 if (--suppress_int == 0 && pending_int) {
Denis Vlasenkob012b102007-02-19 22:43:01 +0000543 raise_interrupt();
544 }
545}
Denys Vlasenko06b11492016-11-04 16:43:18 +0100546#if DEBUG_INTONOFF
547# define INT_ON do { \
548 TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
549 int_on(); \
550} while (0)
551#else
552# define INT_ON int_on()
553#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000554static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000555force_int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000556{
Denys Vlasenkode892052016-10-02 01:49:13 +0200557 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200558 suppress_int = 0;
559 if (pending_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000560 raise_interrupt();
561}
562#define FORCE_INT_ON force_int_on()
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000563
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200564#define SAVE_INT(v) ((v) = suppress_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000565
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000566#define RESTORE_INT(v) do { \
Denys Vlasenkode892052016-10-02 01:49:13 +0200567 barrier(); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200568 suppress_int = (v); \
569 if (suppress_int == 0 && pending_int) \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000570 raise_interrupt(); \
571} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000572
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000573
Denis Vlasenkobc54cff2007-02-23 01:05:52 +0000574/* ============ Stdout/stderr output */
Eric Andersenc470f442003-07-28 09:56:35 +0000575
Eric Andersenc470f442003-07-28 09:56:35 +0000576static void
Denis Vlasenkob012b102007-02-19 22:43:01 +0000577outstr(const char *p, FILE *file)
Denis Vlasenkoe5570da2007-02-19 22:41:55 +0000578{
Denis Vlasenkob012b102007-02-19 22:43:01 +0000579 INT_OFF;
580 fputs(p, file);
581 INT_ON;
582}
583
584static void
585flush_stdout_stderr(void)
586{
587 INT_OFF;
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100588 fflush_all();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000589 INT_ON;
590}
591
Denys Vlasenko9c541002015-10-07 15:44:36 +0200592/* Was called outcslow(c,FILE*), but c was always '\n' */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000593static void
Denys Vlasenko9c541002015-10-07 15:44:36 +0200594newline_and_flush(FILE *dest)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000595{
596 INT_OFF;
Denys Vlasenko9c541002015-10-07 15:44:36 +0200597 putc('\n', dest);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000598 fflush(dest);
599 INT_ON;
600}
601
602static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
603static int
604out1fmt(const char *fmt, ...)
605{
606 va_list ap;
607 int r;
608
609 INT_OFF;
610 va_start(ap, fmt);
611 r = vprintf(fmt, ap);
612 va_end(ap);
613 INT_ON;
614 return r;
615}
616
617static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
618static int
619fmtstr(char *outbuf, size_t length, const char *fmt, ...)
620{
621 va_list ap;
622 int ret;
623
624 va_start(ap, fmt);
625 INT_OFF;
626 ret = vsnprintf(outbuf, length, fmt, ap);
627 va_end(ap);
628 INT_ON;
629 return ret;
630}
631
632static void
633out1str(const char *p)
634{
635 outstr(p, stdout);
636}
637
638static void
639out2str(const char *p)
640{
641 outstr(p, stderr);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100642 flush_stdout_stderr();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000643}
644
645
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000646/* ============ Parser structures */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +0000647
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000648/* control characters in argument strings */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100649#define CTL_FIRST CTLESC
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200650#define CTLESC ((unsigned char)'\201') /* escape next character */
651#define CTLVAR ((unsigned char)'\202') /* variable defn */
652#define CTLENDVAR ((unsigned char)'\203')
653#define CTLBACKQ ((unsigned char)'\204')
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200654#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
655#define CTLENDARI ((unsigned char)'\207')
656#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100657#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000658
659/* variable substitution byte (follows CTLVAR) */
660#define VSTYPE 0x0f /* type of variable substitution */
661#define VSNUL 0x10 /* colon--treat the empty string as unset */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000662
663/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000664#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
665#define VSMINUS 0x2 /* ${var-text} */
666#define VSPLUS 0x3 /* ${var+text} */
667#define VSQUESTION 0x4 /* ${var?message} */
668#define VSASSIGN 0x5 /* ${var=text} */
669#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
670#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
671#define VSTRIMLEFT 0x8 /* ${var#pattern} */
672#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
673#define VSLENGTH 0xa /* ${#var} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100674#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000675#define VSSUBSTR 0xc /* ${var:position:length} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100676#endif
677#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000678#define VSREPLACE 0xd /* ${var/pattern/replacement} */
679#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
680#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000681
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000682static const char dolatstr[] ALIGN1 = {
Ron Yorston549deab2015-05-18 09:57:51 +0200683 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000684};
Ron Yorston549deab2015-05-18 09:57:51 +0200685#define DOLATSTRLEN 6
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000686
Denis Vlasenko559691a2008-10-05 18:39:31 +0000687#define NCMD 0
688#define NPIPE 1
689#define NREDIR 2
690#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000691#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000692#define NAND 5
693#define NOR 6
694#define NSEMI 7
695#define NIF 8
696#define NWHILE 9
697#define NUNTIL 10
698#define NFOR 11
699#define NCASE 12
700#define NCLIST 13
701#define NDEFUN 14
702#define NARG 15
703#define NTO 16
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100704#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +0000705#define NTO2 17
706#endif
707#define NCLOBBER 18
708#define NFROM 19
709#define NFROMTO 20
710#define NAPPEND 21
711#define NTOFD 22
712#define NFROMFD 23
713#define NHERE 24
714#define NXHERE 25
715#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000716#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000717
718union node;
719
720struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000721 smallint type; /* Nxxxx */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000722 union node *assign;
723 union node *args;
724 union node *redirect;
725};
726
727struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000728 smallint type;
729 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000730 struct nodelist *cmdlist;
731};
732
733struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000734 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000735 union node *n;
736 union node *redirect;
737};
738
739struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000740 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000741 union node *ch1;
742 union node *ch2;
743};
744
745struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000746 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000747 union node *test;
748 union node *ifpart;
749 union node *elsepart;
750};
751
752struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000753 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000754 union node *args;
755 union node *body;
756 char *var;
757};
758
759struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000760 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000761 union node *expr;
762 union node *cases;
763};
764
765struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000766 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000767 union node *next;
768 union node *pattern;
769 union node *body;
770};
771
772struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000773 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000774 union node *next;
775 char *text;
776 struct nodelist *backquote;
777};
778
Denis Vlasenko559691a2008-10-05 18:39:31 +0000779/* nfile and ndup layout must match!
780 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
781 * that it is actually NTO2 (>&file), and change its type.
782 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000783struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000784 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000785 union node *next;
786 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000787 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000788 union node *fname;
789 char *expfname;
790};
791
792struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000793 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000794 union node *next;
795 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000796 int dupfd;
797 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000798 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000799};
800
801struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000802 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000803 union node *next;
804 int fd;
805 union node *doc;
806};
807
808struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000809 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000810 union node *com;
811};
812
813union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000814 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000815 struct ncmd ncmd;
816 struct npipe npipe;
817 struct nredir nredir;
818 struct nbinary nbinary;
819 struct nif nif;
820 struct nfor nfor;
821 struct ncase ncase;
822 struct nclist nclist;
823 struct narg narg;
824 struct nfile nfile;
825 struct ndup ndup;
826 struct nhere nhere;
827 struct nnot nnot;
828};
829
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200830/*
831 * NODE_EOF is returned by parsecmd when it encounters an end of file.
832 * It must be distinct from NULL.
833 */
834#define NODE_EOF ((union node *) -1L)
835
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000836struct nodelist {
837 struct nodelist *next;
838 union node *n;
839};
840
841struct funcnode {
842 int count;
843 union node n;
844};
845
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000846/*
847 * Free a parse tree.
848 */
849static void
850freefunc(struct funcnode *f)
851{
852 if (f && --f->count < 0)
853 free(f);
854}
855
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000856
857/* ============ Debugging output */
858
859#if DEBUG
860
861static FILE *tracefile;
862
863static void
864trace_printf(const char *fmt, ...)
865{
866 va_list va;
867
868 if (debug != 1)
869 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000870 if (DEBUG_TIME)
871 fprintf(tracefile, "%u ", (int) time(NULL));
872 if (DEBUG_PID)
873 fprintf(tracefile, "[%u] ", (int) getpid());
874 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200875 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000876 va_start(va, fmt);
877 vfprintf(tracefile, fmt, va);
878 va_end(va);
879}
880
881static void
882trace_vprintf(const char *fmt, va_list va)
883{
884 if (debug != 1)
885 return;
886 vfprintf(tracefile, fmt, va);
Denys Vlasenko474ed062016-10-30 18:30:29 +0100887 fprintf(tracefile, "\n");
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000888}
889
890static void
891trace_puts(const char *s)
892{
893 if (debug != 1)
894 return;
895 fputs(s, tracefile);
896}
897
898static void
899trace_puts_quoted(char *s)
900{
901 char *p;
902 char c;
903
904 if (debug != 1)
905 return;
906 putc('"', tracefile);
907 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100908 switch ((unsigned char)*p) {
909 case '\n': c = 'n'; goto backslash;
910 case '\t': c = 't'; goto backslash;
911 case '\r': c = 'r'; goto backslash;
912 case '\"': c = '\"'; goto backslash;
913 case '\\': c = '\\'; goto backslash;
914 case CTLESC: c = 'e'; goto backslash;
915 case CTLVAR: c = 'v'; goto backslash;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100916 case CTLBACKQ: c = 'q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000917 backslash:
918 putc('\\', tracefile);
919 putc(c, tracefile);
920 break;
921 default:
922 if (*p >= ' ' && *p <= '~')
923 putc(*p, tracefile);
924 else {
925 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +0100926 putc((*p >> 6) & 03, tracefile);
927 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000928 putc(*p & 07, tracefile);
929 }
930 break;
931 }
932 }
933 putc('"', tracefile);
934}
935
936static void
937trace_puts_args(char **ap)
938{
939 if (debug != 1)
940 return;
941 if (!*ap)
942 return;
943 while (1) {
944 trace_puts_quoted(*ap);
945 if (!*++ap) {
946 putc('\n', tracefile);
947 break;
948 }
949 putc(' ', tracefile);
950 }
951}
952
953static void
954opentrace(void)
955{
956 char s[100];
957#ifdef O_APPEND
958 int flags;
959#endif
960
961 if (debug != 1) {
962 if (tracefile)
963 fflush(tracefile);
964 /* leave open because libedit might be using it */
965 return;
966 }
967 strcpy(s, "./trace");
968 if (tracefile) {
969 if (!freopen(s, "a", tracefile)) {
970 fprintf(stderr, "Can't re-open %s\n", s);
971 debug = 0;
972 return;
973 }
974 } else {
975 tracefile = fopen(s, "a");
976 if (tracefile == NULL) {
977 fprintf(stderr, "Can't open %s\n", s);
978 debug = 0;
979 return;
980 }
981 }
982#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000983 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000984 if (flags >= 0)
985 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
986#endif
987 setlinebuf(tracefile);
988 fputs("\nTracing started.\n", tracefile);
989}
990
991static void
992indent(int amount, char *pfx, FILE *fp)
993{
994 int i;
995
996 for (i = 0; i < amount; i++) {
997 if (pfx && i == amount - 1)
998 fputs(pfx, fp);
999 putc('\t', fp);
1000 }
1001}
1002
1003/* little circular references here... */
1004static void shtree(union node *n, int ind, char *pfx, FILE *fp);
1005
1006static void
1007sharg(union node *arg, FILE *fp)
1008{
1009 char *p;
1010 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001011 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001012
1013 if (arg->type != NARG) {
1014 out1fmt("<node type %d>\n", arg->type);
1015 abort();
1016 }
1017 bqlist = arg->narg.backquote;
1018 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01001019 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001020 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -07001021 p++;
1022 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001023 break;
1024 case CTLVAR:
1025 putc('$', fp);
1026 putc('{', fp);
1027 subtype = *++p;
1028 if (subtype == VSLENGTH)
1029 putc('#', fp);
1030
Dan Fandrich77d48722010-09-07 23:38:28 -07001031 while (*p != '=') {
1032 putc(*p, fp);
1033 p++;
1034 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001035
1036 if (subtype & VSNUL)
1037 putc(':', fp);
1038
1039 switch (subtype & VSTYPE) {
1040 case VSNORMAL:
1041 putc('}', fp);
1042 break;
1043 case VSMINUS:
1044 putc('-', fp);
1045 break;
1046 case VSPLUS:
1047 putc('+', fp);
1048 break;
1049 case VSQUESTION:
1050 putc('?', fp);
1051 break;
1052 case VSASSIGN:
1053 putc('=', fp);
1054 break;
1055 case VSTRIMLEFT:
1056 putc('#', fp);
1057 break;
1058 case VSTRIMLEFTMAX:
1059 putc('#', fp);
1060 putc('#', fp);
1061 break;
1062 case VSTRIMRIGHT:
1063 putc('%', fp);
1064 break;
1065 case VSTRIMRIGHTMAX:
1066 putc('%', fp);
1067 putc('%', fp);
1068 break;
1069 case VSLENGTH:
1070 break;
1071 default:
1072 out1fmt("<subtype %d>", subtype);
1073 }
1074 break;
1075 case CTLENDVAR:
1076 putc('}', fp);
1077 break;
1078 case CTLBACKQ:
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001079 putc('$', fp);
1080 putc('(', fp);
1081 shtree(bqlist->n, -1, NULL, fp);
1082 putc(')', fp);
1083 break;
1084 default:
1085 putc(*p, fp);
1086 break;
1087 }
1088 }
1089}
1090
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001091static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001092shcmd(union node *cmd, FILE *fp)
1093{
1094 union node *np;
1095 int first;
1096 const char *s;
1097 int dftfd;
1098
1099 first = 1;
1100 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001101 if (!first)
1102 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001103 sharg(np, fp);
1104 first = 0;
1105 }
1106 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001107 if (!first)
1108 putc(' ', fp);
1109 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001110 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001111 case NTO: s = ">>"+1; dftfd = 1; break;
1112 case NCLOBBER: s = ">|"; dftfd = 1; break;
1113 case NAPPEND: s = ">>"; dftfd = 1; break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01001114#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00001115 case NTO2:
1116#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001117 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001118 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001119 case NFROMFD: s = "<&"; break;
1120 case NFROMTO: s = "<>"; break;
1121 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001122 }
1123 if (np->nfile.fd != dftfd)
1124 fprintf(fp, "%d", np->nfile.fd);
1125 fputs(s, fp);
1126 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1127 fprintf(fp, "%d", np->ndup.dupfd);
1128 } else {
1129 sharg(np->nfile.fname, fp);
1130 }
1131 first = 0;
1132 }
1133}
1134
1135static void
1136shtree(union node *n, int ind, char *pfx, FILE *fp)
1137{
1138 struct nodelist *lp;
1139 const char *s;
1140
1141 if (n == NULL)
1142 return;
1143
1144 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001145
1146 if (n == NODE_EOF) {
1147 fputs("<EOF>", fp);
1148 return;
1149 }
1150
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001151 switch (n->type) {
1152 case NSEMI:
1153 s = "; ";
1154 goto binop;
1155 case NAND:
1156 s = " && ";
1157 goto binop;
1158 case NOR:
1159 s = " || ";
1160 binop:
1161 shtree(n->nbinary.ch1, ind, NULL, fp);
1162 /* if (ind < 0) */
1163 fputs(s, fp);
1164 shtree(n->nbinary.ch2, ind, NULL, fp);
1165 break;
1166 case NCMD:
1167 shcmd(n, fp);
1168 if (ind >= 0)
1169 putc('\n', fp);
1170 break;
1171 case NPIPE:
1172 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001173 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001174 if (lp->next)
1175 fputs(" | ", fp);
1176 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001177 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001178 fputs(" &", fp);
1179 if (ind >= 0)
1180 putc('\n', fp);
1181 break;
1182 default:
1183 fprintf(fp, "<node type %d>", n->type);
1184 if (ind >= 0)
1185 putc('\n', fp);
1186 break;
1187 }
1188}
1189
1190static void
1191showtree(union node *n)
1192{
1193 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001194 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001195}
1196
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001197#endif /* DEBUG */
1198
1199
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001200/* ============ Parser data */
1201
1202/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001203 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1204 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001205struct strlist {
1206 struct strlist *next;
1207 char *text;
1208};
1209
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001210struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001211
Denis Vlasenkob012b102007-02-19 22:43:01 +00001212struct strpush {
1213 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001214 char *prev_string;
1215 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001216#if ENABLE_ASH_ALIAS
1217 struct alias *ap; /* if push was associated with an alias */
1218#endif
1219 char *string; /* remember the string since it may change */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001220
1221 /* Remember last two characters for pungetc. */
1222 int lastc[2];
1223
1224 /* Number of outstanding calls to pungetc. */
1225 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001226};
1227
1228struct parsefile {
1229 struct parsefile *prev; /* preceding file on stack */
1230 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001231 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001232 int left_in_line; /* number of chars left in this line */
1233 int left_in_buffer; /* number of chars left in this buffer past the line */
1234 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001235 char *buf; /* input buffer */
1236 struct strpush *strpush; /* for pushing strings at this level */
1237 struct strpush basestrpush; /* so pushing one is fast */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001238
1239 /* Remember last two characters for pungetc. */
1240 int lastc[2];
1241
1242 /* Number of outstanding calls to pungetc. */
1243 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001244};
1245
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001246static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001247static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001248static int startlinno; /* line # where last token started */
1249static char *commandname; /* currently executing command */
1250static struct strlist *cmdenviron; /* environment for builtin 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
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001307static void raise_error_syntax(const char *) NORETURN;
1308static void
1309raise_error_syntax(const char *msg)
1310{
1311 ash_msg_and_raise_error("syntax error: %s", msg);
1312 /* NOTREACHED */
1313}
1314
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001315static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001316static void
1317ash_msg_and_raise(int cond, const char *msg, ...)
1318{
1319 va_list ap;
1320
1321 va_start(ap, msg);
1322 ash_vmsg_and_raise(cond, msg, ap);
1323 /* NOTREACHED */
1324 va_end(ap);
1325}
1326
1327/*
1328 * error/warning routines for external builtins
1329 */
1330static void
1331ash_msg(const char *fmt, ...)
1332{
1333 va_list ap;
1334
1335 va_start(ap, fmt);
1336 ash_vmsg(fmt, ap);
1337 va_end(ap);
1338}
1339
1340/*
1341 * Return a string describing an error. The returned string may be a
1342 * pointer to a static buffer that will be overwritten on the next call.
1343 * Action describes the operation that got the error.
1344 */
1345static const char *
1346errmsg(int e, const char *em)
1347{
1348 if (e == ENOENT || e == ENOTDIR) {
1349 return em;
1350 }
1351 return strerror(e);
1352}
1353
1354
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001355/* ============ Memory allocation */
1356
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001357#if 0
1358/* I consider these wrappers nearly useless:
1359 * ok, they return you to nearest exception handler, but
1360 * how much memory do you leak in the process, making
1361 * memory starvation worse?
1362 */
1363static void *
1364ckrealloc(void * p, size_t nbytes)
1365{
1366 p = realloc(p, nbytes);
1367 if (!p)
1368 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1369 return p;
1370}
1371
1372static void *
1373ckmalloc(size_t nbytes)
1374{
1375 return ckrealloc(NULL, nbytes);
1376}
1377
1378static void *
1379ckzalloc(size_t nbytes)
1380{
1381 return memset(ckmalloc(nbytes), 0, nbytes);
1382}
1383
1384static char *
1385ckstrdup(const char *s)
1386{
1387 char *p = strdup(s);
1388 if (!p)
1389 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1390 return p;
1391}
1392#else
1393/* Using bbox equivalents. They exit if out of memory */
1394# define ckrealloc xrealloc
1395# define ckmalloc xmalloc
1396# define ckzalloc xzalloc
1397# define ckstrdup xstrdup
1398#endif
1399
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001400/*
1401 * It appears that grabstackstr() will barf with such alignments
1402 * because stalloc() will return a string allocated in a new stackblock.
1403 */
1404#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1405enum {
1406 /* Most machines require the value returned from malloc to be aligned
1407 * in some way. The following macro will get this right
1408 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001409 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001410 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001411 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001412};
1413
1414struct stack_block {
1415 struct stack_block *prev;
1416 char space[MINSIZE];
1417};
1418
1419struct stackmark {
1420 struct stack_block *stackp;
1421 char *stacknxt;
1422 size_t stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001423};
1424
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001425
Denis Vlasenko01631112007-12-16 17:20:38 +00001426struct globals_memstack {
1427 struct stack_block *g_stackp; // = &stackbase;
Denis Vlasenko01631112007-12-16 17:20:38 +00001428 char *g_stacknxt; // = stackbase.space;
1429 char *sstrend; // = stackbase.space + MINSIZE;
1430 size_t g_stacknleft; // = MINSIZE;
Denis Vlasenko01631112007-12-16 17:20:38 +00001431 struct stack_block stackbase;
1432};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001433extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1434#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001435#define g_stackp (G_memstack.g_stackp )
Denis Vlasenko01631112007-12-16 17:20:38 +00001436#define g_stacknxt (G_memstack.g_stacknxt )
1437#define sstrend (G_memstack.sstrend )
1438#define g_stacknleft (G_memstack.g_stacknleft)
Denis Vlasenko01631112007-12-16 17:20:38 +00001439#define stackbase (G_memstack.stackbase )
1440#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001441 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1442 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001443 g_stackp = &stackbase; \
1444 g_stacknxt = stackbase.space; \
1445 g_stacknleft = MINSIZE; \
1446 sstrend = stackbase.space + MINSIZE; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001447} while (0)
1448
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001449
Denis Vlasenko01631112007-12-16 17:20:38 +00001450#define stackblock() ((void *)g_stacknxt)
1451#define stackblocksize() g_stacknleft
1452
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001453/*
1454 * Parse trees for commands are allocated in lifo order, so we use a stack
1455 * to make this more efficient, and also to avoid all sorts of exception
1456 * handling code to handle interrupts in the middle of a parse.
1457 *
1458 * The size 504 was chosen because the Ultrix malloc handles that size
1459 * well.
1460 */
1461static void *
1462stalloc(size_t nbytes)
1463{
1464 char *p;
1465 size_t aligned;
1466
1467 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001468 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001469 size_t len;
1470 size_t blocksize;
1471 struct stack_block *sp;
1472
1473 blocksize = aligned;
1474 if (blocksize < MINSIZE)
1475 blocksize = MINSIZE;
1476 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1477 if (len < blocksize)
1478 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1479 INT_OFF;
1480 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001481 sp->prev = g_stackp;
1482 g_stacknxt = sp->space;
1483 g_stacknleft = blocksize;
1484 sstrend = g_stacknxt + blocksize;
1485 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001486 INT_ON;
1487 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001488 p = g_stacknxt;
1489 g_stacknxt += aligned;
1490 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001491 return p;
1492}
1493
Denis Vlasenko597906c2008-02-20 16:38:54 +00001494static void *
1495stzalloc(size_t nbytes)
1496{
1497 return memset(stalloc(nbytes), 0, nbytes);
1498}
1499
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001500static void
1501stunalloc(void *p)
1502{
1503#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001504 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001505 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001506 abort();
1507 }
1508#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001509 g_stacknleft += g_stacknxt - (char *)p;
1510 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001511}
1512
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001513/*
1514 * Like strdup but works with the ash stack.
1515 */
1516static char *
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02001517sstrdup(const char *p)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001518{
1519 size_t len = strlen(p) + 1;
1520 return memcpy(stalloc(len), p, len);
1521}
1522
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001523static inline void
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001524grabstackblock(size_t len)
1525{
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001526 stalloc(len);
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001527}
1528
1529static void
1530pushstackmark(struct stackmark *mark, size_t len)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001531{
Denis Vlasenko01631112007-12-16 17:20:38 +00001532 mark->stackp = g_stackp;
1533 mark->stacknxt = g_stacknxt;
1534 mark->stacknleft = g_stacknleft;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001535 grabstackblock(len);
1536}
1537
1538static void
1539setstackmark(struct stackmark *mark)
1540{
1541 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001542}
1543
1544static void
1545popstackmark(struct stackmark *mark)
1546{
1547 struct stack_block *sp;
1548
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001549 if (!mark->stackp)
1550 return;
1551
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001552 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001553 while (g_stackp != mark->stackp) {
1554 sp = g_stackp;
1555 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001556 free(sp);
1557 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001558 g_stacknxt = mark->stacknxt;
1559 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001560 sstrend = mark->stacknxt + mark->stacknleft;
1561 INT_ON;
1562}
1563
1564/*
1565 * When the parser reads in a string, it wants to stick the string on the
1566 * stack and only adjust the stack pointer when it knows how big the
1567 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1568 * of space on top of the stack and stackblocklen returns the length of
1569 * this block. Growstackblock will grow this space by at least one byte,
1570 * possibly moving it (like realloc). Grabstackblock actually allocates the
1571 * part of the block that has been used.
1572 */
1573static void
1574growstackblock(void)
1575{
1576 size_t newlen;
1577
Denis Vlasenko01631112007-12-16 17:20:38 +00001578 newlen = g_stacknleft * 2;
1579 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001580 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1581 if (newlen < 128)
1582 newlen += 128;
1583
Denis Vlasenko01631112007-12-16 17:20:38 +00001584 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001585 struct stack_block *sp;
1586 struct stack_block *prevstackp;
1587 size_t grosslen;
1588
1589 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001590 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001591 prevstackp = sp->prev;
1592 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1593 sp = ckrealloc(sp, grosslen);
1594 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001595 g_stackp = sp;
1596 g_stacknxt = sp->space;
1597 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001598 sstrend = sp->space + newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001599 INT_ON;
1600 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001601 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001602 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001603 char *p = stalloc(newlen);
1604
1605 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001606 g_stacknxt = memcpy(p, oldspace, oldlen);
1607 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001608 }
1609}
1610
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001611/*
1612 * The following routines are somewhat easier to use than the above.
1613 * The user declares a variable of type STACKSTR, which may be declared
1614 * to be a register. The macro STARTSTACKSTR initializes things. Then
1615 * the user uses the macro STPUTC to add characters to the string. In
1616 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1617 * grown as necessary. When the user is done, she can just leave the
1618 * string there and refer to it using stackblock(). Or she can allocate
1619 * the space for it using grabstackstr(). If it is necessary to allow
1620 * someone else to use the stack temporarily and then continue to grow
1621 * the string, the user should use grabstack to allocate the space, and
1622 * then call ungrabstr(p) to return to the previous mode of operation.
1623 *
1624 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1625 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1626 * is space for at least one character.
1627 */
1628static void *
1629growstackstr(void)
1630{
1631 size_t len = stackblocksize();
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001632 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001633 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001634}
1635
1636/*
1637 * Called from CHECKSTRSPACE.
1638 */
1639static char *
1640makestrspace(size_t newlen, char *p)
1641{
Denis Vlasenko01631112007-12-16 17:20:38 +00001642 size_t len = p - g_stacknxt;
Denys Vlasenko53d6e032016-09-30 11:24:12 +02001643 size_t size;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001644
1645 for (;;) {
1646 size_t nleft;
1647
1648 size = stackblocksize();
1649 nleft = size - len;
1650 if (nleft >= newlen)
1651 break;
1652 growstackblock();
1653 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001654 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001655}
1656
1657static char *
1658stack_nputstr(const char *s, size_t n, char *p)
1659{
1660 p = makestrspace(n, p);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001661 p = (char *)memcpy(p, s, n) + n;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001662 return p;
1663}
1664
1665static char *
1666stack_putstr(const char *s, char *p)
1667{
1668 return stack_nputstr(s, strlen(s), p);
1669}
1670
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001671static char *
1672_STPUTC(int c, char *p)
1673{
1674 if (p == sstrend)
1675 p = growstackstr();
1676 *p++ = c;
1677 return p;
1678}
1679
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001680#define STARTSTACKSTR(p) ((p) = stackblock())
1681#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001682#define CHECKSTRSPACE(n, p) do { \
1683 char *q = (p); \
1684 size_t l = (n); \
1685 size_t m = sstrend - q; \
1686 if (l > m) \
1687 (p) = makestrspace(l, q); \
1688} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001689#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001690#define STACKSTRNUL(p) do { \
1691 if ((p) == sstrend) \
1692 (p) = growstackstr(); \
1693 *(p) = '\0'; \
1694} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001695#define STUNPUTC(p) (--(p))
1696#define STTOPC(p) ((p)[-1])
1697#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001698
1699#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001700#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001701#define stackstrend() ((void *)sstrend)
1702
1703
1704/* ============ String helpers */
1705
1706/*
1707 * prefix -- see if pfx is a prefix of string.
1708 */
1709static char *
1710prefix(const char *string, const char *pfx)
1711{
1712 while (*pfx) {
1713 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001714 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001715 }
1716 return (char *) string;
1717}
1718
1719/*
1720 * Check for a valid number. This should be elsewhere.
1721 */
1722static int
1723is_number(const char *p)
1724{
1725 do {
1726 if (!isdigit(*p))
1727 return 0;
1728 } while (*++p != '\0');
1729 return 1;
1730}
1731
1732/*
1733 * Convert a string of digits to an integer, printing an error message on
1734 * failure.
1735 */
1736static int
1737number(const char *s)
1738{
1739 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001740 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001741 return atoi(s);
1742}
1743
1744/*
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001745 * Produce a single quoted string suitable as input to the shell.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001746 * The return string is allocated on the stack.
1747 */
1748static char *
1749single_quote(const char *s)
1750{
1751 char *p;
1752
1753 STARTSTACKSTR(p);
1754
1755 do {
1756 char *q;
1757 size_t len;
1758
1759 len = strchrnul(s, '\'') - s;
1760
1761 q = p = makestrspace(len + 3, p);
1762
1763 *q++ = '\'';
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001764 q = (char *)memcpy(q, s, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001765 *q++ = '\'';
1766 s += len;
1767
1768 STADJUST(q - p, p);
1769
Denys Vlasenkocd716832009-11-28 22:14:02 +01001770 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001771 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001772 len = 0;
1773 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001774
1775 q = p = makestrspace(len + 3, p);
1776
1777 *q++ = '"';
Denys Vlasenkocd716832009-11-28 22:14:02 +01001778 q = (char *)memcpy(q, s - len, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001779 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001780
1781 STADJUST(q - p, p);
1782 } while (*s);
1783
Denys Vlasenkocd716832009-11-28 22:14:02 +01001784 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001785
1786 return stackblock();
1787}
1788
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001789/*
1790 * Produce a possibly single quoted string suitable as input to the shell.
1791 * If 'conditional' is nonzero, quoting is only done if the string contains
1792 * non-shellsafe characters, or is identical to a shell keyword (reserved
1793 * word); if it is zero, quoting is always done.
1794 * If quoting was done, the return string is allocated on the stack,
1795 * otherwise a pointer to the original string is returned.
1796 */
1797static const char *
1798maybe_single_quote(const char *s)
1799{
1800 const char *p = s;
1801
1802 while (*p) {
1803 /* Assuming ACSII */
1804 /* quote ctrl_chars space !"#$%&'()* */
1805 if (*p < '+')
1806 goto need_quoting;
1807 /* quote ;<=>? */
1808 if (*p >= ';' && *p <= '?')
1809 goto need_quoting;
1810 /* quote `[\ */
1811 if (*p == '`')
1812 goto need_quoting;
1813 if (*p == '[')
1814 goto need_quoting;
1815 if (*p == '\\')
1816 goto need_quoting;
1817 /* quote {|}~ DEL and high bytes */
1818 if (*p > 'z')
1819 goto need_quoting;
1820 /* Not quoting these: +,-./ 0-9 :@ A-Z ]^_ a-z */
1821 /* TODO: maybe avoid quoting % */
1822 p++;
1823 }
1824 return s;
1825
1826 need_quoting:
1827 return single_quote(s);
1828}
1829
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001830
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001831/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001832
1833static char **argptr; /* argument list for builtin commands */
1834static char *optionarg; /* set by nextopt (like getopt) */
1835static char *optptr; /* used by nextopt */
1836
1837/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001838 * XXX - should get rid of. Have all builtins use getopt(3).
1839 * The library getopt must have the BSD extension static variable
1840 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001841 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001842 * Standard option processing (a la getopt) for builtin routines.
1843 * The only argument that is passed to nextopt is the option string;
1844 * the other arguments are unnecessary. It returns the character,
1845 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001846 */
1847static int
1848nextopt(const char *optstring)
1849{
1850 char *p;
1851 const char *q;
1852 char c;
1853
1854 p = optptr;
1855 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001856 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001857 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001858 if (p == NULL)
1859 return '\0';
1860 if (*p != '-')
1861 return '\0';
1862 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001863 return '\0';
1864 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001865 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001866 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001867 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001868 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001869 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001870 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001871 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001872 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001873 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001874 if (*++q == ':')
1875 q++;
1876 }
1877 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001878 if (*p == '\0') {
1879 p = *argptr++;
1880 if (p == NULL)
1881 ash_msg_and_raise_error("no arg for -%c option", c);
1882 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001883 optionarg = p;
1884 p = NULL;
1885 }
1886 optptr = p;
1887 return c;
1888}
1889
1890
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001891/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001892
Denis Vlasenko01631112007-12-16 17:20:38 +00001893/*
1894 * The parsefile structure pointed to by the global variable parsefile
1895 * contains information about the current file being read.
1896 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001897struct shparam {
1898 int nparam; /* # of positional parameters (without $0) */
1899#if ENABLE_ASH_GETOPTS
1900 int optind; /* next parameter to be processed by getopts */
1901 int optoff; /* used by getopts */
1902#endif
1903 unsigned char malloced; /* if parameter list dynamically allocated */
1904 char **p; /* parameter list */
1905};
1906
1907/*
1908 * Free the list of positional parameters.
1909 */
1910static void
1911freeparam(volatile struct shparam *param)
1912{
Denis Vlasenko01631112007-12-16 17:20:38 +00001913 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001914 char **ap, **ap1;
1915 ap = ap1 = param->p;
1916 while (*ap)
1917 free(*ap++);
1918 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001919 }
1920}
1921
1922#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001923static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001924#endif
1925
1926struct var {
1927 struct var *next; /* next entry in hash list */
1928 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001929 const char *var_text; /* name=value */
1930 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001931 /* the variable gets set/unset */
1932};
1933
1934struct localvar {
1935 struct localvar *next; /* next local variable in list */
1936 struct var *vp; /* the variable that was made local */
1937 int flags; /* saved flags */
1938 const char *text; /* saved text */
1939};
1940
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001941/* flags */
1942#define VEXPORT 0x01 /* variable is exported */
1943#define VREADONLY 0x02 /* variable cannot be modified */
1944#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1945#define VTEXTFIXED 0x08 /* text is statically allocated */
1946#define VSTACK 0x10 /* text is allocated on the stack */
1947#define VUNSET 0x20 /* the variable is not set */
1948#define VNOFUNC 0x40 /* don't call the callback function */
1949#define VNOSET 0x80 /* do not set variable - just readonly test */
1950#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001951#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001952# define VDYNAMIC 0x200 /* dynamic variable */
1953#else
1954# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001955#endif
1956
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001957
Denis Vlasenko01631112007-12-16 17:20:38 +00001958/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001959#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001960static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001961change_lc_all(const char *value)
1962{
1963 if (value && *value != '\0')
1964 setlocale(LC_ALL, value);
1965}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001966static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001967change_lc_ctype(const char *value)
1968{
1969 if (value && *value != '\0')
1970 setlocale(LC_CTYPE, value);
1971}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001972#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001973#if ENABLE_ASH_MAIL
1974static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01001975static void changemail(const char *var_value) FAST_FUNC;
1976#else
1977# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001978#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001979static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001980#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001981static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001982#endif
1983
Denis Vlasenko01631112007-12-16 17:20:38 +00001984static const struct {
1985 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001986 const char *var_text;
1987 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00001988} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02001989 /*
1990 * Note: VEXPORT would not work correctly here for NOFORK applets:
1991 * some environment strings may be constant.
1992 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001993 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001994#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001995 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
1996 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001997#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001998 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1999 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
2000 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
2001 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002002#if ENABLE_ASH_GETOPTS
Denys Vlasenkoe627ac92016-09-30 14:36:59 +02002003 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002004#endif
2005#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002006 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002007#endif
2008#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002009 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
2010 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002011#endif
2012#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002013 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002014#endif
2015};
2016
Denis Vlasenko0b769642008-07-24 07:54:57 +00002017struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00002018
2019struct globals_var {
2020 struct shparam shellparam; /* $@ current positional parameters */
2021 struct redirtab *redirlist;
Denis Vlasenko01631112007-12-16 17:20:38 +00002022 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
2023 struct var *vartab[VTABSIZE];
2024 struct var varinit[ARRAY_SIZE(varinit_data)];
2025};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00002026extern struct globals_var *const ash_ptr_to_globals_var;
2027#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00002028#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00002029//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00002030#define preverrout_fd (G_var.preverrout_fd)
2031#define vartab (G_var.vartab )
2032#define varinit (G_var.varinit )
2033#define INIT_G_var() do { \
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00002034 unsigned i; \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00002035 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
2036 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00002037 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002038 varinit[i].flags = varinit_data[i].flags; \
2039 varinit[i].var_text = varinit_data[i].var_text; \
2040 varinit[i].var_func = varinit_data[i].var_func; \
Denis Vlasenko01631112007-12-16 17:20:38 +00002041 } \
2042} while (0)
2043
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002044#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002045#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002046# define vmail (&vifs)[1]
2047# define vmpath (&vmail)[1]
2048# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002049#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002050# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002051#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002052#define vps1 (&vpath)[1]
2053#define vps2 (&vps1)[1]
2054#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002055#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002056# define voptind (&vps4)[1]
2057# if ENABLE_ASH_RANDOM_SUPPORT
2058# define vrandom (&voptind)[1]
2059# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002060#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002061# if ENABLE_ASH_RANDOM_SUPPORT
2062# define vrandom (&vps4)[1]
2063# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002064#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002065
2066/*
2067 * The following macros access the values of the above variables.
2068 * They have to skip over the name. They return the null string
2069 * for unset variables.
2070 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002071#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002072#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002073#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002074# define mailval() (vmail.var_text + 5)
2075# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002076# define mpathset() ((vmpath.flags & VUNSET) == 0)
2077#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002078#define pathval() (vpath.var_text + 5)
2079#define ps1val() (vps1.var_text + 4)
2080#define ps2val() (vps2.var_text + 4)
2081#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002082#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002083# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002084#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002085
Denis Vlasenko01631112007-12-16 17:20:38 +00002086#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002087static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002088getoptsreset(const char *value)
2089{
Denys Vlasenkoa513bf32016-10-26 02:03:37 +02002090 shellparam.optind = number(value) ?: 1;
Denis Vlasenko01631112007-12-16 17:20:38 +00002091 shellparam.optoff = -1;
2092}
2093#endif
2094
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002095/*
2096 * Compares two strings up to the first = or '\0'. The first
2097 * string must be terminated by '='; the second may be terminated by
2098 * either '=' or '\0'.
2099 */
2100static int
2101varcmp(const char *p, const char *q)
2102{
2103 int c, d;
2104
2105 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002106 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002107 goto out;
2108 p++;
2109 q++;
2110 }
2111 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002112 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002113 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002114 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002115 out:
2116 return c - d;
2117}
2118
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002119/*
2120 * Find the appropriate entry in the hash table from the name.
2121 */
2122static struct var **
2123hashvar(const char *p)
2124{
2125 unsigned hashval;
2126
2127 hashval = ((unsigned char) *p) << 4;
2128 while (*p && *p != '=')
2129 hashval += (unsigned char) *p++;
2130 return &vartab[hashval % VTABSIZE];
2131}
2132
2133static int
2134vpcmp(const void *a, const void *b)
2135{
2136 return varcmp(*(const char **)a, *(const char **)b);
2137}
2138
2139/*
2140 * This routine initializes the builtin variables.
2141 */
2142static void
2143initvar(void)
2144{
2145 struct var *vp;
2146 struct var *end;
2147 struct var **vpp;
2148
2149 /*
2150 * PS1 depends on uid
2151 */
2152#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002153 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002154#else
2155 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002156 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002157#endif
2158 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002159 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002160 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002161 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002162 vp->next = *vpp;
2163 *vpp = vp;
2164 } while (++vp < end);
2165}
2166
2167static struct var **
2168findvar(struct var **vpp, const char *name)
2169{
2170 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002171 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002172 break;
2173 }
2174 }
2175 return vpp;
2176}
2177
2178/*
2179 * Find the value of a variable. Returns NULL if not set.
2180 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002181static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002182lookupvar(const char *name)
2183{
2184 struct var *v;
2185
2186 v = *findvar(hashvar(name), name);
2187 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002188#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002189 /*
2190 * Dynamic variables are implemented roughly the same way they are
2191 * in bash. Namely, they're "special" so long as they aren't unset.
2192 * As soon as they're unset, they're no longer dynamic, and dynamic
2193 * lookup will no longer happen at that point. -- PFM.
2194 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002195 if (v->flags & VDYNAMIC)
2196 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002197#endif
2198 if (!(v->flags & VUNSET))
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002199 return var_end(v->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002200 }
2201 return NULL;
2202}
2203
Denys Vlasenko0b883582016-12-23 16:49:07 +01002204#if ENABLE_UNICODE_SUPPORT
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02002205static void
2206reinit_unicode_for_ash(void)
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002207{
2208 /* Unicode support should be activated even if LANG is set
2209 * _during_ shell execution, not only if it was set when
2210 * shell was started. Therefore, re-check LANG every time:
2211 */
2212 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2213 || ENABLE_UNICODE_USING_LOCALE
2214 ) {
2215 const char *s = lookupvar("LC_ALL");
2216 if (!s) s = lookupvar("LC_CTYPE");
2217 if (!s) s = lookupvar("LANG");
2218 reinit_unicode(s);
2219 }
2220}
Denys Vlasenko0b883582016-12-23 16:49:07 +01002221#else
2222# define reinit_unicode_for_ash() ((void)0)
2223#endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002224
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002225/*
2226 * Search the environment of a builtin command.
2227 */
Mike Frysinger98c52642009-04-02 10:02:37 +00002228static const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002229bltinlookup(const char *name)
2230{
2231 struct strlist *sp;
2232
2233 for (sp = cmdenviron; sp; sp = sp->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002234 if (varcmp(sp->text, name) == 0)
2235 return var_end(sp->text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002236 }
2237 return lookupvar(name);
2238}
2239
2240/*
2241 * Same as setvar except that the variable and value are passed in
2242 * the first argument as name=value. Since the first argument will
2243 * be actually stored in the table, it should not be a string that
2244 * will go away.
2245 * Called with interrupts off.
2246 */
2247static void
2248setvareq(char *s, int flags)
2249{
2250 struct var *vp, **vpp;
2251
2252 vpp = hashvar(s);
2253 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2254 vp = *findvar(vpp, s);
2255 if (vp) {
2256 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2257 const char *n;
2258
2259 if (flags & VNOSAVE)
2260 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002261 n = vp->var_text;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02002262 exitstatus = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002263 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2264 }
2265
2266 if (flags & VNOSET)
2267 return;
2268
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002269 if (vp->var_func && !(flags & VNOFUNC))
2270 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002271
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002272 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2273 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002274
2275 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2276 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002277 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002278 if (flags & VNOSET)
2279 return;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002280 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002281 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002282 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002283 *vpp = vp;
2284 }
2285 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2286 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002287 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002288 vp->flags = flags;
2289}
2290
2291/*
2292 * Set the value of a variable. The flags argument is ored with the
2293 * flags of the variable. If val is NULL, the variable is unset.
2294 */
2295static void
2296setvar(const char *name, const char *val, int flags)
2297{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002298 const char *q;
2299 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002300 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002301 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002302 size_t vallen;
2303
2304 q = endofname(name);
2305 p = strchrnul(q, '=');
2306 namelen = p - name;
2307 if (!namelen || p != q)
2308 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2309 vallen = 0;
2310 if (val == NULL) {
2311 flags |= VUNSET;
2312 } else {
2313 vallen = strlen(val);
2314 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002315
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002316 INT_OFF;
2317 nameeq = ckmalloc(namelen + vallen + 2);
Denys Vlasenkoda2244f2017-07-21 18:51:29 +02002318 p = mempcpy(nameeq, name, namelen);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002319 if (val) {
2320 *p++ = '=';
Denys Vlasenkoda2244f2017-07-21 18:51:29 +02002321 p = mempcpy(p, val, vallen);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002322 }
2323 *p = '\0';
2324 setvareq(nameeq, flags | VNOSAVE);
2325 INT_ON;
2326}
2327
Denys Vlasenko03dad222010-01-12 23:29:57 +01002328static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002329setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002330{
2331 setvar(name, val, 0);
2332}
2333
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002334/*
2335 * Unset the specified variable.
2336 */
2337static int
2338unsetvar(const char *s)
2339{
2340 struct var **vpp;
2341 struct var *vp;
2342 int retval;
2343
2344 vpp = findvar(hashvar(s), s);
2345 vp = *vpp;
2346 retval = 2;
2347 if (vp) {
2348 int flags = vp->flags;
2349
2350 retval = 1;
2351 if (flags & VREADONLY)
2352 goto out;
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002353#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002354 vp->flags &= ~VDYNAMIC;
2355#endif
2356 if (flags & VUNSET)
2357 goto ok;
2358 if ((flags & VSTRFIXED) == 0) {
2359 INT_OFF;
2360 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002361 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002362 *vpp = vp->next;
2363 free(vp);
2364 INT_ON;
2365 } else {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002366 setvar0(s, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002367 vp->flags &= ~VEXPORT;
2368 }
2369 ok:
2370 retval = 0;
2371 }
2372 out:
2373 return retval;
2374}
2375
2376/*
2377 * Process a linked list of variable assignments.
2378 */
2379static void
2380listsetvar(struct strlist *list_set_var, int flags)
2381{
2382 struct strlist *lp = list_set_var;
2383
2384 if (!lp)
2385 return;
2386 INT_OFF;
2387 do {
2388 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002389 lp = lp->next;
2390 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002391 INT_ON;
2392}
2393
2394/*
2395 * Generate a list of variables satisfying the given conditions.
2396 */
2397static char **
2398listvars(int on, int off, char ***end)
2399{
2400 struct var **vpp;
2401 struct var *vp;
2402 char **ep;
2403 int mask;
2404
2405 STARTSTACKSTR(ep);
2406 vpp = vartab;
2407 mask = on | off;
2408 do {
2409 for (vp = *vpp; vp; vp = vp->next) {
2410 if ((vp->flags & mask) == on) {
2411 if (ep == stackstrend())
2412 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002413 *ep++ = (char*)vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002414 }
2415 }
2416 } while (++vpp < vartab + VTABSIZE);
2417 if (ep == stackstrend())
2418 ep = growstackstr();
2419 if (end)
2420 *end = ep;
2421 *ep++ = NULL;
2422 return grabstackstr(ep);
2423}
2424
2425
2426/* ============ Path search helper
2427 *
2428 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002429 * of the path before the first call; path_advance will update
2430 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002431 * the possible path expansions in sequence. If an option (indicated by
2432 * a percent sign) appears in the path entry then the global variable
2433 * pathopt will be set to point to it; otherwise pathopt will be set to
2434 * NULL.
2435 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002436static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002437
2438static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002439path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002440{
2441 const char *p;
2442 char *q;
2443 const char *start;
2444 size_t len;
2445
2446 if (*path == NULL)
2447 return NULL;
2448 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002449 for (p = start; *p && *p != ':' && *p != '%'; p++)
2450 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002451 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2452 while (stackblocksize() < len)
2453 growstackblock();
2454 q = stackblock();
2455 if (p != start) {
2456 memcpy(q, start, p - start);
2457 q += p - start;
2458 *q++ = '/';
2459 }
2460 strcpy(q, name);
2461 pathopt = NULL;
2462 if (*p == '%') {
2463 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002464 while (*p && *p != ':')
2465 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002466 }
2467 if (*p == ':')
2468 *path = p + 1;
2469 else
2470 *path = NULL;
2471 return stalloc(len);
2472}
2473
2474
2475/* ============ Prompt */
2476
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002477static smallint doprompt; /* if set, prompt the user */
2478static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002479
2480#if ENABLE_FEATURE_EDITING
2481static line_input_t *line_input_state;
2482static const char *cmdedit_prompt;
2483static void
2484putprompt(const char *s)
2485{
2486 if (ENABLE_ASH_EXPAND_PRMT) {
2487 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002488 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002489 return;
2490 }
2491 cmdedit_prompt = s;
2492}
2493#else
2494static void
2495putprompt(const char *s)
2496{
2497 out2str(s);
2498}
2499#endif
2500
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002501/* expandstr() needs parsing machinery, so it is far away ahead... */
2502static const char *expandstr(const char *ps);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002503
2504static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002505setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002506{
2507 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002508 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2509
2510 if (!do_set)
2511 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002512
2513 needprompt = 0;
2514
2515 switch (whichprompt) {
2516 case 1:
2517 prompt = ps1val();
2518 break;
2519 case 2:
2520 prompt = ps2val();
2521 break;
2522 default: /* 0 */
2523 prompt = nullstr;
2524 }
2525#if ENABLE_ASH_EXPAND_PRMT
Denys Vlasenko60ca8342016-09-30 11:21:21 +02002526 pushstackmark(&smark, stackblocksize());
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002527 putprompt(expandstr(prompt));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002528 popstackmark(&smark);
Denys Vlasenko48c803a2017-07-01 23:24:48 +02002529#else
2530 putprompt(prompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002531#endif
2532}
2533
2534
2535/* ============ The cd and pwd commands */
2536
2537#define CD_PHYSICAL 1
2538#define CD_PRINT 2
2539
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002540static int
2541cdopt(void)
2542{
2543 int flags = 0;
2544 int i, j;
2545
2546 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002547 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002548 if (i != j) {
2549 flags ^= CD_PHYSICAL;
2550 j = i;
2551 }
2552 }
2553
2554 return flags;
2555}
2556
2557/*
2558 * Update curdir (the name of the current directory) in response to a
2559 * cd command.
2560 */
2561static const char *
2562updatepwd(const char *dir)
2563{
2564 char *new;
2565 char *p;
2566 char *cdcomppath;
2567 const char *lim;
2568
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02002569 cdcomppath = sstrdup(dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002570 STARTSTACKSTR(new);
2571 if (*dir != '/') {
2572 if (curdir == nullstr)
2573 return 0;
2574 new = stack_putstr(curdir, new);
2575 }
2576 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002577 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002578 if (*dir != '/') {
2579 if (new[-1] != '/')
2580 USTPUTC('/', new);
2581 if (new > lim && *lim == '/')
2582 lim++;
2583 } else {
2584 USTPUTC('/', new);
2585 cdcomppath++;
2586 if (dir[1] == '/' && dir[2] != '/') {
2587 USTPUTC('/', new);
2588 cdcomppath++;
2589 lim++;
2590 }
2591 }
2592 p = strtok(cdcomppath, "/");
2593 while (p) {
2594 switch (*p) {
2595 case '.':
2596 if (p[1] == '.' && p[2] == '\0') {
2597 while (new > lim) {
2598 STUNPUTC(new);
2599 if (new[-1] == '/')
2600 break;
2601 }
2602 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002603 }
2604 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002605 break;
2606 /* fall through */
2607 default:
2608 new = stack_putstr(p, new);
2609 USTPUTC('/', new);
2610 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002611 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002612 }
2613 if (new > lim)
2614 STUNPUTC(new);
2615 *new = 0;
2616 return stackblock();
2617}
2618
2619/*
2620 * Find out what the current directory is. If we already know the current
2621 * directory, this routine returns immediately.
2622 */
2623static char *
2624getpwd(void)
2625{
Denis Vlasenko01631112007-12-16 17:20:38 +00002626 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002627 return dir ? dir : nullstr;
2628}
2629
2630static void
2631setpwd(const char *val, int setold)
2632{
2633 char *oldcur, *dir;
2634
2635 oldcur = dir = curdir;
2636
2637 if (setold) {
2638 setvar("OLDPWD", oldcur, VEXPORT);
2639 }
2640 INT_OFF;
2641 if (physdir != nullstr) {
2642 if (physdir != oldcur)
2643 free(physdir);
2644 physdir = nullstr;
2645 }
2646 if (oldcur == val || !val) {
2647 char *s = getpwd();
2648 physdir = s;
2649 if (!val)
2650 dir = s;
2651 } else
2652 dir = ckstrdup(val);
2653 if (oldcur != dir && oldcur != nullstr) {
2654 free(oldcur);
2655 }
2656 curdir = dir;
2657 INT_ON;
2658 setvar("PWD", dir, VEXPORT);
2659}
2660
2661static void hashcd(void);
2662
2663/*
Denys Vlasenko70392332016-10-27 02:31:55 +02002664 * Actually do the chdir. We also call hashcd to let other routines
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002665 * know that the current directory has changed.
2666 */
2667static int
2668docd(const char *dest, int flags)
2669{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002670 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002671 int err;
2672
2673 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2674
2675 INT_OFF;
2676 if (!(flags & CD_PHYSICAL)) {
2677 dir = updatepwd(dest);
2678 if (dir)
2679 dest = dir;
2680 }
2681 err = chdir(dest);
2682 if (err)
2683 goto out;
2684 setpwd(dir, 1);
2685 hashcd();
2686 out:
2687 INT_ON;
2688 return err;
2689}
2690
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002691static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002692cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002693{
2694 const char *dest;
2695 const char *path;
2696 const char *p;
2697 char c;
2698 struct stat statb;
2699 int flags;
2700
2701 flags = cdopt();
2702 dest = *argptr;
2703 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002704 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002705 else if (LONE_DASH(dest)) {
2706 dest = bltinlookup("OLDPWD");
2707 flags |= CD_PRINT;
2708 }
2709 if (!dest)
2710 dest = nullstr;
2711 if (*dest == '/')
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002712 goto step6;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002713 if (*dest == '.') {
2714 c = dest[1];
2715 dotdot:
2716 switch (c) {
2717 case '\0':
2718 case '/':
2719 goto step6;
2720 case '.':
2721 c = dest[2];
2722 if (c != '.')
2723 goto dotdot;
2724 }
2725 }
2726 if (!*dest)
2727 dest = ".";
2728 path = bltinlookup("CDPATH");
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002729 while (path) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002730 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002731 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002732 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2733 if (c && c != ':')
2734 flags |= CD_PRINT;
2735 docd:
2736 if (!docd(p, flags))
2737 goto out;
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002738 goto err;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002739 }
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002740 }
2741
2742 step6:
2743 p = dest;
2744 goto docd;
2745
2746 err:
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002747 ash_msg_and_raise_error("can't cd to %s", dest);
2748 /* NOTREACHED */
2749 out:
2750 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002751 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002752 return 0;
2753}
2754
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002755static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002756pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002757{
2758 int flags;
2759 const char *dir = curdir;
2760
2761 flags = cdopt();
2762 if (flags) {
2763 if (physdir == nullstr)
2764 setpwd(dir, 0);
2765 dir = physdir;
2766 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002767 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002768 return 0;
2769}
2770
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002771
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002772/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002773
Denis Vlasenko834dee72008-10-07 09:18:30 +00002774
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002775#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002776
Eric Andersenc470f442003-07-28 09:56:35 +00002777/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002778#define CWORD 0 /* character is nothing special */
2779#define CNL 1 /* newline character */
2780#define CBACK 2 /* a backslash character */
2781#define CSQUOTE 3 /* single quote */
2782#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002783#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002784#define CBQUOTE 6 /* backwards single quote */
2785#define CVAR 7 /* a dollar sign */
2786#define CENDVAR 8 /* a '}' character */
2787#define CLP 9 /* a left paren in arithmetic */
2788#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002789#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002790#define CCTL 12 /* like CWORD, except it must be escaped */
2791#define CSPCL 13 /* these terminate a word */
2792#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002793
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002794#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002795#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002796# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002797#endif
2798
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002799#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002800
Denys Vlasenko0b883582016-12-23 16:49:07 +01002801#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002802# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002803#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002804# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002805#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002806static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002807#if ENABLE_ASH_ALIAS
2808 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2809#endif
2810 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2811 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2812 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2813 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2814 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2815 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2816 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2817 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2818 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2819 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2820 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002821#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002822 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2823 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2824 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2825#endif
2826#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002827};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002828/* Constants below must match table above */
2829enum {
2830#if ENABLE_ASH_ALIAS
2831 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2832#endif
2833 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2834 CNL_CNL_CNL_CNL , /* 2 */
2835 CWORD_CCTL_CCTL_CWORD , /* 3 */
2836 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2837 CVAR_CVAR_CWORD_CVAR , /* 5 */
2838 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2839 CSPCL_CWORD_CWORD_CLP , /* 7 */
2840 CSPCL_CWORD_CWORD_CRP , /* 8 */
2841 CBACK_CBACK_CCTL_CBACK , /* 9 */
2842 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2843 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2844 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2845 CWORD_CWORD_CWORD_CWORD , /* 13 */
2846 CCTL_CCTL_CCTL_CCTL , /* 14 */
2847};
Eric Andersen2870d962001-07-02 17:27:21 +00002848
Denys Vlasenkocd716832009-11-28 22:14:02 +01002849/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2850 * caller must ensure proper cast on it if c is *char_ptr!
2851 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002852/* Values for syntax param */
2853#define BASESYNTAX 0 /* not in quotes */
2854#define DQSYNTAX 1 /* in double quotes */
2855#define SQSYNTAX 2 /* in single quotes */
2856#define ARISYNTAX 3 /* in arithmetic */
2857#define PSSYNTAX 4 /* prompt. never passed to SIT() */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002858
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002859#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002860
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002861static int
2862SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002863{
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002864 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2865 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2866 /*
2867 * This causes '/' to be prepended with CTLESC in dquoted string,
2868 * making "./file"* treated incorrectly because we feed
2869 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2870 * The "homegrown" glob implementation is okay with that,
2871 * but glibc one isn't. With '/' always treated as CWORD,
2872 * both work fine.
2873 */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002874# if ENABLE_ASH_ALIAS
2875 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002876 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002877 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002878 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2879 11, 3 /* "}~" */
2880 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002881# else
2882 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002883 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002884 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002885 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2886 10, 2 /* "}~" */
2887 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002888# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002889 const char *s;
2890 int indx;
2891
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002892 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002893 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002894# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002895 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002896 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002897 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002898# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002899 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002900 /* Cast is purely for paranoia here,
2901 * just in case someone passed signed char to us */
2902 if ((unsigned char)c >= CTL_FIRST
2903 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002904 ) {
2905 return CCTL;
2906 }
2907 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002908 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002909 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002910 indx = syntax_index_table[s - spec_symbls];
2911 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002912 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002913}
2914
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002915#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002916
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002917static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002918 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002919 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2920 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2921 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2922 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2923 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2924 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2925 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2926 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2927 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2928 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2929 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2930 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2931 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2932 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2933 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2934 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2935 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2936 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2937 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2938 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2939 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2940 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2941 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2942 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2943 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2944 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2945 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2946 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2947 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2948 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2949 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2950 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2951 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2952 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2953 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2954 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2956 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2958 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2959 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2960 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2961 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2962 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2964 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2965 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002966/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
2967 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkocd716832009-11-28 22:14:02 +01002968 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2979 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2980 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2981 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2982 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2983 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2984 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2986 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2987 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2988 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2989 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2990 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2991 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2992 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2993 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2994 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2995 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2996 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2997 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2998 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2999 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
3000 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
3001 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
3002 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
3003 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
3004 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
3005 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
3006 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
3007 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
3008 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
3009 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
3010 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
3011 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
3012 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
3013 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
3014 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
3015 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
3016 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
3017 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
3018 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
3019 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
3020 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
3021 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
3022 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
3023 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
3024 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
3025 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
3026 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
3027 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
3028 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
3029 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
3030 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
3031 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
3032 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
3033 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
3034 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
3035 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
3036 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
3037 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
3038 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
3039 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
3040 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
3041 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
3042 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
3043 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
3044 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
3045 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3046 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
3047 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
3048 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
3050 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
3051 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
3052 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
3053 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
3054 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
3055 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
3056 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3057 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3112 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3113 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3114 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3115 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3116 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3117 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3118 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3119 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3120 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3121 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3122 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3123 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3124 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3125 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3126 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3127 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3128 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3129 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3130 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3131 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3132 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3133 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3134 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3135 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3136 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3137 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3138 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3139 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3140 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3141 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3142 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3143 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3144 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3145 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3146 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3147 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3148 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3149 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3150 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3151 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3152 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3153 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3154 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3155 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3156 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3157 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3158 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3159 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3160 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3161 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3162 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3163 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3164 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3165 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3166 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3167 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3168 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3169 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3170 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3171 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3172 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3173 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3174 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3175 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003176 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003177# if ENABLE_ASH_ALIAS
3178 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3179# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003180};
3181
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003182#if 1
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003183# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003184#else /* debug version, caught one signed char bug */
3185# define SIT(c, syntax) \
3186 ({ \
3187 if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3188 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
Denys Vlasenko0b883582016-12-23 16:49:07 +01003189 if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003190 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3191 ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3192 })
3193#endif
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003194
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003195#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003196
Eric Andersen2870d962001-07-02 17:27:21 +00003197
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003198/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003199
Denis Vlasenko131ae172007-02-18 13:00:19 +00003200#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003201
3202#define ALIASINUSE 1
3203#define ALIASDEAD 2
3204
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003205struct alias {
3206 struct alias *next;
3207 char *name;
3208 char *val;
3209 int flag;
3210};
3211
Denis Vlasenko01631112007-12-16 17:20:38 +00003212
3213static struct alias **atab; // [ATABSIZE];
3214#define INIT_G_alias() do { \
3215 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3216} while (0)
3217
Eric Andersen2870d962001-07-02 17:27:21 +00003218
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003219static struct alias **
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02003220__lookupalias(const char *name)
3221{
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003222 unsigned int hashval;
3223 struct alias **app;
3224 const char *p;
3225 unsigned int ch;
3226
3227 p = name;
3228
3229 ch = (unsigned char)*p;
3230 hashval = ch << 4;
3231 while (ch) {
3232 hashval += ch;
3233 ch = (unsigned char)*++p;
3234 }
3235 app = &atab[hashval % ATABSIZE];
3236
3237 for (; *app; app = &(*app)->next) {
3238 if (strcmp(name, (*app)->name) == 0) {
3239 break;
3240 }
3241 }
3242
3243 return app;
3244}
3245
3246static struct alias *
3247lookupalias(const char *name, int check)
3248{
3249 struct alias *ap = *__lookupalias(name);
3250
3251 if (check && ap && (ap->flag & ALIASINUSE))
3252 return NULL;
3253 return ap;
3254}
3255
3256static struct alias *
3257freealias(struct alias *ap)
3258{
3259 struct alias *next;
3260
3261 if (ap->flag & ALIASINUSE) {
3262 ap->flag |= ALIASDEAD;
3263 return ap;
3264 }
3265
3266 next = ap->next;
3267 free(ap->name);
3268 free(ap->val);
3269 free(ap);
3270 return next;
3271}
Eric Andersencb57d552001-06-28 07:25:16 +00003272
Eric Andersenc470f442003-07-28 09:56:35 +00003273static void
3274setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003275{
3276 struct alias *ap, **app;
3277
3278 app = __lookupalias(name);
3279 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003280 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003281 if (ap) {
3282 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003283 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003284 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003285 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003286 ap->flag &= ~ALIASDEAD;
3287 } else {
3288 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003289 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003290 ap->name = ckstrdup(name);
3291 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003292 /*ap->flag = 0; - ckzalloc did it */
3293 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003294 *app = ap;
3295 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003296 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003297}
3298
Eric Andersenc470f442003-07-28 09:56:35 +00003299static int
3300unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003301{
Eric Andersencb57d552001-06-28 07:25:16 +00003302 struct alias **app;
3303
3304 app = __lookupalias(name);
3305
3306 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003307 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003308 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003309 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003310 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003311 }
3312
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003313 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003314}
3315
Eric Andersenc470f442003-07-28 09:56:35 +00003316static void
3317rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003318{
Eric Andersencb57d552001-06-28 07:25:16 +00003319 struct alias *ap, **app;
3320 int i;
3321
Denis Vlasenkob012b102007-02-19 22:43:01 +00003322 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003323 for (i = 0; i < ATABSIZE; i++) {
3324 app = &atab[i];
3325 for (ap = *app; ap; ap = *app) {
3326 *app = freealias(*app);
3327 if (ap == *app) {
3328 app = &ap->next;
3329 }
3330 }
3331 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003332 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003333}
3334
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003335static void
3336printalias(const struct alias *ap)
3337{
3338 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3339}
3340
Eric Andersencb57d552001-06-28 07:25:16 +00003341/*
3342 * TODO - sort output
3343 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003344static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003345aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003346{
3347 char *n, *v;
3348 int ret = 0;
3349 struct alias *ap;
3350
Denis Vlasenko68404f12008-03-17 09:00:54 +00003351 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003352 int i;
3353
Denis Vlasenko68404f12008-03-17 09:00:54 +00003354 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003355 for (ap = atab[i]; ap; ap = ap->next) {
3356 printalias(ap);
3357 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003358 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003359 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003360 }
3361 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003362 v = strchr(n+1, '=');
3363 if (v == NULL) { /* n+1: funny ksh stuff */
3364 ap = *__lookupalias(n);
3365 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003366 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003367 ret = 1;
3368 } else
3369 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003370 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003371 *v++ = '\0';
3372 setalias(n, v);
3373 }
3374 }
3375
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003376 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003377}
3378
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003379static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003380unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003381{
3382 int i;
3383
Denys Vlasenko6c149f42017-04-12 21:31:32 +02003384 while (nextopt("a") != '\0') {
3385 rmaliases();
3386 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003387 }
3388 for (i = 0; *argptr; argptr++) {
3389 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003390 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003391 i = 1;
3392 }
3393 }
3394
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003395 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003396}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003397
Denis Vlasenko131ae172007-02-18 13:00:19 +00003398#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003399
Eric Andersenc470f442003-07-28 09:56:35 +00003400
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003401/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003402#define FORK_FG 0
3403#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003404#define FORK_NOJOB 2
3405
3406/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003407#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3408#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3409#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003410#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003411
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003412/*
3413 * A job structure contains information about a job. A job is either a
3414 * single process or a set of processes contained in a pipeline. In the
3415 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3416 * array of pids.
3417 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003418struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003419 pid_t ps_pid; /* process id */
3420 int ps_status; /* last process status from wait() */
3421 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003422};
3423
3424struct job {
3425 struct procstat ps0; /* status of process */
3426 struct procstat *ps; /* status or processes when more than one */
3427#if JOBS
3428 int stopstatus; /* status of a stopped job */
3429#endif
Denys Vlasenko4c179372017-01-11 18:44:15 +01003430 unsigned nprocs; /* number of processes */
3431
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003432#define JOBRUNNING 0 /* at least one proc running */
3433#define JOBSTOPPED 1 /* all procs are stopped */
3434#define JOBDONE 2 /* all procs are completed */
Denys Vlasenko4c179372017-01-11 18:44:15 +01003435 unsigned
3436 state: 8,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003437#if JOBS
3438 sigint: 1, /* job was killed by SIGINT */
3439 jobctl: 1, /* job running under job control */
3440#endif
3441 waited: 1, /* true if this entry has been waited for */
3442 used: 1, /* true if this entry is in used */
3443 changed: 1; /* true if status has changed */
3444 struct job *prev_job; /* previous job */
3445};
3446
Denis Vlasenko68404f12008-03-17 09:00:54 +00003447static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003448static int forkshell(struct job *, union node *, int);
3449static int waitforjob(struct job *);
3450
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003451#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003452enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003453#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003454#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003455static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003456static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003457#endif
3458
3459/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003460 * Ignore a signal.
3461 */
3462static void
3463ignoresig(int signo)
3464{
3465 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3466 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3467 /* No, need to do it */
3468 signal(signo, SIG_IGN);
3469 }
3470 sigmode[signo - 1] = S_HARD_IGN;
3471}
3472
3473/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003474 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003475 */
3476static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003477signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003478{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003479 if (signo == SIGCHLD) {
3480 got_sigchld = 1;
3481 if (!trap[SIGCHLD])
3482 return;
3483 }
3484
Denis Vlasenko4b875702009-03-19 13:30:04 +00003485 gotsig[signo - 1] = 1;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003486 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003487
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003488 if (signo == SIGINT && !trap[SIGINT]) {
3489 if (!suppress_int) {
3490 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003491 raise_interrupt(); /* does not return */
3492 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003493 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003494 }
3495}
3496
3497/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003498 * Set the signal handler for the specified signal. The routine figures
3499 * out what it should be set to.
3500 */
3501static void
3502setsignal(int signo)
3503{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003504 char *t;
3505 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003506 struct sigaction act;
3507
3508 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003509 new_act = S_DFL;
3510 if (t != NULL) { /* trap for this sig is set */
3511 new_act = S_CATCH;
3512 if (t[0] == '\0') /* trap is "": ignore this sig */
3513 new_act = S_IGN;
3514 }
3515
3516 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003517 switch (signo) {
3518 case SIGINT:
3519 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003520 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003521 break;
3522 case SIGQUIT:
3523#if DEBUG
3524 if (debug)
3525 break;
3526#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003527 /* man bash:
3528 * "In all cases, bash ignores SIGQUIT. Non-builtin
3529 * commands run by bash have signal handlers
3530 * set to the values inherited by the shell
3531 * from its parent". */
3532 new_act = S_IGN;
3533 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003534 case SIGTERM:
3535 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003536 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003537 break;
3538#if JOBS
3539 case SIGTSTP:
3540 case SIGTTOU:
3541 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003542 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003543 break;
3544#endif
3545 }
3546 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003547//TODO: if !rootshell, we reset SIGQUIT to DFL,
3548//whereas we have to restore it to what shell got on entry
3549//from the parent. See comment above
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003550
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003551 if (signo == SIGCHLD)
3552 new_act = S_CATCH;
3553
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003554 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003555 cur_act = *t;
3556 if (cur_act == 0) {
3557 /* current setting is not yet known */
3558 if (sigaction(signo, NULL, &act)) {
3559 /* pretend it worked; maybe we should give a warning,
3560 * but other shells don't. We don't alter sigmode,
3561 * so we retry every time.
3562 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003563 return;
3564 }
3565 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003566 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003567 if (mflag
3568 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3569 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003570 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003571 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003572 }
3573 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003574 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003575 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003576
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003577 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003578 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003579 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003580 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003581 break;
3582 case S_IGN:
3583 act.sa_handler = SIG_IGN;
3584 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003585 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003586
3587 /* flags and mask matter only if !DFL and !IGN, but we do it
3588 * for all cases for more deterministic behavior:
3589 */
3590 act.sa_flags = 0;
3591 sigfillset(&act.sa_mask);
3592
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003593 sigaction_set(signo, &act);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003594
3595 *t = new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003596}
3597
3598/* mode flags for set_curjob */
3599#define CUR_DELETE 2
3600#define CUR_RUNNING 1
3601#define CUR_STOPPED 0
3602
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003603#if JOBS
3604/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003605static int initialpgrp; //references:2
3606static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003607#endif
3608/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003609static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003610/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003611static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003612/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003613static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003614/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003615static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003616
Denys Vlasenko098b7132017-01-11 19:59:03 +01003617#if 0
3618/* Bash has a feature: it restores termios after a successful wait for
3619 * a foreground job which had at least one stopped or sigkilled member.
3620 * The probable rationale is that SIGSTOP and SIGKILL can preclude task from
3621 * properly restoring tty state. Should we do this too?
3622 * A reproducer: ^Z an interactive python:
3623 *
3624 * # python
3625 * Python 2.7.12 (...)
3626 * >>> ^Z
3627 * { python leaves tty in -icanon -echo state. We do survive that... }
3628 * [1]+ Stopped python
3629 * { ...however, next program (python #2) does not survive it well: }
3630 * # python
3631 * Python 2.7.12 (...)
3632 * >>> Traceback (most recent call last):
3633 * { above, I typed "qwerty<CR>", but -echo state is still in effect }
3634 * File "<stdin>", line 1, in <module>
3635 * NameError: name 'qwerty' is not defined
3636 *
3637 * The implementation below is modeled on bash code and seems to work.
3638 * However, I'm not sure we should do this. For one: what if I'd fg
3639 * the stopped python instead? It'll be confused by "restored" tty state.
3640 */
3641static struct termios shell_tty_info;
3642static void
3643get_tty_state(void)
3644{
3645 if (rootshell && ttyfd >= 0)
3646 tcgetattr(ttyfd, &shell_tty_info);
3647}
3648static void
3649set_tty_state(void)
3650{
3651 /* if (rootshell) - caller ensures this */
3652 if (ttyfd >= 0)
3653 tcsetattr(ttyfd, TCSADRAIN, &shell_tty_info);
3654}
3655static int
3656job_signal_status(struct job *jp)
3657{
3658 int status;
3659 unsigned i;
3660 struct procstat *ps = jp->ps;
3661 for (i = 0; i < jp->nprocs; i++) {
3662 status = ps[i].ps_status;
3663 if (WIFSIGNALED(status) || WIFSTOPPED(status))
3664 return status;
3665 }
3666 return 0;
3667}
3668static void
3669restore_tty_if_stopped_or_signaled(struct job *jp)
3670{
3671//TODO: check what happens if we come from waitforjob() in expbackq()
3672 if (rootshell) {
3673 int s = job_signal_status(jp);
3674 if (s) /* WIFSIGNALED(s) || WIFSTOPPED(s) */
3675 set_tty_state();
3676 }
3677}
3678#else
3679# define get_tty_state() ((void)0)
3680# define restore_tty_if_stopped_or_signaled(jp) ((void)0)
3681#endif
3682
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003683static void
3684set_curjob(struct job *jp, unsigned mode)
3685{
3686 struct job *jp1;
3687 struct job **jpp, **curp;
3688
3689 /* first remove from list */
3690 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003691 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003692 jp1 = *jpp;
3693 if (jp1 == jp)
3694 break;
3695 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003696 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003697 *jpp = jp1->prev_job;
3698
3699 /* Then re-insert in correct position */
3700 jpp = curp;
3701 switch (mode) {
3702 default:
3703#if DEBUG
3704 abort();
3705#endif
3706 case CUR_DELETE:
3707 /* job being deleted */
3708 break;
3709 case CUR_RUNNING:
3710 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003711 * put after all stopped jobs.
3712 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003713 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003714 jp1 = *jpp;
3715#if JOBS
3716 if (!jp1 || jp1->state != JOBSTOPPED)
3717#endif
3718 break;
3719 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003720 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003721 /* FALLTHROUGH */
3722#if JOBS
3723 case CUR_STOPPED:
3724#endif
3725 /* newly stopped job - becomes curjob */
3726 jp->prev_job = *jpp;
3727 *jpp = jp;
3728 break;
3729 }
3730}
3731
3732#if JOBS || DEBUG
3733static int
3734jobno(const struct job *jp)
3735{
3736 return jp - jobtab + 1;
3737}
3738#endif
3739
3740/*
3741 * Convert a job name to a job structure.
3742 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003743#if !JOBS
3744#define getjob(name, getctl) getjob(name)
3745#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003746static struct job *
3747getjob(const char *name, int getctl)
3748{
3749 struct job *jp;
3750 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003751 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003752 unsigned num;
3753 int c;
3754 const char *p;
3755 char *(*match)(const char *, const char *);
3756
3757 jp = curjob;
3758 p = name;
3759 if (!p)
3760 goto currentjob;
3761
3762 if (*p != '%')
3763 goto err;
3764
3765 c = *++p;
3766 if (!c)
3767 goto currentjob;
3768
3769 if (!p[1]) {
3770 if (c == '+' || c == '%') {
3771 currentjob:
3772 err_msg = "No current job";
3773 goto check;
3774 }
3775 if (c == '-') {
3776 if (jp)
3777 jp = jp->prev_job;
3778 err_msg = "No previous job";
3779 check:
3780 if (!jp)
3781 goto err;
3782 goto gotit;
3783 }
3784 }
3785
3786 if (is_number(p)) {
3787 num = atoi(p);
Denys Vlasenko46a45ce2016-09-29 01:10:08 +02003788 if (num > 0 && num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003789 jp = jobtab + num - 1;
3790 if (jp->used)
3791 goto gotit;
3792 goto err;
3793 }
3794 }
3795
3796 match = prefix;
3797 if (*p == '?') {
3798 match = strstr;
3799 p++;
3800 }
3801
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003802 found = NULL;
3803 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003804 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003805 if (found)
3806 goto err;
3807 found = jp;
3808 err_msg = "%s: ambiguous";
3809 }
3810 jp = jp->prev_job;
3811 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003812 if (!found)
3813 goto err;
3814 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003815
3816 gotit:
3817#if JOBS
3818 err_msg = "job %s not created under job control";
3819 if (getctl && jp->jobctl == 0)
3820 goto err;
3821#endif
3822 return jp;
3823 err:
3824 ash_msg_and_raise_error(err_msg, name);
3825}
3826
3827/*
3828 * Mark a job structure as unused.
3829 */
3830static void
3831freejob(struct job *jp)
3832{
3833 struct procstat *ps;
3834 int i;
3835
3836 INT_OFF;
3837 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003838 if (ps->ps_cmd != nullstr)
3839 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003840 }
3841 if (jp->ps != &jp->ps0)
3842 free(jp->ps);
3843 jp->used = 0;
3844 set_curjob(jp, CUR_DELETE);
3845 INT_ON;
3846}
3847
3848#if JOBS
3849static void
3850xtcsetpgrp(int fd, pid_t pgrp)
3851{
3852 if (tcsetpgrp(fd, pgrp))
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003853 ash_msg_and_raise_error("can't set tty process group (%m)");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003854}
3855
3856/*
3857 * Turn job control on and off.
3858 *
3859 * Note: This code assumes that the third arg to ioctl is a character
3860 * pointer, which is true on Berkeley systems but not System V. Since
3861 * System V doesn't have job control yet, this isn't a problem now.
3862 *
3863 * Called with interrupts off.
3864 */
3865static void
3866setjobctl(int on)
3867{
3868 int fd;
3869 int pgrp;
3870
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003871 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003872 return;
3873 if (on) {
3874 int ofd;
3875 ofd = fd = open(_PATH_TTY, O_RDWR);
3876 if (fd < 0) {
3877 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3878 * That sometimes helps to acquire controlling tty.
3879 * Obviously, a workaround for bugs when someone
3880 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003881 fd = 2;
3882 while (!isatty(fd))
3883 if (--fd < 0)
3884 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003885 }
Denys Vlasenko64774602016-10-26 15:24:30 +02003886 /* fd is a tty at this point */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003887 fd = fcntl(fd, F_DUPFD, 10);
Denys Vlasenko10ad6222017-04-17 16:13:32 +02003888 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, don't */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003889 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003890 if (fd < 0)
Denys Vlasenko64774602016-10-26 15:24:30 +02003891 goto out; /* F_DUPFD failed */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003892 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003893 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003894 pgrp = tcgetpgrp(fd);
3895 if (pgrp < 0) {
3896 out:
3897 ash_msg("can't access tty; job control turned off");
3898 mflag = on = 0;
3899 goto close;
3900 }
3901 if (pgrp == getpgrp())
3902 break;
3903 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003904 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003905 initialpgrp = pgrp;
3906
3907 setsignal(SIGTSTP);
3908 setsignal(SIGTTOU);
3909 setsignal(SIGTTIN);
3910 pgrp = rootpid;
3911 setpgid(0, pgrp);
3912 xtcsetpgrp(fd, pgrp);
3913 } else {
3914 /* turning job control off */
3915 fd = ttyfd;
3916 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003917 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003918 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003919 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003920 setpgid(0, pgrp);
3921 setsignal(SIGTSTP);
3922 setsignal(SIGTTOU);
3923 setsignal(SIGTTIN);
3924 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003925 if (fd >= 0)
3926 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003927 fd = -1;
3928 }
3929 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003930 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003931}
3932
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003933static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003934killcmd(int argc, char **argv)
3935{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003936 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003937 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003938 do {
3939 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003940 /*
3941 * "kill %N" - job kill
3942 * Converting to pgrp / pid kill
3943 */
3944 struct job *jp;
3945 char *dst;
3946 int j, n;
3947
3948 jp = getjob(argv[i], 0);
3949 /*
3950 * In jobs started under job control, we signal
3951 * entire process group by kill -PGRP_ID.
3952 * This happens, f.e., in interactive shell.
3953 *
3954 * Otherwise, we signal each child via
3955 * kill PID1 PID2 PID3.
3956 * Testcases:
3957 * sh -c 'sleep 1|sleep 1 & kill %1'
3958 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3959 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3960 */
3961 n = jp->nprocs; /* can't be 0 (I hope) */
3962 if (jp->jobctl)
3963 n = 1;
3964 dst = alloca(n * sizeof(int)*4);
3965 argv[i] = dst;
3966 for (j = 0; j < n; j++) {
3967 struct procstat *ps = &jp->ps[j];
3968 /* Skip non-running and not-stopped members
3969 * (i.e. dead members) of the job
3970 */
3971 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3972 continue;
3973 /*
3974 * kill_main has matching code to expect
3975 * leading space. Needed to not confuse
3976 * negative pids with "kill -SIGNAL_NO" syntax
3977 */
3978 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3979 }
3980 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003981 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003982 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003983 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003984 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003985}
3986
3987static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01003988showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003989{
Denys Vlasenko285ad152009-12-04 23:02:27 +01003990 struct procstat *ps;
3991 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003992
Denys Vlasenko285ad152009-12-04 23:02:27 +01003993 psend = jp->ps + jp->nprocs;
3994 for (ps = jp->ps + 1; ps < psend; ps++)
3995 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003996 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003997 flush_stdout_stderr();
3998}
3999
4000
4001static int
4002restartjob(struct job *jp, int mode)
4003{
4004 struct procstat *ps;
4005 int i;
4006 int status;
4007 pid_t pgid;
4008
4009 INT_OFF;
4010 if (jp->state == JOBDONE)
4011 goto out;
4012 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004013 pgid = jp->ps[0].ps_pid;
Denys Vlasenko098b7132017-01-11 19:59:03 +01004014 if (mode == FORK_FG) {
4015 get_tty_state();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004016 xtcsetpgrp(ttyfd, pgid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01004017 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004018 killpg(pgid, SIGCONT);
4019 ps = jp->ps;
4020 i = jp->nprocs;
4021 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004022 if (WIFSTOPPED(ps->ps_status)) {
4023 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004024 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004025 ps++;
4026 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004027 out:
4028 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
4029 INT_ON;
4030 return status;
4031}
4032
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004033static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004034fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004035{
4036 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004037 int mode;
4038 int retval;
4039
4040 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
4041 nextopt(nullstr);
4042 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004043 do {
4044 jp = getjob(*argv, 1);
4045 if (mode == FORK_BG) {
4046 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004047 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004048 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004049 out1str(jp->ps[0].ps_cmd);
4050 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004051 retval = restartjob(jp, mode);
4052 } while (*argv && *++argv);
4053 return retval;
4054}
4055#endif
4056
4057static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02004058sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004059{
4060 int col;
4061 int st;
4062
4063 col = 0;
4064 if (!WIFEXITED(status)) {
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004065#if JOBS
4066 if (WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004067 st = WSTOPSIG(status);
4068 else
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004069#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004070 st = WTERMSIG(status);
4071 if (sigonly) {
4072 if (st == SIGINT || st == SIGPIPE)
4073 goto out;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004074#if JOBS
4075 if (WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004076 goto out;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004077#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004078 }
4079 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01004080//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004081 col = fmtstr(s, 32, strsignal(st));
4082 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004083 strcpy(s + col, " (core dumped)");
4084 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004085 }
4086 } else if (!sigonly) {
4087 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004088 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004089 }
4090 out:
4091 return col;
4092}
4093
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004094static int
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004095wait_block_or_sig(int *status)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004096{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004097 int pid;
4098
4099 do {
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004100 sigset_t mask;
4101
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004102 /* Poll all children for changes in their state */
4103 got_sigchld = 0;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004104 /* if job control is active, accept stopped processes too */
4105 pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004106 if (pid != 0)
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004107 break; /* Error (e.g. EINTR, ECHILD) or pid */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004108
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004109 /* Children exist, but none are ready. Sleep until interesting signal */
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004110#if 1
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004111 sigfillset(&mask);
4112 sigprocmask(SIG_SETMASK, &mask, &mask);
4113 while (!got_sigchld && !pending_sig)
4114 sigsuspend(&mask);
4115 sigprocmask(SIG_SETMASK, &mask, NULL);
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004116#else /* unsafe: a signal can set pending_sig after check, but before pause() */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004117 while (!got_sigchld && !pending_sig)
4118 pause();
4119#endif
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004120
4121 /* If it was SIGCHLD, poll children again */
4122 } while (got_sigchld);
4123
4124 return pid;
4125}
4126
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004127#define DOWAIT_NONBLOCK 0
4128#define DOWAIT_BLOCK 1
4129#define DOWAIT_BLOCK_OR_SIG 2
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004130
4131static int
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004132dowait(int block, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004133{
4134 int pid;
4135 int status;
4136 struct job *jp;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004137 struct job *thisjob = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004138
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004139 TRACE(("dowait(0x%x) called\n", block));
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00004140
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004141 /* It's wrong to call waitpid() outside of INT_OFF region:
4142 * signal can arrive just after syscall return and handler can
4143 * longjmp away, losing stop/exit notification processing.
4144 * Thus, for "jobs" builtin, and for waiting for a fg job,
4145 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4146 *
4147 * However, for "wait" builtin it is wrong to simply call waitpid()
4148 * in INT_OFF region: "wait" needs to wait for any running job
4149 * to change state, but should exit on any trap too.
4150 * In INT_OFF region, a signal just before syscall entry can set
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004151 * pending_sig variables, but we can't check them, and we would
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004152 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004153 *
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004154 * Because of this, we run inside INT_OFF, but use a special routine
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004155 * which combines waitpid() and sigsuspend().
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004156 * This is the reason why we need to have a handler for SIGCHLD:
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004157 * SIG_DFL handler does not wake sigsuspend().
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004158 */
4159 INT_OFF;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004160 if (block == DOWAIT_BLOCK_OR_SIG) {
4161 pid = wait_block_or_sig(&status);
4162 } else {
4163 int wait_flags = 0;
4164 if (block == DOWAIT_NONBLOCK)
4165 wait_flags = WNOHANG;
4166 /* if job control is active, accept stopped processes too */
4167 if (doing_jobctl)
4168 wait_flags |= WUNTRACED;
4169 /* NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004170 pid = waitpid(-1, &status, wait_flags);
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004171 }
Denis Vlasenkob21f3792009-03-19 23:09:58 +00004172 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4173 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004174 if (pid <= 0)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004175 goto out;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004176
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004177 thisjob = NULL;
4178 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004179 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004180 struct procstat *ps;
4181 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004182 if (jp->state == JOBDONE)
4183 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004184 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004185 ps = jp->ps;
4186 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004187 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004188 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004189 TRACE(("Job %d: changing status of proc %d "
4190 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01004191 jobno(jp), pid, ps->ps_status, status));
4192 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004193 thisjob = jp;
4194 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004195 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004196 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004197#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004198 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004199 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004200 if (WIFSTOPPED(ps->ps_status)) {
4201 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004202 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004203 }
4204#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004205 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004206 if (!thisjob)
4207 continue;
4208
4209 /* Found the job where one of its processes changed its state.
4210 * Is there at least one live and running process in this job? */
4211 if (jobstate != JOBRUNNING) {
4212 /* No. All live processes in the job are stopped
4213 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4214 */
4215 thisjob->changed = 1;
4216 if (thisjob->state != jobstate) {
4217 TRACE(("Job %d: changing state from %d to %d\n",
4218 jobno(thisjob), thisjob->state, jobstate));
4219 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004220#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004221 if (jobstate == JOBSTOPPED)
4222 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004223#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004224 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004225 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004226 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004227 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004228 /* The process wasn't found in job list */
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004229#if JOBS
4230 if (!WIFSTOPPED(status))
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004231 jobless--;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004232#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004233 out:
4234 INT_ON;
4235
4236 if (thisjob && thisjob == job) {
4237 char s[48 + 1];
4238 int len;
4239
Denys Vlasenko9c541002015-10-07 15:44:36 +02004240 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004241 if (len) {
4242 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004243 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004244 out2str(s);
4245 }
4246 }
4247 return pid;
4248}
4249
4250#if JOBS
4251static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004252showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004253{
4254 struct procstat *ps;
4255 struct procstat *psend;
4256 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004257 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004258 char s[16 + 16 + 48];
4259 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004260
4261 ps = jp->ps;
4262
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004263 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004264 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004265 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004266 return;
4267 }
4268
4269 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004270 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004271
4272 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004273 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004274 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004275 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004276
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004277 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004278 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004279
4280 psend = ps + jp->nprocs;
4281
4282 if (jp->state == JOBRUNNING) {
4283 strcpy(s + col, "Running");
4284 col += sizeof("Running") - 1;
4285 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004286 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004287 if (jp->state == JOBSTOPPED)
4288 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004289 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004290 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004291 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004292
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004293 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4294 * or prints several "PID | <cmdN>" lines,
4295 * depending on SHOW_PIDS bit.
4296 * We do not print status of individual processes
4297 * between PID and <cmdN>. bash does it, but not very well:
4298 * first line shows overall job status, not process status,
4299 * making it impossible to know 1st process status.
4300 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004301 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004302 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004303 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004304 s[0] = '\0';
4305 col = 33;
4306 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004307 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004308 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004309 fprintf(out, "%s%*c%s%s",
4310 s,
4311 33 - col >= 0 ? 33 - col : 0, ' ',
4312 ps == jp->ps ? "" : "| ",
4313 ps->ps_cmd
4314 );
4315 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004316 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004317
4318 jp->changed = 0;
4319
4320 if (jp->state == JOBDONE) {
4321 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4322 freejob(jp);
4323 }
4324}
4325
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004326/*
4327 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4328 * statuses have changed since the last call to showjobs.
4329 */
4330static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004331showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004332{
4333 struct job *jp;
4334
Denys Vlasenko883cea42009-07-11 15:31:59 +02004335 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004336
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004337 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004338 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004339 continue;
4340
4341 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004342 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004343 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004344 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004345 }
4346}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004347
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004348static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004349jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004350{
4351 int mode, m;
4352
4353 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004354 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004355 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004356 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004357 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004358 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004359 }
4360
4361 argv = argptr;
4362 if (*argv) {
4363 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004364 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004365 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004366 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004367 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004368 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004369
4370 return 0;
4371}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004372#endif /* JOBS */
4373
Michael Abbott359da5e2009-12-04 23:03:29 +01004374/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004375static int
4376getstatus(struct job *job)
4377{
4378 int status;
4379 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004380 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004381
Michael Abbott359da5e2009-12-04 23:03:29 +01004382 /* Fetch last member's status */
4383 ps = job->ps + job->nprocs - 1;
4384 status = ps->ps_status;
4385 if (pipefail) {
4386 /* "set -o pipefail" mode: use last _nonzero_ status */
4387 while (status == 0 && --ps >= job->ps)
4388 status = ps->ps_status;
4389 }
4390
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004391 retval = WEXITSTATUS(status);
4392 if (!WIFEXITED(status)) {
4393#if JOBS
4394 retval = WSTOPSIG(status);
4395 if (!WIFSTOPPED(status))
4396#endif
4397 {
4398 /* XXX: limits number of signals */
4399 retval = WTERMSIG(status);
4400#if JOBS
4401 if (retval == SIGINT)
4402 job->sigint = 1;
4403#endif
4404 }
4405 retval += 128;
4406 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004407 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004408 jobno(job), job->nprocs, status, retval));
4409 return retval;
4410}
4411
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004412static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004413waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004414{
4415 struct job *job;
4416 int retval;
4417 struct job *jp;
4418
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004419 nextopt(nullstr);
4420 retval = 0;
4421
4422 argv = argptr;
4423 if (!*argv) {
4424 /* wait for all jobs */
4425 for (;;) {
4426 jp = curjob;
4427 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004428 if (!jp) /* no running procs */
4429 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004430 if (jp->state == JOBRUNNING)
4431 break;
4432 jp->waited = 1;
4433 jp = jp->prev_job;
4434 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004435 /* man bash:
4436 * "When bash is waiting for an asynchronous command via
4437 * the wait builtin, the reception of a signal for which a trap
4438 * has been set will cause the wait builtin to return immediately
4439 * with an exit status greater than 128, immediately after which
4440 * the trap is executed."
Denys Vlasenko69188112016-10-27 20:18:18 +02004441 */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004442 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004443 /* if child sends us a signal *and immediately exits*,
4444 * dowait() returns pid > 0. Check this case,
4445 * not "if (dowait() < 0)"!
4446 */
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004447 if (pending_sig)
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004448 goto sigout;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004449 }
4450 }
4451
4452 retval = 127;
4453 do {
4454 if (**argv != '%') {
4455 pid_t pid = number(*argv);
4456 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004457 while (1) {
4458 if (!job)
4459 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004460 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004461 break;
4462 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004463 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004464 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004465 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004466 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004467 /* loop until process terminated or stopped */
Denys Vlasenko69188112016-10-27 20:18:18 +02004468 while (job->state == JOBRUNNING) {
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004469 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004470 if (pending_sig)
4471 goto sigout;
Denys Vlasenko69188112016-10-27 20:18:18 +02004472 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004473 job->waited = 1;
4474 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004475 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004476 } while (*++argv);
4477
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004478 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004479 return retval;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004480 sigout:
4481 retval = 128 + pending_sig;
4482 return retval;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004483}
4484
4485static struct job *
4486growjobtab(void)
4487{
4488 size_t len;
4489 ptrdiff_t offset;
4490 struct job *jp, *jq;
4491
4492 len = njobs * sizeof(*jp);
4493 jq = jobtab;
4494 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4495
4496 offset = (char *)jp - (char *)jq;
4497 if (offset) {
4498 /* Relocate pointers */
4499 size_t l = len;
4500
4501 jq = (struct job *)((char *)jq + l);
4502 while (l) {
4503 l -= sizeof(*jp);
4504 jq--;
4505#define joff(p) ((struct job *)((char *)(p) + l))
4506#define jmove(p) (p) = (void *)((char *)(p) + offset)
4507 if (joff(jp)->ps == &jq->ps0)
4508 jmove(joff(jp)->ps);
4509 if (joff(jp)->prev_job)
4510 jmove(joff(jp)->prev_job);
4511 }
4512 if (curjob)
4513 jmove(curjob);
4514#undef joff
4515#undef jmove
4516 }
4517
4518 njobs += 4;
4519 jobtab = jp;
4520 jp = (struct job *)((char *)jp + len);
4521 jq = jp + 3;
4522 do {
4523 jq->used = 0;
4524 } while (--jq >= jp);
4525 return jp;
4526}
4527
4528/*
4529 * Return a new job structure.
4530 * Called with interrupts off.
4531 */
4532static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004533makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004534{
4535 int i;
4536 struct job *jp;
4537
4538 for (i = njobs, jp = jobtab; ; jp++) {
4539 if (--i < 0) {
4540 jp = growjobtab();
4541 break;
4542 }
4543 if (jp->used == 0)
4544 break;
4545 if (jp->state != JOBDONE || !jp->waited)
4546 continue;
4547#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004548 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004549 continue;
4550#endif
4551 freejob(jp);
4552 break;
4553 }
4554 memset(jp, 0, sizeof(*jp));
4555#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004556 /* jp->jobctl is a bitfield.
Denys Vlasenko098b7132017-01-11 19:59:03 +01004557 * "jp->jobctl |= doing_jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004558 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004559 jp->jobctl = 1;
4560#endif
4561 jp->prev_job = curjob;
4562 curjob = jp;
4563 jp->used = 1;
4564 jp->ps = &jp->ps0;
4565 if (nprocs > 1) {
4566 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4567 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004568 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004569 jobno(jp)));
4570 return jp;
4571}
4572
4573#if JOBS
4574/*
4575 * Return a string identifying a command (to be printed by the
4576 * jobs command).
4577 */
4578static char *cmdnextc;
4579
4580static void
4581cmdputs(const char *s)
4582{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004583 static const char vstype[VSTYPE + 1][3] = {
4584 "", "}", "-", "+", "?", "=",
4585 "%", "%%", "#", "##"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004586 IF_BASH_SUBSTR(, ":")
4587 IF_BASH_PATTERN_SUBST(, "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004588 };
4589
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004590 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004591 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004592 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004593 unsigned char c;
4594 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004595 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004596
Denys Vlasenko46a14772009-12-10 21:27:13 +01004597 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004598 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4599 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004600 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004601 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004602 switch (c) {
4603 case CTLESC:
4604 c = *p++;
4605 break;
4606 case CTLVAR:
4607 subtype = *p++;
4608 if ((subtype & VSTYPE) == VSLENGTH)
4609 str = "${#";
4610 else
4611 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004612 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004613 case CTLENDVAR:
4614 str = "\"}" + !(quoted & 1);
4615 quoted >>= 1;
4616 subtype = 0;
4617 goto dostr;
4618 case CTLBACKQ:
4619 str = "$(...)";
4620 goto dostr;
Denys Vlasenko0b883582016-12-23 16:49:07 +01004621#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004622 case CTLARI:
4623 str = "$((";
4624 goto dostr;
4625 case CTLENDARI:
4626 str = "))";
4627 goto dostr;
4628#endif
4629 case CTLQUOTEMARK:
4630 quoted ^= 1;
4631 c = '"';
4632 break;
4633 case '=':
4634 if (subtype == 0)
4635 break;
4636 if ((subtype & VSTYPE) != VSNORMAL)
4637 quoted <<= 1;
4638 str = vstype[subtype & VSTYPE];
4639 if (subtype & VSNUL)
4640 c = ':';
4641 else
4642 goto checkstr;
4643 break;
4644 case '\'':
4645 case '\\':
4646 case '"':
4647 case '$':
4648 /* These can only happen inside quotes */
4649 cc[0] = c;
4650 str = cc;
4651 c = '\\';
4652 break;
4653 default:
4654 break;
4655 }
4656 USTPUTC(c, nextc);
4657 checkstr:
4658 if (!str)
4659 continue;
4660 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004661 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004662 USTPUTC(c, nextc);
4663 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004664 } /* while *p++ not NUL */
4665
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004666 if (quoted & 1) {
4667 USTPUTC('"', nextc);
4668 }
4669 *nextc = 0;
4670 cmdnextc = nextc;
4671}
4672
4673/* cmdtxt() and cmdlist() call each other */
4674static void cmdtxt(union node *n);
4675
4676static void
4677cmdlist(union node *np, int sep)
4678{
4679 for (; np; np = np->narg.next) {
4680 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004681 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004682 cmdtxt(np);
4683 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004684 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004685 }
4686}
4687
4688static void
4689cmdtxt(union node *n)
4690{
4691 union node *np;
4692 struct nodelist *lp;
4693 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004694
4695 if (!n)
4696 return;
4697 switch (n->type) {
4698 default:
4699#if DEBUG
4700 abort();
4701#endif
4702 case NPIPE:
4703 lp = n->npipe.cmdlist;
4704 for (;;) {
4705 cmdtxt(lp->n);
4706 lp = lp->next;
4707 if (!lp)
4708 break;
4709 cmdputs(" | ");
4710 }
4711 break;
4712 case NSEMI:
4713 p = "; ";
4714 goto binop;
4715 case NAND:
4716 p = " && ";
4717 goto binop;
4718 case NOR:
4719 p = " || ";
4720 binop:
4721 cmdtxt(n->nbinary.ch1);
4722 cmdputs(p);
4723 n = n->nbinary.ch2;
4724 goto donode;
4725 case NREDIR:
4726 case NBACKGND:
4727 n = n->nredir.n;
4728 goto donode;
4729 case NNOT:
4730 cmdputs("!");
4731 n = n->nnot.com;
4732 donode:
4733 cmdtxt(n);
4734 break;
4735 case NIF:
4736 cmdputs("if ");
4737 cmdtxt(n->nif.test);
4738 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004739 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004740 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004741 cmdputs("; else ");
4742 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004743 } else {
4744 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004745 }
4746 p = "; fi";
4747 goto dotail;
4748 case NSUBSHELL:
4749 cmdputs("(");
4750 n = n->nredir.n;
4751 p = ")";
4752 goto dotail;
4753 case NWHILE:
4754 p = "while ";
4755 goto until;
4756 case NUNTIL:
4757 p = "until ";
4758 until:
4759 cmdputs(p);
4760 cmdtxt(n->nbinary.ch1);
4761 n = n->nbinary.ch2;
4762 p = "; done";
4763 dodo:
4764 cmdputs("; do ");
4765 dotail:
4766 cmdtxt(n);
4767 goto dotail2;
4768 case NFOR:
4769 cmdputs("for ");
4770 cmdputs(n->nfor.var);
4771 cmdputs(" in ");
4772 cmdlist(n->nfor.args, 1);
4773 n = n->nfor.body;
4774 p = "; done";
4775 goto dodo;
4776 case NDEFUN:
4777 cmdputs(n->narg.text);
4778 p = "() { ... }";
4779 goto dotail2;
4780 case NCMD:
4781 cmdlist(n->ncmd.args, 1);
4782 cmdlist(n->ncmd.redirect, 0);
4783 break;
4784 case NARG:
4785 p = n->narg.text;
4786 dotail2:
4787 cmdputs(p);
4788 break;
4789 case NHERE:
4790 case NXHERE:
4791 p = "<<...";
4792 goto dotail2;
4793 case NCASE:
4794 cmdputs("case ");
4795 cmdputs(n->ncase.expr->narg.text);
4796 cmdputs(" in ");
4797 for (np = n->ncase.cases; np; np = np->nclist.next) {
4798 cmdtxt(np->nclist.pattern);
4799 cmdputs(") ");
4800 cmdtxt(np->nclist.body);
4801 cmdputs(";; ");
4802 }
4803 p = "esac";
4804 goto dotail2;
4805 case NTO:
4806 p = ">";
4807 goto redir;
4808 case NCLOBBER:
4809 p = ">|";
4810 goto redir;
4811 case NAPPEND:
4812 p = ">>";
4813 goto redir;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004814#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00004815 case NTO2:
4816#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004817 case NTOFD:
4818 p = ">&";
4819 goto redir;
4820 case NFROM:
4821 p = "<";
4822 goto redir;
4823 case NFROMFD:
4824 p = "<&";
4825 goto redir;
4826 case NFROMTO:
4827 p = "<>";
4828 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004829 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004830 cmdputs(p);
4831 if (n->type == NTOFD || n->type == NFROMFD) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004832 cmdputs(utoa(n->ndup.dupfd));
4833 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004834 }
4835 n = n->nfile.fname;
4836 goto donode;
4837 }
4838}
4839
4840static char *
4841commandtext(union node *n)
4842{
4843 char *name;
4844
4845 STARTSTACKSTR(cmdnextc);
4846 cmdtxt(n);
4847 name = stackblock();
Denys Vlasenko6a94cee2016-10-25 17:40:25 +02004848 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004849 return ckstrdup(name);
4850}
4851#endif /* JOBS */
4852
4853/*
4854 * Fork off a subshell. If we are doing job control, give the subshell its
4855 * own process group. Jp is a job structure that the job is to be added to.
4856 * N is the command that will be evaluated by the child. Both jp and n may
4857 * be NULL. The mode parameter can be one of the following:
4858 * FORK_FG - Fork off a foreground process.
4859 * FORK_BG - Fork off a background process.
4860 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4861 * process group even if job control is on.
4862 *
4863 * When job control is turned off, background processes have their standard
4864 * input redirected to /dev/null (except for the second and later processes
4865 * in a pipeline).
4866 *
4867 * Called with interrupts off.
4868 */
4869/*
4870 * Clear traps on a fork.
4871 */
4872static void
4873clear_traps(void)
4874{
4875 char **tp;
4876
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004877 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004878 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004879 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004880 if (trap_ptr == trap)
4881 free(*tp);
4882 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004883 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004884 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004885 setsignal(tp - trap);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004886 }
4887 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004888 may_have_traps = 0;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004889 INT_ON;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004890}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004891
4892/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004893static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004894
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004895/* Called after fork(), in child */
Denys Vlasenko70392332016-10-27 02:31:55 +02004896/* jp and n are NULL when called by openhere() for heredoc support */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004897static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004898forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004899{
4900 int oldlvl;
4901
4902 TRACE(("Child shell %d\n", getpid()));
4903 oldlvl = shlvl;
4904 shlvl++;
4905
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004906 /* man bash: "Non-builtin commands run by bash have signal handlers
4907 * set to the values inherited by the shell from its parent".
4908 * Do we do it correctly? */
4909
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004910 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004911
4912 if (mode == FORK_NOJOB /* is it `xxx` ? */
4913 && n && n->type == NCMD /* is it single cmd? */
4914 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004915 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004916 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4917 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4918 ) {
4919 TRACE(("Trap hack\n"));
4920 /* Awful hack for `trap` or $(trap).
4921 *
4922 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4923 * contains an example where "trap" is executed in a subshell:
4924 *
4925 * save_traps=$(trap)
4926 * ...
4927 * eval "$save_traps"
4928 *
4929 * Standard does not say that "trap" in subshell shall print
4930 * parent shell's traps. It only says that its output
4931 * must have suitable form, but then, in the above example
4932 * (which is not supposed to be normative), it implies that.
4933 *
4934 * bash (and probably other shell) does implement it
4935 * (traps are reset to defaults, but "trap" still shows them),
4936 * but as a result, "trap" logic is hopelessly messed up:
4937 *
4938 * # trap
4939 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4940 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4941 * # true | trap <--- trap is in subshell - no output (ditto)
4942 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4943 * trap -- 'echo Ho' SIGWINCH
4944 * # echo `(trap)` <--- in subshell in subshell - output
4945 * trap -- 'echo Ho' SIGWINCH
4946 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4947 * trap -- 'echo Ho' SIGWINCH
4948 *
4949 * The rules when to forget and when to not forget traps
4950 * get really complex and nonsensical.
4951 *
4952 * Our solution: ONLY bare $(trap) or `trap` is special.
4953 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004954 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02004955 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004956 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004957 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004958 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004959#if JOBS
4960 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004961 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004962 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004963 pid_t pgrp;
4964
4965 if (jp->nprocs == 0)
4966 pgrp = getpid();
4967 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004968 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004969 /* this can fail because we are doing it in the parent also */
4970 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004971 if (mode == FORK_FG)
4972 xtcsetpgrp(ttyfd, pgrp);
4973 setsignal(SIGTSTP);
4974 setsignal(SIGTTOU);
4975 } else
4976#endif
4977 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004978 /* man bash: "When job control is not in effect,
4979 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004980 ignoresig(SIGINT);
4981 ignoresig(SIGQUIT);
4982 if (jp->nprocs == 0) {
4983 close(0);
4984 if (open(bb_dev_null, O_RDONLY) != 0)
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00004985 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004986 }
4987 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004988 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004989 if (iflag) { /* why if iflag only? */
4990 setsignal(SIGINT);
4991 setsignal(SIGTERM);
4992 }
4993 /* man bash:
4994 * "In all cases, bash ignores SIGQUIT. Non-builtin
4995 * commands run by bash have signal handlers
4996 * set to the values inherited by the shell
4997 * from its parent".
4998 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004999 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005000 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005001#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02005002 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01005003 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02005004 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005005 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02005006 /* "jobs": we do not want to clear job list for it,
5007 * instead we remove only _its_ own_ job from job list.
5008 * This makes "jobs .... | cat" more useful.
5009 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005010 freejob(curjob);
5011 return;
5012 }
5013#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005014 for (jp = curjob; jp; jp = jp->prev_job)
5015 freejob(jp);
5016 jobless = 0;
5017}
5018
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00005019/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00005020#if !JOBS
5021#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
5022#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005023static void
5024forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5025{
5026 TRACE(("In parent shell: child = %d\n", pid));
5027 if (!jp) {
Denys Vlasenko70392332016-10-27 02:31:55 +02005028 /* jp is NULL when called by openhere() for heredoc support */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00005029 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
5030 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005031 jobless++;
5032 return;
5033 }
5034#if JOBS
5035 if (mode != FORK_NOJOB && jp->jobctl) {
5036 int pgrp;
5037
5038 if (jp->nprocs == 0)
5039 pgrp = pid;
5040 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01005041 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005042 /* This can fail because we are doing it in the child also */
5043 setpgid(pid, pgrp);
5044 }
5045#endif
5046 if (mode == FORK_BG) {
5047 backgndpid = pid; /* set $! */
5048 set_curjob(jp, CUR_RUNNING);
5049 }
5050 if (jp) {
5051 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01005052 ps->ps_pid = pid;
5053 ps->ps_status = -1;
5054 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005055#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005056 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01005057 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005058#endif
5059 }
5060}
5061
Denys Vlasenko70392332016-10-27 02:31:55 +02005062/* jp and n are NULL when called by openhere() for heredoc support */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005063static int
5064forkshell(struct job *jp, union node *n, int mode)
5065{
5066 int pid;
5067
5068 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5069 pid = fork();
5070 if (pid < 0) {
5071 TRACE(("Fork failed, errno=%d", errno));
5072 if (jp)
5073 freejob(jp);
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +00005074 ash_msg_and_raise_error("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005075 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02005076 if (pid == 0) {
5077 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005078 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005079 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005080 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005081 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005082 return pid;
5083}
5084
5085/*
5086 * Wait for job to finish.
5087 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005088 * Under job control we have the problem that while a child process
5089 * is running interrupts generated by the user are sent to the child
5090 * but not to the shell. This means that an infinite loop started by
5091 * an interactive user may be hard to kill. With job control turned off,
5092 * an interactive user may place an interactive program inside a loop.
5093 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005094 * these interrupts to also abort the loop. The approach we take here
5095 * is to have the shell ignore interrupt signals while waiting for a
5096 * foreground process to terminate, and then send itself an interrupt
5097 * signal if the child process was terminated by an interrupt signal.
5098 * Unfortunately, some programs want to do a bit of cleanup and then
5099 * exit on interrupt; unless these processes terminate themselves by
5100 * sending a signal to themselves (instead of calling exit) they will
5101 * confuse this approach.
5102 *
5103 * Called with interrupts off.
5104 */
5105static int
5106waitforjob(struct job *jp)
5107{
5108 int st;
5109
5110 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005111
5112 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005113 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005114 /* In non-interactive shells, we _can_ get
5115 * a keyboard signal here and be EINTRed,
5116 * but we just loop back, waiting for command to complete.
5117 *
5118 * man bash:
5119 * "If bash is waiting for a command to complete and receives
5120 * a signal for which a trap has been set, the trap
5121 * will not be executed until the command completes."
5122 *
5123 * Reality is that even if trap is not set, bash
5124 * will not act on the signal until command completes.
5125 * Try this. sleep5intoff.c:
5126 * #include <signal.h>
5127 * #include <unistd.h>
5128 * int main() {
5129 * sigset_t set;
5130 * sigemptyset(&set);
5131 * sigaddset(&set, SIGINT);
5132 * sigaddset(&set, SIGQUIT);
5133 * sigprocmask(SIG_BLOCK, &set, NULL);
5134 * sleep(5);
5135 * return 0;
5136 * }
5137 * $ bash -c './sleep5intoff; echo hi'
5138 * ^C^C^C^C <--- pressing ^C once a second
5139 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005140 * $ bash -c './sleep5intoff; echo hi'
5141 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5142 * $ _
5143 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005144 dowait(DOWAIT_BLOCK, jp);
5145 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005146 INT_ON;
5147
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005148 st = getstatus(jp);
5149#if JOBS
5150 if (jp->jobctl) {
5151 xtcsetpgrp(ttyfd, rootpid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01005152 restore_tty_if_stopped_or_signaled(jp);
5153
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005154 /*
5155 * This is truly gross.
5156 * If we're doing job control, then we did a TIOCSPGRP which
5157 * caused us (the shell) to no longer be in the controlling
5158 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
5159 * intuit from the subprocess exit status whether a SIGINT
5160 * occurred, and if so interrupt ourselves. Yuck. - mycroft
5161 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00005162 if (jp->sigint) /* TODO: do the same with all signals */
5163 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005164 }
5165 if (jp->state == JOBDONE)
5166#endif
5167 freejob(jp);
5168 return st;
5169}
5170
5171/*
5172 * return 1 if there are stopped jobs, otherwise 0
5173 */
5174static int
5175stoppedjobs(void)
5176{
5177 struct job *jp;
5178 int retval;
5179
5180 retval = 0;
5181 if (job_warning)
5182 goto out;
5183 jp = curjob;
5184 if (jp && jp->state == JOBSTOPPED) {
5185 out2str("You have stopped jobs.\n");
5186 job_warning = 2;
5187 retval++;
5188 }
5189 out:
5190 return retval;
5191}
5192
5193
Denys Vlasenko70392332016-10-27 02:31:55 +02005194/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005195 * Code for dealing with input/output redirection.
5196 */
5197
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005198#undef EMPTY
5199#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005200#define EMPTY -2 /* marks an unused slot in redirtab */
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005201#define CLOSED -3 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005202
5203/*
5204 * Open a file in noclobber mode.
5205 * The code was copied from bash.
5206 */
5207static int
5208noclobberopen(const char *fname)
5209{
5210 int r, fd;
5211 struct stat finfo, finfo2;
5212
5213 /*
5214 * If the file exists and is a regular file, return an error
5215 * immediately.
5216 */
5217 r = stat(fname, &finfo);
5218 if (r == 0 && S_ISREG(finfo.st_mode)) {
5219 errno = EEXIST;
5220 return -1;
5221 }
5222
5223 /*
5224 * If the file was not present (r != 0), make sure we open it
5225 * exclusively so that if it is created before we open it, our open
5226 * will fail. Make sure that we do not truncate an existing file.
5227 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5228 * file was not a regular file, we leave O_EXCL off.
5229 */
5230 if (r != 0)
5231 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5232 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5233
5234 /* If the open failed, return the file descriptor right away. */
5235 if (fd < 0)
5236 return fd;
5237
5238 /*
5239 * OK, the open succeeded, but the file may have been changed from a
5240 * non-regular file to a regular file between the stat and the open.
5241 * We are assuming that the O_EXCL open handles the case where FILENAME
5242 * did not exist and is symlinked to an existing file between the stat
5243 * and open.
5244 */
5245
5246 /*
5247 * If we can open it and fstat the file descriptor, and neither check
5248 * revealed that it was a regular file, and the file has not been
5249 * replaced, return the file descriptor.
5250 */
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005251 if (fstat(fd, &finfo2) == 0
5252 && !S_ISREG(finfo2.st_mode)
5253 && finfo.st_dev == finfo2.st_dev
5254 && finfo.st_ino == finfo2.st_ino
5255 ) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005256 return fd;
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005257 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005258
5259 /* The file has been replaced. badness. */
5260 close(fd);
5261 errno = EEXIST;
5262 return -1;
5263}
5264
5265/*
5266 * Handle here documents. Normally we fork off a process to write the
5267 * data to a pipe. If the document is short, we can stuff the data in
5268 * the pipe without forking.
5269 */
5270/* openhere needs this forward reference */
5271static void expandhere(union node *arg, int fd);
5272static int
5273openhere(union node *redir)
5274{
5275 int pip[2];
5276 size_t len = 0;
5277
5278 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005279 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005280 if (redir->type == NHERE) {
5281 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005282 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005283 full_write(pip[1], redir->nhere.doc->narg.text, len);
5284 goto out;
5285 }
5286 }
5287 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005288 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005289 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005290 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5291 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5292 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5293 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005294 signal(SIGPIPE, SIG_DFL);
5295 if (redir->type == NHERE)
5296 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005297 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005298 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005299 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005300 }
5301 out:
5302 close(pip[1]);
5303 return pip[0];
5304}
5305
5306static int
5307openredirect(union node *redir)
5308{
5309 char *fname;
5310 int f;
5311
5312 switch (redir->nfile.type) {
Denys Vlasenko557482c2016-09-25 21:24:04 +02005313/* Can't happen, our single caller does this itself */
5314// case NTOFD:
5315// case NFROMFD:
5316// return -1;
5317 case NHERE:
5318 case NXHERE:
5319 return openhere(redir);
5320 }
5321
5322 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5323 * allocated space. Do it only when we know it is safe.
5324 */
5325 fname = redir->nfile.expfname;
5326
5327 switch (redir->nfile.type) {
5328 default:
5329#if DEBUG
5330 abort();
5331#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005332 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005333 f = open(fname, O_RDONLY);
5334 if (f < 0)
5335 goto eopen;
5336 break;
5337 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005338 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005339 if (f < 0)
5340 goto ecreate;
5341 break;
5342 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005343#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005344 case NTO2:
5345#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005346 /* Take care of noclobber mode. */
5347 if (Cflag) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005348 f = noclobberopen(fname);
5349 if (f < 0)
5350 goto ecreate;
5351 break;
5352 }
5353 /* FALLTHROUGH */
5354 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005355 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5356 if (f < 0)
5357 goto ecreate;
5358 break;
5359 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005360 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5361 if (f < 0)
5362 goto ecreate;
5363 break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005364 }
5365
5366 return f;
5367 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005368 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005369 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005370 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005371}
5372
5373/*
Denys Vlasenko64774602016-10-26 15:24:30 +02005374 * Copy a file descriptor to be >= 10. Throws exception on error.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005375 */
5376static int
Denys Vlasenko64774602016-10-26 15:24:30 +02005377savefd(int from)
5378{
5379 int newfd;
5380 int err;
5381
5382 newfd = fcntl(from, F_DUPFD, 10);
5383 err = newfd < 0 ? errno : 0;
5384 if (err != EBADF) {
5385 if (err)
5386 ash_msg_and_raise_error("%d: %m", from);
5387 close(from);
5388 fcntl(newfd, F_SETFD, FD_CLOEXEC);
5389 }
5390
5391 return newfd;
5392}
5393static int
5394dup2_or_raise(int from, int to)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005395{
5396 int newfd;
5397
Denys Vlasenko64774602016-10-26 15:24:30 +02005398 newfd = (from != to) ? dup2(from, to) : to;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005399 if (newfd < 0) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005400 /* Happens when source fd is not open: try "echo >&99" */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005401 ash_msg_and_raise_error("%d: %m", from);
5402 }
5403 return newfd;
5404}
5405
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005406/* Struct def and variable are moved down to the first usage site */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005407struct two_fd_t {
5408 int orig, copy;
5409};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005410struct redirtab {
5411 struct redirtab *next;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005412 int pair_count;
Denys Vlasenko606291b2009-09-23 23:15:43 +02005413 struct two_fd_t two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005414};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005415#define redirlist (G_var.redirlist)
Denys Vlasenko64774602016-10-26 15:24:30 +02005416enum {
5417 COPYFD_RESTORE = (int)~(INT_MAX),
5418};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005419
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005420static int
5421need_to_remember(struct redirtab *rp, int fd)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005422{
5423 int i;
5424
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005425 if (!rp) /* remembering was not requested */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005426 return 0;
5427
5428 for (i = 0; i < rp->pair_count; i++) {
5429 if (rp->two_fd[i].orig == fd) {
5430 /* already remembered */
5431 return 0;
5432 }
5433 }
5434 return 1;
5435}
5436
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005437/* "hidden" fd is a fd used to read scripts, or a copy of such */
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005438static int
5439is_hidden_fd(struct redirtab *rp, int fd)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005440{
5441 int i;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005442 struct parsefile *pf;
5443
5444 if (fd == -1)
5445 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005446 /* Check open scripts' fds */
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005447 pf = g_parsefile;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005448 while (pf) {
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005449 /* We skip pf_fd == 0 case because of the following case:
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005450 * $ ash # running ash interactively
5451 * $ . ./script.sh
5452 * and in script.sh: "exec 9>&0".
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005453 * Even though top-level pf_fd _is_ 0,
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005454 * it's still ok to use it: "read" builtin uses it,
5455 * why should we cripple "exec" builtin?
5456 */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005457 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005458 return 1;
5459 }
5460 pf = pf->prev;
5461 }
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005462
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005463 if (!rp)
5464 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005465 /* Check saved fds of redirects */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005466 fd |= COPYFD_RESTORE;
5467 for (i = 0; i < rp->pair_count; i++) {
5468 if (rp->two_fd[i].copy == fd) {
5469 return 1;
5470 }
5471 }
5472 return 0;
5473}
5474
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005475/*
5476 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5477 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005478 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005479 */
5480/* flags passed to redirect */
5481#define REDIR_PUSH 01 /* save previous values of file descriptors */
5482#define REDIR_SAVEFD2 03 /* set preverrout */
5483static void
5484redirect(union node *redir, int flags)
5485{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005486 struct redirtab *sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005487 int sv_pos;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005488 int i;
5489 int fd;
5490 int newfd;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005491 int copied_fd2 = -1;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005492
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005493 if (!redir) {
5494 return;
5495 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005496
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005497 sv = NULL;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005498 sv_pos = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005499 INT_OFF;
5500 if (flags & REDIR_PUSH) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005501 union node *tmp = redir;
5502 do {
5503 sv_pos++;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005504#if BASH_REDIR_OUTPUT
Chris Metcalfc3c1fb62010-01-08 13:18:06 +01005505 if (tmp->nfile.type == NTO2)
Denis Vlasenko559691a2008-10-05 18:39:31 +00005506 sv_pos++;
5507#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005508 tmp = tmp->nfile.next;
5509 } while (tmp);
5510 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005511 sv->next = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005512 sv->pair_count = sv_pos;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005513 redirlist = sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005514 while (sv_pos > 0) {
5515 sv_pos--;
5516 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5517 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005518 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005519
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005520 do {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005521 int right_fd = -1;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005522 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005523 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005524 right_fd = redir->ndup.dupfd;
5525 //bb_error_msg("doing %d > %d", fd, right_fd);
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005526 /* redirect from/to same file descriptor? */
5527 if (right_fd == fd)
5528 continue;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005529 /* "echo >&10" and 10 is a fd opened to a sh script? */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005530 if (is_hidden_fd(sv, right_fd)) {
5531 errno = EBADF; /* as if it is closed */
5532 ash_msg_and_raise_error("%d: %m", right_fd);
5533 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005534 newfd = -1;
5535 } else {
5536 newfd = openredirect(redir); /* always >= 0 */
5537 if (fd == newfd) {
5538 /* Descriptor wasn't open before redirect.
5539 * Mark it for close in the future */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005540 if (need_to_remember(sv, fd)) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005541 goto remember_to_close;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005542 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005543 continue;
5544 }
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005545 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005546#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005547 redirect_more:
5548#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005549 if (need_to_remember(sv, fd)) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005550 /* Copy old descriptor */
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005551 /* Careful to not accidentally "save"
5552 * to the same fd as right side fd in N>&M */
5553 int minfd = right_fd < 10 ? 10 : right_fd + 1;
Denys Vlasenko86584e12017-01-07 10:15:01 +01005554#if defined(F_DUPFD_CLOEXEC)
5555 i = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
5556#else
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005557 i = fcntl(fd, F_DUPFD, minfd);
Denys Vlasenko86584e12017-01-07 10:15:01 +01005558#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005559 if (i == -1) {
5560 i = errno;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005561 if (i != EBADF) {
5562 /* Strange error (e.g. "too many files" EMFILE?) */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005563 if (newfd >= 0)
5564 close(newfd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005565 errno = i;
5566 ash_msg_and_raise_error("%d: %m", fd);
5567 /* NOTREACHED */
5568 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005569 /* EBADF: it is not open - good, remember to close it */
5570 remember_to_close:
5571 i = CLOSED;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005572 } else { /* fd is open, save its copy */
Denys Vlasenko86584e12017-01-07 10:15:01 +01005573#if !defined(F_DUPFD_CLOEXEC)
5574 fcntl(i, F_SETFD, FD_CLOEXEC);
5575#endif
Denis Vlasenko22f74142008-07-24 22:34:43 +00005576 /* "exec fd>&-" should not close fds
5577 * which point to script file(s).
5578 * Force them to be restored afterwards */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005579 if (is_hidden_fd(sv, fd))
5580 i |= COPYFD_RESTORE;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005581 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005582 if (fd == 2)
5583 copied_fd2 = i;
5584 sv->two_fd[sv_pos].orig = fd;
5585 sv->two_fd[sv_pos].copy = i;
5586 sv_pos++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005587 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005588 if (newfd < 0) {
5589 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005590 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005591 /* Don't want to trigger debugging */
5592 if (fd != -1)
5593 close(fd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005594 } else {
Denys Vlasenko64774602016-10-26 15:24:30 +02005595 dup2_or_raise(redir->ndup.dupfd, fd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005596 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005597 } else if (fd != newfd) { /* move newfd to fd */
Denys Vlasenko64774602016-10-26 15:24:30 +02005598 dup2_or_raise(newfd, fd);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005599#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005600 if (!(redir->nfile.type == NTO2 && fd == 2))
5601#endif
5602 close(newfd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005603 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005604#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005605 if (redir->nfile.type == NTO2 && fd == 1) {
5606 /* We already redirected it to fd 1, now copy it to 2 */
5607 newfd = 1;
5608 fd = 2;
5609 goto redirect_more;
5610 }
5611#endif
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005612 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005613
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005614 INT_ON;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005615 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5616 preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005617}
5618
5619/*
5620 * Undo the effects of the last redirection.
5621 */
5622static void
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005623popredir(int drop, int restore)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005624{
5625 struct redirtab *rp;
5626 int i;
5627
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02005628 if (redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005629 return;
5630 INT_OFF;
5631 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005632 for (i = 0; i < rp->pair_count; i++) {
5633 int fd = rp->two_fd[i].orig;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005634 int copy = rp->two_fd[i].copy;
5635 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005636 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005637 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005638 continue;
5639 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005640 if (copy != EMPTY) {
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005641 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
Denis Vlasenko22f74142008-07-24 22:34:43 +00005642 copy &= ~COPYFD_RESTORE;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005643 /*close(fd);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02005644 dup2_or_raise(copy, fd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005645 }
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005646 close(copy & ~COPYFD_RESTORE);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005647 }
5648 }
5649 redirlist = rp->next;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005650 free(rp);
5651 INT_ON;
5652}
5653
5654/*
5655 * Undo all redirections. Called on error or interrupt.
5656 */
5657
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005658static int
5659redirectsafe(union node *redir, int flags)
5660{
5661 int err;
5662 volatile int saveint;
5663 struct jmploc *volatile savehandler = exception_handler;
5664 struct jmploc jmploc;
5665
5666 SAVE_INT(saveint);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005667 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5668 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005669 if (!err) {
5670 exception_handler = &jmploc;
5671 redirect(redir, flags);
5672 }
5673 exception_handler = savehandler;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00005674 if (err && exception_type != EXERROR)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005675 longjmp(exception_handler->loc, 1);
5676 RESTORE_INT(saveint);
5677 return err;
5678}
5679
5680
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005681/* ============ Routines to expand arguments to commands
5682 *
5683 * We have to deal with backquotes, shell variables, and file metacharacters.
5684 */
5685
Denys Vlasenko0b883582016-12-23 16:49:07 +01005686#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005687static arith_t
5688ash_arith(const char *s)
5689{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005690 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005691 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005692
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005693 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005694 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005695 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005696
5697 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005698 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005699 if (math_state.errmsg)
5700 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005701 INT_ON;
5702
5703 return result;
5704}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005705#endif
5706
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005707/*
5708 * expandarg flags
5709 */
5710#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5711#define EXP_TILDE 0x2 /* do normal tilde expansion */
5712#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5713#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
Denys Vlasenkodb74c6c2016-10-24 21:12:33 +02005714/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5715 * POSIX says for this case:
5716 * Pathname expansion shall not be performed on the word by a
5717 * non-interactive shell; an interactive shell may perform it, but shall
5718 * do so only when the expansion would result in one word.
5719 * Currently, our code complies to the above rule by never globbing
5720 * redirection filenames.
5721 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5722 * (this means that on a typical Linux distro, bash almost always
5723 * performs globbing, and thus diverges from what we do).
5724 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005725#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Ron Yorston549deab2015-05-18 09:57:51 +02005726#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005727#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5728#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005729#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005730/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005731 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005732 */
5733#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5734#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005735#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5736#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Ron Yorston417622c2015-05-18 09:59:14 +02005737#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005738
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005739/* Add CTLESC when necessary. */
Ron Yorston549deab2015-05-18 09:57:51 +02005740#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005741/* Do not skip NUL characters. */
5742#define QUOTES_KEEPNUL EXP_TILDE
5743
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005744/*
5745 * Structure specifying which parts of the string should be searched
5746 * for IFS characters.
5747 */
5748struct ifsregion {
5749 struct ifsregion *next; /* next region in list */
5750 int begoff; /* offset of start of region */
5751 int endoff; /* offset of end of region */
5752 int nulonly; /* search for nul bytes only */
5753};
5754
5755struct arglist {
5756 struct strlist *list;
5757 struct strlist **lastp;
5758};
5759
5760/* output of current string */
5761static char *expdest;
5762/* list of back quote expressions */
5763static struct nodelist *argbackq;
5764/* first struct in list of ifs regions */
5765static struct ifsregion ifsfirst;
5766/* last struct in list */
5767static struct ifsregion *ifslastp;
5768/* holds expanded arg list */
5769static struct arglist exparg;
5770
5771/*
5772 * Our own itoa().
5773 */
Denys Vlasenko0b883582016-12-23 16:49:07 +01005774#if !ENABLE_FEATURE_SH_MATH
Denys Vlasenko26777aa2010-11-22 23:49:10 +01005775/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5776typedef long arith_t;
5777# define ARITH_FMT "%ld"
5778#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005779static int
5780cvtnum(arith_t num)
5781{
5782 int len;
5783
Denys Vlasenko9c541002015-10-07 15:44:36 +02005784 expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest);
5785 len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005786 STADJUST(len, expdest);
5787 return len;
5788}
5789
Denys Vlasenko455e4222016-10-27 14:45:13 +02005790/*
5791 * Break the argument string into pieces based upon IFS and add the
5792 * strings to the argument list. The regions of the string to be
5793 * searched for IFS characters have been stored by recordregion.
5794 */
5795static void
5796ifsbreakup(char *string, struct arglist *arglist)
5797{
5798 struct ifsregion *ifsp;
5799 struct strlist *sp;
5800 char *start;
5801 char *p;
5802 char *q;
5803 const char *ifs, *realifs;
5804 int ifsspc;
5805 int nulonly;
5806
5807 start = string;
5808 if (ifslastp != NULL) {
5809 ifsspc = 0;
5810 nulonly = 0;
5811 realifs = ifsset() ? ifsval() : defifs;
5812 ifsp = &ifsfirst;
5813 do {
5814 p = string + ifsp->begoff;
5815 nulonly = ifsp->nulonly;
5816 ifs = nulonly ? nullstr : realifs;
5817 ifsspc = 0;
5818 while (p < string + ifsp->endoff) {
5819 q = p;
5820 if ((unsigned char)*p == CTLESC)
5821 p++;
5822 if (!strchr(ifs, *p)) {
5823 p++;
5824 continue;
5825 }
5826 if (!nulonly)
5827 ifsspc = (strchr(defifs, *p) != NULL);
5828 /* Ignore IFS whitespace at start */
5829 if (q == start && ifsspc) {
5830 p++;
5831 start = p;
5832 continue;
5833 }
5834 *q = '\0';
5835 sp = stzalloc(sizeof(*sp));
5836 sp->text = start;
5837 *arglist->lastp = sp;
5838 arglist->lastp = &sp->next;
5839 p++;
5840 if (!nulonly) {
5841 for (;;) {
5842 if (p >= string + ifsp->endoff) {
5843 break;
5844 }
5845 q = p;
5846 if ((unsigned char)*p == CTLESC)
5847 p++;
5848 if (strchr(ifs, *p) == NULL) {
5849 p = q;
5850 break;
5851 }
5852 if (strchr(defifs, *p) == NULL) {
5853 if (ifsspc) {
5854 p++;
5855 ifsspc = 0;
5856 } else {
5857 p = q;
5858 break;
5859 }
5860 } else
5861 p++;
5862 }
5863 }
5864 start = p;
5865 } /* while */
5866 ifsp = ifsp->next;
5867 } while (ifsp != NULL);
5868 if (nulonly)
5869 goto add;
5870 }
5871
5872 if (!*start)
5873 return;
5874
5875 add:
5876 sp = stzalloc(sizeof(*sp));
5877 sp->text = start;
5878 *arglist->lastp = sp;
5879 arglist->lastp = &sp->next;
5880}
5881
5882static void
5883ifsfree(void)
5884{
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005885 struct ifsregion *p = ifsfirst.next;
5886
5887 if (!p)
5888 goto out;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005889
5890 INT_OFF;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005891 do {
5892 struct ifsregion *ifsp;
5893 ifsp = p->next;
5894 free(p);
5895 p = ifsp;
5896 } while (p);
Denys Vlasenko455e4222016-10-27 14:45:13 +02005897 ifsfirst.next = NULL;
5898 INT_ON;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005899 out:
5900 ifslastp = NULL;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005901}
5902
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005903static size_t
5904esclen(const char *start, const char *p)
5905{
5906 size_t esc = 0;
5907
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005908 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005909 esc++;
5910 }
5911 return esc;
5912}
5913
5914/*
5915 * Remove any CTLESC characters from a string.
5916 */
5917static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005918rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005919{
Ron Yorston417622c2015-05-18 09:59:14 +02005920 static const char qchars[] ALIGN1 = {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005921 IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005922
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005923 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005924 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005925 unsigned protect_against_glob;
5926 unsigned globbing;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005927 IF_BASH_PATTERN_SUBST(unsigned slash = flag & RMESCAPE_SLASH;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005928
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005929 p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005930 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005931 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005932
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005933 q = p;
5934 r = str;
5935 if (flag & RMESCAPE_ALLOC) {
5936 size_t len = p - str;
5937 size_t fulllen = len + strlen(p) + 1;
5938
5939 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005940 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005941 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005942 /* p and str may be invalidated by makestrspace */
5943 str = (char *)stackblock() + strloc;
5944 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005945 } else if (flag & RMESCAPE_HEAP) {
5946 r = ckmalloc(fulllen);
5947 } else {
5948 r = stalloc(fulllen);
5949 }
5950 q = r;
5951 if (len > 0) {
Denis Vlasenko29eb3592008-05-18 14:06:08 +00005952 q = (char *)memcpy(q, str, len) + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005953 }
5954 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005955
Ron Yorston549deab2015-05-18 09:57:51 +02005956 inquotes = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005957 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005958 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005959 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005960 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005961// Note: both inquotes and protect_against_glob only affect whether
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02005962// CTLESC,<ch> gets converted to <ch> or to \<ch>
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005963 inquotes = ~inquotes;
5964 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005965 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005966 continue;
5967 }
Ron Yorston549deab2015-05-18 09:57:51 +02005968 if ((unsigned char)*p == CTLESC) {
5969 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02005970#if DEBUG
5971 if (*p == '\0')
5972 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
5973#endif
Ron Yorston549deab2015-05-18 09:57:51 +02005974 if (protect_against_glob) {
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02005975 /*
5976 * We used to trust glob() and fnmatch() to eat
5977 * superfluous escapes (\z where z has no
5978 * special meaning anyway). But this causes
5979 * bugs such as string of one greek letter rho
Denys Vlasenkoed79a632017-07-05 19:20:43 +02005980 * (unicode-encoded as two bytes "cf,81")
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02005981 * getting encoded as "cf,CTLESC,81"
5982 * and here, converted to "cf,\,81" -
5983 * which does not go well with some flavors
Denys Vlasenko92b8d9c2017-07-05 19:13:44 +02005984 * of fnmatch() in unicode locales
5985 * (for example, glibc <= 2.22).
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02005986 *
5987 * Lets add "\" only on the chars which need it.
Denys Vlasenko4142f012017-07-05 22:19:28 +02005988 * Testcases for less obvious chars are shown.
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02005989 */
5990 if (*p == '*'
5991 || *p == '?'
5992 || *p == '['
Denys Vlasenko4142f012017-07-05 22:19:28 +02005993 || *p == '\\' /* case '\' in \\ ) echo ok;; *) echo WRONG;; esac */
5994 || *p == ']' /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */
5995 || *p == '-' /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */
5996 || *p == '!' /* case '!' in [\!] ) echo ok;; *) echo WRONG;; esac */
5997 /* Some libc support [^negate], that's why "^" also needs love */
5998 || *p == '^' /* case '^' in [\^] ) echo ok;; *) echo WRONG;; esac */
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02005999 ) {
6000 *q++ = '\\';
6001 }
Ron Yorston549deab2015-05-18 09:57:51 +02006002 }
6003 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006004 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006005 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006006 goto copy;
6007 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006008#if BASH_PATTERN_SUBST
Ron Yorston417622c2015-05-18 09:59:14 +02006009 else if (*p == '/' && slash) {
6010 /* stop handling globbing and mark location of slash */
6011 globbing = slash = 0;
6012 *p = CTLESC;
6013 }
6014#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006015 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006016 copy:
6017 *q++ = *p++;
6018 }
6019 *q = '\0';
6020 if (flag & RMESCAPE_GROW) {
6021 expdest = r;
6022 STADJUST(q - r + 1, expdest);
6023 }
6024 return r;
6025}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006026#define pmatch(a, b) !fnmatch((a), (b), 0)
6027
6028/*
6029 * Prepare a pattern for a expmeta (internal glob(3)) call.
6030 *
6031 * Returns an stalloced string.
6032 */
6033static char *
Ron Yorston549deab2015-05-18 09:57:51 +02006034preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006035{
Ron Yorston549deab2015-05-18 09:57:51 +02006036 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006037}
6038
6039/*
6040 * Put a string on the stack.
6041 */
6042static void
6043memtodest(const char *p, size_t len, int syntax, int quotes)
6044{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006045 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006046
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006047 if (!len)
6048 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006049
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006050 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
6051
6052 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006053 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006054 if (c) {
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01006055 if (quotes & QUOTES_ESC) {
6056 int n = SIT(c, syntax);
6057 if (n == CCTL
6058 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
6059 && n == CBACK
6060 )
6061 ) {
6062 USTPUTC(CTLESC, q);
6063 }
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006064 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006065 } else if (!(quotes & QUOTES_KEEPNUL))
6066 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006067 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006068 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006069
6070 expdest = q;
6071}
6072
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006073static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006074strtodest(const char *p, int syntax, int quotes)
6075{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006076 size_t len = strlen(p);
6077 memtodest(p, len, syntax, quotes);
6078 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006079}
6080
6081/*
6082 * Record the fact that we have to scan this region of the
6083 * string for IFS characters.
6084 */
6085static void
6086recordregion(int start, int end, int nulonly)
6087{
6088 struct ifsregion *ifsp;
6089
6090 if (ifslastp == NULL) {
6091 ifsp = &ifsfirst;
6092 } else {
6093 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00006094 ifsp = ckzalloc(sizeof(*ifsp));
6095 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006096 ifslastp->next = ifsp;
6097 INT_ON;
6098 }
6099 ifslastp = ifsp;
6100 ifslastp->begoff = start;
6101 ifslastp->endoff = end;
6102 ifslastp->nulonly = nulonly;
6103}
6104
6105static void
6106removerecordregions(int endoff)
6107{
6108 if (ifslastp == NULL)
6109 return;
6110
6111 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006112 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006113 struct ifsregion *ifsp;
6114 INT_OFF;
6115 ifsp = ifsfirst.next->next;
6116 free(ifsfirst.next);
6117 ifsfirst.next = ifsp;
6118 INT_ON;
6119 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006120 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006121 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006122 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006123 ifslastp = &ifsfirst;
6124 ifsfirst.endoff = endoff;
6125 }
6126 return;
6127 }
6128
6129 ifslastp = &ifsfirst;
6130 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006131 ifslastp = ifslastp->next;
6132 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006133 struct ifsregion *ifsp;
6134 INT_OFF;
6135 ifsp = ifslastp->next->next;
6136 free(ifslastp->next);
6137 ifslastp->next = ifsp;
6138 INT_ON;
6139 }
6140 if (ifslastp->endoff > endoff)
6141 ifslastp->endoff = endoff;
6142}
6143
6144static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006145exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006146{
Denys Vlasenkocd716832009-11-28 22:14:02 +01006147 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006148 char *name;
6149 struct passwd *pw;
6150 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006151 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006152
6153 name = p + 1;
6154
6155 while ((c = *++p) != '\0') {
6156 switch (c) {
6157 case CTLESC:
6158 return startp;
6159 case CTLQUOTEMARK:
6160 return startp;
6161 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006162 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006163 goto done;
6164 break;
6165 case '/':
6166 case CTLENDVAR:
6167 goto done;
6168 }
6169 }
6170 done:
6171 *p = '\0';
6172 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02006173 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006174 } else {
6175 pw = getpwnam(name);
6176 if (pw == NULL)
6177 goto lose;
6178 home = pw->pw_dir;
6179 }
6180 if (!home || !*home)
6181 goto lose;
6182 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006183 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006184 return p;
6185 lose:
6186 *p = c;
6187 return startp;
6188}
6189
6190/*
6191 * Execute a command inside back quotes. If it's a builtin command, we
6192 * want to save its output in a block obtained from malloc. Otherwise
6193 * we fork off a subprocess and get the output of the command via a pipe.
6194 * Should be called with interrupts off.
6195 */
6196struct backcmd { /* result of evalbackcmd */
6197 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006198 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00006199 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006200 struct job *jp; /* job structure for command */
6201};
6202
6203/* These forward decls are needed to use "eval" code for backticks handling: */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006204#define EV_EXIT 01 /* exit after evaluating tree */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02006205static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006206
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02006207static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006208evalbackcmd(union node *n, struct backcmd *result)
6209{
Denys Vlasenko579ad102016-10-25 21:10:20 +02006210 int pip[2];
6211 struct job *jp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006212
6213 result->fd = -1;
6214 result->buf = NULL;
6215 result->nleft = 0;
6216 result->jp = NULL;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006217 if (n == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006218 goto out;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006219 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006220
Denys Vlasenko579ad102016-10-25 21:10:20 +02006221 if (pipe(pip) < 0)
6222 ash_msg_and_raise_error("pipe call failed");
6223 jp = makejob(/*n,*/ 1);
6224 if (forkshell(jp, n, FORK_NOJOB) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02006225 /* child */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006226 FORCE_INT_ON;
6227 close(pip[0]);
6228 if (pip[1] != 1) {
6229 /*close(1);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02006230 dup2_or_raise(pip[1], 1);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006231 close(pip[1]);
6232 }
Denys Vlasenko960ca382016-10-25 18:12:15 +02006233/* TODO: eflag clearing makes the following not abort:
6234 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6235 * which is what bash does (unless it is in POSIX mode).
6236 * dash deleted "eflag = 0" line in the commit
6237 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6238 * [EVAL] Don't clear eflag in evalbackcmd
6239 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6240 */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006241 eflag = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006242 ifsfree();
Denys Vlasenko579ad102016-10-25 21:10:20 +02006243 evaltree(n, EV_EXIT); /* actually evaltreenr... */
6244 /* NOTREACHED */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006245 }
Denys Vlasenko70392332016-10-27 02:31:55 +02006246 /* parent */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006247 close(pip[1]);
6248 result->fd = pip[0];
6249 result->jp = jp;
6250
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006251 out:
6252 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6253 result->fd, result->buf, result->nleft, result->jp));
6254}
6255
6256/*
6257 * Expand stuff in backwards quotes.
6258 */
6259static void
Ron Yorston549deab2015-05-18 09:57:51 +02006260expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006261{
6262 struct backcmd in;
6263 int i;
6264 char buf[128];
6265 char *p;
6266 char *dest;
6267 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02006268 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006269 struct stackmark smark;
6270
6271 INT_OFF;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02006272 startloc = expdest - (char *)stackblock();
6273 pushstackmark(&smark, startloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006274 evalbackcmd(cmd, &in);
6275 popstackmark(&smark);
6276
6277 p = in.buf;
6278 i = in.nleft;
6279 if (i == 0)
6280 goto read;
6281 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02006282 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006283 read:
6284 if (in.fd < 0)
6285 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01006286 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006287 TRACE(("expbackq: read returns %d\n", i));
6288 if (i <= 0)
6289 break;
6290 p = buf;
6291 }
6292
Denis Vlasenko60818682007-09-28 22:07:23 +00006293 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006294 if (in.fd >= 0) {
6295 close(in.fd);
6296 back_exitstatus = waitforjob(in.jp);
6297 }
6298 INT_ON;
6299
6300 /* Eat all trailing newlines */
6301 dest = expdest;
6302 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6303 STUNPUTC(dest);
6304 expdest = dest;
6305
Ron Yorston549deab2015-05-18 09:57:51 +02006306 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006307 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006308 TRACE(("evalbackq: size:%d:'%.*s'\n",
6309 (int)((dest - (char *)stackblock()) - startloc),
6310 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006311 stackblock() + startloc));
6312}
6313
Denys Vlasenko0b883582016-12-23 16:49:07 +01006314#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006315/*
6316 * Expand arithmetic expression. Backup to start of expression,
6317 * evaluate, place result in (backed up) result, adjust string position.
6318 */
6319static void
Ron Yorston549deab2015-05-18 09:57:51 +02006320expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006321{
6322 char *p, *start;
6323 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006324 int len;
6325
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006326 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006327
6328 /*
6329 * This routine is slightly over-complicated for
6330 * efficiency. Next we scan backwards looking for the
6331 * start of arithmetic.
6332 */
6333 start = stackblock();
6334 p = expdest - 1;
6335 *p = '\0';
6336 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006337 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006338 int esc;
6339
Denys Vlasenkocd716832009-11-28 22:14:02 +01006340 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006341 p--;
6342#if DEBUG
6343 if (p < start) {
6344 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6345 }
6346#endif
6347 }
6348
6349 esc = esclen(start, p);
6350 if (!(esc % 2)) {
6351 break;
6352 }
6353
6354 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006355 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006356
6357 begoff = p - start;
6358
6359 removerecordregions(begoff);
6360
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006361 expdest = p;
6362
Ron Yorston549deab2015-05-18 09:57:51 +02006363 if (flag & QUOTES_ESC)
6364 rmescapes(p + 1, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006365
Ron Yorston549deab2015-05-18 09:57:51 +02006366 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006367
Ron Yorston549deab2015-05-18 09:57:51 +02006368 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006369 recordregion(begoff, begoff + len, 0);
6370}
6371#endif
6372
6373/* argstr needs it */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006374static char *evalvar(char *p, int flags, struct strlist *var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006375
6376/*
6377 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6378 * characters to allow for further processing. Otherwise treat
6379 * $@ like $* since no splitting will be performed.
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006380 *
6381 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
Denys Vlasenko10ad6222017-04-17 16:13:32 +02006382 * over shell variables. Needed for "A=a B=$A; echo $B" case - we use it
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006383 * for correct expansion of "B=$A" word.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006384 */
6385static void
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006386argstr(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006387{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006388 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006389 '=',
6390 ':',
6391 CTLQUOTEMARK,
6392 CTLENDVAR,
6393 CTLESC,
6394 CTLVAR,
6395 CTLBACKQ,
Denys Vlasenko0b883582016-12-23 16:49:07 +01006396#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006397 CTLENDARI,
6398#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006399 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006400 };
6401 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006402 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006403 int inquotes;
6404 size_t length;
6405 int startloc;
6406
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006407 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006408 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006409 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006410 reject++;
6411 }
6412 inquotes = 0;
6413 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006414 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006415 char *q;
6416
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006417 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006418 tilde:
6419 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006420 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006421 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006422 }
6423 start:
6424 startloc = expdest - (char *)stackblock();
6425 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006426 unsigned char c;
6427
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006428 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006429 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006430 if (c) {
6431 if (!(c & 0x80)
Denys Vlasenko0b883582016-12-23 16:49:07 +01006432 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006433 ) {
6434 /* c == '=' || c == ':' || c == CTLENDARI */
6435 length++;
6436 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006437 }
6438 if (length > 0) {
6439 int newloc;
6440 expdest = stack_nputstr(p, length, expdest);
6441 newloc = expdest - (char *)stackblock();
6442 if (breakall && !inquotes && newloc > startloc) {
6443 recordregion(startloc, newloc, 0);
6444 }
6445 startloc = newloc;
6446 }
6447 p += length + 1;
6448 length = 0;
6449
6450 switch (c) {
6451 case '\0':
6452 goto breakloop;
6453 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006454 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006455 p--;
6456 continue;
6457 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006458 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006459 reject++;
6460 /* fall through */
6461 case ':':
6462 /*
6463 * sort of a hack - expand tildes in variable
6464 * assignments (after the first '=' and after ':'s).
6465 */
6466 if (*--p == '~') {
6467 goto tilde;
6468 }
6469 continue;
6470 }
6471
6472 switch (c) {
6473 case CTLENDVAR: /* ??? */
6474 goto breakloop;
6475 case CTLQUOTEMARK:
Ron Yorston549deab2015-05-18 09:57:51 +02006476 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006477 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006478 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6479 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006480 goto start;
6481 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006482 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006483 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006484 p--;
6485 length++;
6486 startloc++;
6487 }
6488 break;
6489 case CTLESC:
6490 startloc++;
6491 length++;
Ron Yorston549deab2015-05-18 09:57:51 +02006492
6493 /*
6494 * Quoted parameter expansion pattern: remove quote
6495 * unless inside inner quotes or we have a literal
6496 * backslash.
6497 */
6498 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6499 EXP_QPAT && *p != '\\')
6500 break;
6501
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006502 goto addquote;
6503 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006504 TRACE(("argstr: evalvar('%s')\n", p));
Ron Yorston549deab2015-05-18 09:57:51 +02006505 p = evalvar(p, flags | inquotes, var_str_list);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006506 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006507 goto start;
6508 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006509 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006510 argbackq = argbackq->next;
6511 goto start;
Denys Vlasenko0b883582016-12-23 16:49:07 +01006512#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006513 case CTLENDARI:
6514 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006515 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006516 goto start;
6517#endif
6518 }
6519 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006520 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006521}
6522
6523static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006524scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6525 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006526{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006527 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006528 char c;
6529
6530 loc = startp;
6531 loc2 = rmesc;
6532 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006533 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006534 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006535
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006536 c = *loc2;
6537 if (zero) {
6538 *loc2 = '\0';
6539 s = rmesc;
6540 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006541 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006542
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006543 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006544 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006545 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006546 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006547 loc++;
6548 loc++;
6549 loc2++;
6550 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006551 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006552}
6553
6554static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006555scanright(char *startp, char *rmesc, char *rmescend,
6556 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006557{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006558#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6559 int try2optimize = match_at_start;
6560#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006561 int esc = 0;
6562 char *loc;
6563 char *loc2;
6564
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006565 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6566 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6567 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6568 * Logic:
6569 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6570 * and on each iteration they go back two/one char until they reach the beginning.
6571 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6572 */
6573 /* TODO: document in what other circumstances we are called. */
6574
6575 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006576 int match;
6577 char c = *loc2;
6578 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006579 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006580 *loc2 = '\0';
6581 s = rmesc;
6582 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006583 match = pmatch(pattern, s);
6584 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006585 *loc2 = c;
6586 if (match)
6587 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006588#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6589 if (try2optimize) {
6590 /* Maybe we can optimize this:
6591 * if pattern ends with unescaped *, we can avoid checking
Denys Vlasenko10ad6222017-04-17 16:13:32 +02006592 * shorter strings: if "foo*" doesn't match "raw_value_of_v",
6593 * it won't match truncated "raw_value_of_" strings too.
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006594 */
6595 unsigned plen = strlen(pattern);
6596 /* Does it end with "*"? */
6597 if (plen != 0 && pattern[--plen] == '*') {
6598 /* "xxxx*" is not escaped */
6599 /* "xxx\*" is escaped */
6600 /* "xx\\*" is not escaped */
6601 /* "x\\\*" is escaped */
6602 int slashes = 0;
6603 while (plen != 0 && pattern[--plen] == '\\')
6604 slashes++;
6605 if (!(slashes & 1))
6606 break; /* ends with unescaped "*" */
6607 }
6608 try2optimize = 0;
6609 }
6610#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006611 loc--;
6612 if (quotes) {
6613 if (--esc < 0) {
6614 esc = esclen(startp, loc);
6615 }
6616 if (esc % 2) {
6617 esc--;
6618 loc--;
6619 }
6620 }
6621 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006622 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006623}
6624
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006625static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006626static void
6627varunset(const char *end, const char *var, const char *umsg, int varflags)
6628{
6629 const char *msg;
6630 const char *tail;
6631
6632 tail = nullstr;
6633 msg = "parameter not set";
6634 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006635 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006636 if (varflags & VSNUL)
6637 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006638 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006639 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006640 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006641 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006642 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006643}
6644
6645static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006646subevalvar(char *p, char *varname, int strloc, int subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006647 int startloc, int varflags, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006648{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006649 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006650 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006651 char *startp;
6652 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006653 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006654 char *str;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006655 int amount, resetloc;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006656 IF_BASH_PATTERN_SUBST(int workloc;)
6657 IF_BASH_PATTERN_SUBST(char *repl = NULL;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006658 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006659 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006660
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006661 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6662 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006663
Ron Yorstoneb6b48b2015-05-18 09:51:35 +02006664 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
Ron Yorston549deab2015-05-18 09:57:51 +02006665 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6666 var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006667 STPUTC('\0', expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006668 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006669 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006670
6671 switch (subtype) {
6672 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006673 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006674 amount = startp - expdest;
6675 STADJUST(amount, expdest);
6676 return startp;
6677
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006678 case VSQUESTION:
6679 varunset(p, varname, startp, varflags);
6680 /* NOTREACHED */
6681
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006682#if BASH_SUBSTR
Denys Vlasenko826360f2017-07-17 17:49:11 +02006683 case VSSUBSTR: {
6684 int pos, len, orig_len;
6685 char *colon;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006686
Denys Vlasenko826360f2017-07-17 17:49:11 +02006687 loc = str = stackblock() + strloc;
6688
6689# if !ENABLE_FEATURE_SH_MATH
6690# define ash_arith number
6691# endif
6692 /* Read POS in ${var:POS:LEN} */
6693 colon = strchr(loc, ':');
6694 if (colon) *colon = '\0';
6695 pos = ash_arith(loc);
6696 if (colon) *colon = ':';
6697
6698 /* Read LEN in ${var:POS:LEN} */
6699 len = str - startp - 1;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006700 /* *loc != '\0', guaranteed by parser */
6701 if (quotes) {
6702 char *ptr;
6703
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006704 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006705 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006706 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006707 len--;
6708 ptr++;
6709 }
6710 }
6711 }
6712 orig_len = len;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006713 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006714 /* ${var::LEN} */
Denys Vlasenko826360f2017-07-17 17:49:11 +02006715 len = ash_arith(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006716 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006717 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006718 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006719 while (*loc && *loc != ':') {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006720 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006721 }
6722 if (*loc++ == ':') {
Denys Vlasenko826360f2017-07-17 17:49:11 +02006723 len = ash_arith(loc);
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006724 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006725 }
Denys Vlasenko826360f2017-07-17 17:49:11 +02006726# undef ash_arith
6727
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006728 if (pos < 0) {
6729 /* ${VAR:$((-n)):l} starts n chars from the end */
6730 pos = orig_len + pos;
6731 }
6732 if ((unsigned)pos >= orig_len) {
6733 /* apart from obvious ${VAR:999999:l},
6734 * covers ${VAR:$((-9999999)):l} - result is ""
Denys Vlasenko826360f2017-07-17 17:49:11 +02006735 * (bash compat)
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006736 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006737 pos = 0;
6738 len = 0;
6739 }
Denys Vlasenko826360f2017-07-17 17:49:11 +02006740 if (len < 0) {
6741 /* ${VAR:N:-M} sets LEN to strlen()-M */
6742 len = (orig_len - pos) + len;
6743 }
6744 if ((unsigned)len > (orig_len - pos))
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006745 len = orig_len - pos;
6746
6747 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006748 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006749 str++;
6750 }
6751 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006752 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006753 *loc++ = *str++;
6754 *loc++ = *str++;
6755 }
6756 *loc = '\0';
6757 amount = loc - expdest;
6758 STADJUST(amount, expdest);
6759 return loc;
Denys Vlasenko826360f2017-07-17 17:49:11 +02006760 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006761#endif /* BASH_SUBSTR */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006762 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006763
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006764 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006765
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006766#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006767 /* We'll comeback here if we grow the stack while handling
6768 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6769 * stack will need rebasing, and we'll need to remove our work
6770 * areas each time
6771 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006772 restart:
6773#endif
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006774
6775 amount = expdest - ((char *)stackblock() + resetloc);
6776 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006777 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006778
6779 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006780 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006781 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006782 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006783 if (rmesc != startp) {
6784 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006785 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006786 }
6787 }
6788 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006789 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02006790 /*
6791 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6792 * The result is a_\_z_c (not a\_\_z_c)!
6793 *
6794 * The search pattern and replace string treat backslashes differently!
6795 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6796 * and string. It's only used on the first call.
6797 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006798 preglob(str, IF_BASH_PATTERN_SUBST(
Ron Yorston417622c2015-05-18 09:59:14 +02006799 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006800 RMESCAPE_SLASH : ) 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006801
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006802#if BASH_PATTERN_SUBST
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006803 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006804 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenko826360f2017-07-17 17:49:11 +02006805 int len;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006806 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006807
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006808 if (!repl) {
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006809 repl = strchr(str, CTLESC);
6810 if (repl)
Ron Yorston417622c2015-05-18 09:59:14 +02006811 *repl++ = '\0';
6812 else
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006813 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006814 }
Ron Yorston417622c2015-05-18 09:59:14 +02006815 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006816
6817 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006818 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006819 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006820
6821 len = 0;
6822 idx = startp;
6823 end = str - 1;
6824 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006825 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006826 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006827 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006828 if (!loc) {
6829 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006830 char *restart_detect = stackblock();
6831 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006832 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006833 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006834 idx++;
6835 len++;
6836 STPUTC(*idx, expdest);
6837 }
6838 if (stackblock() != restart_detect)
6839 goto restart;
6840 idx++;
6841 len++;
6842 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006843 /* continue; - prone to quadratic behavior, smarter code: */
6844 if (idx >= end)
6845 break;
6846 if (str[0] == '*') {
6847 /* Pattern is "*foo". If "*foo" does not match "long_string",
6848 * it would never match "ong_string" etc, no point in trying.
6849 */
6850 goto skip_matching;
6851 }
6852 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006853 }
6854
6855 if (subtype == VSREPLACEALL) {
6856 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006857 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006858 idx++;
6859 idx++;
6860 rmesc++;
6861 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006862 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006863 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006864 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006865
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006866 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006867 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006868 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006869 if (quotes && *loc == '\\') {
6870 STPUTC(CTLESC, expdest);
6871 len++;
6872 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006873 STPUTC(*loc, expdest);
6874 if (stackblock() != restart_detect)
6875 goto restart;
6876 len++;
6877 }
6878
6879 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006880 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006881 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006882 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006883 STPUTC(*idx, expdest);
6884 if (stackblock() != restart_detect)
6885 goto restart;
6886 len++;
6887 idx++;
6888 }
6889 break;
6890 }
6891 }
6892
6893 /* We've put the replaced text into a buffer at workloc, now
6894 * move it to the right place and adjust the stack.
6895 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006896 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006897 startp = (char *)stackblock() + startloc;
6898 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006899 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006900 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006901 STADJUST(-amount, expdest);
6902 return startp;
6903 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006904#endif /* BASH_PATTERN_SUBST */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006905
6906 subtype -= VSTRIMRIGHT;
6907#if DEBUG
6908 if (subtype < 0 || subtype > 7)
6909 abort();
6910#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006911 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006912 zero = subtype >> 1;
6913 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6914 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6915
6916 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6917 if (loc) {
6918 if (zero) {
6919 memmove(startp, loc, str - loc);
6920 loc = startp + (str - loc) - 1;
6921 }
6922 *loc = '\0';
6923 amount = loc - expdest;
6924 STADJUST(amount, expdest);
6925 }
6926 return loc;
6927}
6928
6929/*
6930 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006931 * name parameter (examples):
6932 * ash -c 'echo $1' name:'1='
6933 * ash -c 'echo $qwe' name:'qwe='
6934 * ash -c 'echo $$' name:'$='
6935 * ash -c 'echo ${$}' name:'$='
6936 * ash -c 'echo ${$##q}' name:'$=q'
6937 * ash -c 'echo ${#$}' name:'$='
6938 * note: examples with bad shell syntax:
6939 * ash -c 'echo ${#$1}' name:'$=1'
6940 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006941 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02006942static NOINLINE ssize_t
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006943varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int *quotedp)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006944{
Mike Frysinger98c52642009-04-02 10:02:37 +00006945 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006946 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006947 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006948 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006949 int sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006950 int quoted = *quotedp;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006951 int subtype = varflags & VSTYPE;
6952 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6953 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006954 int syntax;
6955
6956 sep = (flags & EXP_FULL) << CHAR_BIT;
6957 syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006958
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006959 switch (*name) {
6960 case '$':
6961 num = rootpid;
6962 goto numvar;
6963 case '?':
6964 num = exitstatus;
6965 goto numvar;
6966 case '#':
6967 num = shellparam.nparam;
6968 goto numvar;
6969 case '!':
6970 num = backgndpid;
6971 if (num == 0)
6972 return -1;
6973 numvar:
6974 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006975 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006976 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00006977 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006978 for (i = NOPTS - 1; i >= 0; i--) {
6979 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00006980 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006981 len++;
6982 }
6983 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006984 check_1char_name:
6985#if 0
6986 /* handles cases similar to ${#$1} */
6987 if (name[2] != '\0')
6988 raise_error_syntax("bad substitution");
6989#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006990 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006991 case '@':
6992 if (quoted && sep)
6993 goto param;
6994 /* fall through */
6995 case '*': {
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006996 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006997 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006998
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006999 if (quoted)
7000 sep = 0;
7001 sep |= ifsset() ? ifsval()[0] : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007002 param:
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007003 sepc = sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007004 *quotedp = !sepc;
7005 ap = shellparam.p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007006 if (!ap)
7007 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007008 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007009 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007010
7011 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007012 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007013 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007014 }
7015 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007016 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007017 } /* case '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007018 case '0':
7019 case '1':
7020 case '2':
7021 case '3':
7022 case '4':
7023 case '5':
7024 case '6':
7025 case '7':
7026 case '8':
7027 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02007028 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007029 if (num < 0 || num > shellparam.nparam)
7030 return -1;
7031 p = num ? shellparam.p[num - 1] : arg0;
7032 goto value;
7033 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007034 /* NB: name has form "VAR=..." */
7035
7036 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
7037 * which should be considered before we check variables. */
7038 if (var_str_list) {
7039 unsigned name_len = (strchrnul(name, '=') - name) + 1;
7040 p = NULL;
7041 do {
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00007042 char *str, *eq;
7043 str = var_str_list->text;
7044 eq = strchr(str, '=');
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007045 if (!eq) /* stop at first non-assignment */
7046 break;
7047 eq++;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00007048 if (name_len == (unsigned)(eq - str)
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007049 && strncmp(str, name, name_len) == 0
7050 ) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007051 p = eq;
7052 /* goto value; - WRONG! */
7053 /* think "A=1 A=2 B=$A" */
7054 }
7055 var_str_list = var_str_list->next;
7056 } while (var_str_list);
7057 if (p)
7058 goto value;
7059 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007060 p = lookupvar(name);
7061 value:
7062 if (!p)
7063 return -1;
7064
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007065 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007066#if ENABLE_UNICODE_SUPPORT
7067 if (subtype == VSLENGTH && len > 0) {
7068 reinit_unicode_for_ash();
7069 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00007070 STADJUST(-len, expdest);
7071 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007072 len = unicode_strlen(p);
7073 }
7074 }
7075#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007076 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007077 }
7078
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007079 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007080 STADJUST(-len, expdest);
7081 return len;
7082}
7083
7084/*
7085 * Expand a variable, and return a pointer to the next character in the
7086 * input string.
7087 */
7088static char *
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007089evalvar(char *p, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007090{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007091 char varflags;
7092 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02007093 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007094 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007095 char *var;
7096 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007097 int startloc;
7098 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007099
Denys Vlasenkob0d63382009-09-16 16:18:32 +02007100 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007101 subtype = varflags & VSTYPE;
Denys Vlasenko88e15702016-10-26 01:55:56 +02007102
7103 if (!subtype)
7104 raise_error_syntax("bad substitution");
7105
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007106 quoted = flag & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007107 var = p;
7108 easy = (!quoted || (*var == '@' && shellparam.nparam));
7109 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02007110 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007111
7112 again:
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007113 varlen = varvalue(var, varflags, flag, var_str_list, &quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007114 if (varflags & VSNUL)
7115 varlen--;
7116
7117 if (subtype == VSPLUS) {
7118 varlen = -1 - varlen;
7119 goto vsplus;
7120 }
7121
7122 if (subtype == VSMINUS) {
7123 vsplus:
7124 if (varlen < 0) {
7125 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02007126 p,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007127 flag | EXP_TILDE | EXP_WORD,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007128 var_str_list
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007129 );
7130 goto end;
7131 }
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007132 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007133 }
7134
7135 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007136 if (varlen >= 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007137 goto record;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007138
7139 subevalvar(p, var, 0, subtype, startloc, varflags,
7140 flag & ~QUOTES_ESC, var_str_list);
7141 varflags &= ~VSNUL;
7142 /*
7143 * Remove any recorded regions beyond
7144 * start of variable
7145 */
7146 removerecordregions(startloc);
7147 goto again;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007148 }
7149
7150 if (varlen < 0 && uflag)
7151 varunset(p, var, 0, 0);
7152
7153 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007154 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007155 goto record;
7156 }
7157
7158 if (subtype == VSNORMAL) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007159 record:
7160 if (!easy)
7161 goto end;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007162 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007163 goto end;
7164 }
7165
7166#if DEBUG
7167 switch (subtype) {
7168 case VSTRIMLEFT:
7169 case VSTRIMLEFTMAX:
7170 case VSTRIMRIGHT:
7171 case VSTRIMRIGHTMAX:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007172#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007173 case VSSUBSTR:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007174#endif
7175#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007176 case VSREPLACE:
7177 case VSREPLACEALL:
7178#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007179 break;
7180 default:
7181 abort();
7182 }
7183#endif
7184
7185 if (varlen >= 0) {
7186 /*
7187 * Terminate the string and start recording the pattern
7188 * right after it
7189 */
7190 STPUTC('\0', expdest);
7191 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007192 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007193 startloc, varflags, flag, var_str_list)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007194 int amount = expdest - (
7195 (char *)stackblock() + patloc - 1
7196 );
7197 STADJUST(-amount, expdest);
7198 }
7199 /* Remove any recorded regions beyond start of variable */
7200 removerecordregions(startloc);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007201 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007202 }
7203
7204 end:
7205 if (subtype != VSNORMAL) { /* skip to end of alternative */
7206 int nesting = 1;
7207 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007208 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007209 if (c == CTLESC)
7210 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02007211 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007212 if (varlen >= 0)
7213 argbackq = argbackq->next;
7214 } else if (c == CTLVAR) {
7215 if ((*p++ & VSTYPE) != VSNORMAL)
7216 nesting++;
7217 } else if (c == CTLENDVAR) {
7218 if (--nesting == 0)
7219 break;
7220 }
7221 }
7222 }
7223 return p;
7224}
7225
7226/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007227 * Add a file name to the list.
7228 */
7229static void
7230addfname(const char *name)
7231{
7232 struct strlist *sp;
7233
Denis Vlasenko597906c2008-02-20 16:38:54 +00007234 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02007235 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007236 *exparg.lastp = sp;
7237 exparg.lastp = &sp->next;
7238}
7239
Felix Fietkaub5b21122017-01-31 21:58:55 +01007240/* Avoid glob() (and thus, stat() et al) for words like "echo" */
7241static int
7242hasmeta(const char *p)
7243{
7244 static const char chars[] ALIGN1 = {
7245 '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
7246 };
7247
7248 for (;;) {
7249 p = strpbrk(p, chars);
7250 if (!p)
7251 break;
7252 switch ((unsigned char) *p) {
7253 case CTLQUOTEMARK:
7254 for (;;) {
7255 p++;
7256 if (*p == CTLQUOTEMARK)
7257 break;
7258 if (*p == CTLESC)
7259 p++;
7260 if (*p == '\0') /* huh? */
7261 return 0;
7262 }
7263 break;
7264 case '\\':
7265 case CTLESC:
7266 p++;
7267 if (*p == '\0')
7268 return 0;
7269 break;
7270 case '[':
7271 if (!strchr(p + 1, ']')) {
7272 /* It's not a properly closed [] pattern,
7273 * but other metas may follow. Continue checking.
7274 * my[file* _is_ globbed by bash
7275 * and matches filenames like "my[file1".
7276 */
7277 break;
7278 }
7279 /* fallthrough */
7280 default:
7281 /* case '*': */
7282 /* case '?': */
7283 return 1;
7284 }
7285 p++;
7286 }
7287
7288 return 0;
7289}
7290
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007291/* If we want to use glob() from libc... */
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007292#if !ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007293
7294/* Add the result of glob() to the list */
7295static void
7296addglob(const glob_t *pglob)
7297{
7298 char **p = pglob->gl_pathv;
7299
7300 do {
7301 addfname(*p);
7302 } while (*++p);
7303}
7304static void
7305expandmeta(struct strlist *str /*, int flag*/)
7306{
7307 /* TODO - EXP_REDIR */
7308
7309 while (str) {
7310 char *p;
7311 glob_t pglob;
7312 int i;
7313
7314 if (fflag)
7315 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007316
Felix Fietkaub5b21122017-01-31 21:58:55 +01007317 if (!hasmeta(str->text))
7318 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007319
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007320 INT_OFF;
7321 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007322// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7323// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7324//
7325// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7326// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7327// Which means you need to unescape the string, right? Not so fast:
7328// if there _is_ a file named "file\?" (with backslash), it is returned
7329// as "file\?" too (whichever pattern you used to find it, say, "file*").
Denys Vlasenko10ad6222017-04-17 16:13:32 +02007330// You DON'T KNOW by looking at the result whether you need to unescape it.
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007331//
7332// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7333// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7334// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7335// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7336// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7337// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7338 i = glob(p, 0, NULL, &pglob);
7339 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007340 if (p != str->text)
7341 free(p);
7342 switch (i) {
7343 case 0:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007344#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007345 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7346 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7347 goto nometa2;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007348#endif
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007349 addglob(&pglob);
7350 globfree(&pglob);
7351 INT_ON;
7352 break;
7353 case GLOB_NOMATCH:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007354 //nometa2:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007355 globfree(&pglob);
7356 INT_ON;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007357 nometa:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007358 *exparg.lastp = str;
7359 rmescapes(str->text, 0);
7360 exparg.lastp = &str->next;
7361 break;
7362 default: /* GLOB_NOSPACE */
7363 globfree(&pglob);
7364 INT_ON;
7365 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7366 }
7367 str = str->next;
7368 }
7369}
7370
7371#else
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007372/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007373
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007374/*
7375 * Do metacharacter (i.e. *, ?, [...]) expansion.
7376 */
7377static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007378expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007379{
7380 char *p;
7381 const char *cp;
7382 char *start;
7383 char *endname;
7384 int metaflag;
7385 struct stat statb;
7386 DIR *dirp;
7387 struct dirent *dp;
7388 int atend;
7389 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007390 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007391
7392 metaflag = 0;
7393 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007394 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007395 if (*p == '*' || *p == '?')
7396 metaflag = 1;
7397 else if (*p == '[') {
7398 char *q = p + 1;
7399 if (*q == '!')
7400 q++;
7401 for (;;) {
7402 if (*q == '\\')
7403 q++;
7404 if (*q == '/' || *q == '\0')
7405 break;
7406 if (*++q == ']') {
7407 metaflag = 1;
7408 break;
7409 }
7410 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007411 } else {
7412 if (*p == '\\')
7413 esc++;
7414 if (p[esc] == '/') {
7415 if (metaflag)
7416 break;
7417 start = p + esc + 1;
7418 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007419 }
7420 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007421 if (metaflag == 0) { /* we've reached the end of the file name */
7422 if (enddir != expdir)
7423 metaflag++;
7424 p = name;
7425 do {
7426 if (*p == '\\')
7427 p++;
7428 *enddir++ = *p;
7429 } while (*p++);
7430 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7431 addfname(expdir);
7432 return;
7433 }
7434 endname = p;
7435 if (name < start) {
7436 p = name;
7437 do {
7438 if (*p == '\\')
7439 p++;
7440 *enddir++ = *p++;
7441 } while (p < start);
7442 }
7443 if (enddir == expdir) {
7444 cp = ".";
7445 } else if (enddir == expdir + 1 && *expdir == '/') {
7446 cp = "/";
7447 } else {
7448 cp = expdir;
7449 enddir[-1] = '\0';
7450 }
7451 dirp = opendir(cp);
7452 if (dirp == NULL)
7453 return;
7454 if (enddir != expdir)
7455 enddir[-1] = '/';
7456 if (*endname == 0) {
7457 atend = 1;
7458 } else {
7459 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007460 *endname = '\0';
7461 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007462 }
7463 matchdot = 0;
7464 p = start;
7465 if (*p == '\\')
7466 p++;
7467 if (*p == '.')
7468 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007469 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007470 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007471 continue;
7472 if (pmatch(start, dp->d_name)) {
7473 if (atend) {
7474 strcpy(enddir, dp->d_name);
7475 addfname(expdir);
7476 } else {
7477 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7478 continue;
7479 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007480 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007481 }
7482 }
7483 }
7484 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007485 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007486 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007487}
7488
7489static struct strlist *
7490msort(struct strlist *list, int len)
7491{
7492 struct strlist *p, *q = NULL;
7493 struct strlist **lpp;
7494 int half;
7495 int n;
7496
7497 if (len <= 1)
7498 return list;
7499 half = len >> 1;
7500 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007501 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007502 q = p;
7503 p = p->next;
7504 }
7505 q->next = NULL; /* terminate first half of list */
7506 q = msort(list, half); /* sort first half of list */
7507 p = msort(p, len - half); /* sort second half */
7508 lpp = &list;
7509 for (;;) {
7510#if ENABLE_LOCALE_SUPPORT
7511 if (strcoll(p->text, q->text) < 0)
7512#else
7513 if (strcmp(p->text, q->text) < 0)
7514#endif
7515 {
7516 *lpp = p;
7517 lpp = &p->next;
7518 p = *lpp;
7519 if (p == NULL) {
7520 *lpp = q;
7521 break;
7522 }
7523 } else {
7524 *lpp = q;
7525 lpp = &q->next;
7526 q = *lpp;
7527 if (q == NULL) {
7528 *lpp = p;
7529 break;
7530 }
7531 }
7532 }
7533 return list;
7534}
7535
7536/*
7537 * Sort the results of file name expansion. It calculates the number of
7538 * strings to sort and then calls msort (short for merge sort) to do the
7539 * work.
7540 */
7541static struct strlist *
7542expsort(struct strlist *str)
7543{
7544 int len;
7545 struct strlist *sp;
7546
7547 len = 0;
7548 for (sp = str; sp; sp = sp->next)
7549 len++;
7550 return msort(str, len);
7551}
7552
7553static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007554expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007555{
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007556 /* TODO - EXP_REDIR */
7557
7558 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007559 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007560 struct strlist **savelastp;
7561 struct strlist *sp;
7562 char *p;
7563
7564 if (fflag)
7565 goto nometa;
Felix Fietkaub5b21122017-01-31 21:58:55 +01007566 if (!hasmeta(str->text))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007567 goto nometa;
7568 savelastp = exparg.lastp;
7569
7570 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007571 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007572 {
7573 int i = strlen(str->text);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007574//BUGGY estimation of how long expanded name can be
7575 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007576 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007577 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007578 free(expdir);
7579 if (p != str->text)
7580 free(p);
7581 INT_ON;
7582 if (exparg.lastp == savelastp) {
7583 /*
7584 * no matches
7585 */
7586 nometa:
7587 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007588 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007589 exparg.lastp = &str->next;
7590 } else {
7591 *exparg.lastp = NULL;
7592 *savelastp = sp = expsort(*savelastp);
7593 while (sp->next != NULL)
7594 sp = sp->next;
7595 exparg.lastp = &sp->next;
7596 }
7597 str = str->next;
7598 }
7599}
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007600#endif /* ENABLE_ASH_INTERNAL_GLOB */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007601
7602/*
7603 * Perform variable substitution and command substitution on an argument,
7604 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7605 * perform splitting and file name expansion. When arglist is NULL, perform
7606 * here document expansion.
7607 */
7608static void
7609expandarg(union node *arg, struct arglist *arglist, int flag)
7610{
7611 struct strlist *sp;
7612 char *p;
7613
7614 argbackq = arg->narg.backquote;
7615 STARTSTACKSTR(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007616 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007617 argstr(arg->narg.text, flag,
7618 /* var_str_list: */ arglist ? arglist->list : NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007619 p = _STPUTC('\0', expdest);
7620 expdest = p - 1;
7621 if (arglist == NULL) {
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007622 /* here document expanded */
7623 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007624 }
7625 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007626 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007627 exparg.lastp = &exparg.list;
7628 /*
7629 * TODO - EXP_REDIR
7630 */
7631 if (flag & EXP_FULL) {
7632 ifsbreakup(p, &exparg);
7633 *exparg.lastp = NULL;
7634 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007635 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007636 } else {
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007637 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007638 rmescapes(p, 0);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007639 TRACE(("expandarg: rmescapes:'%s'\n", p));
7640 }
Denis Vlasenko597906c2008-02-20 16:38:54 +00007641 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007642 sp->text = p;
7643 *exparg.lastp = sp;
7644 exparg.lastp = &sp->next;
7645 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007646 *exparg.lastp = NULL;
7647 if (exparg.list) {
7648 *arglist->lastp = exparg.list;
7649 arglist->lastp = exparg.lastp;
7650 }
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007651
7652 out:
7653 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007654}
7655
7656/*
7657 * Expand shell variables and backquotes inside a here document.
7658 */
7659static void
7660expandhere(union node *arg, int fd)
7661{
Ron Yorston549deab2015-05-18 09:57:51 +02007662 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007663 full_write(fd, stackblock(), expdest - (char *)stackblock());
7664}
7665
7666/*
7667 * Returns true if the pattern matches the string.
7668 */
7669static int
7670patmatch(char *pattern, const char *string)
7671{
Denys Vlasenkobd43c672017-07-05 23:12:15 +02007672 char *p = preglob(pattern, 0);
7673 //bb_error_msg("fnmatch(pattern:'%s',str:'%s')", p, string);
7674 return pmatch(p, string);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007675}
7676
7677/*
7678 * See if a pattern matches in a case statement.
7679 */
7680static int
7681casematch(union node *pattern, char *val)
7682{
7683 struct stackmark smark;
7684 int result;
7685
7686 setstackmark(&smark);
7687 argbackq = pattern->narg.backquote;
7688 STARTSTACKSTR(expdest);
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007689 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7690 /* var_str_list: */ NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007691 STACKSTRNUL(expdest);
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007692 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007693 result = patmatch(stackblock(), val);
7694 popstackmark(&smark);
7695 return result;
7696}
7697
7698
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007699/* ============ find_command */
7700
7701struct builtincmd {
7702 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007703 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007704 /* unsigned flags; */
7705};
7706#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007707/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007708 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007709#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007710#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007711
7712struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007713 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007714 union param {
7715 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007716 /* index >= 0 for commands without path (slashes) */
7717 /* (TODO: what exactly does the value mean? PATH position?) */
7718 /* index == -1 for commands with slashes */
7719 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007720 const struct builtincmd *cmd;
7721 struct funcnode *func;
7722 } u;
7723};
7724/* values of cmdtype */
7725#define CMDUNKNOWN -1 /* no entry in table for command */
7726#define CMDNORMAL 0 /* command is an executable program */
7727#define CMDFUNCTION 1 /* command is a shell function */
7728#define CMDBUILTIN 2 /* command is a shell builtin */
7729
7730/* action to find_command() */
7731#define DO_ERR 0x01 /* prints errors */
7732#define DO_ABS 0x02 /* checks absolute paths */
7733#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7734#define DO_ALTPATH 0x08 /* using alternate path */
7735#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7736
7737static void find_command(char *, struct cmdentry *, int, const char *);
7738
7739
7740/* ============ Hashing commands */
7741
7742/*
7743 * When commands are first encountered, they are entered in a hash table.
7744 * This ensures that a full path search will not have to be done for them
7745 * on each invocation.
7746 *
7747 * We should investigate converting to a linear search, even though that
7748 * would make the command name "hash" a misnomer.
7749 */
7750
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007751struct tblentry {
7752 struct tblentry *next; /* next entry in hash chain */
7753 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007754 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007755 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007756 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007757};
7758
Denis Vlasenko01631112007-12-16 17:20:38 +00007759static struct tblentry **cmdtable;
7760#define INIT_G_cmdtable() do { \
7761 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7762} while (0)
7763
7764static int builtinloc = -1; /* index in path of %builtin, or -1 */
7765
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007766
7767static void
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007768tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007769{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007770#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007771 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007772 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007773 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007774 while (*envp)
7775 putenv(*envp++);
Denys Vlasenko69a5ec92017-07-07 19:08:56 +02007776 run_applet_no_and_exit(applet_no, cmd, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007777 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007778 /* re-exec ourselves with the new arguments */
7779 execve(bb_busybox_exec_path, argv, envp);
7780 /* If they called chroot or otherwise made the binary no longer
7781 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007782 }
7783#endif
7784
7785 repeat:
7786#ifdef SYSV
7787 do {
7788 execve(cmd, argv, envp);
7789 } while (errno == EINTR);
7790#else
7791 execve(cmd, argv, envp);
7792#endif
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007793 if (cmd != (char*) bb_busybox_exec_path && errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007794 /* Run "cmd" as a shell script:
7795 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7796 * "If the execve() function fails with ENOEXEC, the shell
7797 * shall execute a command equivalent to having a shell invoked
7798 * with the command name as its first operand,
7799 * with any remaining arguments passed to the new shell"
7800 *
7801 * That is, do not use $SHELL, user's shell, or /bin/sh;
7802 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007803 *
7804 * Note that bash reads ~80 chars of the file, and if it sees
7805 * a zero byte before it sees newline, it doesn't try to
7806 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007807 * message and exit code 126. For one, this prevents attempts
7808 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007809 */
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007810 argv[0] = cmd;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007811 cmd = (char*) bb_busybox_exec_path;
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007812 /* NB: this is only possible because all callers of shellexec()
7813 * ensure that the argv[-1] slot exists!
7814 */
7815 argv--;
7816 argv[0] = (char*) "ash";
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007817 goto repeat;
7818 }
7819}
7820
7821/*
7822 * Exec a program. Never returns. If you change this routine, you may
7823 * have to change the find_command routine as well.
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007824 * argv[-1] must exist and be writable! See tryexec() for why.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007825 */
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007826static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN;
7827static void shellexec(char *prog, char **argv, const char *path, int idx)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007828{
7829 char *cmdname;
7830 int e;
7831 char **envp;
7832 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007833 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007834
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007835 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007836 if (strchr(prog, '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007837#if ENABLE_FEATURE_SH_STANDALONE
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007838 || (applet_no = find_applet_by_name(prog)) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007839#endif
7840 ) {
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007841 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007842 if (applet_no >= 0) {
7843 /* We tried execing ourself, but it didn't work.
7844 * Maybe /proc/self/exe doesn't exist?
7845 * Try $PATH search.
7846 */
7847 goto try_PATH;
7848 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007849 e = errno;
7850 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007851 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007852 e = ENOENT;
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007853 while ((cmdname = path_advance(&path, prog)) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007854 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007855 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007856 if (errno != ENOENT && errno != ENOTDIR)
7857 e = errno;
7858 }
7859 stunalloc(cmdname);
7860 }
7861 }
7862
7863 /* Map to POSIX errors */
7864 switch (e) {
7865 case EACCES:
7866 exerrno = 126;
7867 break;
7868 case ENOENT:
7869 exerrno = 127;
7870 break;
7871 default:
7872 exerrno = 2;
7873 break;
7874 }
7875 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007876 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007877 prog, e, suppress_int));
7878 ash_msg_and_raise(EXEXIT, "%s: %s", prog, errmsg(e, "not found"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007879 /* NOTREACHED */
7880}
7881
7882static void
7883printentry(struct tblentry *cmdp)
7884{
7885 int idx;
7886 const char *path;
7887 char *name;
7888
7889 idx = cmdp->param.index;
7890 path = pathval();
7891 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007892 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007893 stunalloc(name);
7894 } while (--idx >= 0);
7895 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7896}
7897
7898/*
7899 * Clear out command entries. The argument specifies the first entry in
7900 * PATH which has changed.
7901 */
7902static void
7903clearcmdentry(int firstchange)
7904{
7905 struct tblentry **tblp;
7906 struct tblentry **pp;
7907 struct tblentry *cmdp;
7908
7909 INT_OFF;
7910 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7911 pp = tblp;
7912 while ((cmdp = *pp) != NULL) {
7913 if ((cmdp->cmdtype == CMDNORMAL &&
7914 cmdp->param.index >= firstchange)
7915 || (cmdp->cmdtype == CMDBUILTIN &&
7916 builtinloc >= firstchange)
7917 ) {
7918 *pp = cmdp->next;
7919 free(cmdp);
7920 } else {
7921 pp = &cmdp->next;
7922 }
7923 }
7924 }
7925 INT_ON;
7926}
7927
7928/*
7929 * Locate a command in the command hash table. If "add" is nonzero,
7930 * add the command to the table if it is not already present. The
7931 * variable "lastcmdentry" is set to point to the address of the link
7932 * pointing to the entry, so that delete_cmd_entry can delete the
7933 * entry.
7934 *
7935 * Interrupts must be off if called with add != 0.
7936 */
7937static struct tblentry **lastcmdentry;
7938
7939static struct tblentry *
7940cmdlookup(const char *name, int add)
7941{
7942 unsigned int hashval;
7943 const char *p;
7944 struct tblentry *cmdp;
7945 struct tblentry **pp;
7946
7947 p = name;
7948 hashval = (unsigned char)*p << 4;
7949 while (*p)
7950 hashval += (unsigned char)*p++;
7951 hashval &= 0x7FFF;
7952 pp = &cmdtable[hashval % CMDTABLESIZE];
7953 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7954 if (strcmp(cmdp->cmdname, name) == 0)
7955 break;
7956 pp = &cmdp->next;
7957 }
7958 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007959 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7960 + strlen(name)
7961 /* + 1 - already done because
7962 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007963 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007964 cmdp->cmdtype = CMDUNKNOWN;
7965 strcpy(cmdp->cmdname, name);
7966 }
7967 lastcmdentry = pp;
7968 return cmdp;
7969}
7970
7971/*
7972 * Delete the command entry returned on the last lookup.
7973 */
7974static void
7975delete_cmd_entry(void)
7976{
7977 struct tblentry *cmdp;
7978
7979 INT_OFF;
7980 cmdp = *lastcmdentry;
7981 *lastcmdentry = cmdp->next;
7982 if (cmdp->cmdtype == CMDFUNCTION)
7983 freefunc(cmdp->param.func);
7984 free(cmdp);
7985 INT_ON;
7986}
7987
7988/*
7989 * Add a new command entry, replacing any existing command entry for
7990 * the same name - except special builtins.
7991 */
7992static void
7993addcmdentry(char *name, struct cmdentry *entry)
7994{
7995 struct tblentry *cmdp;
7996
7997 cmdp = cmdlookup(name, 1);
7998 if (cmdp->cmdtype == CMDFUNCTION) {
7999 freefunc(cmdp->param.func);
8000 }
8001 cmdp->cmdtype = entry->cmdtype;
8002 cmdp->param = entry->u;
8003 cmdp->rehash = 0;
8004}
8005
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008006static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008007hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008008{
8009 struct tblentry **pp;
8010 struct tblentry *cmdp;
8011 int c;
8012 struct cmdentry entry;
8013 char *name;
8014
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008015 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008016 clearcmdentry(0);
8017 return 0;
8018 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008019
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008020 if (*argptr == NULL) {
8021 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8022 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8023 if (cmdp->cmdtype == CMDNORMAL)
8024 printentry(cmdp);
8025 }
8026 }
8027 return 0;
8028 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008029
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008030 c = 0;
8031 while ((name = *argptr) != NULL) {
8032 cmdp = cmdlookup(name, 0);
8033 if (cmdp != NULL
8034 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008035 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
8036 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008037 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008038 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008039 find_command(name, &entry, DO_ERR, pathval());
8040 if (entry.cmdtype == CMDUNKNOWN)
8041 c = 1;
8042 argptr++;
8043 }
8044 return c;
8045}
8046
8047/*
8048 * Called when a cd is done. Marks all commands so the next time they
8049 * are executed they will be rehashed.
8050 */
8051static void
8052hashcd(void)
8053{
8054 struct tblentry **pp;
8055 struct tblentry *cmdp;
8056
8057 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8058 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008059 if (cmdp->cmdtype == CMDNORMAL
8060 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02008061 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008062 && builtinloc > 0)
8063 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008064 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008065 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008066 }
8067 }
8068}
8069
8070/*
8071 * Fix command hash table when PATH changed.
8072 * Called before PATH is changed. The argument is the new value of PATH;
8073 * pathval() still returns the old value at this point.
8074 * Called with interrupts off.
8075 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008076static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008077changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008078{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008079 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008080 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008081 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008082 int idx_bltin;
8083
8084 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008085 firstchange = 9999; /* assume no change */
8086 idx = 0;
8087 idx_bltin = -1;
8088 for (;;) {
8089 if (*old != *new) {
8090 firstchange = idx;
8091 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008092 || (*old == ':' && *new == '\0')
8093 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008094 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008095 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008096 old = new; /* ignore subsequent differences */
8097 }
8098 if (*new == '\0')
8099 break;
8100 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
8101 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008102 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008103 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008104 new++;
8105 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008106 }
8107 if (builtinloc < 0 && idx_bltin >= 0)
8108 builtinloc = idx_bltin; /* zap builtins */
8109 if (builtinloc >= 0 && idx_bltin < 0)
8110 firstchange = 0;
8111 clearcmdentry(firstchange);
8112 builtinloc = idx_bltin;
8113}
Ron Yorston95ebcf72015-11-03 09:42:23 +00008114enum {
8115 TEOF,
8116 TNL,
8117 TREDIR,
8118 TWORD,
8119 TSEMI,
8120 TBACKGND,
8121 TAND,
8122 TOR,
8123 TPIPE,
8124 TLP,
8125 TRP,
8126 TENDCASE,
8127 TENDBQUOTE,
8128 TNOT,
8129 TCASE,
8130 TDO,
8131 TDONE,
8132 TELIF,
8133 TELSE,
8134 TESAC,
8135 TFI,
8136 TFOR,
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008137#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +00008138 TFUNCTION,
8139#endif
8140 TIF,
8141 TIN,
8142 TTHEN,
8143 TUNTIL,
8144 TWHILE,
8145 TBEGIN,
8146 TEND
8147};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008148typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008149
Denys Vlasenko888527c2016-10-02 16:54:17 +02008150/* Nth bit indicates if token marks the end of a list */
8151enum {
8152 tokendlist = 0
8153 /* 0 */ | (1u << TEOF)
8154 /* 1 */ | (0u << TNL)
8155 /* 2 */ | (0u << TREDIR)
8156 /* 3 */ | (0u << TWORD)
8157 /* 4 */ | (0u << TSEMI)
8158 /* 5 */ | (0u << TBACKGND)
8159 /* 6 */ | (0u << TAND)
8160 /* 7 */ | (0u << TOR)
8161 /* 8 */ | (0u << TPIPE)
8162 /* 9 */ | (0u << TLP)
8163 /* 10 */ | (1u << TRP)
8164 /* 11 */ | (1u << TENDCASE)
8165 /* 12 */ | (1u << TENDBQUOTE)
8166 /* 13 */ | (0u << TNOT)
8167 /* 14 */ | (0u << TCASE)
8168 /* 15 */ | (1u << TDO)
8169 /* 16 */ | (1u << TDONE)
8170 /* 17 */ | (1u << TELIF)
8171 /* 18 */ | (1u << TELSE)
8172 /* 19 */ | (1u << TESAC)
8173 /* 20 */ | (1u << TFI)
8174 /* 21 */ | (0u << TFOR)
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008175#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008176 /* 22 */ | (0u << TFUNCTION)
Denys Vlasenko80729a42016-10-02 22:33:15 +02008177#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008178 /* 23 */ | (0u << TIF)
8179 /* 24 */ | (0u << TIN)
8180 /* 25 */ | (1u << TTHEN)
8181 /* 26 */ | (0u << TUNTIL)
8182 /* 27 */ | (0u << TWHILE)
8183 /* 28 */ | (0u << TBEGIN)
8184 /* 29 */ | (1u << TEND)
8185 , /* thus far 29 bits used */
8186};
8187
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008188static const char *const tokname_array[] = {
Denys Vlasenko888527c2016-10-02 16:54:17 +02008189 "end of file",
8190 "newline",
8191 "redirection",
8192 "word",
8193 ";",
8194 "&",
8195 "&&",
8196 "||",
8197 "|",
8198 "(",
8199 ")",
8200 ";;",
8201 "`",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008202#define KWDOFFSET 13
8203 /* the following are keywords */
Denys Vlasenko888527c2016-10-02 16:54:17 +02008204 "!",
8205 "case",
8206 "do",
8207 "done",
8208 "elif",
8209 "else",
8210 "esac",
8211 "fi",
8212 "for",
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008213#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008214 "function",
Ron Yorston95ebcf72015-11-03 09:42:23 +00008215#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008216 "if",
8217 "in",
8218 "then",
8219 "until",
8220 "while",
8221 "{",
8222 "}",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008223};
8224
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008225/* Wrapper around strcmp for qsort/bsearch/... */
8226static int
8227pstrcmp(const void *a, const void *b)
8228{
Denys Vlasenko888527c2016-10-02 16:54:17 +02008229 return strcmp((char*)a, *(char**)b);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008230}
8231
8232static const char *const *
8233findkwd(const char *s)
8234{
8235 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00008236 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8237 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008238}
8239
8240/*
8241 * Locate and print what a word is...
8242 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008243static int
Ron Yorston3f221112015-08-03 13:47:33 +01008244describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008245{
8246 struct cmdentry entry;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008247#if ENABLE_ASH_ALIAS
8248 const struct alias *ap;
8249#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008250
8251 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008252
8253 if (describe_command_verbose) {
8254 out1str(command);
8255 }
8256
8257 /* First look at the keywords */
8258 if (findkwd(command)) {
8259 out1str(describe_command_verbose ? " is a shell keyword" : command);
8260 goto out;
8261 }
8262
8263#if ENABLE_ASH_ALIAS
8264 /* Then look at the aliases */
8265 ap = lookupalias(command, 0);
8266 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008267 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008268 out1str("alias ");
8269 printalias(ap);
8270 return 0;
8271 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00008272 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008273 goto out;
8274 }
8275#endif
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008276 /* Brute force */
8277 find_command(command, &entry, DO_ABS, path);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008278
8279 switch (entry.cmdtype) {
8280 case CMDNORMAL: {
8281 int j = entry.u.index;
8282 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008283 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008284 p = command;
8285 } else {
8286 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008287 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008288 stunalloc(p);
8289 } while (--j >= 0);
8290 }
8291 if (describe_command_verbose) {
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008292 out1fmt(" is %s", p);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008293 } else {
8294 out1str(p);
8295 }
8296 break;
8297 }
8298
8299 case CMDFUNCTION:
8300 if (describe_command_verbose) {
8301 out1str(" is a shell function");
8302 } else {
8303 out1str(command);
8304 }
8305 break;
8306
8307 case CMDBUILTIN:
8308 if (describe_command_verbose) {
8309 out1fmt(" is a %sshell builtin",
8310 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8311 "special " : nullstr
8312 );
8313 } else {
8314 out1str(command);
8315 }
8316 break;
8317
8318 default:
8319 if (describe_command_verbose) {
8320 out1str(": not found\n");
8321 }
8322 return 127;
8323 }
8324 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008325 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008326 return 0;
8327}
8328
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008329static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008330typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008331{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008332 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008333 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008334 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008335
Denis Vlasenko46846e22007-05-20 13:08:31 +00008336 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008337 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008338 i++;
8339 verbose = 0;
8340 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008341 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008342 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008343 }
8344 return err;
8345}
8346
8347#if ENABLE_ASH_CMDCMD
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008348/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8349static char **
8350parse_command_args(char **argv, const char **path)
8351{
8352 char *cp, c;
8353
8354 for (;;) {
8355 cp = *++argv;
8356 if (!cp)
8357 return NULL;
8358 if (*cp++ != '-')
8359 break;
8360 c = *cp++;
8361 if (!c)
8362 break;
8363 if (c == '-' && !*cp) {
8364 if (!*++argv)
8365 return NULL;
8366 break;
8367 }
8368 do {
8369 switch (c) {
8370 case 'p':
8371 *path = bb_default_path;
8372 break;
8373 default:
8374 /* run 'typecmd' for other options */
8375 return NULL;
8376 }
8377 c = *cp++;
8378 } while (c);
8379 }
8380 return argv;
8381}
8382
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008383static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008384commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008385{
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008386 char *cmd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008387 int c;
8388 enum {
8389 VERIFY_BRIEF = 1,
8390 VERIFY_VERBOSE = 2,
8391 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008392 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008393
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008394 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8395 * never reaches this function.
8396 */
8397
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008398 while ((c = nextopt("pvV")) != '\0')
8399 if (c == 'V')
8400 verify |= VERIFY_VERBOSE;
8401 else if (c == 'v')
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008402 /*verify |= VERIFY_BRIEF*/;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008403#if DEBUG
8404 else if (c != 'p')
8405 abort();
8406#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008407 else
8408 path = bb_default_path;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008409
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008410 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008411 cmd = *argptr;
8412 if (/*verify && */ cmd)
8413 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008414
8415 return 0;
8416}
8417#endif
8418
8419
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008420/*static int funcblocksize; // size of structures in function */
8421/*static int funcstringsize; // size of strings in node */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008422static void *funcblock; /* block to allocate function from */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008423static char *funcstring_end; /* end of block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008424
Eric Andersencb57d552001-06-28 07:25:16 +00008425/* flags in argument to evaltree */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008426#define EV_EXIT 01 /* exit after evaluating tree */
8427#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Eric Andersencb57d552001-06-28 07:25:16 +00008428
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008429static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008430 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8431 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8432 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8433 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8434 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8435 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8436 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8437 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8438 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8439 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8440 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8441 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8442 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8443 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8444 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8445 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8446 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008447#if BASH_REDIR_OUTPUT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008448 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008449#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008450 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8451 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8452 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8453 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8454 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8455 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8456 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8457 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8458 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008459};
8460
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008461static int calcsize(int funcblocksize, union node *n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008462
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008463static int
8464sizenodelist(int funcblocksize, struct nodelist *lp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008465{
8466 while (lp) {
8467 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008468 funcblocksize = calcsize(funcblocksize, lp->n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008469 lp = lp->next;
8470 }
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008471 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008472}
8473
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008474static int
8475calcsize(int funcblocksize, union node *n)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008476{
8477 if (n == NULL)
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008478 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008479 funcblocksize += nodesize[n->type];
8480 switch (n->type) {
8481 case NCMD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008482 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8483 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8484 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008485 break;
8486 case NPIPE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008487 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008488 break;
8489 case NREDIR:
8490 case NBACKGND:
8491 case NSUBSHELL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008492 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8493 funcblocksize = calcsize(funcblocksize, n->nredir.n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008494 break;
8495 case NAND:
8496 case NOR:
8497 case NSEMI:
8498 case NWHILE:
8499 case NUNTIL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008500 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8501 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008502 break;
8503 case NIF:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008504 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8505 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8506 funcblocksize = calcsize(funcblocksize, n->nif.test);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008507 break;
8508 case NFOR:
Denys Vlasenko561639a2016-10-07 04:28:33 +02008509 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008510 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8511 funcblocksize = calcsize(funcblocksize, n->nfor.args);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008512 break;
8513 case NCASE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008514 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8515 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008516 break;
8517 case NCLIST:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008518 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8519 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8520 funcblocksize = calcsize(funcblocksize, n->nclist.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008521 break;
8522 case NDEFUN:
8523 case NARG:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008524 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
Denys Vlasenko561639a2016-10-07 04:28:33 +02008525 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008526 funcblocksize = calcsize(funcblocksize, n->narg.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008527 break;
8528 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008529#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008530 case NTO2:
8531#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008532 case NCLOBBER:
8533 case NFROM:
8534 case NFROMTO:
8535 case NAPPEND:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008536 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8537 funcblocksize = calcsize(funcblocksize, n->nfile.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008538 break;
8539 case NTOFD:
8540 case NFROMFD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008541 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8542 funcblocksize = calcsize(funcblocksize, n->ndup.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008543 break;
8544 case NHERE:
8545 case NXHERE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008546 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8547 funcblocksize = calcsize(funcblocksize, n->nhere.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008548 break;
8549 case NNOT:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008550 funcblocksize = calcsize(funcblocksize, n->nnot.com);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008551 break;
8552 };
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008553 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008554}
8555
8556static char *
8557nodeckstrdup(char *s)
8558{
Denys Vlasenko561639a2016-10-07 04:28:33 +02008559 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008560 return strcpy(funcstring_end, s);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008561}
8562
8563static union node *copynode(union node *);
8564
8565static struct nodelist *
8566copynodelist(struct nodelist *lp)
8567{
8568 struct nodelist *start;
8569 struct nodelist **lpp;
8570
8571 lpp = &start;
8572 while (lp) {
8573 *lpp = funcblock;
8574 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8575 (*lpp)->n = copynode(lp->n);
8576 lp = lp->next;
8577 lpp = &(*lpp)->next;
8578 }
8579 *lpp = NULL;
8580 return start;
8581}
8582
8583static union node *
8584copynode(union node *n)
8585{
8586 union node *new;
8587
8588 if (n == NULL)
8589 return NULL;
8590 new = funcblock;
8591 funcblock = (char *) funcblock + nodesize[n->type];
8592
8593 switch (n->type) {
8594 case NCMD:
8595 new->ncmd.redirect = copynode(n->ncmd.redirect);
8596 new->ncmd.args = copynode(n->ncmd.args);
8597 new->ncmd.assign = copynode(n->ncmd.assign);
8598 break;
8599 case NPIPE:
8600 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008601 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008602 break;
8603 case NREDIR:
8604 case NBACKGND:
8605 case NSUBSHELL:
8606 new->nredir.redirect = copynode(n->nredir.redirect);
8607 new->nredir.n = copynode(n->nredir.n);
8608 break;
8609 case NAND:
8610 case NOR:
8611 case NSEMI:
8612 case NWHILE:
8613 case NUNTIL:
8614 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8615 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8616 break;
8617 case NIF:
8618 new->nif.elsepart = copynode(n->nif.elsepart);
8619 new->nif.ifpart = copynode(n->nif.ifpart);
8620 new->nif.test = copynode(n->nif.test);
8621 break;
8622 case NFOR:
8623 new->nfor.var = nodeckstrdup(n->nfor.var);
8624 new->nfor.body = copynode(n->nfor.body);
8625 new->nfor.args = copynode(n->nfor.args);
8626 break;
8627 case NCASE:
8628 new->ncase.cases = copynode(n->ncase.cases);
8629 new->ncase.expr = copynode(n->ncase.expr);
8630 break;
8631 case NCLIST:
8632 new->nclist.body = copynode(n->nclist.body);
8633 new->nclist.pattern = copynode(n->nclist.pattern);
8634 new->nclist.next = copynode(n->nclist.next);
8635 break;
8636 case NDEFUN:
8637 case NARG:
8638 new->narg.backquote = copynodelist(n->narg.backquote);
8639 new->narg.text = nodeckstrdup(n->narg.text);
8640 new->narg.next = copynode(n->narg.next);
8641 break;
8642 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008643#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008644 case NTO2:
8645#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008646 case NCLOBBER:
8647 case NFROM:
8648 case NFROMTO:
8649 case NAPPEND:
8650 new->nfile.fname = copynode(n->nfile.fname);
8651 new->nfile.fd = n->nfile.fd;
8652 new->nfile.next = copynode(n->nfile.next);
8653 break;
8654 case NTOFD:
8655 case NFROMFD:
8656 new->ndup.vname = copynode(n->ndup.vname);
8657 new->ndup.dupfd = n->ndup.dupfd;
8658 new->ndup.fd = n->ndup.fd;
8659 new->ndup.next = copynode(n->ndup.next);
8660 break;
8661 case NHERE:
8662 case NXHERE:
8663 new->nhere.doc = copynode(n->nhere.doc);
8664 new->nhere.fd = n->nhere.fd;
8665 new->nhere.next = copynode(n->nhere.next);
8666 break;
8667 case NNOT:
8668 new->nnot.com = copynode(n->nnot.com);
8669 break;
8670 };
8671 new->type = n->type;
8672 return new;
8673}
8674
8675/*
8676 * Make a copy of a parse tree.
8677 */
8678static struct funcnode *
8679copyfunc(union node *n)
8680{
8681 struct funcnode *f;
8682 size_t blocksize;
8683
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008684 /*funcstringsize = 0;*/
8685 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8686 f = ckzalloc(blocksize /* + funcstringsize */);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008687 funcblock = (char *) f + offsetof(struct funcnode, n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008688 funcstring_end = (char *) f + blocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008689 copynode(n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008690 /* f->count = 0; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008691 return f;
8692}
8693
8694/*
8695 * Define a shell function.
8696 */
8697static void
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008698defun(union node *func)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008699{
8700 struct cmdentry entry;
8701
8702 INT_OFF;
8703 entry.cmdtype = CMDFUNCTION;
8704 entry.u.func = copyfunc(func);
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008705 addcmdentry(func->narg.text, &entry);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008706 INT_ON;
8707}
8708
Denis Vlasenko4b875702009-03-19 13:30:04 +00008709/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008710#define SKIPBREAK (1 << 0)
8711#define SKIPCONT (1 << 1)
8712#define SKIPFUNC (1 << 2)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008713static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008714static int skipcount; /* number of levels to skip */
8715static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008716static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008717
Denis Vlasenko4b875702009-03-19 13:30:04 +00008718/* Forward decl way out to parsing code - dotrap needs it */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008719static int evalstring(char *s, int flags);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008720
Denis Vlasenko4b875702009-03-19 13:30:04 +00008721/* Called to execute a trap.
8722 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008723 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008724 *
8725 * Perhaps we should avoid entering new trap handlers
8726 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008727 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008728static void
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008729dotrap(void)
8730{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008731 uint8_t *g;
8732 int sig;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008733 uint8_t last_status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008734
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008735 if (!pending_sig)
8736 return;
8737
8738 last_status = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008739 pending_sig = 0;
Denys Vlasenkode892052016-10-02 01:49:13 +02008740 barrier();
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008741
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008742 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008743 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008744 char *p;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008745
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008746 if (!*g)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008747 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008748
8749 if (evalskip) {
8750 pending_sig = sig;
8751 break;
8752 }
8753
8754 p = trap[sig];
Denis Vlasenko4b875702009-03-19 13:30:04 +00008755 /* non-trapped SIGINT is handled separately by raise_interrupt,
8756 * don't upset it by resetting gotsig[SIGINT-1] */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008757 if (sig == SIGINT && !p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008758 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008759
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008760 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008761 *g = 0;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008762 if (!p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008763 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008764 evalstring(p, 0);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008765 }
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008766 exitstatus = last_status;
8767 TRACE(("dotrap returns\n"));
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008768}
8769
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008770/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008771static int evalloop(union node *, int);
8772static int evalfor(union node *, int);
8773static int evalcase(union node *, int);
8774static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008775static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008776static int evalpipe(union node *, int);
8777static int evalcommand(union node *, int);
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008778static int evalbltin(const struct builtincmd *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008779static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008780
Eric Andersen62483552001-07-10 06:09:16 +00008781/*
Eric Andersenc470f442003-07-28 09:56:35 +00008782 * Evaluate a parse tree. The value is left in the global variable
8783 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008784 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008785static int
Eric Andersenc470f442003-07-28 09:56:35 +00008786evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008787{
Eric Andersenc470f442003-07-28 09:56:35 +00008788 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008789 int (*evalfn)(union node *, int);
8790 int status = 0;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008791
Eric Andersenc470f442003-07-28 09:56:35 +00008792 if (n == NULL) {
8793 TRACE(("evaltree(NULL) called\n"));
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02008794 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00008795 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008796 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008797
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008798 dotrap();
8799
Eric Andersenc470f442003-07-28 09:56:35 +00008800 switch (n->type) {
8801 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008802#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008803 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008804 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008805 break;
8806#endif
8807 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008808 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008809 goto setstatus;
8810 case NREDIR:
8811 expredir(n->nredir.redirect);
8812 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8813 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008814 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008815 }
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02008816 if (n->nredir.redirect)
8817 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
Eric Andersenc470f442003-07-28 09:56:35 +00008818 goto setstatus;
8819 case NCMD:
8820 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008821 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008822 if (eflag && !(flags & EV_TESTED))
8823 checkexit = ~0;
8824 goto calleval;
8825 case NFOR:
8826 evalfn = evalfor;
8827 goto calleval;
8828 case NWHILE:
8829 case NUNTIL:
8830 evalfn = evalloop;
8831 goto calleval;
8832 case NSUBSHELL:
8833 case NBACKGND:
8834 evalfn = evalsubshell;
Denys Vlasenkocf98b0c2016-10-25 18:19:39 +02008835 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00008836 case NPIPE:
8837 evalfn = evalpipe;
8838 goto checkexit;
8839 case NCASE:
8840 evalfn = evalcase;
8841 goto calleval;
8842 case NAND:
8843 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008844 case NSEMI: {
8845
Eric Andersenc470f442003-07-28 09:56:35 +00008846#if NAND + 1 != NOR
8847#error NAND + 1 != NOR
8848#endif
8849#if NOR + 1 != NSEMI
8850#error NOR + 1 != NSEMI
8851#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008852 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008853 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00008854 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008855 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008856 );
Denys Vlasenkobc1a0082016-10-02 15:31:33 +02008857 if ((!status) == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00008858 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008859 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008860 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008861 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008862 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008863 status = evalfn(n, flags);
8864 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008865 }
Eric Andersenc470f442003-07-28 09:56:35 +00008866 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008867 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008868 if (evalskip)
8869 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008870 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00008871 n = n->nif.ifpart;
8872 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008873 }
8874 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008875 n = n->nif.elsepart;
8876 goto evaln;
8877 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008878 status = 0;
8879 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00008880 case NDEFUN:
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008881 defun(n);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008882 /* Not necessary. To test it:
8883 * "false; f() { qwerty; }; echo $?" should print 0.
8884 */
8885 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008886 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00008887 exitstatus = status;
8888 break;
8889 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008890 out:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008891 /* Order of checks below is important:
8892 * signal handlers trigger before exit caused by "set -e".
8893 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008894 dotrap();
8895
8896 if (checkexit & status)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008897 raise_exception(EXEXIT);
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008898 if (flags & EV_EXIT)
8899 raise_exception(EXEXIT);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008900
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008901 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008902 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00008903}
8904
Eric Andersenc470f442003-07-28 09:56:35 +00008905#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8906static
8907#endif
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008908int evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
Eric Andersenc470f442003-07-28 09:56:35 +00008909
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02008910static int
8911skiploop(void)
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008912{
8913 int skip = evalskip;
8914
8915 switch (skip) {
8916 case 0:
8917 break;
8918 case SKIPBREAK:
8919 case SKIPCONT:
8920 if (--skipcount <= 0) {
8921 evalskip = 0;
8922 break;
8923 }
8924 skip = SKIPBREAK;
8925 break;
8926 }
8927 return skip;
8928}
8929
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008930static int
Eric Andersenc470f442003-07-28 09:56:35 +00008931evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008932{
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008933 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00008934 int status;
8935
8936 loopnest++;
8937 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008938 flags &= EV_TESTED;
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008939 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008940 int i;
8941
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008942 i = evaltree(n->nbinary.ch1, EV_TESTED);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008943 skip = skiploop();
8944 if (skip == SKIPFUNC)
8945 status = i;
8946 if (skip)
8947 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00008948 if (n->type != NWHILE)
8949 i = !i;
8950 if (i != 0)
8951 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008952 status = evaltree(n->nbinary.ch2, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008953 skip = skiploop();
8954 } while (!(skip & ~SKIPCONT));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008955 loopnest--;
8956
8957 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008958}
8959
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008960static int
Eric Andersenc470f442003-07-28 09:56:35 +00008961evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008962{
8963 struct arglist arglist;
8964 union node *argp;
8965 struct strlist *sp;
8966 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008967 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008968
8969 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008970 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008971 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008972 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02008973 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersencb57d552001-06-28 07:25:16 +00008974 }
8975 *arglist.lastp = NULL;
8976
Eric Andersencb57d552001-06-28 07:25:16 +00008977 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008978 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008979 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008980 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008981 status = evaltree(n->nfor.body, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008982 if (skiploop() & ~SKIPCONT)
Eric Andersencb57d552001-06-28 07:25:16 +00008983 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008984 }
8985 loopnest--;
Eric Andersencb57d552001-06-28 07:25:16 +00008986 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008987
8988 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008989}
8990
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008991static int
Eric Andersenc470f442003-07-28 09:56:35 +00008992evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008993{
8994 union node *cp;
8995 union node *patp;
8996 struct arglist arglist;
8997 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008998 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008999
9000 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009001 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00009002 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00009003 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009004 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
9005 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00009006 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009007 /* Ensure body is non-empty as otherwise
9008 * EV_EXIT may prevent us from setting the
9009 * exit status.
9010 */
9011 if (evalskip == 0 && cp->nclist.body) {
9012 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00009013 }
9014 goto out;
9015 }
9016 }
9017 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009018 out:
Eric Andersencb57d552001-06-28 07:25:16 +00009019 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009020
9021 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009022}
9023
Eric Andersenc470f442003-07-28 09:56:35 +00009024/*
9025 * Kick off a subshell to evaluate a tree.
9026 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009027static int
Eric Andersenc470f442003-07-28 09:56:35 +00009028evalsubshell(union node *n, int flags)
9029{
9030 struct job *jp;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009031 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
Eric Andersenc470f442003-07-28 09:56:35 +00009032 int status;
9033
9034 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02009035 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00009036 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009037 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009038 if (backgnd == FORK_FG)
9039 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009040 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009041 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009042 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009043 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009044 flags |= EV_EXIT;
9045 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02009046 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00009047 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00009048 redirect(n->nredir.redirect, 0);
9049 evaltreenr(n->nredir.n, flags);
9050 /* never returns */
9051 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009052 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00009053 status = 0;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009054 if (backgnd == FORK_FG)
Eric Andersenc470f442003-07-28 09:56:35 +00009055 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009056 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009057 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009058}
9059
Eric Andersenc470f442003-07-28 09:56:35 +00009060/*
9061 * Compute the names of the files in a redirection list.
9062 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009063static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00009064static void
9065expredir(union node *n)
9066{
9067 union node *redir;
9068
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009069 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009070 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009071
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009072 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009073 fn.lastp = &fn.list;
9074 switch (redir->type) {
9075 case NFROMTO:
9076 case NFROM:
9077 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009078#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009079 case NTO2:
9080#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009081 case NCLOBBER:
9082 case NAPPEND:
9083 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02009084 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009085#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009086 store_expfname:
9087#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009088#if 0
9089// By the design of stack allocator, the loop of this kind:
9090// while true; do while true; do break; done </dev/null; done
9091// will look like a memory leak: ash plans to free expfname's
9092// of "/dev/null" as soon as it finishes running the loop
9093// (in this case, never).
9094// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01009095 if (redir->nfile.expfname)
9096 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009097// It results in corrupted state of stacked allocations.
9098#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009099 redir->nfile.expfname = fn.list->text;
9100 break;
9101 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00009102 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00009103 if (redir->ndup.vname) {
9104 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009105 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009106 ash_msg_and_raise_error("redir error");
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009107#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009108//FIXME: we used expandarg with different args!
9109 if (!isdigit_str9(fn.list->text)) {
9110 /* >&file, not >&fd */
9111 if (redir->nfile.fd != 1) /* 123>&file - BAD */
9112 ash_msg_and_raise_error("redir error");
9113 redir->type = NTO2;
9114 goto store_expfname;
9115 }
9116#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009117 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009118 }
9119 break;
9120 }
9121 }
9122}
9123
Eric Andersencb57d552001-06-28 07:25:16 +00009124/*
Eric Andersencb57d552001-06-28 07:25:16 +00009125 * Evaluate a pipeline. All the processes in the pipeline are children
9126 * of the process creating the pipeline. (This differs from some versions
9127 * of the shell, which make the last process in a pipeline the parent
9128 * of all the rest.)
9129 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009130static int
Eric Andersenc470f442003-07-28 09:56:35 +00009131evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009132{
9133 struct job *jp;
9134 struct nodelist *lp;
9135 int pipelen;
9136 int prevfd;
9137 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009138 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009139
Eric Andersenc470f442003-07-28 09:56:35 +00009140 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00009141 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009142 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00009143 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009144 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009145 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009146 if (n->npipe.pipe_backgnd == 0)
9147 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009148 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00009149 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009150 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009151 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00009152 pip[1] = -1;
9153 if (lp->next) {
9154 if (pipe(pip) < 0) {
9155 close(prevfd);
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00009156 ash_msg_and_raise_error("pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00009157 }
9158 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009159 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02009160 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009161 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00009162 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009163 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00009164 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009165 if (prevfd > 0) {
9166 dup2(prevfd, 0);
9167 close(prevfd);
9168 }
9169 if (pip[1] > 1) {
9170 dup2(pip[1], 1);
9171 close(pip[1]);
9172 }
Eric Andersenc470f442003-07-28 09:56:35 +00009173 evaltreenr(lp->n, flags);
9174 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00009175 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009176 /* parent */
Eric Andersencb57d552001-06-28 07:25:16 +00009177 if (prevfd >= 0)
9178 close(prevfd);
9179 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00009180 /* Don't want to trigger debugging */
9181 if (pip[1] != -1)
9182 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009183 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009184 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009185 status = waitforjob(jp);
9186 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00009187 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009188 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009189
9190 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009191}
9192
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009193/*
9194 * Controls whether the shell is interactive or not.
9195 */
9196static void
9197setinteractive(int on)
9198{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009199 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009200
9201 if (++on == is_interactive)
9202 return;
9203 is_interactive = on;
9204 setsignal(SIGINT);
9205 setsignal(SIGQUIT);
9206 setsignal(SIGTERM);
9207#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9208 if (is_interactive > 1) {
9209 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009210 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009211
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009212 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009213 /* note: ash and hush share this string */
9214 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009215 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9216 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009217 bb_banner,
9218 "built-in shell (ash)"
9219 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009220 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009221 }
9222 }
9223#endif
9224}
9225
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009226static void
9227optschanged(void)
9228{
9229#if DEBUG
9230 opentrace();
9231#endif
9232 setinteractive(iflag);
9233 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009234#if ENABLE_FEATURE_EDITING_VI
9235 if (viflag)
9236 line_input_state->flags |= VI_MODE;
9237 else
9238 line_input_state->flags &= ~VI_MODE;
9239#else
9240 viflag = 0; /* forcibly keep the option off */
9241#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009242}
9243
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009244static struct localvar *localvars;
9245
9246/*
9247 * Called after a function returns.
9248 * Interrupts must be off.
9249 */
9250static void
9251poplocalvars(void)
9252{
9253 struct localvar *lvp;
9254 struct var *vp;
9255
9256 while ((lvp = localvars) != NULL) {
9257 localvars = lvp->next;
9258 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02009259 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009260 if (vp == NULL) { /* $- saved */
9261 memcpy(optlist, lvp->text, sizeof(optlist));
9262 free((char*)lvp->text);
9263 optschanged();
9264 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009265 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009266 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009267 if (vp->var_func)
9268 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009269 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009270 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009271 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009272 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009273 }
9274 free(lvp);
9275 }
9276}
9277
9278static int
9279evalfun(struct funcnode *func, int argc, char **argv, int flags)
9280{
9281 volatile struct shparam saveparam;
9282 struct localvar *volatile savelocalvars;
9283 struct jmploc *volatile savehandler;
9284 struct jmploc jmploc;
9285 int e;
9286
9287 saveparam = shellparam;
9288 savelocalvars = localvars;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009289 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009290 e = setjmp(jmploc.loc);
9291 if (e) {
9292 goto funcdone;
9293 }
9294 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009295 exception_handler = &jmploc;
9296 localvars = NULL;
Denis Vlasenko01631112007-12-16 17:20:38 +00009297 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009298 func->count++;
9299 funcnest++;
9300 INT_ON;
9301 shellparam.nparam = argc - 1;
9302 shellparam.p = argv + 1;
9303#if ENABLE_ASH_GETOPTS
9304 shellparam.optind = 1;
9305 shellparam.optoff = -1;
9306#endif
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009307 evaltree(func->n.narg.next, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00009308 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009309 INT_OFF;
9310 funcnest--;
9311 freefunc(func);
9312 poplocalvars();
9313 localvars = savelocalvars;
9314 freeparam(&shellparam);
9315 shellparam = saveparam;
9316 exception_handler = savehandler;
9317 INT_ON;
9318 evalskip &= ~SKIPFUNC;
9319 return e;
9320}
9321
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009322/*
9323 * Make a variable a local variable. When a variable is made local, it's
9324 * value and flags are saved in a localvar structure. The saved values
9325 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009326 * "-" as a special case: it makes changes to "set +-options" local
9327 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009328 */
9329static void
9330mklocal(char *name)
9331{
9332 struct localvar *lvp;
9333 struct var **vpp;
9334 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009335 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009336
9337 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009338 /* Cater for duplicate "local". Examples:
9339 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9340 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9341 */
9342 lvp = localvars;
9343 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009344 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009345 if (eq)
9346 setvareq(name, 0);
9347 /* else:
9348 * it's a duplicate "local VAR" declaration, do nothing
9349 */
Denys Vlasenko06b11492016-11-04 16:43:18 +01009350 goto ret;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009351 }
9352 lvp = lvp->next;
9353 }
9354
9355 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009356 if (LONE_DASH(name)) {
9357 char *p;
9358 p = ckmalloc(sizeof(optlist));
9359 lvp->text = memcpy(p, optlist, sizeof(optlist));
9360 vp = NULL;
9361 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009362 vpp = hashvar(name);
9363 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009364 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009365 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009366 if (eq)
9367 setvareq(name, VSTRFIXED);
9368 else
9369 setvar(name, NULL, VSTRFIXED);
9370 vp = *vpp; /* the new variable */
9371 lvp->flags = VUNSET;
9372 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009373 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009374 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009375 /* make sure neither "struct var" nor string gets freed
9376 * during (un)setting:
9377 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009378 vp->flags |= VSTRFIXED|VTEXTFIXED;
9379 if (eq)
9380 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009381 else
9382 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009383 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009384 }
9385 }
9386 lvp->vp = vp;
9387 lvp->next = localvars;
9388 localvars = lvp;
Denys Vlasenko06b11492016-11-04 16:43:18 +01009389 ret:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009390 INT_ON;
9391}
9392
9393/*
9394 * The "local" command.
9395 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009396static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009397localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009398{
9399 char *name;
9400
Ron Yorstonef2386b2015-10-29 16:19:14 +00009401 if (!funcnest)
9402 ash_msg_and_raise_error("not in a function");
9403
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009404 argv = argptr;
9405 while ((name = *argv++) != NULL) {
9406 mklocal(name);
9407 }
9408 return 0;
9409}
9410
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009411static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009412falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009413{
9414 return 1;
9415}
9416
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009417static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009418truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009419{
9420 return 0;
9421}
9422
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009423static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009424execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009425{
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009426 optionarg = NULL;
9427 while (nextopt("a:") != '\0')
9428 /* nextopt() sets optionarg to "-a ARGV0" */;
9429
9430 argv = argptr;
9431 if (argv[0]) {
9432 char *prog;
9433
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009434 iflag = 0; /* exit on error */
9435 mflag = 0;
9436 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009437 /* We should set up signals for "exec CMD"
9438 * the same way as for "CMD" without "exec".
9439 * But optschanged->setinteractive->setsignal
9440 * still thought we are a root shell. Therefore, for example,
9441 * SIGQUIT is still set to IGN. Fix it:
9442 */
9443 shlvl++;
9444 setsignal(SIGQUIT);
9445 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9446 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9447 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9448
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009449 prog = argv[0];
9450 if (optionarg)
9451 argv[0] = optionarg;
9452 shellexec(prog, argv, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009453 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009454 }
9455 return 0;
9456}
9457
9458/*
9459 * The return command.
9460 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009461static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009462returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009463{
9464 /*
9465 * If called outside a function, do what ksh does;
9466 * skip the rest of the file.
9467 */
Denys Vlasenko6a0710e2016-09-30 14:18:34 +02009468 evalskip = SKIPFUNC;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009469 return argv[1] ? number(argv[1]) : exitstatus;
9470}
9471
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009472/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009473static int breakcmd(int, char **) FAST_FUNC;
9474static int dotcmd(int, char **) FAST_FUNC;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009475static int evalcmd(int, char **, int) FAST_FUNC;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009476static int exitcmd(int, char **) FAST_FUNC;
9477static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009478#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009479static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009480#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009481#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009482static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009483#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009484#if MAX_HISTORY
9485static int historycmd(int, char **) FAST_FUNC;
9486#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009487#if ENABLE_FEATURE_SH_MATH
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009488static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009489#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009490static int readcmd(int, char **) FAST_FUNC;
9491static int setcmd(int, char **) FAST_FUNC;
9492static int shiftcmd(int, char **) FAST_FUNC;
9493static int timescmd(int, char **) FAST_FUNC;
9494static int trapcmd(int, char **) FAST_FUNC;
9495static int umaskcmd(int, char **) FAST_FUNC;
9496static int unsetcmd(int, char **) FAST_FUNC;
9497static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009498
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009499#define BUILTIN_NOSPEC "0"
9500#define BUILTIN_SPECIAL "1"
9501#define BUILTIN_REGULAR "2"
9502#define BUILTIN_SPEC_REG "3"
9503#define BUILTIN_ASSIGN "4"
9504#define BUILTIN_SPEC_ASSG "5"
9505#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009506#define BUILTIN_SPEC_REG_ASSG "7"
9507
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009508/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko265062d2017-01-10 15:13:30 +01009509#if ENABLE_ASH_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009510static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009511#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009512#if ENABLE_ASH_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009513static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009514#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009515#if ENABLE_ASH_TEST || BASH_TEST2
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009516static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009517#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009518
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009519/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009520static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009521 { BUILTIN_SPEC_REG "." , dotcmd },
9522 { BUILTIN_SPEC_REG ":" , truecmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009523#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009524 { BUILTIN_REGULAR "[" , testcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009525#endif
9526#if BASH_TEST2
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009527 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009528#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009529#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009530 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009531#endif
9532#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009533 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009534#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009535 { BUILTIN_SPEC_REG "break" , breakcmd },
9536 { BUILTIN_REGULAR "cd" , cdcmd },
9537 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009538#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009539 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009540#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009541 { BUILTIN_SPEC_REG "continue", breakcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009542#if ENABLE_ASH_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009543 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009544#endif
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009545 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009546 { BUILTIN_SPEC_REG "exec" , execcmd },
9547 { BUILTIN_SPEC_REG "exit" , exitcmd },
9548 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9549 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009550#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009551 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009552#endif
9553#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009554 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009555#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009556 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009557#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009558 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009559#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009560#if MAX_HISTORY
9561 { BUILTIN_NOSPEC "history" , historycmd },
9562#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009563#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009564 { BUILTIN_REGULAR "jobs" , jobscmd },
9565 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009566#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009567#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009568 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009569#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009570 { BUILTIN_ASSIGN "local" , localcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009571#if ENABLE_ASH_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009572 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009573#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009574 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9575 { BUILTIN_REGULAR "read" , readcmd },
9576 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9577 { BUILTIN_SPEC_REG "return" , returncmd },
9578 { BUILTIN_SPEC_REG "set" , setcmd },
9579 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009580#if BASH_SOURCE
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009581 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009582#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009583#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009584 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009585#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009586 { BUILTIN_SPEC_REG "times" , timescmd },
9587 { BUILTIN_SPEC_REG "trap" , trapcmd },
9588 { BUILTIN_REGULAR "true" , truecmd },
9589 { BUILTIN_NOSPEC "type" , typecmd },
9590 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9591 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009592#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009593 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009594#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009595 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9596 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009597};
9598
Denis Vlasenko80591b02008-03-25 07:49:43 +00009599/* Should match the above table! */
9600#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009601 /* . : */ 2 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009602 /* [ */ 1 * ENABLE_ASH_TEST + \
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009603 /* [[ */ 1 * BASH_TEST2 + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009604 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9605 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9606 /* break cd cddir */ 3)
9607#define EVALCMD (COMMANDCMD + \
9608 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9609 /* continue */ 1 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009610 /* echo */ 1 * ENABLE_ASH_ECHO + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009611 0)
9612#define EXECCMD (EVALCMD + \
9613 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009614
9615/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009616 * Search the table of builtin commands.
9617 */
Denys Vlasenko888527c2016-10-02 16:54:17 +02009618static int
9619pstrcmp1(const void *a, const void *b)
9620{
9621 return strcmp((char*)a, *(char**)b + 1);
9622}
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009623static struct builtincmd *
9624find_builtin(const char *name)
9625{
9626 struct builtincmd *bp;
9627
9628 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009629 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denys Vlasenko888527c2016-10-02 16:54:17 +02009630 pstrcmp1
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009631 );
9632 return bp;
9633}
9634
9635/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009636 * Execute a simple command.
9637 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009638static int
9639isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009640{
9641 const char *q = endofname(p);
9642 if (p == q)
9643 return 0;
9644 return *q == '=';
9645}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009646static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009647bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009648{
9649 /* Preserve exitstatus of a previous possible redirection
9650 * as POSIX mandates */
9651 return back_exitstatus;
9652}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009653static int
Eric Andersenc470f442003-07-28 09:56:35 +00009654evalcommand(union node *cmd, int flags)
9655{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009656 static const struct builtincmd null_bltin = {
9657 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009658 };
Eric Andersenc470f442003-07-28 09:56:35 +00009659 struct stackmark smark;
9660 union node *argp;
9661 struct arglist arglist;
9662 struct arglist varlist;
9663 char **argv;
9664 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009665 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009666 struct cmdentry cmdentry;
9667 struct job *jp;
9668 char *lastarg;
9669 const char *path;
9670 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009671 int status;
9672 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00009673 struct builtincmd *bcmd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009674 smallint cmd_is_exec;
9675 smallint pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009676
9677 /* First expand the arguments. */
9678 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9679 setstackmark(&smark);
9680 back_exitstatus = 0;
9681
9682 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009683 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009684 varlist.lastp = &varlist.list;
9685 *varlist.lastp = NULL;
9686 arglist.lastp = &arglist.list;
9687 *arglist.lastp = NULL;
9688
9689 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009690 if (cmd->ncmd.args) {
Paul Foxc3850c82005-07-20 18:23:39 +00009691 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9692 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9693 }
9694
Eric Andersenc470f442003-07-28 09:56:35 +00009695 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9696 struct strlist **spp;
9697
9698 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00009699 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00009700 expandarg(argp, &arglist, EXP_VARTILDE);
9701 else
9702 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9703
Eric Andersenc470f442003-07-28 09:56:35 +00009704 for (sp = *spp; sp; sp = sp->next)
9705 argc++;
9706 }
9707
Denys Vlasenko65a8b852016-10-26 22:29:11 +02009708 /* Reserve one extra spot at the front for shellexec. */
9709 nargv = stalloc(sizeof(char *) * (argc + 2));
9710 argv = ++nargv;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009711 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009712 TRACE(("evalcommand arg: %s\n", sp->text));
9713 *nargv++ = sp->text;
9714 }
9715 *nargv = NULL;
9716
9717 lastarg = NULL;
9718 if (iflag && funcnest == 0 && argc > 0)
9719 lastarg = nargv[-1];
9720
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009721 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009722 expredir(cmd->ncmd.redirect);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009723 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009724
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009725 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009726 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9727 struct strlist **spp;
9728 char *p;
9729
9730 spp = varlist.lastp;
9731 expandarg(argp, &varlist, EXP_VARTILDE);
9732
9733 /*
9734 * Modify the command lookup path, if a PATH= assignment
9735 * is present
9736 */
9737 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009738 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009739 path = p;
9740 }
9741
9742 /* Print the command if xflag is set. */
9743 if (xflag) {
Denys Vlasenko42ba7572017-07-21 13:20:14 +02009744 const char *pfx = "";
Eric Andersenc470f442003-07-28 09:56:35 +00009745
Denys Vlasenko42ba7572017-07-21 13:20:14 +02009746 fdprintf(preverrout_fd, "%s", expandstr(ps4val()));
9747
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009748 sp = varlist.list;
Denys Vlasenko42ba7572017-07-21 13:20:14 +02009749 while (sp) {
9750 char *varval = sp->text;
9751 char *eq = strchrnul(varval, '=');
9752 if (*eq)
9753 eq++;
9754 fdprintf(preverrout_fd, "%s%.*s%s",
9755 pfx,
9756 (int)(eq - varval), varval,
9757 maybe_single_quote(eq)
9758 );
9759 sp = sp->next;
9760 pfx = " ";
9761 }
9762
9763 sp = arglist.list;
9764 while (sp) {
9765 fdprintf(preverrout_fd, "%s%s",
9766 pfx,
9767 /* always quote if matches reserved word: */
9768 findkwd(sp->text)
9769 ? single_quote(sp->text)
9770 : maybe_single_quote(sp->text)
9771 );
9772 sp = sp->next;
9773 pfx = " ";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009774 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009775 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009776 }
9777
9778 cmd_is_exec = 0;
9779 spclbltin = -1;
9780
9781 /* Now locate the command. */
9782 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009783 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02009784#if ENABLE_ASH_CMDCMD
9785 const char *oldpath = path + 5;
9786#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009787 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009788 for (;;) {
9789 find_command(argv[0], &cmdentry, cmd_flag, path);
9790 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009791 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009792 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009793 goto bail;
9794 }
9795
9796 /* implement bltin and command here */
9797 if (cmdentry.cmdtype != CMDBUILTIN)
9798 break;
9799 if (spclbltin < 0)
9800 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9801 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009802 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009803#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009804 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009805 path = oldpath;
9806 nargv = parse_command_args(argv, &path);
9807 if (!nargv)
9808 break;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02009809 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
9810 * nargv => "PROG". path is updated if -p.
9811 */
Eric Andersenc470f442003-07-28 09:56:35 +00009812 argc -= nargv - argv;
9813 argv = nargv;
9814 cmd_flag |= DO_NOFUNC;
9815 } else
9816#endif
9817 break;
9818 }
9819 }
9820
9821 if (status) {
Ron Yorstonea7d2f62017-01-03 11:18:23 +01009822 bail:
9823 exitstatus = status;
9824
Eric Andersenc470f442003-07-28 09:56:35 +00009825 /* We have a redirection error. */
9826 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009827 raise_exception(EXERROR);
Ron Yorstonea7d2f62017-01-03 11:18:23 +01009828
Eric Andersenc470f442003-07-28 09:56:35 +00009829 goto out;
9830 }
9831
9832 /* Execute the command. */
9833 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009834 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009835
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009836#if ENABLE_FEATURE_SH_NOFORK
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009837/* (1) BUG: if variables are set, we need to fork, or save/restore them
9838 * around run_nofork_applet() call.
9839 * (2) Should this check also be done in forkshell()?
9840 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9841 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009842 /* find_command() encodes applet_no as (-2 - applet_no) */
9843 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009844 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009845 listsetvar(varlist.list, VEXPORT|VSTACK);
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009846 /* run <applet>_main() */
Ron Yorston5ccb0e92016-10-20 12:24:02 +01009847 status = run_nofork_applet(applet_no, argv);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009848 break;
9849 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009850#endif
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009851 /* Can we avoid forking off? For example, very last command
9852 * in a script or a subshell does not need forking,
9853 * we can just exec it.
9854 */
Denys Vlasenko238bf182010-05-18 15:49:07 +02009855 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009856 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009857 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009858 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009859 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009860 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009861 /* parent */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009862 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009863 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009864 TRACE(("forked child exited with %d\n", status));
Eric Andersenc470f442003-07-28 09:56:35 +00009865 break;
9866 }
Denys Vlasenko238bf182010-05-18 15:49:07 +02009867 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009868 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +02009869 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +00009870 }
9871 listsetvar(varlist.list, VEXPORT|VSTACK);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02009872 shellexec(argv[0], argv, path, cmdentry.u.index);
Eric Andersenc470f442003-07-28 09:56:35 +00009873 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009874 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +00009875 case CMDBUILTIN:
9876 cmdenviron = varlist.list;
9877 if (cmdenviron) {
9878 struct strlist *list = cmdenviron;
9879 int i = VNOSET;
9880 if (spclbltin > 0 || argc == 0) {
9881 i = 0;
9882 if (cmd_is_exec && argc > 1)
9883 i = VEXPORT;
9884 }
9885 listsetvar(list, i);
9886 }
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009887 /* Tight loop with builtins only:
9888 * "while kill -0 $child; do true; done"
9889 * will never exit even if $child died, unless we do this
9890 * to reap the zombie and make kill detect that it's gone: */
9891 dowait(DOWAIT_NONBLOCK, NULL);
9892
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009893 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009894 if (exception_type == EXERROR && spclbltin <= 0) {
9895 FORCE_INT_ON;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02009896 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009897 }
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009898 raise:
9899 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009900 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009901 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009902
9903 case CMDFUNCTION:
9904 listsetvar(varlist.list, 0);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009905 /* See above for the rationale */
9906 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009907 if (evalfun(cmdentry.u.func, argc, argv, flags))
9908 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009909 readstatus:
9910 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009911 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009912 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +00009913
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009914 out:
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02009915 if (cmd->ncmd.redirect)
9916 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009917 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +00009918 /* dsl: I think this is intended to be used to support
9919 * '_' in 'vi' command mode during line editing...
9920 * However I implemented that within libedit itself.
9921 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009922 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009923 }
Eric Andersenc470f442003-07-28 09:56:35 +00009924 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009925
9926 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009927}
9928
9929static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009930evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009931{
Eric Andersenc470f442003-07-28 09:56:35 +00009932 char *volatile savecmdname;
9933 struct jmploc *volatile savehandler;
9934 struct jmploc jmploc;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009935 int status;
Eric Andersenc470f442003-07-28 09:56:35 +00009936 int i;
9937
9938 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009939 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009940 i = setjmp(jmploc.loc);
9941 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +00009942 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009943 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00009944 commandname = argv[0];
9945 argptr = argv + 1;
9946 optptr = NULL; /* initialize nextopt */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009947 if (cmd == EVALCMD)
9948 status = evalcmd(argc, argv, flags);
9949 else
9950 status = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009951 flush_stdout_stderr();
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009952 status |= ferror(stdout);
9953 exitstatus = status;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009954 cmddone:
Rob Landleyf296f0b2006-07-06 01:09:21 +00009955 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009956 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009957 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +00009958
9959 return i;
9960}
9961
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009962static int
9963goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009964{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02009965 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009966}
9967
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009968
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009969/*
9970 * Search for a command. This is called before we fork so that the
9971 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009972 * the child. The check for "goodname" is an overly conservative
9973 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009974 */
Eric Andersenc470f442003-07-28 09:56:35 +00009975static void
9976prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009977{
9978 struct cmdentry entry;
9979
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009980 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9981 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009982}
9983
Eric Andersencb57d552001-06-28 07:25:16 +00009984
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009985/* ============ Builtin commands
9986 *
9987 * Builtin commands whose functions are closely tied to evaluation
9988 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +00009989 */
9990
9991/*
Eric Andersencb57d552001-06-28 07:25:16 +00009992 * Handle break and continue commands. Break, continue, and return are
9993 * all handled by setting the evalskip flag. The evaluation routines
9994 * above all check this flag, and if it is set they start skipping
9995 * commands rather than executing them. The variable skipcount is
9996 * the number of loops to break/continue, or the number of function
9997 * levels to return. (The latter is always 1.) It should probably
9998 * be an error to break out of more loops than exist, but it isn't
9999 * in the standard shell so we don't make it one here.
10000 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010001static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010002breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010003{
Denis Vlasenko68404f12008-03-17 09:00:54 +000010004 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010005
Aaron Lehmann2aef3a62001-12-31 06:03:12 +000010006 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +020010007 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +000010008 if (n > loopnest)
10009 n = loopnest;
10010 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000010011 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +000010012 skipcount = n;
10013 }
10014 return 0;
10015}
10016
Eric Andersenc470f442003-07-28 09:56:35 +000010017
Denys Vlasenko70392332016-10-27 02:31:55 +020010018/*
Eric Andersen90898442003-08-06 11:20:52 +000010019 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +000010020 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010021
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010022enum {
10023 INPUT_PUSH_FILE = 1,
10024 INPUT_NOFILE_OK = 2,
10025};
Eric Andersencb57d552001-06-28 07:25:16 +000010026
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010027static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010028/* values of checkkwd variable */
10029#define CHKALIAS 0x1
10030#define CHKKWD 0x2
10031#define CHKNL 0x4
10032
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010033/*
10034 * Push a string back onto the input at this current parsefile level.
10035 * We handle aliases this way.
10036 */
10037#if !ENABLE_ASH_ALIAS
10038#define pushstring(s, ap) pushstring(s)
10039#endif
10040static void
10041pushstring(char *s, struct alias *ap)
10042{
10043 struct strpush *sp;
10044 int len;
10045
10046 len = strlen(s);
10047 INT_OFF;
10048 if (g_parsefile->strpush) {
10049 sp = ckzalloc(sizeof(*sp));
10050 sp->prev = g_parsefile->strpush;
10051 } else {
10052 sp = &(g_parsefile->basestrpush);
10053 }
10054 g_parsefile->strpush = sp;
10055 sp->prev_string = g_parsefile->next_to_pgetc;
10056 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010057 sp->unget = g_parsefile->unget;
10058 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010059#if ENABLE_ASH_ALIAS
10060 sp->ap = ap;
10061 if (ap) {
10062 ap->flag |= ALIASINUSE;
10063 sp->string = s;
10064 }
10065#endif
10066 g_parsefile->next_to_pgetc = s;
10067 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010068 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010069 INT_ON;
10070}
10071
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010072static void
10073popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010074{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010075 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +000010076
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010077 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010078#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010079 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010080 if (g_parsefile->next_to_pgetc[-1] == ' '
10081 || g_parsefile->next_to_pgetc[-1] == '\t'
10082 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010083 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010084 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010085 if (sp->string != sp->ap->val) {
10086 free(sp->string);
10087 }
10088 sp->ap->flag &= ~ALIASINUSE;
10089 if (sp->ap->flag & ALIASDEAD) {
10090 unalias(sp->ap->name);
10091 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010092 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010093#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010094 g_parsefile->next_to_pgetc = sp->prev_string;
10095 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010096 g_parsefile->unget = sp->unget;
10097 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010098 g_parsefile->strpush = sp->prev;
10099 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010100 free(sp);
10101 INT_ON;
10102}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010103
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010104static int
10105preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010106{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010107 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +000010108 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010109
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010110 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +000010111#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +000010112 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010113 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +010010114 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010115 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010116 int timeout = -1;
10117# if ENABLE_ASH_IDLE_TIMEOUT
10118 if (iflag) {
10119 const char *tmout_var = lookupvar("TMOUT");
10120 if (tmout_var) {
10121 timeout = atoi(tmout_var) * 1000;
10122 if (timeout <= 0)
10123 timeout = -1;
10124 }
10125 }
10126# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010127# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010128 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010129# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +020010130 reinit_unicode_for_ash();
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010131 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010132 if (nr == 0) {
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010133 /* ^C pressed, "convert" to SIGINT */
10134 write(STDOUT_FILENO, "^C", 2);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010135 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010136 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010137 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010138 raise(SIGINT);
10139 return 1;
10140 }
Denys Vlasenko8660aeb2016-11-24 17:44:02 +010010141 exitstatus = 128 + SIGINT;
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010142 bb_putchar('\n');
Eric Andersenc470f442003-07-28 09:56:35 +000010143 goto retry;
10144 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010145 if (nr < 0) {
10146 if (errno == 0) {
10147 /* Ctrl+D pressed */
10148 nr = 0;
10149 }
10150# if ENABLE_ASH_IDLE_TIMEOUT
10151 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +020010152 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010153 exitshell();
10154 }
10155# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010156 }
Eric Andersencb57d552001-06-28 07:25:16 +000010157 }
10158#else
Ron Yorston61d6ae22015-04-19 10:50:25 +010010159 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +000010160#endif
10161
Denys Vlasenko80c5b682011-05-08 21:21:10 +020010162#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +000010163 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010164 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +000010165 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +000010166 if (flags >= 0 && (flags & O_NONBLOCK)) {
10167 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +000010168 if (fcntl(0, F_SETFL, flags) >= 0) {
10169 out2str("sh: turning off NDELAY mode\n");
10170 goto retry;
10171 }
10172 }
10173 }
10174 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +000010175#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010176 return nr;
10177}
10178
10179/*
10180 * Refill the input buffer and return the next input character:
10181 *
10182 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010183 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
10184 * or we are reading from a string so we can't refill the buffer,
10185 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +020010186 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +000010187 * 4) Process input up to the next newline, deleting nul characters.
10188 */
Denis Vlasenko727752d2008-11-28 03:41:47 +000010189//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
10190#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010191static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010192static int
Eric Andersenc470f442003-07-28 09:56:35 +000010193preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010194{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010195 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010196 int more;
Eric Andersencb57d552001-06-28 07:25:16 +000010197
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010198 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000010199#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010200 if (g_parsefile->left_in_line == -1
10201 && g_parsefile->strpush->ap
10202 && g_parsefile->next_to_pgetc[-1] != ' '
10203 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +000010204 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010205 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +000010206 return PEOA;
10207 }
Eric Andersen2870d962001-07-02 17:27:21 +000010208#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010209 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010210 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010211 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010212 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010213 * "pgetc" needs refilling.
10214 */
10215
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010216 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010217 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010218 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010219 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010220 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010221 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010222 /* even in failure keep left_in_line and next_to_pgetc
10223 * in lock step, for correct multi-layer pungetc.
10224 * left_in_line was decremented before preadbuffer(),
10225 * must inc next_to_pgetc: */
10226 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010227 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010228 }
Eric Andersencb57d552001-06-28 07:25:16 +000010229
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010230 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010231 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010232 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010233 again:
10234 more = preadfd();
10235 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010236 /* don't try reading again */
10237 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010238 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010239 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010240 return PEOF;
10241 }
10242 }
10243
Denis Vlasenko727752d2008-11-28 03:41:47 +000010244 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010245 * Set g_parsefile->left_in_line
10246 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010247 * NUL chars are deleted.
10248 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010249 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010250 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010251 char c;
Eric Andersencb57d552001-06-28 07:25:16 +000010252
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010253 more--;
Eric Andersenc470f442003-07-28 09:56:35 +000010254
Denis Vlasenko727752d2008-11-28 03:41:47 +000010255 c = *q;
10256 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010257 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010258 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010259 q++;
10260 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010261 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010262 break;
10263 }
Eric Andersencb57d552001-06-28 07:25:16 +000010264 }
10265
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010266 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010267 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10268 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010269 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010270 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010271 }
10272 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010273 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +000010274
Eric Andersencb57d552001-06-28 07:25:16 +000010275 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010276 char save = *q;
10277 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010278 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010279 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +000010280 }
10281
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010282 pgetc_debug("preadbuffer at %d:%p'%s'",
10283 g_parsefile->left_in_line,
10284 g_parsefile->next_to_pgetc,
10285 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +010010286 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010287}
10288
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010289static void
10290nlprompt(void)
10291{
10292 g_parsefile->linno++;
10293 setprompt_if(doprompt, 2);
10294}
10295static void
10296nlnoprompt(void)
10297{
10298 g_parsefile->linno++;
10299 needprompt = doprompt;
10300}
10301
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010302static int
10303pgetc(void)
10304{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010305 int c;
10306
10307 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010308 g_parsefile->left_in_line,
10309 g_parsefile->next_to_pgetc,
10310 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010311 if (g_parsefile->unget)
10312 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010313
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010314 if (--g_parsefile->left_in_line >= 0)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +010010315 c = (unsigned char)*g_parsefile->next_to_pgetc++;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010316 else
10317 c = preadbuffer();
10318
10319 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10320 g_parsefile->lastc[0] = c;
10321
10322 return c;
10323}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010324
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010325#if ENABLE_ASH_ALIAS
10326static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010327pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010328{
10329 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010330 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010331 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010332 g_parsefile->left_in_line,
10333 g_parsefile->next_to_pgetc,
10334 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010335 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010336 } while (c == PEOA);
10337 return c;
10338}
10339#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010340# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010341#endif
10342
10343/*
10344 * Read a line from the script.
10345 */
10346static char *
10347pfgets(char *line, int len)
10348{
10349 char *p = line;
10350 int nleft = len;
10351 int c;
10352
10353 while (--nleft > 0) {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010354 c = pgetc_without_PEOA();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010355 if (c == PEOF) {
10356 if (p == line)
10357 return NULL;
10358 break;
10359 }
10360 *p++ = c;
10361 if (c == '\n')
10362 break;
10363 }
10364 *p = '\0';
10365 return line;
10366}
10367
Eric Andersenc470f442003-07-28 09:56:35 +000010368/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010369 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010370 * PEOF may be pushed back.
10371 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010372static void
Eric Andersenc470f442003-07-28 09:56:35 +000010373pungetc(void)
10374{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010375 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010376}
10377
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010378/* This one eats backslash+newline */
10379static int
10380pgetc_eatbnl(void)
10381{
10382 int c;
10383
10384 while ((c = pgetc()) == '\\') {
10385 if (pgetc() != '\n') {
10386 pungetc();
10387 break;
10388 }
10389
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010390 nlprompt();
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010391 }
10392
10393 return c;
10394}
10395
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010396/*
10397 * To handle the "." command, a stack of input files is used. Pushfile
10398 * adds a new entry to the stack and popfile restores the previous level.
10399 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010400static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010401pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010402{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010403 struct parsefile *pf;
10404
Denis Vlasenko597906c2008-02-20 16:38:54 +000010405 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010406 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010407 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010408 /*pf->strpush = NULL; - ckzalloc did it */
10409 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010410 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010411 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010412}
10413
10414static void
10415popfile(void)
10416{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010417 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010418
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010010419 if (pf == &basepf)
10420 return;
10421
Denis Vlasenkob012b102007-02-19 22:43:01 +000010422 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010423 if (pf->pf_fd >= 0)
10424 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010425 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010426 while (pf->strpush)
10427 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010428 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010429 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010430 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010431}
10432
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010433/*
10434 * Return to top level.
10435 */
10436static void
10437popallfiles(void)
10438{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010439 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010440 popfile();
10441}
10442
10443/*
10444 * Close the file(s) that the shell is reading commands from. Called
10445 * after a fork is done.
10446 */
10447static void
10448closescript(void)
10449{
10450 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010451 if (g_parsefile->pf_fd > 0) {
10452 close(g_parsefile->pf_fd);
10453 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010454 }
10455}
10456
10457/*
10458 * Like setinputfile, but takes an open file descriptor. Call this with
10459 * interrupts off.
10460 */
10461static void
10462setinputfd(int fd, int push)
10463{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010464 if (push) {
10465 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010466 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010467 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010468 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010469 if (g_parsefile->buf == NULL)
10470 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010471 g_parsefile->left_in_buffer = 0;
10472 g_parsefile->left_in_line = 0;
10473 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010474}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010475
Eric Andersenc470f442003-07-28 09:56:35 +000010476/*
10477 * Set the input to take input from a file. If push is set, push the
10478 * old input onto the stack first.
10479 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010480static int
10481setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010482{
10483 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010484
Denis Vlasenkob012b102007-02-19 22:43:01 +000010485 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010486 fd = open(fname, O_RDONLY);
10487 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010488 if (flags & INPUT_NOFILE_OK)
10489 goto out;
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010490 exitstatus = 127;
Denis Vlasenko9604e1b2009-03-03 18:47:56 +000010491 ash_msg_and_raise_error("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010492 }
Denys Vlasenko64774602016-10-26 15:24:30 +020010493 if (fd < 10)
10494 fd = savefd(fd);
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020010495 else
10496 close_on_exec_on(fd);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010497 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010498 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010499 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010500 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010501}
10502
Eric Andersencb57d552001-06-28 07:25:16 +000010503/*
10504 * Like setinputfile, but takes input from a string.
10505 */
Eric Andersenc470f442003-07-28 09:56:35 +000010506static void
10507setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010508{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010509 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010510 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010511 g_parsefile->next_to_pgetc = string;
10512 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010513 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010514 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010515 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010516}
10517
10518
Denys Vlasenko70392332016-10-27 02:31:55 +020010519/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010520 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010521 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010522
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010523#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010524
Denys Vlasenko23841622015-10-09 15:52:03 +020010525/* Hash of mtimes of mailboxes */
10526static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010527/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010528static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010529
Eric Andersencb57d552001-06-28 07:25:16 +000010530/*
Eric Andersenc470f442003-07-28 09:56:35 +000010531 * Print appropriate message(s) if mail has arrived.
10532 * If mail_var_path_changed is set,
10533 * then the value of MAIL has mail_var_path_changed,
10534 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010535 */
Eric Andersenc470f442003-07-28 09:56:35 +000010536static void
10537chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010538{
Eric Andersencb57d552001-06-28 07:25:16 +000010539 const char *mpath;
10540 char *p;
10541 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010542 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010543 struct stackmark smark;
10544 struct stat statb;
10545
Eric Andersencb57d552001-06-28 07:25:16 +000010546 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010547 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010548 new_hash = 0;
10549 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010550 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010551 if (p == NULL)
10552 break;
10553 if (*p == '\0')
10554 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010555 for (q = p; *q; q++)
10556 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010557#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010558 if (q[-1] != '/')
10559 abort();
10560#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010561 q[-1] = '\0'; /* delete trailing '/' */
10562 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010563 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010564 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010565 /* Very simplistic "hash": just a sum of all mtimes */
10566 new_hash += (unsigned)statb.st_mtime;
10567 }
10568 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010569 if (mailtime_hash != 0)
10570 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010571 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010572 }
Eric Andersenc470f442003-07-28 09:56:35 +000010573 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010574 popstackmark(&smark);
10575}
Eric Andersencb57d552001-06-28 07:25:16 +000010576
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010577static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010578changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010579{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010580 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010581}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010582
Denis Vlasenko131ae172007-02-18 13:00:19 +000010583#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010584
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010585
10586/* ============ ??? */
10587
Eric Andersencb57d552001-06-28 07:25:16 +000010588/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010589 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010590 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010591static void
10592setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010593{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010594 char **newparam;
10595 char **ap;
10596 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010597
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010598 for (nparam = 0; argv[nparam]; nparam++)
10599 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010600 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10601 while (*argv) {
10602 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010603 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010604 *ap = NULL;
10605 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010606 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010607 shellparam.nparam = nparam;
10608 shellparam.p = newparam;
10609#if ENABLE_ASH_GETOPTS
10610 shellparam.optind = 1;
10611 shellparam.optoff = -1;
10612#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010613}
10614
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010615/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010616 * Process shell options. The global variable argptr contains a pointer
10617 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010618 *
10619 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10620 * For a non-interactive shell, an error condition encountered
10621 * by a special built-in ... shall cause the shell to write a diagnostic message
10622 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010623 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010624 * ...
10625 * Utility syntax error (option or operand error) Shall exit
10626 * ...
10627 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10628 * we see that bash does not do that (set "finishes" with error code 1 instead,
10629 * and shell continues), and people rely on this behavior!
10630 * Testcase:
10631 * set -o barfoo 2>/dev/null
10632 * echo $?
10633 *
10634 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010635 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010636static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010637plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010638{
10639 int i;
10640
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010641 if (name) {
10642 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010643 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010644 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010645 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010646 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010647 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010648 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010649 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010650 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010651 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010652 if (val) {
10653 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10654 } else {
10655 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10656 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010657 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010658 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010659}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010660static void
10661setoption(int flag, int val)
10662{
10663 int i;
10664
10665 for (i = 0; i < NOPTS; i++) {
10666 if (optletters(i) == flag) {
10667 optlist[i] = val;
10668 return;
10669 }
10670 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010671 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010672 /* NOTREACHED */
10673}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010674static int
Eric Andersenc470f442003-07-28 09:56:35 +000010675options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +000010676{
10677 char *p;
10678 int val;
10679 int c;
10680
10681 if (cmdline)
10682 minusc = NULL;
10683 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010684 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010685 if (c != '-' && c != '+')
10686 break;
10687 argptr++;
10688 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010689 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010690 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010691 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010692 if (!cmdline) {
10693 /* "-" means turn off -x and -v */
10694 if (p[0] == '\0')
10695 xflag = vflag = 0;
10696 /* "--" means reset params */
10697 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010698 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010699 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010700 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010701 }
Eric Andersencb57d552001-06-28 07:25:16 +000010702 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010703 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010704 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010705 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010706 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010707 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010708 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010709 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010710 /* it already printed err message */
10711 return 1; /* error */
10712 }
Eric Andersencb57d552001-06-28 07:25:16 +000010713 if (*argptr)
10714 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010715 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10716 isloginsh = 1;
10717 /* bash does not accept +-login, we also won't */
10718 } else if (cmdline && val && (c == '-')) { /* long options */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010719 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +000010720 isloginsh = 1;
10721 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010722 } else {
10723 setoption(c, val);
10724 }
10725 }
10726 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010727 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010728}
10729
Eric Andersencb57d552001-06-28 07:25:16 +000010730/*
Eric Andersencb57d552001-06-28 07:25:16 +000010731 * The shift builtin command.
10732 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010733static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010734shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010735{
10736 int n;
10737 char **ap1, **ap2;
10738
10739 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010740 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010741 n = number(argv[1]);
10742 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010743 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010744 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010745 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010746 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010747 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010748 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010749 }
10750 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010751 while ((*ap2++ = *ap1++) != NULL)
10752 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010753#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010754 shellparam.optind = 1;
10755 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010756#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010757 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010758 return 0;
10759}
10760
Eric Andersencb57d552001-06-28 07:25:16 +000010761/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010762 * POSIX requires that 'set' (but not export or readonly) output the
10763 * variables in lexicographic order - by the locale's collating order (sigh).
10764 * Maybe we could keep them in an ordered balanced binary tree
10765 * instead of hashed lists.
10766 * For now just roll 'em through qsort for printing...
10767 */
10768static int
10769showvars(const char *sep_prefix, int on, int off)
10770{
10771 const char *sep;
10772 char **ep, **epend;
10773
10774 ep = listvars(on, off, &epend);
10775 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10776
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010777 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010778
10779 for (; ep < epend; ep++) {
10780 const char *p;
10781 const char *q;
10782
10783 p = strchrnul(*ep, '=');
10784 q = nullstr;
10785 if (*p)
10786 q = single_quote(++p);
10787 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10788 }
10789 return 0;
10790}
10791
10792/*
Eric Andersencb57d552001-06-28 07:25:16 +000010793 * The set command builtin.
10794 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010795static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010796setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010797{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010798 int retval;
10799
Denis Vlasenko68404f12008-03-17 09:00:54 +000010800 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010801 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010802
Denis Vlasenkob012b102007-02-19 22:43:01 +000010803 INT_OFF;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010804 retval = options(/*cmdline:*/ 0);
10805 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010806 optschanged();
10807 if (*argptr != NULL) {
10808 setparam(argptr);
10809 }
Eric Andersencb57d552001-06-28 07:25:16 +000010810 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010811 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010812 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010813}
10814
Denis Vlasenko131ae172007-02-18 13:00:19 +000010815#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010816static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010817change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010818{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010819 uint32_t t;
10820
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010821 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010822 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010823 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010824 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010825 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010826 vrandom.flags &= ~VNOFUNC;
10827 } else {
10828 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010829 t = strtoul(value, NULL, 10);
10830 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010831 }
Eric Andersenef02f822004-03-11 13:34:24 +000010832}
Eric Andersen16767e22004-03-16 05:14:10 +000010833#endif
10834
Denis Vlasenko131ae172007-02-18 13:00:19 +000010835#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010836static int
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010837getopts(char *optstr, char *optvar, char **optfirst)
Eric Andersencb57d552001-06-28 07:25:16 +000010838{
10839 char *p, *q;
10840 char c = '?';
10841 int done = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010842 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000010843 char **optnext;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010844 int ind = shellparam.optind;
10845 int off = shellparam.optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010846
Denys Vlasenko9c541002015-10-07 15:44:36 +020010847 sbuf[1] = '\0';
10848
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010849 shellparam.optind = -1;
10850 optnext = optfirst + ind - 1;
Eric Andersena48b0a32003-10-22 10:56:47 +000010851
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010852 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
Eric Andersencb57d552001-06-28 07:25:16 +000010853 p = NULL;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010854 else
10855 p = optnext[-1] + off;
Eric Andersencb57d552001-06-28 07:25:16 +000010856 if (p == NULL || *p == '\0') {
10857 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010858 p = *optnext;
10859 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010860 atend:
Eric Andersencb57d552001-06-28 07:25:16 +000010861 p = NULL;
10862 done = 1;
10863 goto out;
10864 }
10865 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010866 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010867 goto atend;
10868 }
10869
10870 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010871 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010872 if (*q == '\0') {
10873 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010874 sbuf[0] = c;
10875 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010876 setvar0("OPTARG", sbuf);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010877 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010878 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010879 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010880 }
10881 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010882 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010883 }
10884 if (*++q == ':')
10885 q++;
10886 }
10887
10888 if (*++q == ':') {
10889 if (*p == '\0' && (p = *optnext) == NULL) {
10890 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010891 sbuf[0] = c;
10892 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010893 setvar0("OPTARG", sbuf);
Eric Andersencb57d552001-06-28 07:25:16 +000010894 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010895 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010896 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010897 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010898 c = '?';
10899 }
Eric Andersenc470f442003-07-28 09:56:35 +000010900 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010901 }
10902
10903 if (p == *optnext)
10904 optnext++;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010905 setvar0("OPTARG", p);
Eric Andersencb57d552001-06-28 07:25:16 +000010906 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010907 } else
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010908 setvar0("OPTARG", nullstr);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010909 out:
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010910 ind = optnext - optfirst + 1;
10911 setvar("OPTIND", itoa(ind), VNOFUNC);
Denys Vlasenko9c541002015-10-07 15:44:36 +020010912 sbuf[0] = c;
10913 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010914 setvar0(optvar, sbuf);
10915
10916 shellparam.optoff = p ? p - *(optnext - 1) : -1;
10917 shellparam.optind = ind;
10918
Eric Andersencb57d552001-06-28 07:25:16 +000010919 return done;
10920}
Eric Andersenc470f442003-07-28 09:56:35 +000010921
10922/*
10923 * The getopts builtin. Shellparam.optnext points to the next argument
10924 * to be processed. Shellparam.optptr points to the next character to
10925 * be processed in the current argument. If shellparam.optnext is NULL,
10926 * then it's the first time getopts has been called.
10927 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010928static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000010929getoptscmd(int argc, char **argv)
10930{
10931 char **optbase;
10932
10933 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010934 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010935 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000010936 optbase = shellparam.p;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010937 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
Eric Andersenc470f442003-07-28 09:56:35 +000010938 shellparam.optind = 1;
10939 shellparam.optoff = -1;
10940 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010941 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010942 optbase = &argv[3];
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010943 if ((unsigned)shellparam.optind > argc - 2) {
Eric Andersenc470f442003-07-28 09:56:35 +000010944 shellparam.optind = 1;
10945 shellparam.optoff = -1;
10946 }
10947 }
10948
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010949 return getopts(argv[1], argv[2], optbase);
Eric Andersenc470f442003-07-28 09:56:35 +000010950}
Denis Vlasenko131ae172007-02-18 13:00:19 +000010951#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000010952
Eric Andersencb57d552001-06-28 07:25:16 +000010953
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010954/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000010955
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010956struct heredoc {
10957 struct heredoc *next; /* next here document in list */
10958 union node *here; /* redirection node */
10959 char *eofmark; /* string indicating end of input */
10960 smallint striptabs; /* if set, strip leading tabs */
10961};
10962
10963static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010964static smallint quoteflag; /* set if (part of) last token was quoted */
10965static token_id_t lasttoken; /* last token read (integer id Txxx) */
10966static struct heredoc *heredoclist; /* list of here documents to read */
10967static char *wordtext; /* text of last word returned by readtoken */
10968static struct nodelist *backquotelist;
10969static union node *redirnode;
10970static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010971
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010972static const char *
10973tokname(char *buf, int tok)
10974{
10975 if (tok < TSEMI)
Denys Vlasenko888527c2016-10-02 16:54:17 +020010976 return tokname_array[tok];
10977 sprintf(buf, "\"%s\"", tokname_array[tok]);
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010978 return buf;
10979}
10980
10981/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010982 * Called when an unexpected token is read during the parse. The argument
10983 * is the token that is expected, or -1 if more than one type of token can
10984 * occur at this point.
10985 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010986static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010987static void
10988raise_error_unexpected_syntax(int token)
10989{
10990 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010991 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010992 int l;
10993
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010994 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010995 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010996 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010997 raise_error_syntax(msg);
10998 /* NOTREACHED */
10999}
Eric Andersencb57d552001-06-28 07:25:16 +000011000
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011001#define EOFMARKLEN 79
Eric Andersencb57d552001-06-28 07:25:16 +000011002
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011003/* parsing is heavily cross-recursive, need these forward decls */
11004static union node *andor(void);
11005static union node *pipeline(void);
11006static union node *parse_command(void);
11007static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000011008static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011009static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000011010
Eric Andersenc470f442003-07-28 09:56:35 +000011011static union node *
11012list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000011013{
11014 union node *n1, *n2, *n3;
11015 int tok;
11016
Eric Andersencb57d552001-06-28 07:25:16 +000011017 n1 = NULL;
11018 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011019 switch (peektoken()) {
11020 case TNL:
11021 if (!(nlflag & 1))
11022 break;
11023 parseheredoc();
11024 return n1;
11025
11026 case TEOF:
11027 if (!n1 && (nlflag & 1))
11028 n1 = NODE_EOF;
11029 parseheredoc();
11030 return n1;
11031 }
11032
11033 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko888527c2016-10-02 16:54:17 +020011034 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
Ron Yorstonc0e00762015-10-29 11:30:55 +000011035 return n1;
11036 nlflag |= 2;
11037
Eric Andersencb57d552001-06-28 07:25:16 +000011038 n2 = andor();
11039 tok = readtoken();
11040 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000011041 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011042 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011043 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011044 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011045 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000011046 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011047 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011048 n2 = n3;
11049 }
11050 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000011051 }
11052 }
11053 if (n1 == NULL) {
11054 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011055 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011056 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011057 n3->type = NSEMI;
11058 n3->nbinary.ch1 = n1;
11059 n3->nbinary.ch2 = n2;
11060 n1 = n3;
11061 }
11062 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011063 case TNL:
11064 case TEOF:
11065 tokpushback = 1;
11066 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000011067 case TBACKGND:
11068 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000011069 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011070 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000011071 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011072 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011073 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011074 return n1;
11075 }
11076 }
11077}
11078
Eric Andersenc470f442003-07-28 09:56:35 +000011079static union node *
11080andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011081{
Eric Andersencb57d552001-06-28 07:25:16 +000011082 union node *n1, *n2, *n3;
11083 int t;
11084
Eric Andersencb57d552001-06-28 07:25:16 +000011085 n1 = pipeline();
11086 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011087 t = readtoken();
11088 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000011089 t = NAND;
11090 } else if (t == TOR) {
11091 t = NOR;
11092 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011093 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011094 return n1;
11095 }
Eric Andersenc470f442003-07-28 09:56:35 +000011096 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011097 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011098 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011099 n3->type = t;
11100 n3->nbinary.ch1 = n1;
11101 n3->nbinary.ch2 = n2;
11102 n1 = n3;
11103 }
11104}
11105
Eric Andersenc470f442003-07-28 09:56:35 +000011106static union node *
11107pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011108{
Eric Andersencb57d552001-06-28 07:25:16 +000011109 union node *n1, *n2, *pipenode;
11110 struct nodelist *lp, *prev;
11111 int negate;
11112
11113 negate = 0;
11114 TRACE(("pipeline: entered\n"));
11115 if (readtoken() == TNOT) {
11116 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000011117 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011118 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011119 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011120 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011121 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011122 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000011123 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011124 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011125 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000011126 pipenode->npipe.cmdlist = lp;
11127 lp->n = n1;
11128 do {
11129 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011130 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000011131 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011132 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011133 prev->next = lp;
11134 } while (readtoken() == TPIPE);
11135 lp->next = NULL;
11136 n1 = pipenode;
11137 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011138 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011139 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011140 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000011141 n2->type = NNOT;
11142 n2->nnot.com = n1;
11143 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011144 }
11145 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000011146}
11147
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011148static union node *
11149makename(void)
11150{
11151 union node *n;
11152
Denis Vlasenko597906c2008-02-20 16:38:54 +000011153 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011154 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011155 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011156 n->narg.text = wordtext;
11157 n->narg.backquote = backquotelist;
11158 return n;
11159}
11160
11161static void
11162fixredir(union node *n, const char *text, int err)
11163{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011164 int fd;
11165
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011166 TRACE(("Fix redir %s %d\n", text, err));
11167 if (!err)
11168 n->ndup.vname = NULL;
11169
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011170 fd = bb_strtou(text, NULL, 10);
11171 if (!errno && fd >= 0)
11172 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011173 else if (LONE_DASH(text))
11174 n->ndup.dupfd = -1;
11175 else {
11176 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011177 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011178 n->ndup.vname = makename();
11179 }
11180}
11181
11182/*
11183 * Returns true if the text contains nothing to expand (no dollar signs
11184 * or backquotes).
11185 */
11186static int
Denis Vlasenko68819d12008-12-15 11:26:36 +000011187noexpand(const char *text)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011188{
Denys Vlasenkocd716832009-11-28 22:14:02 +010011189 unsigned char c;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011190
Denys Vlasenkocd716832009-11-28 22:14:02 +010011191 while ((c = *text++) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011192 if (c == CTLQUOTEMARK)
11193 continue;
11194 if (c == CTLESC)
Denys Vlasenkocd716832009-11-28 22:14:02 +010011195 text++;
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011196 else if (SIT(c, BASESYNTAX) == CCTL)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011197 return 0;
11198 }
11199 return 1;
11200}
11201
11202static void
11203parsefname(void)
11204{
11205 union node *n = redirnode;
11206
11207 if (readtoken() != TWORD)
11208 raise_error_unexpected_syntax(-1);
11209 if (n->type == NHERE) {
11210 struct heredoc *here = heredoc;
11211 struct heredoc *p;
11212 int i;
11213
11214 if (quoteflag == 0)
11215 n->type = NXHERE;
11216 TRACE(("Here document %d\n", n->type));
11217 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011218 raise_error_syntax("illegal eof marker for << redirection");
Denys Vlasenkob6c84342009-08-29 20:23:20 +020011219 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011220 here->eofmark = wordtext;
11221 here->next = NULL;
11222 if (heredoclist == NULL)
11223 heredoclist = here;
11224 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011225 for (p = heredoclist; p->next; p = p->next)
11226 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011227 p->next = here;
11228 }
11229 } else if (n->type == NTOFD || n->type == NFROMFD) {
11230 fixredir(n, wordtext, 0);
11231 } else {
11232 n->nfile.fname = makename();
11233 }
11234}
Eric Andersencb57d552001-06-28 07:25:16 +000011235
Eric Andersenc470f442003-07-28 09:56:35 +000011236static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011237simplecmd(void)
11238{
11239 union node *args, **app;
11240 union node *n = NULL;
11241 union node *vars, **vpp;
11242 union node **rpp, *redir;
11243 int savecheckkwd;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011244#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011245 smallint double_brackets_flag = 0;
11246#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011247 IF_BASH_FUNCTION(smallint function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011248
11249 args = NULL;
11250 app = &args;
11251 vars = NULL;
11252 vpp = &vars;
11253 redir = NULL;
11254 rpp = &redir;
11255
11256 savecheckkwd = CHKALIAS;
11257 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000011258 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011259 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011260 t = readtoken();
11261 switch (t) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011262#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011263 case TFUNCTION:
11264 if (peektoken() != TWORD)
11265 raise_error_unexpected_syntax(TWORD);
11266 function_flag = 1;
11267 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011268#endif
11269#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011270 case TAND: /* "&&" */
11271 case TOR: /* "||" */
11272 if (!double_brackets_flag) {
11273 tokpushback = 1;
11274 goto out;
11275 }
11276 wordtext = (char *) (t == TAND ? "-a" : "-o");
11277#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011278 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011279 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011280 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011281 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011282 n->narg.text = wordtext;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011283#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011284 if (strcmp("[[", wordtext) == 0)
11285 double_brackets_flag = 1;
11286 else if (strcmp("]]", wordtext) == 0)
11287 double_brackets_flag = 0;
11288#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011289 n->narg.backquote = backquotelist;
11290 if (savecheckkwd && isassignment(wordtext)) {
11291 *vpp = n;
11292 vpp = &n->narg.next;
11293 } else {
11294 *app = n;
11295 app = &n->narg.next;
11296 savecheckkwd = 0;
11297 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011298#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011299 if (function_flag) {
11300 checkkwd = CHKNL | CHKKWD;
11301 switch (peektoken()) {
11302 case TBEGIN:
11303 case TIF:
11304 case TCASE:
11305 case TUNTIL:
11306 case TWHILE:
11307 case TFOR:
11308 goto do_func;
11309 case TLP:
11310 function_flag = 0;
11311 break;
11312 case TWORD:
11313 if (strcmp("[[", wordtext) == 0)
11314 goto do_func;
11315 /* fall through */
11316 default:
11317 raise_error_unexpected_syntax(-1);
11318 }
11319 }
11320#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011321 break;
11322 case TREDIR:
11323 *rpp = n = redirnode;
11324 rpp = &n->nfile.next;
11325 parsefname(); /* read name of redirection file */
11326 break;
11327 case TLP:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011328 IF_BASH_FUNCTION(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011329 if (args && app == &args->narg.next
11330 && !vars && !redir
11331 ) {
11332 struct builtincmd *bcmd;
11333 const char *name;
11334
11335 /* We have a function */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011336 if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011337 raise_error_unexpected_syntax(TRP);
11338 name = n->narg.text;
11339 if (!goodname(name)
11340 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11341 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011342 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011343 }
11344 n->type = NDEFUN;
11345 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11346 n->narg.next = parse_command();
11347 return n;
11348 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011349 IF_BASH_FUNCTION(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011350 /* fall through */
11351 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011352 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011353 goto out;
11354 }
11355 }
11356 out:
11357 *app = NULL;
11358 *vpp = NULL;
11359 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011360 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011361 n->type = NCMD;
11362 n->ncmd.args = args;
11363 n->ncmd.assign = vars;
11364 n->ncmd.redirect = redir;
11365 return n;
11366}
11367
11368static union node *
11369parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011370{
Eric Andersencb57d552001-06-28 07:25:16 +000011371 union node *n1, *n2;
11372 union node *ap, **app;
11373 union node *cp, **cpp;
11374 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011375 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011376 int t;
11377
11378 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011379 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011380
Eric Andersencb57d552001-06-28 07:25:16 +000011381 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011382 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011383 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011384 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011385 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011386 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011387 n1->type = NIF;
11388 n1->nif.test = list(0);
11389 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011390 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011391 n1->nif.ifpart = list(0);
11392 n2 = n1;
11393 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011394 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011395 n2 = n2->nif.elsepart;
11396 n2->type = NIF;
11397 n2->nif.test = list(0);
11398 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011399 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011400 n2->nif.ifpart = list(0);
11401 }
11402 if (lasttoken == TELSE)
11403 n2->nif.elsepart = list(0);
11404 else {
11405 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011406 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011407 }
Eric Andersenc470f442003-07-28 09:56:35 +000011408 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011409 break;
11410 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011411 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011412 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011413 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011414 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011415 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011416 got = readtoken();
11417 if (got != TDO) {
Denys Vlasenko888527c2016-10-02 16:54:17 +020011418 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
Denis Vlasenko131ae172007-02-18 13:00:19 +000011419 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011420 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011421 }
11422 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011423 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011424 break;
11425 }
11426 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011427 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011428 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011429 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011430 n1->type = NFOR;
11431 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011432 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011433 if (readtoken() == TIN) {
11434 app = &ap;
11435 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011436 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011437 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011438 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011439 n2->narg.text = wordtext;
11440 n2->narg.backquote = backquotelist;
11441 *app = n2;
11442 app = &n2->narg.next;
11443 }
11444 *app = NULL;
11445 n1->nfor.args = ap;
11446 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011447 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011448 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011449 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011450 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011451 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011452 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011453 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011454 n1->nfor.args = n2;
11455 /*
11456 * Newline or semicolon here is optional (but note
11457 * that the original Bourne shell only allowed NL).
11458 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011459 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011460 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011461 }
Eric Andersenc470f442003-07-28 09:56:35 +000011462 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011463 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011464 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011465 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011466 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011467 break;
11468 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011469 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011470 n1->type = NCASE;
11471 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011472 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011473 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011474 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011475 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011476 n2->narg.text = wordtext;
11477 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011478 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11479 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011480 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011481 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011482 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011483 checkkwd = CHKNL | CHKKWD;
11484 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011485 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011486 if (lasttoken == TLP)
11487 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011488 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011489 cp->type = NCLIST;
11490 app = &cp->nclist.pattern;
11491 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011492 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011493 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011494 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011495 ap->narg.text = wordtext;
11496 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011497 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011498 break;
11499 app = &ap->narg.next;
11500 readtoken();
11501 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011502 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011503 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011504 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011505 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011506
Eric Andersenc470f442003-07-28 09:56:35 +000011507 cpp = &cp->nclist.next;
11508
11509 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011510 t = readtoken();
11511 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011512 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011513 raise_error_unexpected_syntax(TENDCASE);
11514 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011515 }
Eric Andersenc470f442003-07-28 09:56:35 +000011516 }
Eric Andersencb57d552001-06-28 07:25:16 +000011517 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011518 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011519 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011520 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011521 n1->type = NSUBSHELL;
11522 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011523 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011524 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011525 break;
11526 case TBEGIN:
11527 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011528 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011529 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011530 IF_BASH_FUNCTION(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011531 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011532 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011533 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011534 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011535 }
11536
Eric Andersenc470f442003-07-28 09:56:35 +000011537 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011538 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011539
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011540 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011541 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011542 checkkwd = CHKKWD | CHKALIAS;
11543 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011544 while (readtoken() == TREDIR) {
11545 *rpp = n2 = redirnode;
11546 rpp = &n2->nfile.next;
11547 parsefname();
11548 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011549 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011550 *rpp = NULL;
11551 if (redir) {
11552 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011553 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011554 n2->type = NREDIR;
11555 n2->nredir.n = n1;
11556 n1 = n2;
11557 }
11558 n1->nredir.redirect = redir;
11559 }
Eric Andersencb57d552001-06-28 07:25:16 +000011560 return n1;
11561}
11562
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011563#if BASH_DOLLAR_SQUOTE
Denys Vlasenko37dc08b2016-10-02 04:38:07 +020011564static int
11565decode_dollar_squote(void)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011566{
11567 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11568 int c, cnt;
11569 char *p;
11570 char buf[4];
11571
11572 c = pgetc();
11573 p = strchr(C_escapes, c);
11574 if (p) {
11575 buf[0] = c;
11576 p = buf;
11577 cnt = 3;
11578 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11579 do {
11580 c = pgetc();
11581 *++p = c;
11582 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11583 pungetc();
11584 } else if (c == 'x') { /* \xHH */
11585 do {
11586 c = pgetc();
11587 *++p = c;
11588 } while (isxdigit(c) && --cnt);
11589 pungetc();
11590 if (cnt == 3) { /* \x but next char is "bad" */
11591 c = 'x';
11592 goto unrecognized;
11593 }
11594 } else { /* simple seq like \\ or \t */
11595 p++;
11596 }
11597 *p = '\0';
11598 p = buf;
11599 c = bb_process_escape_sequence((void*)&p);
11600 } else { /* unrecognized "\z": print both chars unless ' or " */
11601 if (c != '\'' && c != '"') {
11602 unrecognized:
11603 c |= 0x100; /* "please encode \, then me" */
11604 }
11605 }
11606 return c;
11607}
11608#endif
11609
Eric Andersencb57d552001-06-28 07:25:16 +000011610/*
11611 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11612 * is not NULL, read a here document. In the latter case, eofmark is the
11613 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011614 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011615 * is the first character of the input token or document.
11616 *
11617 * Because C does not have internal subroutines, I have simulated them
11618 * using goto's to implement the subroutine linkage. The following macros
11619 * will run code that appears at the end of readtoken1.
11620 */
Eric Andersen2870d962001-07-02 17:27:21 +000011621#define CHECKEND() {goto checkend; checkend_return:;}
11622#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11623#define PARSESUB() {goto parsesub; parsesub_return:;}
11624#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11625#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11626#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011627static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011628readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011629{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011630 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011631 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011632 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020011633 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +000011634 char line[EOFMARKLEN + 1];
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011635 struct nodelist *bqlist;
11636 smallint quotef;
11637 smallint dblquote;
11638 smallint oldstyle;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011639 IF_FEATURE_SH_MATH(smallint prevsyntax;) /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011640 smallint pssyntax; /* we are expanding a prompt string */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011641 int varnest; /* levels of variables expansion */
Denys Vlasenko0b883582016-12-23 16:49:07 +010011642 IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */
11643 IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011644 int dqvarnest; /* levels of variables expansion within double quotes */
11645
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011646 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011647
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011648 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011649 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011650 quotef = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011651 IF_FEATURE_SH_MATH(prevsyntax = 0;)
Denis Vlasenko46a53062007-09-24 18:30:02 +000011652 pssyntax = (syntax == PSSYNTAX);
11653 if (pssyntax)
11654 syntax = DQSYNTAX;
Denis Vlasenko46a53062007-09-24 18:30:02 +000011655 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011656 varnest = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011657 IF_FEATURE_SH_MATH(arinest = 0;)
11658 IF_FEATURE_SH_MATH(parenlevel = 0;)
Eric Andersencb57d552001-06-28 07:25:16 +000011659 dqvarnest = 0;
11660
11661 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011662 loop:
11663 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011664 CHECKEND(); /* set c to PEOF if at end of here document */
11665 for (;;) { /* until end of line or end of word */
11666 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11667 switch (SIT(c, syntax)) {
11668 case CNL: /* '\n' */
11669 if (syntax == BASESYNTAX)
11670 goto endword; /* exit outer loop */
11671 USTPUTC(c, out);
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011672 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011673 c = pgetc();
11674 goto loop; /* continue outer loop */
11675 case CWORD:
11676 USTPUTC(c, out);
11677 break;
11678 case CCTL:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011679#if BASH_DOLLAR_SQUOTE
Denys Vlasenko958581a2010-09-12 15:04:27 +020011680 if (c == '\\' && bash_dollar_squote) {
11681 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020011682 if (c == '\0') {
11683 /* skip $'\000', $'\x00' (like bash) */
11684 break;
11685 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011686 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020011687 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011688 c = (unsigned char)c;
Denys Vlasenko13f20912016-09-25 20:54:25 +020011689 if (eofmark == NULL || dblquote)
11690 USTPUTC(CTLESC, out);
11691 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011692 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011693 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011694#endif
Denys Vlasenko13f20912016-09-25 20:54:25 +020011695 if (eofmark == NULL || dblquote)
11696 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011697 USTPUTC(c, out);
11698 break;
11699 case CBACK: /* backslash */
11700 c = pgetc_without_PEOA();
11701 if (c == PEOF) {
11702 USTPUTC(CTLESC, out);
11703 USTPUTC('\\', out);
11704 pungetc();
11705 } else if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011706 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011707 } else {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011708 if (c == '$' && pssyntax) {
Eric Andersenc470f442003-07-28 09:56:35 +000011709 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011710 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011711 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011712 /* Backslash is retained if we are in "str" and next char isn't special */
11713 if (dblquote
11714 && c != '\\'
11715 && c != '`'
11716 && c != '$'
11717 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011718 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011719 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011720 }
Ron Yorston549deab2015-05-18 09:57:51 +020011721 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011722 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011723 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011724 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011725 break;
11726 case CSQUOTE:
11727 syntax = SQSYNTAX;
11728 quotemark:
11729 if (eofmark == NULL) {
11730 USTPUTC(CTLQUOTEMARK, out);
11731 }
11732 break;
11733 case CDQUOTE:
11734 syntax = DQSYNTAX;
11735 dblquote = 1;
11736 goto quotemark;
11737 case CENDQUOTE:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011738 IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020011739 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011740 USTPUTC(c, out);
11741 } else {
11742 if (dqvarnest == 0) {
11743 syntax = BASESYNTAX;
11744 dblquote = 0;
11745 }
11746 quotef = 1;
11747 goto quotemark;
11748 }
11749 break;
11750 case CVAR: /* '$' */
11751 PARSESUB(); /* parse substitution */
11752 break;
11753 case CENDVAR: /* '}' */
11754 if (varnest > 0) {
11755 varnest--;
11756 if (dqvarnest > 0) {
11757 dqvarnest--;
11758 }
11759 c = CTLENDVAR;
11760 }
11761 USTPUTC(c, out);
11762 break;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011763#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko958581a2010-09-12 15:04:27 +020011764 case CLP: /* '(' in arithmetic */
11765 parenlevel++;
11766 USTPUTC(c, out);
11767 break;
11768 case CRP: /* ')' in arithmetic */
11769 if (parenlevel > 0) {
11770 parenlevel--;
11771 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011772 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020011773 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011774 if (--arinest == 0) {
11775 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011776 }
11777 } else {
11778 /*
11779 * unbalanced parens
11780 * (don't 2nd guess - no error)
11781 */
11782 pungetc();
11783 }
11784 }
11785 USTPUTC(c, out);
11786 break;
11787#endif
11788 case CBQUOTE: /* '`' */
11789 PARSEBACKQOLD();
11790 break;
11791 case CENDFILE:
11792 goto endword; /* exit outer loop */
11793 case CIGN:
11794 break;
11795 default:
11796 if (varnest == 0) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011797#if BASH_REDIR_OUTPUT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011798 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011799//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020011800 if (pgetc() == '>')
11801 c = 0x100 + '>'; /* flag &> */
11802 pungetc();
11803 }
11804#endif
11805 goto endword; /* exit outer loop */
11806 }
11807 IF_ASH_ALIAS(if (c != PEOA))
11808 USTPUTC(c, out);
11809 }
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020011810 c = pgetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011811 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011812 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011813
Denys Vlasenko0b883582016-12-23 16:49:07 +010011814#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000011815 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011816 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011817#endif
Ron Yorston0e056f72015-07-01 16:45:40 +010011818 if (syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011819 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011820 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011821 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011822 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011823 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011824 }
11825 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011826 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011827 out = stackblock();
11828 if (eofmark == NULL) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011829 if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011830 && quotef == 0
11831 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011832 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011833 PARSEREDIR(); /* passed as params: out, c */
11834 lasttoken = TREDIR;
11835 return lasttoken;
11836 }
11837 /* else: non-number X seen, interpret it
11838 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011839 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011840 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011841 }
11842 quoteflag = quotef;
11843 backquotelist = bqlist;
11844 grabstackblock(len);
11845 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011846 lasttoken = TWORD;
11847 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011848/* end of readtoken routine */
11849
Eric Andersencb57d552001-06-28 07:25:16 +000011850/*
11851 * Check to see whether we are at the end of the here document. When this
11852 * is called, c is set to the first character of the next input line. If
11853 * we are at the end of the here document, this routine sets the c to PEOF.
11854 */
Eric Andersenc470f442003-07-28 09:56:35 +000011855checkend: {
11856 if (eofmark) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000011857#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011858 if (c == PEOA)
11859 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011860#endif
11861 if (striptabs) {
11862 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011863 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011864 }
Eric Andersenc470f442003-07-28 09:56:35 +000011865 }
11866 if (c == *eofmark) {
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011867 if (pfgets(line, sizeof(line)) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000011868 char *p, *q;
Denys Vlasenko350e6862016-10-26 16:26:45 +020011869 int cc;
Eric Andersencb57d552001-06-28 07:25:16 +000011870
Eric Andersenc470f442003-07-28 09:56:35 +000011871 p = line;
Denys Vlasenko350e6862016-10-26 16:26:45 +020011872 for (q = eofmark + 1;; p++, q++) {
11873 cc = *p;
11874 if (cc == '\n')
11875 cc = 0;
11876 if (!*q || cc != *q)
11877 break;
11878 }
11879 if (cc == *q) {
Eric Andersenc470f442003-07-28 09:56:35 +000011880 c = PEOF;
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011881 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011882 } else {
11883 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011884 }
11885 }
11886 }
11887 }
Eric Andersenc470f442003-07-28 09:56:35 +000011888 goto checkend_return;
11889}
Eric Andersencb57d552001-06-28 07:25:16 +000011890
Eric Andersencb57d552001-06-28 07:25:16 +000011891/*
11892 * Parse a redirection operator. The variable "out" points to a string
11893 * specifying the fd to be redirected. The variable "c" contains the
11894 * first character of the redirection operator.
11895 */
Eric Andersenc470f442003-07-28 09:56:35 +000011896parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011897 /* out is already checked to be a valid number or "" */
11898 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000011899 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000011900
Denis Vlasenko597906c2008-02-20 16:38:54 +000011901 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000011902 if (c == '>') {
11903 np->nfile.fd = 1;
11904 c = pgetc();
11905 if (c == '>')
11906 np->type = NAPPEND;
11907 else if (c == '|')
11908 np->type = NCLOBBER;
11909 else if (c == '&')
11910 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011911 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000011912 else {
11913 np->type = NTO;
11914 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011915 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000011916 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011917#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000011918 else if (c == 0x100 + '>') { /* this flags &> redirection */
11919 np->nfile.fd = 1;
11920 pgetc(); /* this is '>', no need to check */
11921 np->type = NTO2;
11922 }
11923#endif
11924 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000011925 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011926 c = pgetc();
11927 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000011928 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011929 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011930 np = stzalloc(sizeof(struct nhere));
11931 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011932 }
11933 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011934 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000011935 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011936 c = pgetc();
11937 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000011938 heredoc->striptabs = 1;
11939 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011940 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011941 pungetc();
11942 }
11943 break;
11944
11945 case '&':
11946 np->type = NFROMFD;
11947 break;
11948
11949 case '>':
11950 np->type = NFROMTO;
11951 break;
11952
11953 default:
11954 np->type = NFROM;
11955 pungetc();
11956 break;
11957 }
Eric Andersencb57d552001-06-28 07:25:16 +000011958 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011959 if (fd >= 0)
11960 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011961 redirnode = np;
11962 goto parseredir_return;
11963}
Eric Andersencb57d552001-06-28 07:25:16 +000011964
Eric Andersencb57d552001-06-28 07:25:16 +000011965/*
11966 * Parse a substitution. At this point, we have read the dollar sign
11967 * and nothing else.
11968 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000011969
11970/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11971 * (assuming ascii char codes, as the original implementation did) */
11972#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011973 (((unsigned)(c) - 33 < 32) \
11974 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000011975parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010011976 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011977 int typeloc;
Eric Andersencb57d552001-06-28 07:25:16 +000011978
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011979 c = pgetc_eatbnl();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011980 if (c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011981 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000011982 ) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011983#if BASH_DOLLAR_SQUOTE
Ron Yorston84ba50c2016-04-03 22:43:14 +010011984 if (syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011985 bash_dollar_squote = 1;
11986 else
11987#endif
11988 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011989 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011990 } else if (c == '(') {
11991 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011992 if (pgetc_eatbnl() == '(') {
Denys Vlasenko0b883582016-12-23 16:49:07 +010011993#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000011994 PARSEARITH();
11995#else
Denys Vlasenko4f8079d2017-07-17 17:11:48 +020011996 raise_error_syntax("support for $((arith)) is disabled");
Eric Andersenc470f442003-07-28 09:56:35 +000011997#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011998 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011999 pungetc();
12000 PARSEBACKQNEW();
12001 }
12002 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012003 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000012004 USTPUTC(CTLVAR, out);
12005 typeloc = out - (char *)stackblock();
Denys Vlasenko3df14102016-10-26 16:41:13 +020012006 STADJUST(1, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012007 subtype = VSNORMAL;
12008 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012009 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012010 subtype = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000012011 }
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012012 varname:
Denys Vlasenko3df14102016-10-26 16:41:13 +020012013 if (is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012014 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000012015 do {
12016 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012017 c = pgetc_eatbnl();
Denys Vlasenko3df14102016-10-26 16:41:13 +020012018 } while (is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012019 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012020 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000012021 do {
12022 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012023 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012024 } while (isdigit(c));
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012025 } else if (is_special(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012026 /* $[{[#]]<specialchar>[}] */
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012027 int cc = c;
12028
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012029 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012030 if (!subtype && cc == '#') {
12031 subtype = VSLENGTH;
12032 if (c == '_' || isalnum(c))
12033 goto varname;
12034 cc = c;
12035 c = pgetc_eatbnl();
12036 if (cc == '}' || c != '}') {
12037 pungetc();
12038 subtype = 0;
12039 c = cc;
12040 cc = '#';
12041 }
12042 }
12043 USTPUTC(cc, out);
Denis Vlasenko559691a2008-10-05 18:39:31 +000012044 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020012045 goto badsub;
Denis Vlasenko559691a2008-10-05 18:39:31 +000012046 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012047 if (c != '}' && subtype == VSLENGTH) {
12048 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020012049 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012050 }
Eric Andersencb57d552001-06-28 07:25:16 +000012051
Eric Andersenc470f442003-07-28 09:56:35 +000012052 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012053 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012054 /* ${VAR...} but not $VAR or ${#VAR} */
12055 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000012056 switch (c) {
12057 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012058 c = pgetc_eatbnl();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012059#if BASH_SUBSTR
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012060 /* This check is only needed to not misinterpret
12061 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
12062 * constructs.
12063 */
12064 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012065 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012066 pungetc();
Denys Vlasenko88e15702016-10-26 01:55:56 +020012067 break; /* "goto badsub" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012068 }
12069#endif
Denys Vlasenko3df14102016-10-26 16:41:13 +020012070 subtype = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000012071 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012072 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012073 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000012074 if (p == NULL)
Denys Vlasenko88e15702016-10-26 01:55:56 +020012075 break;
Denys Vlasenko3df14102016-10-26 16:41:13 +020012076 subtype |= p - types + VSNORMAL;
Eric Andersenc470f442003-07-28 09:56:35 +000012077 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012078 }
Eric Andersenc470f442003-07-28 09:56:35 +000012079 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012080 case '#': {
12081 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012082 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012083 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012084 if (c != cc)
Denys Vlasenko88e15702016-10-26 01:55:56 +020012085 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012086 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012087 break;
12088 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012089#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012090 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020012091 /* ${v/[/]pattern/repl} */
12092//TODO: encode pattern and repl separately.
12093// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012094 subtype = VSREPLACE;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012095 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012096 if (c != '/')
Denys Vlasenko88e15702016-10-26 01:55:56 +020012097 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012098 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012099 break;
12100#endif
Eric Andersencb57d552001-06-28 07:25:16 +000012101 }
Eric Andersenc470f442003-07-28 09:56:35 +000012102 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020012103 badsub:
Eric Andersenc470f442003-07-28 09:56:35 +000012104 pungetc();
12105 }
Denys Vlasenko3df14102016-10-26 16:41:13 +020012106 ((unsigned char *)stackblock())[typeloc] = subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012107 if (subtype != VSNORMAL) {
12108 varnest++;
Denys Vlasenko3df14102016-10-26 16:41:13 +020012109 if (dblquote)
Eric Andersenc470f442003-07-28 09:56:35 +000012110 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000012111 }
Denys Vlasenko88e15702016-10-26 01:55:56 +020012112 STPUTC('=', out);
Eric Andersencb57d552001-06-28 07:25:16 +000012113 }
Eric Andersenc470f442003-07-28 09:56:35 +000012114 goto parsesub_return;
12115}
Eric Andersencb57d552001-06-28 07:25:16 +000012116
Eric Andersencb57d552001-06-28 07:25:16 +000012117/*
12118 * Called to parse command substitutions. Newstyle is set if the command
12119 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
12120 * list of commands (passed by reference), and savelen is the number of
12121 * characters on the top of the stack which must be preserved.
12122 */
Eric Andersenc470f442003-07-28 09:56:35 +000012123parsebackq: {
12124 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012125 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010012126 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000012127 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012128 smallint saveprompt = 0;
12129
Eric Andersenc470f442003-07-28 09:56:35 +000012130 str = NULL;
12131 savelen = out - (char *)stackblock();
12132 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012133 /*
12134 * FIXME: this can allocate very large block on stack and SEGV.
12135 * Example:
12136 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020012137 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012138 * a hundred command substitutions stack overflows.
12139 * With larger prepended string, SEGV happens sooner.
12140 */
Ron Yorston072fc602015-07-01 16:46:18 +010012141 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000012142 memcpy(str, stackblock(), savelen);
12143 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012144
Eric Andersenc470f442003-07-28 09:56:35 +000012145 if (oldstyle) {
12146 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010012147 * treatment to some slashes, and then push the string and
12148 * reread it as input, interpreting it normally.
12149 */
Eric Andersenc470f442003-07-28 09:56:35 +000012150 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000012151 size_t psavelen;
12152 char *pstr;
12153
Eric Andersenc470f442003-07-28 09:56:35 +000012154 STARTSTACKSTR(pout);
12155 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012156 int pc;
12157
12158 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012159 pc = pgetc();
12160 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000012161 case '`':
12162 goto done;
12163
12164 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012165 pc = pgetc();
12166 if (pc == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012167 nlprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012168 /*
12169 * If eating a newline, avoid putting
12170 * the newline into the new character
12171 * stream (via the STPUTC after the
12172 * switch).
12173 */
12174 continue;
12175 }
12176 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012177 && (!dblquote || pc != '"')
12178 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000012179 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012180 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010012181 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000012182 break;
12183 }
12184 /* fall through */
12185
12186 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012187 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012188 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012189 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000012190
12191 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012192 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012193 break;
12194
12195 default:
12196 break;
12197 }
12198 STPUTC(pc, pout);
12199 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012200 done:
Eric Andersenc470f442003-07-28 09:56:35 +000012201 STPUTC('\0', pout);
12202 psavelen = pout - (char *)stackblock();
12203 if (psavelen > 0) {
12204 pstr = grabstackstr(pout);
12205 setinputstring(pstr);
12206 }
12207 }
12208 nlpp = &bqlist;
12209 while (*nlpp)
12210 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012211 *nlpp = stzalloc(sizeof(**nlpp));
12212 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012213
12214 if (oldstyle) {
12215 saveprompt = doprompt;
12216 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012217 }
12218
Eric Andersenc470f442003-07-28 09:56:35 +000012219 n = list(2);
12220
12221 if (oldstyle)
12222 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012223 else if (readtoken() != TRP)
12224 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000012225
12226 (*nlpp)->n = n;
12227 if (oldstyle) {
12228 /*
12229 * Start reading from old file again, ignoring any pushed back
12230 * tokens left from the backquote parsing
12231 */
12232 popfile();
12233 tokpushback = 0;
12234 }
12235 while (stackblocksize() <= savelen)
12236 growstackblock();
12237 STARTSTACKSTR(out);
12238 if (str) {
12239 memcpy(out, str, savelen);
12240 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012241 }
Ron Yorston549deab2015-05-18 09:57:51 +020012242 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012243 if (oldstyle)
12244 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012245 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000012246}
12247
Denys Vlasenko0b883582016-12-23 16:49:07 +010012248#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000012249/*
12250 * Parse an arithmetic expansion (indicate start of one and set state)
12251 */
Eric Andersenc470f442003-07-28 09:56:35 +000012252parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000012253 if (++arinest == 1) {
12254 prevsyntax = syntax;
12255 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000012256 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020012257 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012258 goto parsearith_return;
12259}
12260#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012261} /* end of readtoken */
12262
Eric Andersencb57d552001-06-28 07:25:16 +000012263/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012264 * Read the next input token.
12265 * If the token is a word, we set backquotelist to the list of cmds in
12266 * backquotes. We set quoteflag to true if any part of the word was
12267 * quoted.
12268 * If the token is TREDIR, then we set redirnode to a structure containing
12269 * the redirection.
12270 * In all cases, the variable startlinno is set to the number of the line
12271 * on which the token starts.
12272 *
12273 * [Change comment: here documents and internal procedures]
12274 * [Readtoken shouldn't have any arguments. Perhaps we should make the
12275 * word parsing code into a separate routine. In this case, readtoken
12276 * doesn't need to have any internal procedures, but parseword does.
12277 * We could also make parseoperator in essence the main routine, and
12278 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000012279 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012280#define NEW_xxreadtoken
12281#ifdef NEW_xxreadtoken
12282/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012283static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000012284 '\n', '(', ')', /* singles */
12285 '&', '|', ';', /* doubles */
12286 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012287};
Eric Andersencb57d552001-06-28 07:25:16 +000012288
Denis Vlasenko834dee72008-10-07 09:18:30 +000012289#define xxreadtoken_singles 3
12290#define xxreadtoken_doubles 3
12291
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012292static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012293 TNL, TLP, TRP, /* only single occurrence allowed */
12294 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12295 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012296 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012297};
12298
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012299static int
12300xxreadtoken(void)
12301{
12302 int c;
12303
12304 if (tokpushback) {
12305 tokpushback = 0;
12306 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012307 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012308 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012309 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012310 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012311 c = pgetc();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000012312 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012313 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012314
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012315 if (c == '#') {
12316 while ((c = pgetc()) != '\n' && c != PEOF)
12317 continue;
12318 pungetc();
12319 } else if (c == '\\') {
12320 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012321 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012322 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012323 }
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012324 nlprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012325 } else {
12326 const char *p;
12327
12328 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12329 if (c != PEOF) {
12330 if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012331 nlnoprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012332 }
12333
12334 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000012335 if (p == NULL)
12336 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012337
Denis Vlasenko834dee72008-10-07 09:18:30 +000012338 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12339 int cc = pgetc();
12340 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012341 p += xxreadtoken_doubles + 1;
12342 } else {
12343 pungetc();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012344#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012345 if (c == '&' && cc == '>') /* &> */
12346 break; /* return readtoken1(...) */
12347#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012348 }
12349 }
12350 }
12351 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12352 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012353 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012354 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012355
12356 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012357}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012358#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012359#define RETURN(token) return lasttoken = token
12360static int
12361xxreadtoken(void)
12362{
12363 int c;
12364
12365 if (tokpushback) {
12366 tokpushback = 0;
12367 return lasttoken;
12368 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012369 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012370 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012371 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012372 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012373 switch (c) {
12374 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012375 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012376 continue;
12377 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012378 while ((c = pgetc()) != '\n' && c != PEOF)
12379 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012380 pungetc();
12381 continue;
12382 case '\\':
12383 if (pgetc() == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012384 nlprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012385 continue;
12386 }
12387 pungetc();
12388 goto breakloop;
12389 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012390 nlnoprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012391 RETURN(TNL);
12392 case PEOF:
12393 RETURN(TEOF);
12394 case '&':
12395 if (pgetc() == '&')
12396 RETURN(TAND);
12397 pungetc();
12398 RETURN(TBACKGND);
12399 case '|':
12400 if (pgetc() == '|')
12401 RETURN(TOR);
12402 pungetc();
12403 RETURN(TPIPE);
12404 case ';':
12405 if (pgetc() == ';')
12406 RETURN(TENDCASE);
12407 pungetc();
12408 RETURN(TSEMI);
12409 case '(':
12410 RETURN(TLP);
12411 case ')':
12412 RETURN(TRP);
12413 default:
12414 goto breakloop;
12415 }
12416 }
12417 breakloop:
12418 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12419#undef RETURN
12420}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012421#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012422
12423static int
12424readtoken(void)
12425{
12426 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012427 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012428#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012429 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012430#endif
12431
12432#if ENABLE_ASH_ALIAS
12433 top:
12434#endif
12435
12436 t = xxreadtoken();
12437
12438 /*
12439 * eat newlines
12440 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012441 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012442 while (t == TNL) {
12443 parseheredoc();
12444 t = xxreadtoken();
12445 }
12446 }
12447
12448 if (t != TWORD || quoteflag) {
12449 goto out;
12450 }
12451
12452 /*
12453 * check for keywords
12454 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012455 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012456 const char *const *pp;
12457
12458 pp = findkwd(wordtext);
12459 if (pp) {
12460 lasttoken = t = pp - tokname_array;
Denys Vlasenko888527c2016-10-02 16:54:17 +020012461 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012462 goto out;
12463 }
12464 }
12465
12466 if (checkkwd & CHKALIAS) {
12467#if ENABLE_ASH_ALIAS
12468 struct alias *ap;
12469 ap = lookupalias(wordtext, 1);
12470 if (ap != NULL) {
12471 if (*ap->val) {
12472 pushstring(ap->val, ap);
12473 }
12474 goto top;
12475 }
12476#endif
12477 }
12478 out:
12479 checkkwd = 0;
12480#if DEBUG
12481 if (!alreadyseen)
Denys Vlasenko888527c2016-10-02 16:54:17 +020012482 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012483 else
Denys Vlasenko888527c2016-10-02 16:54:17 +020012484 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012485#endif
12486 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012487}
12488
Ron Yorstonc0e00762015-10-29 11:30:55 +000012489static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012490peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012491{
12492 int t;
12493
12494 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012495 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012496 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012497}
Eric Andersencb57d552001-06-28 07:25:16 +000012498
12499/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012500 * Read and parse a command. Returns NODE_EOF on end of file.
12501 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012502 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012503static union node *
12504parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012505{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012506 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012507 checkkwd = 0;
12508 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012509 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012510 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012511 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012512 return list(1);
12513}
12514
12515/*
12516 * Input any here documents.
12517 */
12518static void
12519parseheredoc(void)
12520{
12521 struct heredoc *here;
12522 union node *n;
12523
12524 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012525 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012526
12527 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012528 setprompt_if(needprompt, 2);
12529 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012530 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012531 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012532 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012533 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012534 n->narg.text = wordtext;
12535 n->narg.backquote = backquotelist;
12536 here->here->nhere.doc = n;
12537 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012538 }
Eric Andersencb57d552001-06-28 07:25:16 +000012539}
12540
12541
12542/*
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012543 * called by editline -- any expansions to the prompt should be added here.
Eric Andersencb57d552001-06-28 07:25:16 +000012544 */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012545static const char *
12546expandstr(const char *ps)
12547{
12548 union node n;
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012549 int saveprompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012550
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000012551 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12552 * and token processing _can_ alter it (delete NULs etc). */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012553 setinputstring((char *)ps);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012554
12555 saveprompt = doprompt;
12556 doprompt = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000012557 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012558 doprompt = saveprompt;
12559
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012560 popfile();
12561
12562 n.narg.type = NARG;
12563 n.narg.next = NULL;
12564 n.narg.text = wordtext;
12565 n.narg.backquote = backquotelist;
12566
Ron Yorston549deab2015-05-18 09:57:51 +020012567 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012568 return stackblock();
12569}
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012570
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012571/*
12572 * Execute a command or commands contained in a string.
12573 */
12574static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012575evalstring(char *s, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000012576{
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012577 struct jmploc *volatile savehandler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012578 struct jmploc jmploc;
12579 int ex;
12580
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012581 union node *n;
12582 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012583 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012584
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012585 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012586 setinputstring(s);
12587 setstackmark(&smark);
12588
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012589 status = 0;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012590 /* On exception inside execution loop, we must popfile().
12591 * Try interactively:
12592 * readonly a=a
12593 * command eval "a=b" # throws "is read only" error
12594 * "command BLTIN" is not supposed to abort (even in non-interactive use).
12595 * But if we skip popfile(), we hit EOF in eval's string, and exit.
12596 */
12597 savehandler = exception_handler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012598 ex = setjmp(jmploc.loc);
12599 if (ex)
12600 goto out;
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012601 exception_handler = &jmploc;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012602
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012603 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012604 int i;
12605
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012606 i = evaltree(n, flags);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012607 if (n)
12608 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012609 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012610 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012611 break;
12612 }
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012613 out:
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012614 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012615 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012616 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012617
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012618 exception_handler = savehandler;
12619 if (ex)
12620 longjmp(exception_handler->loc, ex);
12621
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012622 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000012623}
12624
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012625/*
12626 * The eval command.
12627 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012628static int FAST_FUNC
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012629evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012630{
12631 char *p;
12632 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012633
Denis Vlasenko68404f12008-03-17 09:00:54 +000012634 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012635 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012636 argv += 2;
12637 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012638 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012639 for (;;) {
12640 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012641 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012642 if (p == NULL)
12643 break;
12644 STPUTC(' ', concat);
12645 }
12646 STPUTC('\0', concat);
12647 p = grabstackstr(concat);
12648 }
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012649 return evalstring(p, flags & EV_TESTED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012650 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012651 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012652}
12653
12654/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012655 * Read and execute commands.
12656 * "Top" is nonzero for the top level command loop;
12657 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012658 */
12659static int
12660cmdloop(int top)
12661{
12662 union node *n;
12663 struct stackmark smark;
12664 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012665 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012666 int numeof = 0;
12667
12668 TRACE(("cmdloop(%d) called\n", top));
12669 for (;;) {
12670 int skip;
12671
12672 setstackmark(&smark);
12673#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012674 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020012675 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012676#endif
12677 inter = 0;
12678 if (iflag && top) {
12679 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012680 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012681 }
12682 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012683#if DEBUG
12684 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012685 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012686#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012687 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012688 if (!top || numeof >= 50)
12689 break;
12690 if (!stoppedjobs()) {
12691 if (!Iflag)
12692 break;
12693 out2str("\nUse \"exit\" to leave shell.\n");
12694 }
12695 numeof++;
12696 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012697 int i;
12698
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012699 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12700 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012701 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012702 i = evaltree(n, 0);
12703 if (n)
12704 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012705 }
12706 popstackmark(&smark);
12707 skip = evalskip;
12708
12709 if (skip) {
Denys Vlasenko6a0710e2016-09-30 14:18:34 +020012710 evalskip &= ~SKIPFUNC;
Denys Vlasenko0840c912016-10-01 15:27:44 +020012711 break;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012712 }
12713 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012714 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012715}
12716
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012717/*
12718 * Take commands from a file. To be compatible we should do a path
12719 * search for the file, which is necessary to find sub-commands.
12720 */
12721static char *
12722find_dot_file(char *name)
12723{
12724 char *fullname;
12725 const char *path = pathval();
12726 struct stat statb;
12727
12728 /* don't try this for absolute or relative paths */
12729 if (strchr(name, '/'))
12730 return name;
12731
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012732 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012733 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12734 /*
12735 * Don't bother freeing here, since it will
12736 * be freed by the caller.
12737 */
12738 return fullname;
12739 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012740 if (fullname != name)
12741 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012742 }
12743
12744 /* not found in the PATH */
12745 ash_msg_and_raise_error("%s: not found", name);
12746 /* NOTREACHED */
12747}
12748
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012749static int FAST_FUNC
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012750dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012751{
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012752 /* "false; . empty_file; echo $?" should print 0, not 1: */
12753 int status = 0;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012754 char *fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012755 char **argv;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012756 char *args_need_save;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012757 struct strlist *sp;
12758 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012759
12760 for (sp = cmdenviron; sp; sp = sp->next)
Denis Vlasenko4222ae42007-02-25 02:37:49 +000012761 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012762
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012763 nextopt(nullstr); /* handle possible "--" */
12764 argv = argptr;
12765
12766 if (!argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012767 /* bash says: "bash: .: filename argument required" */
12768 return 2; /* bash compat */
12769 }
12770
Denys Vlasenko091f8312013-03-17 14:25:22 +010012771 /* This aborts if file isn't found, which is POSIXly correct.
12772 * bash returns exitcode 1 instead.
12773 */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012774 fullname = find_dot_file(argv[0]);
12775 argv++;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012776 args_need_save = argv[0];
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010012777 if (args_need_save) { /* ". FILE ARGS", and ARGS are not empty */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012778 int argc;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012779 saveparam = shellparam;
12780 shellparam.malloced = 0;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012781 argc = 1;
12782 while (argv[argc])
12783 argc++;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012784 shellparam.nparam = argc;
12785 shellparam.p = argv;
12786 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012787
Denys Vlasenko091f8312013-03-17 14:25:22 +010012788 /* This aborts if file can't be opened, which is POSIXly correct.
12789 * bash returns exitcode 1 instead.
12790 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012791 setinputfile(fullname, INPUT_PUSH_FILE);
12792 commandname = fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012793 status = cmdloop(0);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012794 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012795
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012796 if (args_need_save) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012797 freeparam(&shellparam);
12798 shellparam = saveparam;
12799 };
12800
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012801 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012802}
12803
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012804static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012805exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012806{
12807 if (stoppedjobs())
12808 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012809 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012810 exitstatus = number(argv[1]);
12811 raise_exception(EXEXIT);
12812 /* NOTREACHED */
12813}
12814
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012815/*
12816 * Read a file containing shell functions.
12817 */
12818static void
12819readcmdfile(char *name)
12820{
12821 setinputfile(name, INPUT_PUSH_FILE);
12822 cmdloop(0);
12823 popfile();
12824}
12825
12826
Denis Vlasenkocc571512007-02-23 21:10:35 +000012827/* ============ find_command inplementation */
12828
12829/*
12830 * Resolve a command name. If you change this routine, you may have to
12831 * change the shellexec routine as well.
12832 */
12833static void
12834find_command(char *name, struct cmdentry *entry, int act, const char *path)
12835{
12836 struct tblentry *cmdp;
12837 int idx;
12838 int prev;
12839 char *fullname;
12840 struct stat statb;
12841 int e;
12842 int updatetbl;
12843 struct builtincmd *bcmd;
12844
12845 /* If name contains a slash, don't use PATH or hash table */
12846 if (strchr(name, '/') != NULL) {
12847 entry->u.index = -1;
12848 if (act & DO_ABS) {
12849 while (stat(name, &statb) < 0) {
12850#ifdef SYSV
12851 if (errno == EINTR)
12852 continue;
12853#endif
12854 entry->cmdtype = CMDUNKNOWN;
12855 return;
12856 }
12857 }
12858 entry->cmdtype = CMDNORMAL;
12859 return;
12860 }
12861
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012862/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012863
12864 updatetbl = (path == pathval());
12865 if (!updatetbl) {
12866 act |= DO_ALTPATH;
12867 if (strstr(path, "%builtin") != NULL)
12868 act |= DO_ALTBLTIN;
12869 }
12870
12871 /* If name is in the table, check answer will be ok */
12872 cmdp = cmdlookup(name, 0);
12873 if (cmdp != NULL) {
12874 int bit;
12875
12876 switch (cmdp->cmdtype) {
12877 default:
12878#if DEBUG
12879 abort();
12880#endif
12881 case CMDNORMAL:
12882 bit = DO_ALTPATH;
12883 break;
12884 case CMDFUNCTION:
12885 bit = DO_NOFUNC;
12886 break;
12887 case CMDBUILTIN:
12888 bit = DO_ALTBLTIN;
12889 break;
12890 }
12891 if (act & bit) {
12892 updatetbl = 0;
12893 cmdp = NULL;
12894 } else if (cmdp->rehash == 0)
12895 /* if not invalidated by cd, we're done */
12896 goto success;
12897 }
12898
12899 /* If %builtin not in path, check for builtin next */
12900 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012901 if (bcmd) {
12902 if (IS_BUILTIN_REGULAR(bcmd))
12903 goto builtin_success;
12904 if (act & DO_ALTPATH) {
12905 if (!(act & DO_ALTBLTIN))
12906 goto builtin_success;
12907 } else if (builtinloc <= 0) {
12908 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000012909 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012910 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000012911
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012912#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000012913 {
12914 int applet_no = find_applet_by_name(name);
12915 if (applet_no >= 0) {
12916 entry->cmdtype = CMDNORMAL;
12917 entry->u.index = -2 - applet_no;
12918 return;
12919 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012920 }
12921#endif
12922
Denis Vlasenkocc571512007-02-23 21:10:35 +000012923 /* We have to search path. */
12924 prev = -1; /* where to start */
12925 if (cmdp && cmdp->rehash) { /* doing a rehash */
12926 if (cmdp->cmdtype == CMDBUILTIN)
12927 prev = builtinloc;
12928 else
12929 prev = cmdp->param.index;
12930 }
12931
12932 e = ENOENT;
12933 idx = -1;
12934 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012935 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000012936 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012937 /* NB: code below will still use fullname
12938 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012939 idx++;
12940 if (pathopt) {
12941 if (prefix(pathopt, "builtin")) {
12942 if (bcmd)
12943 goto builtin_success;
12944 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000012945 }
12946 if ((act & DO_NOFUNC)
12947 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020012948 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012949 continue;
12950 }
12951 }
12952 /* if rehash, don't redo absolute path names */
12953 if (fullname[0] == '/' && idx <= prev) {
12954 if (idx < prev)
12955 continue;
12956 TRACE(("searchexec \"%s\": no change\n", name));
12957 goto success;
12958 }
12959 while (stat(fullname, &statb) < 0) {
12960#ifdef SYSV
12961 if (errno == EINTR)
12962 continue;
12963#endif
12964 if (errno != ENOENT && errno != ENOTDIR)
12965 e = errno;
12966 goto loop;
12967 }
12968 e = EACCES; /* if we fail, this will be the error */
12969 if (!S_ISREG(statb.st_mode))
12970 continue;
12971 if (pathopt) { /* this is a %func directory */
12972 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012973 /* NB: stalloc will return space pointed by fullname
12974 * (because we don't have any intervening allocations
12975 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012976 readcmdfile(fullname);
12977 cmdp = cmdlookup(name, 0);
12978 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12979 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12980 stunalloc(fullname);
12981 goto success;
12982 }
12983 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12984 if (!updatetbl) {
12985 entry->cmdtype = CMDNORMAL;
12986 entry->u.index = idx;
12987 return;
12988 }
12989 INT_OFF;
12990 cmdp = cmdlookup(name, 1);
12991 cmdp->cmdtype = CMDNORMAL;
12992 cmdp->param.index = idx;
12993 INT_ON;
12994 goto success;
12995 }
12996
12997 /* We failed. If there was an entry for this command, delete it */
12998 if (cmdp && updatetbl)
12999 delete_cmd_entry();
13000 if (act & DO_ERR)
13001 ash_msg("%s: %s", name, errmsg(e, "not found"));
13002 entry->cmdtype = CMDUNKNOWN;
13003 return;
13004
13005 builtin_success:
13006 if (!updatetbl) {
13007 entry->cmdtype = CMDBUILTIN;
13008 entry->u.cmd = bcmd;
13009 return;
13010 }
13011 INT_OFF;
13012 cmdp = cmdlookup(name, 1);
13013 cmdp->cmdtype = CMDBUILTIN;
13014 cmdp->param.cmd = bcmd;
13015 INT_ON;
13016 success:
13017 cmdp->rehash = 0;
13018 entry->cmdtype = cmdp->cmdtype;
13019 entry->u = cmdp->param;
13020}
13021
13022
Eric Andersencb57d552001-06-28 07:25:16 +000013023/*
Eric Andersencb57d552001-06-28 07:25:16 +000013024 * The trap builtin.
13025 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013026static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013027trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013028{
13029 char *action;
13030 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013031 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013032
Eric Andersenc470f442003-07-28 09:56:35 +000013033 nextopt(nullstr);
13034 ap = argptr;
13035 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013036 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013037 char *tr = trap_ptr[signo];
13038 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013039 /* note: bash adds "SIG", but only if invoked
13040 * as "bash". If called as "sh", or if set -o posix,
13041 * then it prints short signal names.
13042 * We are printing short names: */
13043 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013044 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013045 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013046 /* trap_ptr != trap only if we are in special-cased `trap` code.
13047 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013048 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013049 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000013050 }
13051 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013052 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013053 if (trap_ptr != trap) {
13054 free(trap_ptr);
13055 trap_ptr = trap;
13056 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013057 */
Eric Andersencb57d552001-06-28 07:25:16 +000013058 return 0;
13059 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013060
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013061 action = NULL;
13062 if (ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000013063 action = *ap++;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013064 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013065 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000013066 signo = get_signum(*ap);
Denys Vlasenkoe9aba3e2017-07-01 21:09:27 +020013067 if (signo < 0 || signo >= NSIG) {
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013068 /* Mimic bash message exactly */
13069 ash_msg("%s: invalid signal specification", *ap);
13070 exitcode = 1;
13071 goto next;
13072 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000013073 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000013074 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000013075 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000013076 action = NULL;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013077 else {
13078 if (action[0]) /* not NULL and not "" and not "-" */
13079 may_have_traps = 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013080 action = ckstrdup(action);
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013081 }
Eric Andersencb57d552001-06-28 07:25:16 +000013082 }
Denis Vlasenko60818682007-09-28 22:07:23 +000013083 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000013084 trap[signo] = action;
13085 if (signo != 0)
13086 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013087 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013088 next:
Eric Andersencb57d552001-06-28 07:25:16 +000013089 ap++;
13090 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013091 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013092}
13093
Eric Andersenc470f442003-07-28 09:56:35 +000013094
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013095/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000013096
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013097#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013098static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013099helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013100{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000013101 unsigned col;
13102 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000013103
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020013104 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000013105 "Built-in commands:\n"
13106 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000013107 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013108 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000013109 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013110 if (col > 60) {
13111 out1fmt("\n");
13112 col = 0;
13113 }
13114 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013115# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000013116 {
13117 const char *a = applet_names;
13118 while (*a) {
13119 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
13120 if (col > 60) {
13121 out1fmt("\n");
13122 col = 0;
13123 }
Ron Yorston2b919582016-04-08 11:57:20 +010013124 while (*a++ != '\0')
13125 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013126 }
13127 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013128# endif
Denys Vlasenkoebedb942016-10-02 18:45:09 +020013129 newline_and_flush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000013130 return EXIT_SUCCESS;
13131}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013132#endif
Eric Andersenc470f442003-07-28 09:56:35 +000013133
Flemming Madsend96ffda2013-04-07 18:47:24 +020013134#if MAX_HISTORY
13135static int FAST_FUNC
13136historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13137{
13138 show_history(line_input_state);
13139 return EXIT_SUCCESS;
13140}
13141#endif
13142
Eric Andersencb57d552001-06-28 07:25:16 +000013143/*
Eric Andersencb57d552001-06-28 07:25:16 +000013144 * The export and readonly commands.
13145 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013146static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013147exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000013148{
13149 struct var *vp;
13150 char *name;
13151 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000013152 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020013153 char opt;
13154 int flag;
13155 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000013156
Denys Vlasenkod5275882012-10-01 13:41:17 +020013157 /* "readonly" in bash accepts, but ignores -n.
13158 * We do the same: it saves a conditional in nextopt's param.
13159 */
13160 flag_off = 0;
13161 while ((opt = nextopt("np")) != '\0') {
13162 if (opt == 'n')
13163 flag_off = VEXPORT;
13164 }
13165 flag = VEXPORT;
13166 if (argv[0][0] == 'r') {
13167 flag = VREADONLY;
13168 flag_off = 0; /* readonly ignores -n */
13169 }
13170 flag_off = ~flag_off;
13171
Denys Vlasenko10ad6222017-04-17 16:13:32 +020013172 /*if (opt_p_not_specified) - bash doesn't check this. Try "export -p NAME" */
Denys Vlasenkod5275882012-10-01 13:41:17 +020013173 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013174 aptr = argptr;
13175 name = *aptr;
13176 if (name) {
13177 do {
13178 p = strchr(name, '=');
13179 if (p != NULL) {
13180 p++;
13181 } else {
13182 vp = *findvar(hashvar(name), name);
13183 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020013184 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013185 continue;
13186 }
Eric Andersencb57d552001-06-28 07:25:16 +000013187 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013188 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013189 } while ((name = *++aptr) != NULL);
13190 return 0;
13191 }
Eric Andersencb57d552001-06-28 07:25:16 +000013192 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013193
13194 /* No arguments. Show the list of exported or readonly vars.
13195 * -n is ignored.
13196 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013197 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000013198 return 0;
13199}
13200
Eric Andersencb57d552001-06-28 07:25:16 +000013201/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013202 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000013203 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013204static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013205unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000013206{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013207 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000013208
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013209 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013210 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013211 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000013212}
13213
Eric Andersencb57d552001-06-28 07:25:16 +000013214/*
Eric Andersencb57d552001-06-28 07:25:16 +000013215 * The unset builtin command. We unset the function before we unset the
13216 * variable to allow a function to be unset when there is a readonly variable
13217 * with the same name.
13218 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013219static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013220unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013221{
13222 char **ap;
13223 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013224 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013225 int ret = 0;
13226
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013227 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000013228 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000013229 }
Eric Andersencb57d552001-06-28 07:25:16 +000013230
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013231 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013232 if (flag != 'f') {
13233 i = unsetvar(*ap);
13234 ret |= i;
13235 if (!(i & 2))
13236 continue;
13237 }
13238 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000013239 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000013240 }
Eric Andersenc470f442003-07-28 09:56:35 +000013241 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000013242}
13243
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000013244static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013245 ' ', offsetof(struct tms, tms_utime),
13246 '\n', offsetof(struct tms, tms_stime),
13247 ' ', offsetof(struct tms, tms_cutime),
13248 '\n', offsetof(struct tms, tms_cstime),
13249 0
13250};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013251static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013252timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013253{
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020013254 unsigned long clk_tck, s, t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013255 const unsigned char *p;
13256 struct tms buf;
13257
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020013258 clk_tck = bb_clk_tck();
Eric Andersencb57d552001-06-28 07:25:16 +000013259 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013260
13261 p = timescmd_str;
13262 do {
13263 t = *(clock_t *)(((char *) &buf) + p[1]);
13264 s = t / clk_tck;
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020013265 t = t % clk_tck;
13266 out1fmt("%lum%lu.%03lus%c",
13267 s / 60, s % 60,
13268 (t * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013269 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013270 p += 2;
13271 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013272
Eric Andersencb57d552001-06-28 07:25:16 +000013273 return 0;
13274}
13275
Denys Vlasenko0b883582016-12-23 16:49:07 +010013276#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000013277/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013278 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013279 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000013280 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013281 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000013282 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013283static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013284letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013285{
Denis Vlasenko68404f12008-03-17 09:00:54 +000013286 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000013287
Denis Vlasenko68404f12008-03-17 09:00:54 +000013288 argv++;
13289 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000013290 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000013291 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013292 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013293 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013294
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000013295 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000013296}
Eric Andersenc470f442003-07-28 09:56:35 +000013297#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013298
Eric Andersenc470f442003-07-28 09:56:35 +000013299/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013300 * The read builtin. Options:
13301 * -r Do not interpret '\' specially
13302 * -s Turn off echo (tty only)
13303 * -n NCHARS Read NCHARS max
13304 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13305 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13306 * -u FD Read from given FD instead of fd 0
Eric Andersenc470f442003-07-28 09:56:35 +000013307 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013308 * TODO: bash also has:
13309 * -a ARRAY Read into array[0],[1],etc
13310 * -d DELIM End on DELIM char, not newline
13311 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000013312 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013313static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013314readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013315{
Denys Vlasenko73067272010-01-12 22:11:24 +010013316 char *opt_n = NULL;
13317 char *opt_p = NULL;
13318 char *opt_t = NULL;
13319 char *opt_u = NULL;
13320 int read_flags = 0;
13321 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000013322 int i;
13323
Denys Vlasenko73067272010-01-12 22:11:24 +010013324 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000013325 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000013326 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010013327 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013328 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013329 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010013330 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013331 break;
13332 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010013333 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000013334 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013335 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010013336 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013337 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013338 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010013339 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000013340 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013341 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010013342 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013343 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013344 default:
13345 break;
13346 }
Eric Andersenc470f442003-07-28 09:56:35 +000013347 }
Paul Fox02eb9342005-09-07 16:56:02 +000013348
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013349 /* "read -s" needs to save/restore termios, can't allow ^C
13350 * to jump out of it.
13351 */
Denys Vlasenkof5470412017-05-22 19:34:45 +020013352 again:
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013353 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013354 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010013355 argptr,
13356 bltinlookup("IFS"), /* can be NULL */
13357 read_flags,
13358 opt_n,
13359 opt_p,
13360 opt_t,
13361 opt_u
13362 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013363 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000013364
Denys Vlasenkof5470412017-05-22 19:34:45 +020013365 if ((uintptr_t)r == 1 && errno == EINTR) {
13366 /* to get SIGCHLD: sleep 1 & read x; echo $x */
13367 if (pending_sig == 0)
13368 goto again;
13369 }
13370
Denys Vlasenko73067272010-01-12 22:11:24 +010013371 if ((uintptr_t)r > 1)
13372 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000013373
Denys Vlasenko73067272010-01-12 22:11:24 +010013374 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000013375}
13376
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013377static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020013378umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013379{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013380 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000013381
Eric Andersenc470f442003-07-28 09:56:35 +000013382 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000013383 int symbolic_mode = 0;
13384
13385 while (nextopt("S") != '\0') {
13386 symbolic_mode = 1;
13387 }
13388
Denis Vlasenkob012b102007-02-19 22:43:01 +000013389 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013390 mask = umask(0);
13391 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013392 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013393
Denys Vlasenko6283f982015-10-07 16:56:20 +020013394 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013395 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013396 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013397 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013398 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013399
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013400 i = 2;
13401 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013402 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013403 *p++ = permuser[i];
13404 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013405 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013406 if (!(mask & 0400)) *p++ = 'r';
13407 if (!(mask & 0200)) *p++ = 'w';
13408 if (!(mask & 0100)) *p++ = 'x';
13409 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013410 if (--i < 0)
13411 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013412 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013413 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013414 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013415 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013416 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013417 }
13418 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013419 char *modestr = *argptr;
13420 /* numeric umasks are taken as-is */
13421 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
13422 if (!isdigit(modestr[0]))
13423 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013424 mask = bb_parse_mode(modestr, mask);
13425 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013426 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013427 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013428 if (!isdigit(modestr[0]))
13429 mask ^= 0777;
13430 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013431 }
13432 return 0;
13433}
13434
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013435static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013436ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013437{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013438 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013439}
13440
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013441/* ============ main() and helpers */
13442
13443/*
13444 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013445 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013446static void
13447exitshell(void)
13448{
13449 struct jmploc loc;
13450 char *p;
13451 int status;
13452
Denys Vlasenkobede2152011-09-04 16:12:33 +020013453#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13454 save_history(line_input_state);
13455#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013456 status = exitstatus;
13457 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13458 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013459 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013460 status = exitstatus;
13461 goto out;
13462 }
13463 exception_handler = &loc;
13464 p = trap[0];
13465 if (p) {
13466 trap[0] = NULL;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013467 evalskip = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013468 evalstring(p, 0);
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013469 /*free(p); - we'll exit soon */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013470 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013471 out:
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013472 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13473 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13474 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013475 setjobctl(0);
Denys Vlasenkocaee80c2016-10-25 20:49:53 +020013476 flush_stdout_stderr();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013477 _exit(status);
13478 /* NOTREACHED */
13479}
13480
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013481static void
13482init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013483{
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013484 /* we will never free this */
13485 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013486
Denys Vlasenko458c1f22016-10-27 23:51:19 +020013487 sigmode[SIGCHLD - 1] = S_DFL;
13488 setsignal(SIGCHLD);
13489
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013490 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13491 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13492 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013493 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013494
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013495 {
13496 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013497 const char *p;
13498 struct stat st1, st2;
13499
13500 initvar();
13501 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenkob6838b52016-09-30 11:33:47 +020013502 p = endofname(*envp);
13503 if (p != *envp && *p == '=') {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013504 setvareq(*envp, VEXPORT|VTEXTFIXED);
13505 }
13506 }
13507
Denys Vlasenkoe627ac92016-09-30 14:36:59 +020013508 setvareq((char*)defoptindvar, VTEXTFIXED);
13509
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013510 setvar0("PPID", utoa(getppid()));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013511#if BASH_SHLVL_VAR
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013512 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013513 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013514#endif
13515#if BASH_HOSTNAME_VAR
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013516 if (!lookupvar("HOSTNAME")) {
13517 struct utsname uts;
13518 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013519 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013520 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013521#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013522 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013523 if (p) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013524 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013525 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13526 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013527 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013528 }
13529 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013530 setpwd(p, 0);
13531 }
13532}
13533
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013534
13535//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013536//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013537//usage:#define ash_full_usage "\n\n"
13538//usage: "Unix shell interpreter"
13539
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013540/*
13541 * Process the shell command line arguments.
13542 */
13543static void
Denis Vlasenko68404f12008-03-17 09:00:54 +000013544procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013545{
13546 int i;
13547 const char *xminusc;
13548 char **xargv;
13549
13550 xargv = argv;
13551 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013552 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013553 xargv++;
13554 for (i = 0; i < NOPTS; i++)
13555 optlist[i] = 2;
13556 argptr = xargv;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013557 if (options(/*cmdline:*/ 1)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013558 /* it already printed err message */
13559 raise_exception(EXERROR);
13560 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013561 xargv = argptr;
13562 xminusc = minusc;
13563 if (*xargv == NULL) {
13564 if (xminusc)
13565 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13566 sflag = 1;
13567 }
13568 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13569 iflag = 1;
13570 if (mflag == 2)
13571 mflag = iflag;
13572 for (i = 0; i < NOPTS; i++)
13573 if (optlist[i] == 2)
13574 optlist[i] = 0;
13575#if DEBUG == 2
13576 debug = 1;
13577#endif
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013578 /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013579 if (xminusc) {
13580 minusc = *xargv++;
13581 if (*xargv)
13582 goto setarg0;
13583 } else if (!sflag) {
13584 setinputfile(*xargv, 0);
13585 setarg0:
13586 arg0 = *xargv++;
13587 commandname = arg0;
13588 }
13589
13590 shellparam.p = xargv;
13591#if ENABLE_ASH_GETOPTS
13592 shellparam.optind = 1;
13593 shellparam.optoff = -1;
13594#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013595 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013596 while (*xargv) {
13597 shellparam.nparam++;
13598 xargv++;
13599 }
13600 optschanged();
13601}
13602
13603/*
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013604 * Read /etc/profile, ~/.profile, $ENV.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013605 */
13606static void
13607read_profile(const char *name)
13608{
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013609 name = expandstr(name);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013610 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13611 return;
Denys Vlasenko0840c912016-10-01 15:27:44 +020013612 cmdloop(0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013613 popfile();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013614}
13615
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013616/*
13617 * This routine is called when an error or an interrupt occurs in an
13618 * interactive shell and control is returned to the main command loop.
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013619 * (In dash, this function is auto-generated by build machinery).
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013620 */
13621static void
13622reset(void)
13623{
13624 /* from eval.c: */
13625 evalskip = 0;
13626 loopnest = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013627
13628 /* from expand.c: */
13629 ifsfree();
13630
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013631 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013632 g_parsefile->left_in_buffer = 0;
13633 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013634 popallfiles();
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013635
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013636 /* from redir.c: */
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020013637 while (redirlist)
13638 popredir(/*drop:*/ 0, /*restore:*/ 0);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013639}
13640
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013641#if PROFILE
13642static short profile_buf[16384];
13643extern int etext();
13644#endif
13645
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013646/*
13647 * Main routine. We initialize things, parse the arguments, execute
13648 * profiles if we're a login shell, and then call cmdloop to execute
13649 * commands. The setjmp call sets up the location to jump to when an
13650 * exception occurs. When an exception occurs the variable "state"
13651 * is used to figure out how far we had gotten.
13652 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013653int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013654int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013655{
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013656 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013657 struct jmploc jmploc;
13658 struct stackmark smark;
13659
Denis Vlasenko01631112007-12-16 17:20:38 +000013660 /* Initialize global data */
13661 INIT_G_misc();
13662 INIT_G_memstack();
13663 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013664#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013665 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013666#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013667 INIT_G_cmdtable();
13668
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013669#if PROFILE
13670 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13671#endif
13672
13673#if ENABLE_FEATURE_EDITING
13674 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13675#endif
13676 state = 0;
13677 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013678 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013679 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013680
13681 reset();
13682
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013683 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013684 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013685 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013686 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013687 }
13688 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020013689 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013690 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013691
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013692 popstackmark(&smark);
13693 FORCE_INT_ON; /* enable interrupts */
13694 if (s == 1)
13695 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013696 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013697 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013698 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013699 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013700 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013701 }
13702 exception_handler = &jmploc;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013703 rootpid = getpid();
13704
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013705 init();
13706 setstackmark(&smark);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013707 procargs(argv);
Denys Vlasenko474ed062016-10-30 18:30:29 +010013708#if DEBUG
13709 TRACE(("Shell args: "));
13710 trace_puts_args(argv);
13711#endif
Denis Vlasenko68404f12008-03-17 09:00:54 +000013712
Denys Vlasenko6088e132010-12-25 23:58:42 +010013713 if (argv[0] && argv[0][0] == '-')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013714 isloginsh = 1;
13715 if (isloginsh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013716 const char *hp;
13717
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013718 state = 1;
13719 read_profile("/etc/profile");
13720 state1:
13721 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013722 hp = lookupvar("HOME");
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013723 if (hp)
13724 read_profile("$HOME/.profile");
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013725 }
13726 state2:
13727 state = 3;
13728 if (
13729#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013730 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013731#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013732 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013733 ) {
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013734 const char *shinit = lookupvar("ENV");
13735 if (shinit != NULL && *shinit != '\0')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013736 read_profile(shinit);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013737 }
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013738 popstackmark(&smark);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013739 state3:
13740 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013741 if (minusc) {
13742 /* evalstring pushes parsefile stack.
13743 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013744 * is one of stacked source fds.
13745 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013746 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013747 // ^^ not necessary since now we special-case fd 0
13748 // in is_hidden_fd() to not be considered "hidden fd"
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013749 evalstring(minusc, 0);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013750 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013751
13752 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020013753#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013754 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013755 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013756 if (!hp) {
13757 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013758 if (hp) {
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013759 INT_OFF;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013760 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013761 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013762 free((char*)hp);
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013763 INT_ON;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013764 hp = lookupvar("HISTFILE");
13765 }
13766 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013767 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013768 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013769# if ENABLE_FEATURE_SH_HISTFILESIZE
13770 hp = lookupvar("HISTFILESIZE");
13771 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13772# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013773 }
13774#endif
13775 state4: /* XXX ??? - why isn't this before the "if" statement */
13776 cmdloop(1);
13777 }
13778#if PROFILE
13779 monitor(0);
13780#endif
13781#ifdef GPROF
13782 {
13783 extern void _mcleanup(void);
13784 _mcleanup();
13785 }
13786#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013787 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013788 exitshell();
13789 /* NOTREACHED */
13790}
13791
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013792
Eric Andersendf82f612001-06-28 07:46:40 +000013793/*-
13794 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013795 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013796 *
13797 * This code is derived from software contributed to Berkeley by
13798 * Kenneth Almquist.
13799 *
13800 * Redistribution and use in source and binary forms, with or without
13801 * modification, are permitted provided that the following conditions
13802 * are met:
13803 * 1. Redistributions of source code must retain the above copyright
13804 * notice, this list of conditions and the following disclaimer.
13805 * 2. Redistributions in binary form must reproduce the above copyright
13806 * notice, this list of conditions and the following disclaimer in the
13807 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013808 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013809 * may be used to endorse or promote products derived from this software
13810 * without specific prior written permission.
13811 *
13812 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13813 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13814 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13815 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13816 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13817 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13818 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13819 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13820 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13821 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13822 * SUCH DAMAGE.
13823 */