blob: 0ae086e985a000152882d60629fc5e70ed8dd27f [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);
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02001661 p = (char *)mempcpy(p, s, 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++ = '\'';
Denys Vlasenko94af83e2017-07-23 21:55:40 +02001764 q = (char *)mempcpy(q, s, 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 Vlasenko5ace96a2017-07-23 21:46:02 +02001778 q = (char *)mempcpy(q, s - 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.
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001791 * If quoting was done, the return string is allocated on the stack,
1792 * otherwise a pointer to the original string is returned.
1793 */
1794static const char *
1795maybe_single_quote(const char *s)
1796{
1797 const char *p = s;
1798
1799 while (*p) {
1800 /* Assuming ACSII */
1801 /* quote ctrl_chars space !"#$%&'()* */
1802 if (*p < '+')
1803 goto need_quoting;
1804 /* quote ;<=>? */
1805 if (*p >= ';' && *p <= '?')
1806 goto need_quoting;
1807 /* quote `[\ */
1808 if (*p == '`')
1809 goto need_quoting;
1810 if (*p == '[')
1811 goto need_quoting;
1812 if (*p == '\\')
1813 goto need_quoting;
1814 /* quote {|}~ DEL and high bytes */
1815 if (*p > 'z')
1816 goto need_quoting;
1817 /* Not quoting these: +,-./ 0-9 :@ A-Z ]^_ a-z */
1818 /* TODO: maybe avoid quoting % */
1819 p++;
1820 }
1821 return s;
1822
1823 need_quoting:
1824 return single_quote(s);
1825}
1826
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001827
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001828/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001829
1830static char **argptr; /* argument list for builtin commands */
1831static char *optionarg; /* set by nextopt (like getopt) */
1832static char *optptr; /* used by nextopt */
1833
1834/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001835 * XXX - should get rid of. Have all builtins use getopt(3).
1836 * The library getopt must have the BSD extension static variable
1837 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001838 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001839 * Standard option processing (a la getopt) for builtin routines.
1840 * The only argument that is passed to nextopt is the option string;
1841 * the other arguments are unnecessary. It returns the character,
1842 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001843 */
1844static int
1845nextopt(const char *optstring)
1846{
1847 char *p;
1848 const char *q;
1849 char c;
1850
1851 p = optptr;
1852 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001853 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001854 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001855 if (p == NULL)
1856 return '\0';
1857 if (*p != '-')
1858 return '\0';
1859 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001860 return '\0';
1861 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001862 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001863 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001864 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001865 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001866 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001867 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001868 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001869 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001870 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001871 if (*++q == ':')
1872 q++;
1873 }
1874 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001875 if (*p == '\0') {
1876 p = *argptr++;
1877 if (p == NULL)
1878 ash_msg_and_raise_error("no arg for -%c option", c);
1879 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001880 optionarg = p;
1881 p = NULL;
1882 }
1883 optptr = p;
1884 return c;
1885}
1886
1887
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001888/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001889
Denis Vlasenko01631112007-12-16 17:20:38 +00001890/*
1891 * The parsefile structure pointed to by the global variable parsefile
1892 * contains information about the current file being read.
1893 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001894struct shparam {
1895 int nparam; /* # of positional parameters (without $0) */
1896#if ENABLE_ASH_GETOPTS
1897 int optind; /* next parameter to be processed by getopts */
1898 int optoff; /* used by getopts */
1899#endif
1900 unsigned char malloced; /* if parameter list dynamically allocated */
1901 char **p; /* parameter list */
1902};
1903
1904/*
1905 * Free the list of positional parameters.
1906 */
1907static void
1908freeparam(volatile struct shparam *param)
1909{
Denis Vlasenko01631112007-12-16 17:20:38 +00001910 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001911 char **ap, **ap1;
1912 ap = ap1 = param->p;
1913 while (*ap)
1914 free(*ap++);
1915 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001916 }
1917}
1918
1919#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001920static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001921#endif
1922
1923struct var {
1924 struct var *next; /* next entry in hash list */
1925 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001926 const char *var_text; /* name=value */
1927 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001928 /* the variable gets set/unset */
1929};
1930
1931struct localvar {
1932 struct localvar *next; /* next local variable in list */
1933 struct var *vp; /* the variable that was made local */
1934 int flags; /* saved flags */
1935 const char *text; /* saved text */
1936};
1937
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001938/* flags */
1939#define VEXPORT 0x01 /* variable is exported */
1940#define VREADONLY 0x02 /* variable cannot be modified */
1941#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1942#define VTEXTFIXED 0x08 /* text is statically allocated */
1943#define VSTACK 0x10 /* text is allocated on the stack */
1944#define VUNSET 0x20 /* the variable is not set */
1945#define VNOFUNC 0x40 /* don't call the callback function */
1946#define VNOSET 0x80 /* do not set variable - just readonly test */
1947#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001948#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001949# define VDYNAMIC 0x200 /* dynamic variable */
1950#else
1951# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001952#endif
1953
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001954
Denis Vlasenko01631112007-12-16 17:20:38 +00001955/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001956#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001957static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001958change_lc_all(const char *value)
1959{
1960 if (value && *value != '\0')
1961 setlocale(LC_ALL, value);
1962}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001963static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001964change_lc_ctype(const char *value)
1965{
1966 if (value && *value != '\0')
1967 setlocale(LC_CTYPE, value);
1968}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001969#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001970#if ENABLE_ASH_MAIL
1971static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01001972static void changemail(const char *var_value) FAST_FUNC;
1973#else
1974# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001975#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001976static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001977#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001978static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001979#endif
1980
Denis Vlasenko01631112007-12-16 17:20:38 +00001981static const struct {
1982 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001983 const char *var_text;
1984 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00001985} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02001986 /*
1987 * Note: VEXPORT would not work correctly here for NOFORK applets:
1988 * some environment strings may be constant.
1989 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001990 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001991#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001992 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
1993 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001994#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001995 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1996 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1997 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1998 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001999#if ENABLE_ASH_GETOPTS
Denys Vlasenkoe627ac92016-09-30 14:36:59 +02002000 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002001#endif
2002#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002003 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002004#endif
2005#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002006 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
2007 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002008#endif
2009#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002010 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002011#endif
2012};
2013
Denis Vlasenko0b769642008-07-24 07:54:57 +00002014struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00002015
2016struct globals_var {
2017 struct shparam shellparam; /* $@ current positional parameters */
2018 struct redirtab *redirlist;
Denis Vlasenko01631112007-12-16 17:20:38 +00002019 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
2020 struct var *vartab[VTABSIZE];
2021 struct var varinit[ARRAY_SIZE(varinit_data)];
2022};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00002023extern struct globals_var *const ash_ptr_to_globals_var;
2024#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00002025#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00002026//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00002027#define preverrout_fd (G_var.preverrout_fd)
2028#define vartab (G_var.vartab )
2029#define varinit (G_var.varinit )
2030#define INIT_G_var() do { \
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00002031 unsigned i; \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00002032 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
2033 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00002034 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002035 varinit[i].flags = varinit_data[i].flags; \
2036 varinit[i].var_text = varinit_data[i].var_text; \
2037 varinit[i].var_func = varinit_data[i].var_func; \
Denis Vlasenko01631112007-12-16 17:20:38 +00002038 } \
2039} while (0)
2040
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002041#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002042#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002043# define vmail (&vifs)[1]
2044# define vmpath (&vmail)[1]
2045# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002046#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002047# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002048#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002049#define vps1 (&vpath)[1]
2050#define vps2 (&vps1)[1]
2051#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002052#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002053# define voptind (&vps4)[1]
2054# if ENABLE_ASH_RANDOM_SUPPORT
2055# define vrandom (&voptind)[1]
2056# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002057#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002058# if ENABLE_ASH_RANDOM_SUPPORT
2059# define vrandom (&vps4)[1]
2060# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002061#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002062
2063/*
2064 * The following macros access the values of the above variables.
2065 * They have to skip over the name. They return the null string
2066 * for unset variables.
2067 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002068#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002069#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002070#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002071# define mailval() (vmail.var_text + 5)
2072# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002073# define mpathset() ((vmpath.flags & VUNSET) == 0)
2074#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002075#define pathval() (vpath.var_text + 5)
2076#define ps1val() (vps1.var_text + 4)
2077#define ps2val() (vps2.var_text + 4)
2078#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002079#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002080# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002081#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002082
Denis Vlasenko01631112007-12-16 17:20:38 +00002083#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002084static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002085getoptsreset(const char *value)
2086{
Denys Vlasenkoa513bf32016-10-26 02:03:37 +02002087 shellparam.optind = number(value) ?: 1;
Denis Vlasenko01631112007-12-16 17:20:38 +00002088 shellparam.optoff = -1;
2089}
2090#endif
2091
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002092/*
2093 * Compares two strings up to the first = or '\0'. The first
2094 * string must be terminated by '='; the second may be terminated by
2095 * either '=' or '\0'.
2096 */
2097static int
2098varcmp(const char *p, const char *q)
2099{
2100 int c, d;
2101
2102 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002103 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002104 goto out;
2105 p++;
2106 q++;
2107 }
2108 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002109 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002110 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002111 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002112 out:
2113 return c - d;
2114}
2115
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002116/*
2117 * Find the appropriate entry in the hash table from the name.
2118 */
2119static struct var **
2120hashvar(const char *p)
2121{
2122 unsigned hashval;
2123
2124 hashval = ((unsigned char) *p) << 4;
2125 while (*p && *p != '=')
2126 hashval += (unsigned char) *p++;
2127 return &vartab[hashval % VTABSIZE];
2128}
2129
2130static int
2131vpcmp(const void *a, const void *b)
2132{
2133 return varcmp(*(const char **)a, *(const char **)b);
2134}
2135
2136/*
2137 * This routine initializes the builtin variables.
2138 */
2139static void
2140initvar(void)
2141{
2142 struct var *vp;
2143 struct var *end;
2144 struct var **vpp;
2145
2146 /*
2147 * PS1 depends on uid
2148 */
2149#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002150 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002151#else
2152 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002153 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002154#endif
2155 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002156 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002157 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002158 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002159 vp->next = *vpp;
2160 *vpp = vp;
2161 } while (++vp < end);
2162}
2163
2164static struct var **
2165findvar(struct var **vpp, const char *name)
2166{
2167 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002168 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002169 break;
2170 }
2171 }
2172 return vpp;
2173}
2174
2175/*
2176 * Find the value of a variable. Returns NULL if not set.
2177 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002178static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002179lookupvar(const char *name)
2180{
2181 struct var *v;
2182
2183 v = *findvar(hashvar(name), name);
2184 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002185#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002186 /*
2187 * Dynamic variables are implemented roughly the same way they are
2188 * in bash. Namely, they're "special" so long as they aren't unset.
2189 * As soon as they're unset, they're no longer dynamic, and dynamic
2190 * lookup will no longer happen at that point. -- PFM.
2191 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002192 if (v->flags & VDYNAMIC)
2193 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002194#endif
2195 if (!(v->flags & VUNSET))
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002196 return var_end(v->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002197 }
2198 return NULL;
2199}
2200
Denys Vlasenko0b883582016-12-23 16:49:07 +01002201#if ENABLE_UNICODE_SUPPORT
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02002202static void
2203reinit_unicode_for_ash(void)
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002204{
2205 /* Unicode support should be activated even if LANG is set
2206 * _during_ shell execution, not only if it was set when
2207 * shell was started. Therefore, re-check LANG every time:
2208 */
2209 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2210 || ENABLE_UNICODE_USING_LOCALE
2211 ) {
2212 const char *s = lookupvar("LC_ALL");
2213 if (!s) s = lookupvar("LC_CTYPE");
2214 if (!s) s = lookupvar("LANG");
2215 reinit_unicode(s);
2216 }
2217}
Denys Vlasenko0b883582016-12-23 16:49:07 +01002218#else
2219# define reinit_unicode_for_ash() ((void)0)
2220#endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002221
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002222/*
2223 * Search the environment of a builtin command.
2224 */
Mike Frysinger98c52642009-04-02 10:02:37 +00002225static const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002226bltinlookup(const char *name)
2227{
2228 struct strlist *sp;
2229
2230 for (sp = cmdenviron; sp; sp = sp->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002231 if (varcmp(sp->text, name) == 0)
2232 return var_end(sp->text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002233 }
2234 return lookupvar(name);
2235}
2236
2237/*
2238 * Same as setvar except that the variable and value are passed in
2239 * the first argument as name=value. Since the first argument will
2240 * be actually stored in the table, it should not be a string that
2241 * will go away.
2242 * Called with interrupts off.
2243 */
2244static void
2245setvareq(char *s, int flags)
2246{
2247 struct var *vp, **vpp;
2248
2249 vpp = hashvar(s);
2250 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2251 vp = *findvar(vpp, s);
2252 if (vp) {
2253 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2254 const char *n;
2255
2256 if (flags & VNOSAVE)
2257 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002258 n = vp->var_text;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02002259 exitstatus = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002260 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2261 }
2262
2263 if (flags & VNOSET)
2264 return;
2265
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002266 if (vp->var_func && !(flags & VNOFUNC))
2267 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002268
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002269 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2270 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002271
2272 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2273 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002274 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002275 if (flags & VNOSET)
2276 return;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002277 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002278 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002279 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002280 *vpp = vp;
2281 }
2282 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2283 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002284 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002285 vp->flags = flags;
2286}
2287
2288/*
2289 * Set the value of a variable. The flags argument is ored with the
2290 * flags of the variable. If val is NULL, the variable is unset.
2291 */
2292static void
2293setvar(const char *name, const char *val, int flags)
2294{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002295 const char *q;
2296 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002297 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002298 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002299 size_t vallen;
2300
2301 q = endofname(name);
2302 p = strchrnul(q, '=');
2303 namelen = p - name;
2304 if (!namelen || p != q)
2305 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2306 vallen = 0;
2307 if (val == NULL) {
2308 flags |= VUNSET;
2309 } else {
2310 vallen = strlen(val);
2311 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002312
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002313 INT_OFF;
2314 nameeq = ckmalloc(namelen + vallen + 2);
Denys Vlasenkoda2244f2017-07-21 18:51:29 +02002315 p = mempcpy(nameeq, name, namelen);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002316 if (val) {
2317 *p++ = '=';
Denys Vlasenkoda2244f2017-07-21 18:51:29 +02002318 p = mempcpy(p, val, vallen);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002319 }
2320 *p = '\0';
2321 setvareq(nameeq, flags | VNOSAVE);
2322 INT_ON;
2323}
2324
Denys Vlasenko03dad222010-01-12 23:29:57 +01002325static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002326setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002327{
2328 setvar(name, val, 0);
2329}
2330
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002331/*
2332 * Unset the specified variable.
2333 */
2334static int
2335unsetvar(const char *s)
2336{
2337 struct var **vpp;
2338 struct var *vp;
2339 int retval;
2340
2341 vpp = findvar(hashvar(s), s);
2342 vp = *vpp;
2343 retval = 2;
2344 if (vp) {
2345 int flags = vp->flags;
2346
2347 retval = 1;
2348 if (flags & VREADONLY)
2349 goto out;
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002350#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002351 vp->flags &= ~VDYNAMIC;
2352#endif
2353 if (flags & VUNSET)
2354 goto ok;
2355 if ((flags & VSTRFIXED) == 0) {
2356 INT_OFF;
2357 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002358 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002359 *vpp = vp->next;
2360 free(vp);
2361 INT_ON;
2362 } else {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002363 setvar0(s, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002364 vp->flags &= ~VEXPORT;
2365 }
2366 ok:
2367 retval = 0;
2368 }
2369 out:
2370 return retval;
2371}
2372
2373/*
2374 * Process a linked list of variable assignments.
2375 */
2376static void
2377listsetvar(struct strlist *list_set_var, int flags)
2378{
2379 struct strlist *lp = list_set_var;
2380
2381 if (!lp)
2382 return;
2383 INT_OFF;
2384 do {
2385 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002386 lp = lp->next;
2387 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002388 INT_ON;
2389}
2390
2391/*
2392 * Generate a list of variables satisfying the given conditions.
2393 */
2394static char **
2395listvars(int on, int off, char ***end)
2396{
2397 struct var **vpp;
2398 struct var *vp;
2399 char **ep;
2400 int mask;
2401
2402 STARTSTACKSTR(ep);
2403 vpp = vartab;
2404 mask = on | off;
2405 do {
2406 for (vp = *vpp; vp; vp = vp->next) {
2407 if ((vp->flags & mask) == on) {
2408 if (ep == stackstrend())
2409 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002410 *ep++ = (char*)vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002411 }
2412 }
2413 } while (++vpp < vartab + VTABSIZE);
2414 if (ep == stackstrend())
2415 ep = growstackstr();
2416 if (end)
2417 *end = ep;
2418 *ep++ = NULL;
2419 return grabstackstr(ep);
2420}
2421
2422
2423/* ============ Path search helper
2424 *
2425 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002426 * of the path before the first call; path_advance will update
2427 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002428 * the possible path expansions in sequence. If an option (indicated by
2429 * a percent sign) appears in the path entry then the global variable
2430 * pathopt will be set to point to it; otherwise pathopt will be set to
2431 * NULL.
2432 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002433static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002434
2435static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002436path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002437{
2438 const char *p;
2439 char *q;
2440 const char *start;
2441 size_t len;
2442
2443 if (*path == NULL)
2444 return NULL;
2445 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002446 for (p = start; *p && *p != ':' && *p != '%'; p++)
2447 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002448 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2449 while (stackblocksize() < len)
2450 growstackblock();
2451 q = stackblock();
2452 if (p != start) {
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02002453 q = mempcpy(q, start, p - start);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002454 *q++ = '/';
2455 }
2456 strcpy(q, name);
2457 pathopt = NULL;
2458 if (*p == '%') {
2459 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002460 while (*p && *p != ':')
2461 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002462 }
2463 if (*p == ':')
2464 *path = p + 1;
2465 else
2466 *path = NULL;
2467 return stalloc(len);
2468}
2469
2470
2471/* ============ Prompt */
2472
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002473static smallint doprompt; /* if set, prompt the user */
2474static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002475
2476#if ENABLE_FEATURE_EDITING
2477static line_input_t *line_input_state;
2478static const char *cmdedit_prompt;
2479static void
2480putprompt(const char *s)
2481{
2482 if (ENABLE_ASH_EXPAND_PRMT) {
2483 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002484 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002485 return;
2486 }
2487 cmdedit_prompt = s;
2488}
2489#else
2490static void
2491putprompt(const char *s)
2492{
2493 out2str(s);
2494}
2495#endif
2496
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002497/* expandstr() needs parsing machinery, so it is far away ahead... */
2498static const char *expandstr(const char *ps);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002499
2500static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002501setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002502{
2503 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002504 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2505
2506 if (!do_set)
2507 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002508
2509 needprompt = 0;
2510
2511 switch (whichprompt) {
2512 case 1:
2513 prompt = ps1val();
2514 break;
2515 case 2:
2516 prompt = ps2val();
2517 break;
2518 default: /* 0 */
2519 prompt = nullstr;
2520 }
2521#if ENABLE_ASH_EXPAND_PRMT
Denys Vlasenko60ca8342016-09-30 11:21:21 +02002522 pushstackmark(&smark, stackblocksize());
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002523 putprompt(expandstr(prompt));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002524 popstackmark(&smark);
Denys Vlasenko48c803a2017-07-01 23:24:48 +02002525#else
2526 putprompt(prompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002527#endif
2528}
2529
2530
2531/* ============ The cd and pwd commands */
2532
2533#define CD_PHYSICAL 1
2534#define CD_PRINT 2
2535
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002536static int
2537cdopt(void)
2538{
2539 int flags = 0;
2540 int i, j;
2541
2542 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002543 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002544 if (i != j) {
2545 flags ^= CD_PHYSICAL;
2546 j = i;
2547 }
2548 }
2549
2550 return flags;
2551}
2552
2553/*
2554 * Update curdir (the name of the current directory) in response to a
2555 * cd command.
2556 */
2557static const char *
2558updatepwd(const char *dir)
2559{
2560 char *new;
2561 char *p;
2562 char *cdcomppath;
2563 const char *lim;
2564
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02002565 cdcomppath = sstrdup(dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002566 STARTSTACKSTR(new);
2567 if (*dir != '/') {
2568 if (curdir == nullstr)
2569 return 0;
2570 new = stack_putstr(curdir, new);
2571 }
2572 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002573 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002574 if (*dir != '/') {
2575 if (new[-1] != '/')
2576 USTPUTC('/', new);
2577 if (new > lim && *lim == '/')
2578 lim++;
2579 } else {
2580 USTPUTC('/', new);
2581 cdcomppath++;
2582 if (dir[1] == '/' && dir[2] != '/') {
2583 USTPUTC('/', new);
2584 cdcomppath++;
2585 lim++;
2586 }
2587 }
2588 p = strtok(cdcomppath, "/");
2589 while (p) {
2590 switch (*p) {
2591 case '.':
2592 if (p[1] == '.' && p[2] == '\0') {
2593 while (new > lim) {
2594 STUNPUTC(new);
2595 if (new[-1] == '/')
2596 break;
2597 }
2598 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002599 }
2600 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002601 break;
2602 /* fall through */
2603 default:
2604 new = stack_putstr(p, new);
2605 USTPUTC('/', new);
2606 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002607 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002608 }
2609 if (new > lim)
2610 STUNPUTC(new);
2611 *new = 0;
2612 return stackblock();
2613}
2614
2615/*
2616 * Find out what the current directory is. If we already know the current
2617 * directory, this routine returns immediately.
2618 */
2619static char *
2620getpwd(void)
2621{
Denis Vlasenko01631112007-12-16 17:20:38 +00002622 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002623 return dir ? dir : nullstr;
2624}
2625
2626static void
2627setpwd(const char *val, int setold)
2628{
2629 char *oldcur, *dir;
2630
2631 oldcur = dir = curdir;
2632
2633 if (setold) {
2634 setvar("OLDPWD", oldcur, VEXPORT);
2635 }
2636 INT_OFF;
2637 if (physdir != nullstr) {
2638 if (physdir != oldcur)
2639 free(physdir);
2640 physdir = nullstr;
2641 }
2642 if (oldcur == val || !val) {
2643 char *s = getpwd();
2644 physdir = s;
2645 if (!val)
2646 dir = s;
2647 } else
2648 dir = ckstrdup(val);
2649 if (oldcur != dir && oldcur != nullstr) {
2650 free(oldcur);
2651 }
2652 curdir = dir;
2653 INT_ON;
2654 setvar("PWD", dir, VEXPORT);
2655}
2656
2657static void hashcd(void);
2658
2659/*
Denys Vlasenko70392332016-10-27 02:31:55 +02002660 * Actually do the chdir. We also call hashcd to let other routines
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002661 * know that the current directory has changed.
2662 */
2663static int
2664docd(const char *dest, int flags)
2665{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002666 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002667 int err;
2668
2669 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2670
2671 INT_OFF;
2672 if (!(flags & CD_PHYSICAL)) {
2673 dir = updatepwd(dest);
2674 if (dir)
2675 dest = dir;
2676 }
2677 err = chdir(dest);
2678 if (err)
2679 goto out;
2680 setpwd(dir, 1);
2681 hashcd();
2682 out:
2683 INT_ON;
2684 return err;
2685}
2686
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002687static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002688cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002689{
2690 const char *dest;
2691 const char *path;
2692 const char *p;
2693 char c;
2694 struct stat statb;
2695 int flags;
2696
2697 flags = cdopt();
2698 dest = *argptr;
2699 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002700 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002701 else if (LONE_DASH(dest)) {
2702 dest = bltinlookup("OLDPWD");
2703 flags |= CD_PRINT;
2704 }
2705 if (!dest)
2706 dest = nullstr;
2707 if (*dest == '/')
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002708 goto step6;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002709 if (*dest == '.') {
2710 c = dest[1];
2711 dotdot:
2712 switch (c) {
2713 case '\0':
2714 case '/':
2715 goto step6;
2716 case '.':
2717 c = dest[2];
2718 if (c != '.')
2719 goto dotdot;
2720 }
2721 }
2722 if (!*dest)
2723 dest = ".";
2724 path = bltinlookup("CDPATH");
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002725 while (path) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002726 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002727 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002728 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2729 if (c && c != ':')
2730 flags |= CD_PRINT;
2731 docd:
2732 if (!docd(p, flags))
2733 goto out;
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002734 goto err;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002735 }
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002736 }
2737
2738 step6:
2739 p = dest;
2740 goto docd;
2741
2742 err:
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002743 ash_msg_and_raise_error("can't cd to %s", dest);
2744 /* NOTREACHED */
2745 out:
2746 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002747 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002748 return 0;
2749}
2750
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002751static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002752pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002753{
2754 int flags;
2755 const char *dir = curdir;
2756
2757 flags = cdopt();
2758 if (flags) {
2759 if (physdir == nullstr)
2760 setpwd(dir, 0);
2761 dir = physdir;
2762 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002763 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002764 return 0;
2765}
2766
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002767
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002768/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002769
Denis Vlasenko834dee72008-10-07 09:18:30 +00002770
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002771#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002772
Eric Andersenc470f442003-07-28 09:56:35 +00002773/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002774#define CWORD 0 /* character is nothing special */
2775#define CNL 1 /* newline character */
2776#define CBACK 2 /* a backslash character */
2777#define CSQUOTE 3 /* single quote */
2778#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002779#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002780#define CBQUOTE 6 /* backwards single quote */
2781#define CVAR 7 /* a dollar sign */
2782#define CENDVAR 8 /* a '}' character */
2783#define CLP 9 /* a left paren in arithmetic */
2784#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002785#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002786#define CCTL 12 /* like CWORD, except it must be escaped */
2787#define CSPCL 13 /* these terminate a word */
2788#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002789
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002790#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002791#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002792# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002793#endif
2794
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002795#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002796
Denys Vlasenko0b883582016-12-23 16:49:07 +01002797#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002798# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002799#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002800# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002801#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002802static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002803#if ENABLE_ASH_ALIAS
2804 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2805#endif
2806 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2807 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2808 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2809 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2810 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2811 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2812 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2813 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2814 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2815 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2816 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002817#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002818 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2819 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2820 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2821#endif
2822#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002823};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002824/* Constants below must match table above */
2825enum {
2826#if ENABLE_ASH_ALIAS
2827 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2828#endif
2829 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2830 CNL_CNL_CNL_CNL , /* 2 */
2831 CWORD_CCTL_CCTL_CWORD , /* 3 */
2832 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2833 CVAR_CVAR_CWORD_CVAR , /* 5 */
2834 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2835 CSPCL_CWORD_CWORD_CLP , /* 7 */
2836 CSPCL_CWORD_CWORD_CRP , /* 8 */
2837 CBACK_CBACK_CCTL_CBACK , /* 9 */
2838 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2839 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2840 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2841 CWORD_CWORD_CWORD_CWORD , /* 13 */
2842 CCTL_CCTL_CCTL_CCTL , /* 14 */
2843};
Eric Andersen2870d962001-07-02 17:27:21 +00002844
Denys Vlasenkocd716832009-11-28 22:14:02 +01002845/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2846 * caller must ensure proper cast on it if c is *char_ptr!
2847 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002848/* Values for syntax param */
2849#define BASESYNTAX 0 /* not in quotes */
2850#define DQSYNTAX 1 /* in double quotes */
2851#define SQSYNTAX 2 /* in single quotes */
2852#define ARISYNTAX 3 /* in arithmetic */
2853#define PSSYNTAX 4 /* prompt. never passed to SIT() */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002854
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002855#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002856
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002857static int
2858SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002859{
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002860 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2861 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2862 /*
2863 * This causes '/' to be prepended with CTLESC in dquoted string,
2864 * making "./file"* treated incorrectly because we feed
2865 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2866 * The "homegrown" glob implementation is okay with that,
2867 * but glibc one isn't. With '/' always treated as CWORD,
2868 * both work fine.
2869 */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002870# if ENABLE_ASH_ALIAS
2871 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002872 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002873 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002874 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2875 11, 3 /* "}~" */
2876 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002877# else
2878 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002879 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002880 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002881 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2882 10, 2 /* "}~" */
2883 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002884# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002885 const char *s;
2886 int indx;
2887
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002888 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002889 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002890# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002891 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002892 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002893 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002894# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002895 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002896 /* Cast is purely for paranoia here,
2897 * just in case someone passed signed char to us */
2898 if ((unsigned char)c >= CTL_FIRST
2899 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002900 ) {
2901 return CCTL;
2902 }
2903 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002904 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002905 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002906 indx = syntax_index_table[s - spec_symbls];
2907 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002908 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002909}
2910
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002911#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002912
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002913static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002914 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002915 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2916 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2917 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2918 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2919 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2920 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2921 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2922 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2923 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2924 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2925 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2926 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2927 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2928 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2929 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2930 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2931 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2932 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2933 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2934 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2935 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2936 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2937 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2938 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2939 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2940 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2941 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2942 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2943 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2944 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2945 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2946 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2947 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2948 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2949 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2950 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2952 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2954 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2955 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2956 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2957 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2958 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2960 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2961 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002962/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
2963 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkocd716832009-11-28 22:14:02 +01002964 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2975 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2976 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2977 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2978 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2979 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2980 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2983 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2986 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2987 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2988 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2989 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2990 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2991 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2992 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2993 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2994 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2995 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2996 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2997 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2998 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2999 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
3000 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
3001 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
3002 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
3003 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
3004 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
3005 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
3006 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
3007 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
3008 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
3009 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
3010 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
3011 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
3012 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
3013 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
3014 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
3015 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
3016 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
3017 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
3018 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
3019 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
3020 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
3021 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
3022 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
3023 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
3024 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
3025 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
3026 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
3027 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
3028 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
3029 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
3030 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
3031 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
3032 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
3033 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
3034 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
3035 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
3036 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
3037 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
3038 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
3039 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
3040 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
3041 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3042 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
3043 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
3044 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
3046 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
3047 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
3048 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
3049 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
3050 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
3051 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
3052 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3053 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3112 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3113 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3114 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3115 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3116 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3117 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3118 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3119 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3120 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3121 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3122 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3123 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3124 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3125 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3126 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3127 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3128 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3129 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3130 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3131 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3132 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3133 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3134 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3135 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3136 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3137 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3138 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3139 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3140 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3141 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3142 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3143 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3144 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3145 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3146 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3147 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3148 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3149 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3150 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3151 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3152 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3153 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3154 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3155 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3156 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3157 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3158 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3159 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3160 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3161 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3162 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3163 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3164 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3165 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3166 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3167 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3168 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3169 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3170 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3171 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003172 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003173# if ENABLE_ASH_ALIAS
3174 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3175# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003176};
3177
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003178#if 1
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003179# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003180#else /* debug version, caught one signed char bug */
3181# define SIT(c, syntax) \
3182 ({ \
3183 if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3184 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
Denys Vlasenko0b883582016-12-23 16:49:07 +01003185 if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003186 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3187 ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3188 })
3189#endif
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003190
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003191#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003192
Eric Andersen2870d962001-07-02 17:27:21 +00003193
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003194/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003195
Denis Vlasenko131ae172007-02-18 13:00:19 +00003196#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003197
3198#define ALIASINUSE 1
3199#define ALIASDEAD 2
3200
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003201struct alias {
3202 struct alias *next;
3203 char *name;
3204 char *val;
3205 int flag;
3206};
3207
Denis Vlasenko01631112007-12-16 17:20:38 +00003208
3209static struct alias **atab; // [ATABSIZE];
3210#define INIT_G_alias() do { \
3211 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3212} while (0)
3213
Eric Andersen2870d962001-07-02 17:27:21 +00003214
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003215static struct alias **
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02003216__lookupalias(const char *name)
3217{
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003218 unsigned int hashval;
3219 struct alias **app;
3220 const char *p;
3221 unsigned int ch;
3222
3223 p = name;
3224
3225 ch = (unsigned char)*p;
3226 hashval = ch << 4;
3227 while (ch) {
3228 hashval += ch;
3229 ch = (unsigned char)*++p;
3230 }
3231 app = &atab[hashval % ATABSIZE];
3232
3233 for (; *app; app = &(*app)->next) {
3234 if (strcmp(name, (*app)->name) == 0) {
3235 break;
3236 }
3237 }
3238
3239 return app;
3240}
3241
3242static struct alias *
3243lookupalias(const char *name, int check)
3244{
3245 struct alias *ap = *__lookupalias(name);
3246
3247 if (check && ap && (ap->flag & ALIASINUSE))
3248 return NULL;
3249 return ap;
3250}
3251
3252static struct alias *
3253freealias(struct alias *ap)
3254{
3255 struct alias *next;
3256
3257 if (ap->flag & ALIASINUSE) {
3258 ap->flag |= ALIASDEAD;
3259 return ap;
3260 }
3261
3262 next = ap->next;
3263 free(ap->name);
3264 free(ap->val);
3265 free(ap);
3266 return next;
3267}
Eric Andersencb57d552001-06-28 07:25:16 +00003268
Eric Andersenc470f442003-07-28 09:56:35 +00003269static void
3270setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003271{
3272 struct alias *ap, **app;
3273
3274 app = __lookupalias(name);
3275 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003276 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003277 if (ap) {
3278 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003279 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003280 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003281 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003282 ap->flag &= ~ALIASDEAD;
3283 } else {
3284 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003285 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003286 ap->name = ckstrdup(name);
3287 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003288 /*ap->flag = 0; - ckzalloc did it */
3289 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003290 *app = ap;
3291 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003292 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003293}
3294
Eric Andersenc470f442003-07-28 09:56:35 +00003295static int
3296unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003297{
Eric Andersencb57d552001-06-28 07:25:16 +00003298 struct alias **app;
3299
3300 app = __lookupalias(name);
3301
3302 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003303 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003304 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003305 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003306 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003307 }
3308
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003309 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003310}
3311
Eric Andersenc470f442003-07-28 09:56:35 +00003312static void
3313rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003314{
Eric Andersencb57d552001-06-28 07:25:16 +00003315 struct alias *ap, **app;
3316 int i;
3317
Denis Vlasenkob012b102007-02-19 22:43:01 +00003318 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003319 for (i = 0; i < ATABSIZE; i++) {
3320 app = &atab[i];
3321 for (ap = *app; ap; ap = *app) {
3322 *app = freealias(*app);
3323 if (ap == *app) {
3324 app = &ap->next;
3325 }
3326 }
3327 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003328 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003329}
3330
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003331static void
3332printalias(const struct alias *ap)
3333{
3334 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3335}
3336
Eric Andersencb57d552001-06-28 07:25:16 +00003337/*
3338 * TODO - sort output
3339 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003340static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003341aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003342{
3343 char *n, *v;
3344 int ret = 0;
3345 struct alias *ap;
3346
Denis Vlasenko68404f12008-03-17 09:00:54 +00003347 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003348 int i;
3349
Denis Vlasenko68404f12008-03-17 09:00:54 +00003350 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003351 for (ap = atab[i]; ap; ap = ap->next) {
3352 printalias(ap);
3353 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003354 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003355 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003356 }
3357 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003358 v = strchr(n+1, '=');
3359 if (v == NULL) { /* n+1: funny ksh stuff */
3360 ap = *__lookupalias(n);
3361 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003362 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003363 ret = 1;
3364 } else
3365 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003366 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003367 *v++ = '\0';
3368 setalias(n, v);
3369 }
3370 }
3371
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003372 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003373}
3374
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003375static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003376unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003377{
3378 int i;
3379
Denys Vlasenko6c149f42017-04-12 21:31:32 +02003380 while (nextopt("a") != '\0') {
3381 rmaliases();
3382 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003383 }
3384 for (i = 0; *argptr; argptr++) {
3385 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003386 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003387 i = 1;
3388 }
3389 }
3390
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003391 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003392}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003393
Denis Vlasenko131ae172007-02-18 13:00:19 +00003394#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003395
Eric Andersenc470f442003-07-28 09:56:35 +00003396
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003397/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003398#define FORK_FG 0
3399#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003400#define FORK_NOJOB 2
3401
3402/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003403#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3404#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3405#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003406#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003407
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003408/*
3409 * A job structure contains information about a job. A job is either a
3410 * single process or a set of processes contained in a pipeline. In the
3411 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3412 * array of pids.
3413 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003414struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003415 pid_t ps_pid; /* process id */
3416 int ps_status; /* last process status from wait() */
3417 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003418};
3419
3420struct job {
3421 struct procstat ps0; /* status of process */
3422 struct procstat *ps; /* status or processes when more than one */
3423#if JOBS
3424 int stopstatus; /* status of a stopped job */
3425#endif
Denys Vlasenko4c179372017-01-11 18:44:15 +01003426 unsigned nprocs; /* number of processes */
3427
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003428#define JOBRUNNING 0 /* at least one proc running */
3429#define JOBSTOPPED 1 /* all procs are stopped */
3430#define JOBDONE 2 /* all procs are completed */
Denys Vlasenko4c179372017-01-11 18:44:15 +01003431 unsigned
3432 state: 8,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003433#if JOBS
3434 sigint: 1, /* job was killed by SIGINT */
3435 jobctl: 1, /* job running under job control */
3436#endif
3437 waited: 1, /* true if this entry has been waited for */
3438 used: 1, /* true if this entry is in used */
3439 changed: 1; /* true if status has changed */
3440 struct job *prev_job; /* previous job */
3441};
3442
Denis Vlasenko68404f12008-03-17 09:00:54 +00003443static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003444static int forkshell(struct job *, union node *, int);
3445static int waitforjob(struct job *);
3446
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003447#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003448enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003449#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003450#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003451static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003452static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003453#endif
3454
3455/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003456 * Ignore a signal.
3457 */
3458static void
3459ignoresig(int signo)
3460{
3461 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3462 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3463 /* No, need to do it */
3464 signal(signo, SIG_IGN);
3465 }
3466 sigmode[signo - 1] = S_HARD_IGN;
3467}
3468
3469/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003470 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003471 */
3472static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003473signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003474{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003475 if (signo == SIGCHLD) {
3476 got_sigchld = 1;
3477 if (!trap[SIGCHLD])
3478 return;
3479 }
3480
Denis Vlasenko4b875702009-03-19 13:30:04 +00003481 gotsig[signo - 1] = 1;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003482 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003483
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003484 if (signo == SIGINT && !trap[SIGINT]) {
3485 if (!suppress_int) {
3486 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003487 raise_interrupt(); /* does not return */
3488 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003489 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003490 }
3491}
3492
3493/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003494 * Set the signal handler for the specified signal. The routine figures
3495 * out what it should be set to.
3496 */
3497static void
3498setsignal(int signo)
3499{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003500 char *t;
3501 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003502 struct sigaction act;
3503
3504 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003505 new_act = S_DFL;
3506 if (t != NULL) { /* trap for this sig is set */
3507 new_act = S_CATCH;
3508 if (t[0] == '\0') /* trap is "": ignore this sig */
3509 new_act = S_IGN;
3510 }
3511
3512 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003513 switch (signo) {
3514 case SIGINT:
3515 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003516 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003517 break;
3518 case SIGQUIT:
3519#if DEBUG
3520 if (debug)
3521 break;
3522#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003523 /* man bash:
3524 * "In all cases, bash ignores SIGQUIT. Non-builtin
3525 * commands run by bash have signal handlers
3526 * set to the values inherited by the shell
3527 * from its parent". */
3528 new_act = S_IGN;
3529 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003530 case SIGTERM:
3531 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003532 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003533 break;
3534#if JOBS
3535 case SIGTSTP:
3536 case SIGTTOU:
3537 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003538 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003539 break;
3540#endif
3541 }
3542 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003543//TODO: if !rootshell, we reset SIGQUIT to DFL,
3544//whereas we have to restore it to what shell got on entry
3545//from the parent. See comment above
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003546
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003547 if (signo == SIGCHLD)
3548 new_act = S_CATCH;
3549
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003550 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003551 cur_act = *t;
3552 if (cur_act == 0) {
3553 /* current setting is not yet known */
3554 if (sigaction(signo, NULL, &act)) {
3555 /* pretend it worked; maybe we should give a warning,
3556 * but other shells don't. We don't alter sigmode,
3557 * so we retry every time.
3558 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003559 return;
3560 }
3561 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003562 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003563 if (mflag
3564 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3565 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003566 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003567 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003568 }
3569 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003570 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003571 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003572
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003573 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003574 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003575 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003576 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003577 break;
3578 case S_IGN:
3579 act.sa_handler = SIG_IGN;
3580 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003581 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003582
3583 /* flags and mask matter only if !DFL and !IGN, but we do it
3584 * for all cases for more deterministic behavior:
3585 */
3586 act.sa_flags = 0;
3587 sigfillset(&act.sa_mask);
3588
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003589 sigaction_set(signo, &act);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003590
3591 *t = new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003592}
3593
3594/* mode flags for set_curjob */
3595#define CUR_DELETE 2
3596#define CUR_RUNNING 1
3597#define CUR_STOPPED 0
3598
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003599#if JOBS
3600/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003601static int initialpgrp; //references:2
3602static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003603#endif
3604/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003605static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003606/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003607static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003608/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003609static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003610/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003611static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003612
Denys Vlasenko098b7132017-01-11 19:59:03 +01003613#if 0
3614/* Bash has a feature: it restores termios after a successful wait for
3615 * a foreground job which had at least one stopped or sigkilled member.
3616 * The probable rationale is that SIGSTOP and SIGKILL can preclude task from
3617 * properly restoring tty state. Should we do this too?
3618 * A reproducer: ^Z an interactive python:
3619 *
3620 * # python
3621 * Python 2.7.12 (...)
3622 * >>> ^Z
3623 * { python leaves tty in -icanon -echo state. We do survive that... }
3624 * [1]+ Stopped python
3625 * { ...however, next program (python #2) does not survive it well: }
3626 * # python
3627 * Python 2.7.12 (...)
3628 * >>> Traceback (most recent call last):
3629 * { above, I typed "qwerty<CR>", but -echo state is still in effect }
3630 * File "<stdin>", line 1, in <module>
3631 * NameError: name 'qwerty' is not defined
3632 *
3633 * The implementation below is modeled on bash code and seems to work.
3634 * However, I'm not sure we should do this. For one: what if I'd fg
3635 * the stopped python instead? It'll be confused by "restored" tty state.
3636 */
3637static struct termios shell_tty_info;
3638static void
3639get_tty_state(void)
3640{
3641 if (rootshell && ttyfd >= 0)
3642 tcgetattr(ttyfd, &shell_tty_info);
3643}
3644static void
3645set_tty_state(void)
3646{
3647 /* if (rootshell) - caller ensures this */
3648 if (ttyfd >= 0)
3649 tcsetattr(ttyfd, TCSADRAIN, &shell_tty_info);
3650}
3651static int
3652job_signal_status(struct job *jp)
3653{
3654 int status;
3655 unsigned i;
3656 struct procstat *ps = jp->ps;
3657 for (i = 0; i < jp->nprocs; i++) {
3658 status = ps[i].ps_status;
3659 if (WIFSIGNALED(status) || WIFSTOPPED(status))
3660 return status;
3661 }
3662 return 0;
3663}
3664static void
3665restore_tty_if_stopped_or_signaled(struct job *jp)
3666{
3667//TODO: check what happens if we come from waitforjob() in expbackq()
3668 if (rootshell) {
3669 int s = job_signal_status(jp);
3670 if (s) /* WIFSIGNALED(s) || WIFSTOPPED(s) */
3671 set_tty_state();
3672 }
3673}
3674#else
3675# define get_tty_state() ((void)0)
3676# define restore_tty_if_stopped_or_signaled(jp) ((void)0)
3677#endif
3678
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003679static void
3680set_curjob(struct job *jp, unsigned mode)
3681{
3682 struct job *jp1;
3683 struct job **jpp, **curp;
3684
3685 /* first remove from list */
3686 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003687 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003688 jp1 = *jpp;
3689 if (jp1 == jp)
3690 break;
3691 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003692 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003693 *jpp = jp1->prev_job;
3694
3695 /* Then re-insert in correct position */
3696 jpp = curp;
3697 switch (mode) {
3698 default:
3699#if DEBUG
3700 abort();
3701#endif
3702 case CUR_DELETE:
3703 /* job being deleted */
3704 break;
3705 case CUR_RUNNING:
3706 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003707 * put after all stopped jobs.
3708 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003709 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003710 jp1 = *jpp;
3711#if JOBS
3712 if (!jp1 || jp1->state != JOBSTOPPED)
3713#endif
3714 break;
3715 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003716 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003717 /* FALLTHROUGH */
3718#if JOBS
3719 case CUR_STOPPED:
3720#endif
3721 /* newly stopped job - becomes curjob */
3722 jp->prev_job = *jpp;
3723 *jpp = jp;
3724 break;
3725 }
3726}
3727
3728#if JOBS || DEBUG
3729static int
3730jobno(const struct job *jp)
3731{
3732 return jp - jobtab + 1;
3733}
3734#endif
3735
3736/*
3737 * Convert a job name to a job structure.
3738 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003739#if !JOBS
3740#define getjob(name, getctl) getjob(name)
3741#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003742static struct job *
3743getjob(const char *name, int getctl)
3744{
3745 struct job *jp;
3746 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003747 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003748 unsigned num;
3749 int c;
3750 const char *p;
3751 char *(*match)(const char *, const char *);
3752
3753 jp = curjob;
3754 p = name;
3755 if (!p)
3756 goto currentjob;
3757
3758 if (*p != '%')
3759 goto err;
3760
3761 c = *++p;
3762 if (!c)
3763 goto currentjob;
3764
3765 if (!p[1]) {
3766 if (c == '+' || c == '%') {
3767 currentjob:
3768 err_msg = "No current job";
3769 goto check;
3770 }
3771 if (c == '-') {
3772 if (jp)
3773 jp = jp->prev_job;
3774 err_msg = "No previous job";
3775 check:
3776 if (!jp)
3777 goto err;
3778 goto gotit;
3779 }
3780 }
3781
3782 if (is_number(p)) {
3783 num = atoi(p);
Denys Vlasenko46a45ce2016-09-29 01:10:08 +02003784 if (num > 0 && num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003785 jp = jobtab + num - 1;
3786 if (jp->used)
3787 goto gotit;
3788 goto err;
3789 }
3790 }
3791
3792 match = prefix;
3793 if (*p == '?') {
3794 match = strstr;
3795 p++;
3796 }
3797
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003798 found = NULL;
3799 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003800 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003801 if (found)
3802 goto err;
3803 found = jp;
3804 err_msg = "%s: ambiguous";
3805 }
3806 jp = jp->prev_job;
3807 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003808 if (!found)
3809 goto err;
3810 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003811
3812 gotit:
3813#if JOBS
3814 err_msg = "job %s not created under job control";
3815 if (getctl && jp->jobctl == 0)
3816 goto err;
3817#endif
3818 return jp;
3819 err:
3820 ash_msg_and_raise_error(err_msg, name);
3821}
3822
3823/*
3824 * Mark a job structure as unused.
3825 */
3826static void
3827freejob(struct job *jp)
3828{
3829 struct procstat *ps;
3830 int i;
3831
3832 INT_OFF;
3833 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003834 if (ps->ps_cmd != nullstr)
3835 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003836 }
3837 if (jp->ps != &jp->ps0)
3838 free(jp->ps);
3839 jp->used = 0;
3840 set_curjob(jp, CUR_DELETE);
3841 INT_ON;
3842}
3843
3844#if JOBS
3845static void
3846xtcsetpgrp(int fd, pid_t pgrp)
3847{
3848 if (tcsetpgrp(fd, pgrp))
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003849 ash_msg_and_raise_error("can't set tty process group (%m)");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003850}
3851
3852/*
3853 * Turn job control on and off.
3854 *
3855 * Note: This code assumes that the third arg to ioctl is a character
3856 * pointer, which is true on Berkeley systems but not System V. Since
3857 * System V doesn't have job control yet, this isn't a problem now.
3858 *
3859 * Called with interrupts off.
3860 */
3861static void
3862setjobctl(int on)
3863{
3864 int fd;
3865 int pgrp;
3866
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003867 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003868 return;
3869 if (on) {
3870 int ofd;
3871 ofd = fd = open(_PATH_TTY, O_RDWR);
3872 if (fd < 0) {
3873 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3874 * That sometimes helps to acquire controlling tty.
3875 * Obviously, a workaround for bugs when someone
3876 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003877 fd = 2;
3878 while (!isatty(fd))
3879 if (--fd < 0)
3880 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003881 }
Denys Vlasenko64774602016-10-26 15:24:30 +02003882 /* fd is a tty at this point */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003883 fd = fcntl(fd, F_DUPFD, 10);
Denys Vlasenko10ad6222017-04-17 16:13:32 +02003884 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, don't */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003885 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003886 if (fd < 0)
Denys Vlasenko64774602016-10-26 15:24:30 +02003887 goto out; /* F_DUPFD failed */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003888 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003889 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003890 pgrp = tcgetpgrp(fd);
3891 if (pgrp < 0) {
3892 out:
3893 ash_msg("can't access tty; job control turned off");
3894 mflag = on = 0;
3895 goto close;
3896 }
3897 if (pgrp == getpgrp())
3898 break;
3899 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003900 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003901 initialpgrp = pgrp;
3902
3903 setsignal(SIGTSTP);
3904 setsignal(SIGTTOU);
3905 setsignal(SIGTTIN);
3906 pgrp = rootpid;
3907 setpgid(0, pgrp);
3908 xtcsetpgrp(fd, pgrp);
3909 } else {
3910 /* turning job control off */
3911 fd = ttyfd;
3912 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003913 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003914 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003915 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003916 setpgid(0, pgrp);
3917 setsignal(SIGTSTP);
3918 setsignal(SIGTTOU);
3919 setsignal(SIGTTIN);
3920 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003921 if (fd >= 0)
3922 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003923 fd = -1;
3924 }
3925 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003926 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003927}
3928
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003929static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003930killcmd(int argc, char **argv)
3931{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003932 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003933 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003934 do {
3935 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003936 /*
3937 * "kill %N" - job kill
3938 * Converting to pgrp / pid kill
3939 */
3940 struct job *jp;
3941 char *dst;
3942 int j, n;
3943
3944 jp = getjob(argv[i], 0);
3945 /*
3946 * In jobs started under job control, we signal
3947 * entire process group by kill -PGRP_ID.
3948 * This happens, f.e., in interactive shell.
3949 *
3950 * Otherwise, we signal each child via
3951 * kill PID1 PID2 PID3.
3952 * Testcases:
3953 * sh -c 'sleep 1|sleep 1 & kill %1'
3954 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3955 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3956 */
3957 n = jp->nprocs; /* can't be 0 (I hope) */
3958 if (jp->jobctl)
3959 n = 1;
3960 dst = alloca(n * sizeof(int)*4);
3961 argv[i] = dst;
3962 for (j = 0; j < n; j++) {
3963 struct procstat *ps = &jp->ps[j];
3964 /* Skip non-running and not-stopped members
3965 * (i.e. dead members) of the job
3966 */
3967 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3968 continue;
3969 /*
3970 * kill_main has matching code to expect
3971 * leading space. Needed to not confuse
3972 * negative pids with "kill -SIGNAL_NO" syntax
3973 */
3974 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3975 }
3976 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003977 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003978 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003979 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003980 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003981}
3982
3983static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01003984showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003985{
Denys Vlasenko285ad152009-12-04 23:02:27 +01003986 struct procstat *ps;
3987 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003988
Denys Vlasenko285ad152009-12-04 23:02:27 +01003989 psend = jp->ps + jp->nprocs;
3990 for (ps = jp->ps + 1; ps < psend; ps++)
3991 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003992 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003993 flush_stdout_stderr();
3994}
3995
3996
3997static int
3998restartjob(struct job *jp, int mode)
3999{
4000 struct procstat *ps;
4001 int i;
4002 int status;
4003 pid_t pgid;
4004
4005 INT_OFF;
4006 if (jp->state == JOBDONE)
4007 goto out;
4008 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004009 pgid = jp->ps[0].ps_pid;
Denys Vlasenko098b7132017-01-11 19:59:03 +01004010 if (mode == FORK_FG) {
4011 get_tty_state();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004012 xtcsetpgrp(ttyfd, pgid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01004013 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004014 killpg(pgid, SIGCONT);
4015 ps = jp->ps;
4016 i = jp->nprocs;
4017 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004018 if (WIFSTOPPED(ps->ps_status)) {
4019 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004020 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004021 ps++;
4022 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004023 out:
4024 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
4025 INT_ON;
4026 return status;
4027}
4028
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004029static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004030fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004031{
4032 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004033 int mode;
4034 int retval;
4035
4036 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
4037 nextopt(nullstr);
4038 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004039 do {
4040 jp = getjob(*argv, 1);
4041 if (mode == FORK_BG) {
4042 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004043 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004044 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004045 out1str(jp->ps[0].ps_cmd);
4046 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004047 retval = restartjob(jp, mode);
4048 } while (*argv && *++argv);
4049 return retval;
4050}
4051#endif
4052
4053static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02004054sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004055{
4056 int col;
4057 int st;
4058
4059 col = 0;
4060 if (!WIFEXITED(status)) {
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004061#if JOBS
4062 if (WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004063 st = WSTOPSIG(status);
4064 else
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004065#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004066 st = WTERMSIG(status);
4067 if (sigonly) {
4068 if (st == SIGINT || st == SIGPIPE)
4069 goto out;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004070#if JOBS
4071 if (WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004072 goto out;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004073#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004074 }
4075 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01004076//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004077 col = fmtstr(s, 32, strsignal(st));
4078 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004079 strcpy(s + col, " (core dumped)");
4080 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004081 }
4082 } else if (!sigonly) {
4083 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004084 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004085 }
4086 out:
4087 return col;
4088}
4089
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004090static int
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004091wait_block_or_sig(int *status)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004092{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004093 int pid;
4094
4095 do {
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004096 sigset_t mask;
4097
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004098 /* Poll all children for changes in their state */
4099 got_sigchld = 0;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004100 /* if job control is active, accept stopped processes too */
4101 pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004102 if (pid != 0)
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004103 break; /* Error (e.g. EINTR, ECHILD) or pid */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004104
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004105 /* Children exist, but none are ready. Sleep until interesting signal */
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004106#if 1
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004107 sigfillset(&mask);
4108 sigprocmask(SIG_SETMASK, &mask, &mask);
4109 while (!got_sigchld && !pending_sig)
4110 sigsuspend(&mask);
4111 sigprocmask(SIG_SETMASK, &mask, NULL);
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004112#else /* unsafe: a signal can set pending_sig after check, but before pause() */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004113 while (!got_sigchld && !pending_sig)
4114 pause();
4115#endif
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004116
4117 /* If it was SIGCHLD, poll children again */
4118 } while (got_sigchld);
4119
4120 return pid;
4121}
4122
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004123#define DOWAIT_NONBLOCK 0
4124#define DOWAIT_BLOCK 1
4125#define DOWAIT_BLOCK_OR_SIG 2
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004126
4127static int
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004128dowait(int block, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004129{
4130 int pid;
4131 int status;
4132 struct job *jp;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004133 struct job *thisjob = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004134
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004135 TRACE(("dowait(0x%x) called\n", block));
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00004136
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004137 /* It's wrong to call waitpid() outside of INT_OFF region:
4138 * signal can arrive just after syscall return and handler can
4139 * longjmp away, losing stop/exit notification processing.
4140 * Thus, for "jobs" builtin, and for waiting for a fg job,
4141 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4142 *
4143 * However, for "wait" builtin it is wrong to simply call waitpid()
4144 * in INT_OFF region: "wait" needs to wait for any running job
4145 * to change state, but should exit on any trap too.
4146 * In INT_OFF region, a signal just before syscall entry can set
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004147 * pending_sig variables, but we can't check them, and we would
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004148 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004149 *
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004150 * Because of this, we run inside INT_OFF, but use a special routine
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004151 * which combines waitpid() and sigsuspend().
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004152 * This is the reason why we need to have a handler for SIGCHLD:
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004153 * SIG_DFL handler does not wake sigsuspend().
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004154 */
4155 INT_OFF;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004156 if (block == DOWAIT_BLOCK_OR_SIG) {
4157 pid = wait_block_or_sig(&status);
4158 } else {
4159 int wait_flags = 0;
4160 if (block == DOWAIT_NONBLOCK)
4161 wait_flags = WNOHANG;
4162 /* if job control is active, accept stopped processes too */
4163 if (doing_jobctl)
4164 wait_flags |= WUNTRACED;
4165 /* NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004166 pid = waitpid(-1, &status, wait_flags);
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004167 }
Denis Vlasenkob21f3792009-03-19 23:09:58 +00004168 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4169 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004170 if (pid <= 0)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004171 goto out;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004172
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004173 thisjob = NULL;
4174 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004175 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004176 struct procstat *ps;
4177 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004178 if (jp->state == JOBDONE)
4179 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004180 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004181 ps = jp->ps;
4182 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004183 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004184 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004185 TRACE(("Job %d: changing status of proc %d "
4186 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01004187 jobno(jp), pid, ps->ps_status, status));
4188 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004189 thisjob = jp;
4190 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004191 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004192 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004193#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004194 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004195 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004196 if (WIFSTOPPED(ps->ps_status)) {
4197 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004198 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004199 }
4200#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004201 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004202 if (!thisjob)
4203 continue;
4204
4205 /* Found the job where one of its processes changed its state.
4206 * Is there at least one live and running process in this job? */
4207 if (jobstate != JOBRUNNING) {
4208 /* No. All live processes in the job are stopped
4209 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4210 */
4211 thisjob->changed = 1;
4212 if (thisjob->state != jobstate) {
4213 TRACE(("Job %d: changing state from %d to %d\n",
4214 jobno(thisjob), thisjob->state, jobstate));
4215 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004216#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004217 if (jobstate == JOBSTOPPED)
4218 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004219#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004220 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004221 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004222 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004223 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004224 /* The process wasn't found in job list */
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004225#if JOBS
4226 if (!WIFSTOPPED(status))
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004227 jobless--;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004228#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004229 out:
4230 INT_ON;
4231
4232 if (thisjob && thisjob == job) {
4233 char s[48 + 1];
4234 int len;
4235
Denys Vlasenko9c541002015-10-07 15:44:36 +02004236 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004237 if (len) {
4238 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004239 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004240 out2str(s);
4241 }
4242 }
4243 return pid;
4244}
4245
4246#if JOBS
4247static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004248showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004249{
4250 struct procstat *ps;
4251 struct procstat *psend;
4252 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004253 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004254 char s[16 + 16 + 48];
4255 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004256
4257 ps = jp->ps;
4258
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004259 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004260 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004261 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004262 return;
4263 }
4264
4265 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004266 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004267
4268 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004269 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004270 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004271 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004272
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004273 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004274 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004275
4276 psend = ps + jp->nprocs;
4277
4278 if (jp->state == JOBRUNNING) {
4279 strcpy(s + col, "Running");
4280 col += sizeof("Running") - 1;
4281 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004282 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004283 if (jp->state == JOBSTOPPED)
4284 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004285 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004286 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004287 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004288
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004289 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4290 * or prints several "PID | <cmdN>" lines,
4291 * depending on SHOW_PIDS bit.
4292 * We do not print status of individual processes
4293 * between PID and <cmdN>. bash does it, but not very well:
4294 * first line shows overall job status, not process status,
4295 * making it impossible to know 1st process status.
4296 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004297 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004298 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004299 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004300 s[0] = '\0';
4301 col = 33;
4302 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004303 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004304 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004305 fprintf(out, "%s%*c%s%s",
4306 s,
4307 33 - col >= 0 ? 33 - col : 0, ' ',
4308 ps == jp->ps ? "" : "| ",
4309 ps->ps_cmd
4310 );
4311 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004312 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004313
4314 jp->changed = 0;
4315
4316 if (jp->state == JOBDONE) {
4317 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4318 freejob(jp);
4319 }
4320}
4321
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004322/*
4323 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4324 * statuses have changed since the last call to showjobs.
4325 */
4326static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004327showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004328{
4329 struct job *jp;
4330
Denys Vlasenko883cea42009-07-11 15:31:59 +02004331 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004332
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004333 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004334 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004335 continue;
4336
4337 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004338 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004339 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004340 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004341 }
4342}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004343
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004344static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004345jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004346{
4347 int mode, m;
4348
4349 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004350 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004351 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004352 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004353 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004354 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004355 }
4356
4357 argv = argptr;
4358 if (*argv) {
4359 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004360 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004361 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004362 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004363 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004364 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004365
4366 return 0;
4367}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004368#endif /* JOBS */
4369
Michael Abbott359da5e2009-12-04 23:03:29 +01004370/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004371static int
4372getstatus(struct job *job)
4373{
4374 int status;
4375 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004376 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004377
Michael Abbott359da5e2009-12-04 23:03:29 +01004378 /* Fetch last member's status */
4379 ps = job->ps + job->nprocs - 1;
4380 status = ps->ps_status;
4381 if (pipefail) {
4382 /* "set -o pipefail" mode: use last _nonzero_ status */
4383 while (status == 0 && --ps >= job->ps)
4384 status = ps->ps_status;
4385 }
4386
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004387 retval = WEXITSTATUS(status);
4388 if (!WIFEXITED(status)) {
4389#if JOBS
4390 retval = WSTOPSIG(status);
4391 if (!WIFSTOPPED(status))
4392#endif
4393 {
4394 /* XXX: limits number of signals */
4395 retval = WTERMSIG(status);
4396#if JOBS
4397 if (retval == SIGINT)
4398 job->sigint = 1;
4399#endif
4400 }
4401 retval += 128;
4402 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004403 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004404 jobno(job), job->nprocs, status, retval));
4405 return retval;
4406}
4407
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004408static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004409waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004410{
4411 struct job *job;
4412 int retval;
4413 struct job *jp;
4414
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004415 nextopt(nullstr);
4416 retval = 0;
4417
4418 argv = argptr;
4419 if (!*argv) {
4420 /* wait for all jobs */
4421 for (;;) {
4422 jp = curjob;
4423 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004424 if (!jp) /* no running procs */
4425 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004426 if (jp->state == JOBRUNNING)
4427 break;
4428 jp->waited = 1;
4429 jp = jp->prev_job;
4430 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004431 /* man bash:
4432 * "When bash is waiting for an asynchronous command via
4433 * the wait builtin, the reception of a signal for which a trap
4434 * has been set will cause the wait builtin to return immediately
4435 * with an exit status greater than 128, immediately after which
4436 * the trap is executed."
Denys Vlasenko69188112016-10-27 20:18:18 +02004437 */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004438 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004439 /* if child sends us a signal *and immediately exits*,
4440 * dowait() returns pid > 0. Check this case,
4441 * not "if (dowait() < 0)"!
4442 */
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004443 if (pending_sig)
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004444 goto sigout;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004445 }
4446 }
4447
4448 retval = 127;
4449 do {
4450 if (**argv != '%') {
4451 pid_t pid = number(*argv);
4452 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004453 while (1) {
4454 if (!job)
4455 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004456 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004457 break;
4458 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004459 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004460 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004461 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004462 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004463 /* loop until process terminated or stopped */
Denys Vlasenko69188112016-10-27 20:18:18 +02004464 while (job->state == JOBRUNNING) {
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004465 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004466 if (pending_sig)
4467 goto sigout;
Denys Vlasenko69188112016-10-27 20:18:18 +02004468 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004469 job->waited = 1;
4470 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004471 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004472 } while (*++argv);
4473
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004474 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004475 return retval;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004476 sigout:
4477 retval = 128 + pending_sig;
4478 return retval;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004479}
4480
4481static struct job *
4482growjobtab(void)
4483{
4484 size_t len;
4485 ptrdiff_t offset;
4486 struct job *jp, *jq;
4487
4488 len = njobs * sizeof(*jp);
4489 jq = jobtab;
4490 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4491
4492 offset = (char *)jp - (char *)jq;
4493 if (offset) {
4494 /* Relocate pointers */
4495 size_t l = len;
4496
4497 jq = (struct job *)((char *)jq + l);
4498 while (l) {
4499 l -= sizeof(*jp);
4500 jq--;
4501#define joff(p) ((struct job *)((char *)(p) + l))
4502#define jmove(p) (p) = (void *)((char *)(p) + offset)
4503 if (joff(jp)->ps == &jq->ps0)
4504 jmove(joff(jp)->ps);
4505 if (joff(jp)->prev_job)
4506 jmove(joff(jp)->prev_job);
4507 }
4508 if (curjob)
4509 jmove(curjob);
4510#undef joff
4511#undef jmove
4512 }
4513
4514 njobs += 4;
4515 jobtab = jp;
4516 jp = (struct job *)((char *)jp + len);
4517 jq = jp + 3;
4518 do {
4519 jq->used = 0;
4520 } while (--jq >= jp);
4521 return jp;
4522}
4523
4524/*
4525 * Return a new job structure.
4526 * Called with interrupts off.
4527 */
4528static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004529makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004530{
4531 int i;
4532 struct job *jp;
4533
4534 for (i = njobs, jp = jobtab; ; jp++) {
4535 if (--i < 0) {
4536 jp = growjobtab();
4537 break;
4538 }
4539 if (jp->used == 0)
4540 break;
4541 if (jp->state != JOBDONE || !jp->waited)
4542 continue;
4543#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004544 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004545 continue;
4546#endif
4547 freejob(jp);
4548 break;
4549 }
4550 memset(jp, 0, sizeof(*jp));
4551#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004552 /* jp->jobctl is a bitfield.
Denys Vlasenko098b7132017-01-11 19:59:03 +01004553 * "jp->jobctl |= doing_jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004554 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004555 jp->jobctl = 1;
4556#endif
4557 jp->prev_job = curjob;
4558 curjob = jp;
4559 jp->used = 1;
4560 jp->ps = &jp->ps0;
4561 if (nprocs > 1) {
4562 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4563 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004564 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004565 jobno(jp)));
4566 return jp;
4567}
4568
4569#if JOBS
4570/*
4571 * Return a string identifying a command (to be printed by the
4572 * jobs command).
4573 */
4574static char *cmdnextc;
4575
4576static void
4577cmdputs(const char *s)
4578{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004579 static const char vstype[VSTYPE + 1][3] = {
4580 "", "}", "-", "+", "?", "=",
4581 "%", "%%", "#", "##"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004582 IF_BASH_SUBSTR(, ":")
4583 IF_BASH_PATTERN_SUBST(, "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004584 };
4585
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004586 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004587 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004588 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004589 unsigned char c;
4590 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004591 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004592
Denys Vlasenko46a14772009-12-10 21:27:13 +01004593 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004594 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4595 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004596 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004597 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004598 switch (c) {
4599 case CTLESC:
4600 c = *p++;
4601 break;
4602 case CTLVAR:
4603 subtype = *p++;
4604 if ((subtype & VSTYPE) == VSLENGTH)
4605 str = "${#";
4606 else
4607 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004608 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004609 case CTLENDVAR:
4610 str = "\"}" + !(quoted & 1);
4611 quoted >>= 1;
4612 subtype = 0;
4613 goto dostr;
4614 case CTLBACKQ:
4615 str = "$(...)";
4616 goto dostr;
Denys Vlasenko0b883582016-12-23 16:49:07 +01004617#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004618 case CTLARI:
4619 str = "$((";
4620 goto dostr;
4621 case CTLENDARI:
4622 str = "))";
4623 goto dostr;
4624#endif
4625 case CTLQUOTEMARK:
4626 quoted ^= 1;
4627 c = '"';
4628 break;
4629 case '=':
4630 if (subtype == 0)
4631 break;
4632 if ((subtype & VSTYPE) != VSNORMAL)
4633 quoted <<= 1;
4634 str = vstype[subtype & VSTYPE];
4635 if (subtype & VSNUL)
4636 c = ':';
4637 else
4638 goto checkstr;
4639 break;
4640 case '\'':
4641 case '\\':
4642 case '"':
4643 case '$':
4644 /* These can only happen inside quotes */
4645 cc[0] = c;
4646 str = cc;
4647 c = '\\';
4648 break;
4649 default:
4650 break;
4651 }
4652 USTPUTC(c, nextc);
4653 checkstr:
4654 if (!str)
4655 continue;
4656 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004657 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004658 USTPUTC(c, nextc);
4659 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004660 } /* while *p++ not NUL */
4661
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004662 if (quoted & 1) {
4663 USTPUTC('"', nextc);
4664 }
4665 *nextc = 0;
4666 cmdnextc = nextc;
4667}
4668
4669/* cmdtxt() and cmdlist() call each other */
4670static void cmdtxt(union node *n);
4671
4672static void
4673cmdlist(union node *np, int sep)
4674{
4675 for (; np; np = np->narg.next) {
4676 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004677 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004678 cmdtxt(np);
4679 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004680 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004681 }
4682}
4683
4684static void
4685cmdtxt(union node *n)
4686{
4687 union node *np;
4688 struct nodelist *lp;
4689 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004690
4691 if (!n)
4692 return;
4693 switch (n->type) {
4694 default:
4695#if DEBUG
4696 abort();
4697#endif
4698 case NPIPE:
4699 lp = n->npipe.cmdlist;
4700 for (;;) {
4701 cmdtxt(lp->n);
4702 lp = lp->next;
4703 if (!lp)
4704 break;
4705 cmdputs(" | ");
4706 }
4707 break;
4708 case NSEMI:
4709 p = "; ";
4710 goto binop;
4711 case NAND:
4712 p = " && ";
4713 goto binop;
4714 case NOR:
4715 p = " || ";
4716 binop:
4717 cmdtxt(n->nbinary.ch1);
4718 cmdputs(p);
4719 n = n->nbinary.ch2;
4720 goto donode;
4721 case NREDIR:
4722 case NBACKGND:
4723 n = n->nredir.n;
4724 goto donode;
4725 case NNOT:
4726 cmdputs("!");
4727 n = n->nnot.com;
4728 donode:
4729 cmdtxt(n);
4730 break;
4731 case NIF:
4732 cmdputs("if ");
4733 cmdtxt(n->nif.test);
4734 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004735 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004736 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004737 cmdputs("; else ");
4738 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004739 } else {
4740 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004741 }
4742 p = "; fi";
4743 goto dotail;
4744 case NSUBSHELL:
4745 cmdputs("(");
4746 n = n->nredir.n;
4747 p = ")";
4748 goto dotail;
4749 case NWHILE:
4750 p = "while ";
4751 goto until;
4752 case NUNTIL:
4753 p = "until ";
4754 until:
4755 cmdputs(p);
4756 cmdtxt(n->nbinary.ch1);
4757 n = n->nbinary.ch2;
4758 p = "; done";
4759 dodo:
4760 cmdputs("; do ");
4761 dotail:
4762 cmdtxt(n);
4763 goto dotail2;
4764 case NFOR:
4765 cmdputs("for ");
4766 cmdputs(n->nfor.var);
4767 cmdputs(" in ");
4768 cmdlist(n->nfor.args, 1);
4769 n = n->nfor.body;
4770 p = "; done";
4771 goto dodo;
4772 case NDEFUN:
4773 cmdputs(n->narg.text);
4774 p = "() { ... }";
4775 goto dotail2;
4776 case NCMD:
4777 cmdlist(n->ncmd.args, 1);
4778 cmdlist(n->ncmd.redirect, 0);
4779 break;
4780 case NARG:
4781 p = n->narg.text;
4782 dotail2:
4783 cmdputs(p);
4784 break;
4785 case NHERE:
4786 case NXHERE:
4787 p = "<<...";
4788 goto dotail2;
4789 case NCASE:
4790 cmdputs("case ");
4791 cmdputs(n->ncase.expr->narg.text);
4792 cmdputs(" in ");
4793 for (np = n->ncase.cases; np; np = np->nclist.next) {
4794 cmdtxt(np->nclist.pattern);
4795 cmdputs(") ");
4796 cmdtxt(np->nclist.body);
4797 cmdputs(";; ");
4798 }
4799 p = "esac";
4800 goto dotail2;
4801 case NTO:
4802 p = ">";
4803 goto redir;
4804 case NCLOBBER:
4805 p = ">|";
4806 goto redir;
4807 case NAPPEND:
4808 p = ">>";
4809 goto redir;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004810#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00004811 case NTO2:
4812#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004813 case NTOFD:
4814 p = ">&";
4815 goto redir;
4816 case NFROM:
4817 p = "<";
4818 goto redir;
4819 case NFROMFD:
4820 p = "<&";
4821 goto redir;
4822 case NFROMTO:
4823 p = "<>";
4824 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004825 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004826 cmdputs(p);
4827 if (n->type == NTOFD || n->type == NFROMFD) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004828 cmdputs(utoa(n->ndup.dupfd));
4829 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004830 }
4831 n = n->nfile.fname;
4832 goto donode;
4833 }
4834}
4835
4836static char *
4837commandtext(union node *n)
4838{
4839 char *name;
4840
4841 STARTSTACKSTR(cmdnextc);
4842 cmdtxt(n);
4843 name = stackblock();
Denys Vlasenko6a94cee2016-10-25 17:40:25 +02004844 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004845 return ckstrdup(name);
4846}
4847#endif /* JOBS */
4848
4849/*
4850 * Fork off a subshell. If we are doing job control, give the subshell its
4851 * own process group. Jp is a job structure that the job is to be added to.
4852 * N is the command that will be evaluated by the child. Both jp and n may
4853 * be NULL. The mode parameter can be one of the following:
4854 * FORK_FG - Fork off a foreground process.
4855 * FORK_BG - Fork off a background process.
4856 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4857 * process group even if job control is on.
4858 *
4859 * When job control is turned off, background processes have their standard
4860 * input redirected to /dev/null (except for the second and later processes
4861 * in a pipeline).
4862 *
4863 * Called with interrupts off.
4864 */
4865/*
4866 * Clear traps on a fork.
4867 */
4868static void
4869clear_traps(void)
4870{
4871 char **tp;
4872
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004873 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004874 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004875 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004876 if (trap_ptr == trap)
4877 free(*tp);
4878 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004879 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004880 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004881 setsignal(tp - trap);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004882 }
4883 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004884 may_have_traps = 0;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004885 INT_ON;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004886}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004887
4888/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004889static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004890
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004891/* Called after fork(), in child */
Denys Vlasenko70392332016-10-27 02:31:55 +02004892/* jp and n are NULL when called by openhere() for heredoc support */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004893static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004894forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004895{
4896 int oldlvl;
4897
4898 TRACE(("Child shell %d\n", getpid()));
4899 oldlvl = shlvl;
4900 shlvl++;
4901
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004902 /* man bash: "Non-builtin commands run by bash have signal handlers
4903 * set to the values inherited by the shell from its parent".
4904 * Do we do it correctly? */
4905
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004906 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004907
4908 if (mode == FORK_NOJOB /* is it `xxx` ? */
4909 && n && n->type == NCMD /* is it single cmd? */
4910 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004911 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004912 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4913 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4914 ) {
4915 TRACE(("Trap hack\n"));
4916 /* Awful hack for `trap` or $(trap).
4917 *
4918 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4919 * contains an example where "trap" is executed in a subshell:
4920 *
4921 * save_traps=$(trap)
4922 * ...
4923 * eval "$save_traps"
4924 *
4925 * Standard does not say that "trap" in subshell shall print
4926 * parent shell's traps. It only says that its output
4927 * must have suitable form, but then, in the above example
4928 * (which is not supposed to be normative), it implies that.
4929 *
4930 * bash (and probably other shell) does implement it
4931 * (traps are reset to defaults, but "trap" still shows them),
4932 * but as a result, "trap" logic is hopelessly messed up:
4933 *
4934 * # trap
4935 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4936 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4937 * # true | trap <--- trap is in subshell - no output (ditto)
4938 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4939 * trap -- 'echo Ho' SIGWINCH
4940 * # echo `(trap)` <--- in subshell in subshell - output
4941 * trap -- 'echo Ho' SIGWINCH
4942 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4943 * trap -- 'echo Ho' SIGWINCH
4944 *
4945 * The rules when to forget and when to not forget traps
4946 * get really complex and nonsensical.
4947 *
4948 * Our solution: ONLY bare $(trap) or `trap` is special.
4949 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004950 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02004951 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004952 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004953 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004954 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004955#if JOBS
4956 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004957 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004958 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004959 pid_t pgrp;
4960
4961 if (jp->nprocs == 0)
4962 pgrp = getpid();
4963 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004964 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004965 /* this can fail because we are doing it in the parent also */
4966 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004967 if (mode == FORK_FG)
4968 xtcsetpgrp(ttyfd, pgrp);
4969 setsignal(SIGTSTP);
4970 setsignal(SIGTTOU);
4971 } else
4972#endif
4973 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004974 /* man bash: "When job control is not in effect,
4975 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004976 ignoresig(SIGINT);
4977 ignoresig(SIGQUIT);
4978 if (jp->nprocs == 0) {
4979 close(0);
4980 if (open(bb_dev_null, O_RDONLY) != 0)
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00004981 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004982 }
4983 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004984 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004985 if (iflag) { /* why if iflag only? */
4986 setsignal(SIGINT);
4987 setsignal(SIGTERM);
4988 }
4989 /* man bash:
4990 * "In all cases, bash ignores SIGQUIT. Non-builtin
4991 * commands run by bash have signal handlers
4992 * set to the values inherited by the shell
4993 * from its parent".
4994 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004995 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004996 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004997#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02004998 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01004999 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02005000 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005001 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02005002 /* "jobs": we do not want to clear job list for it,
5003 * instead we remove only _its_ own_ job from job list.
5004 * This makes "jobs .... | cat" more useful.
5005 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005006 freejob(curjob);
5007 return;
5008 }
5009#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005010 for (jp = curjob; jp; jp = jp->prev_job)
5011 freejob(jp);
5012 jobless = 0;
5013}
5014
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00005015/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00005016#if !JOBS
5017#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
5018#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005019static void
5020forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5021{
5022 TRACE(("In parent shell: child = %d\n", pid));
5023 if (!jp) {
Denys Vlasenko70392332016-10-27 02:31:55 +02005024 /* jp is NULL when called by openhere() for heredoc support */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00005025 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
5026 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005027 jobless++;
5028 return;
5029 }
5030#if JOBS
5031 if (mode != FORK_NOJOB && jp->jobctl) {
5032 int pgrp;
5033
5034 if (jp->nprocs == 0)
5035 pgrp = pid;
5036 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01005037 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005038 /* This can fail because we are doing it in the child also */
5039 setpgid(pid, pgrp);
5040 }
5041#endif
5042 if (mode == FORK_BG) {
5043 backgndpid = pid; /* set $! */
5044 set_curjob(jp, CUR_RUNNING);
5045 }
5046 if (jp) {
5047 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01005048 ps->ps_pid = pid;
5049 ps->ps_status = -1;
5050 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005051#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005052 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01005053 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005054#endif
5055 }
5056}
5057
Denys Vlasenko70392332016-10-27 02:31:55 +02005058/* jp and n are NULL when called by openhere() for heredoc support */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005059static int
5060forkshell(struct job *jp, union node *n, int mode)
5061{
5062 int pid;
5063
5064 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5065 pid = fork();
5066 if (pid < 0) {
5067 TRACE(("Fork failed, errno=%d", errno));
5068 if (jp)
5069 freejob(jp);
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +00005070 ash_msg_and_raise_error("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005071 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02005072 if (pid == 0) {
5073 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005074 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005075 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005076 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005077 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005078 return pid;
5079}
5080
5081/*
5082 * Wait for job to finish.
5083 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005084 * Under job control we have the problem that while a child process
5085 * is running interrupts generated by the user are sent to the child
5086 * but not to the shell. This means that an infinite loop started by
5087 * an interactive user may be hard to kill. With job control turned off,
5088 * an interactive user may place an interactive program inside a loop.
5089 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005090 * these interrupts to also abort the loop. The approach we take here
5091 * is to have the shell ignore interrupt signals while waiting for a
5092 * foreground process to terminate, and then send itself an interrupt
5093 * signal if the child process was terminated by an interrupt signal.
5094 * Unfortunately, some programs want to do a bit of cleanup and then
5095 * exit on interrupt; unless these processes terminate themselves by
5096 * sending a signal to themselves (instead of calling exit) they will
5097 * confuse this approach.
5098 *
5099 * Called with interrupts off.
5100 */
5101static int
5102waitforjob(struct job *jp)
5103{
5104 int st;
5105
5106 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005107
5108 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005109 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005110 /* In non-interactive shells, we _can_ get
5111 * a keyboard signal here and be EINTRed,
5112 * but we just loop back, waiting for command to complete.
5113 *
5114 * man bash:
5115 * "If bash is waiting for a command to complete and receives
5116 * a signal for which a trap has been set, the trap
5117 * will not be executed until the command completes."
5118 *
5119 * Reality is that even if trap is not set, bash
5120 * will not act on the signal until command completes.
5121 * Try this. sleep5intoff.c:
5122 * #include <signal.h>
5123 * #include <unistd.h>
5124 * int main() {
5125 * sigset_t set;
5126 * sigemptyset(&set);
5127 * sigaddset(&set, SIGINT);
5128 * sigaddset(&set, SIGQUIT);
5129 * sigprocmask(SIG_BLOCK, &set, NULL);
5130 * sleep(5);
5131 * return 0;
5132 * }
5133 * $ bash -c './sleep5intoff; echo hi'
5134 * ^C^C^C^C <--- pressing ^C once a second
5135 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005136 * $ bash -c './sleep5intoff; echo hi'
5137 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5138 * $ _
5139 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005140 dowait(DOWAIT_BLOCK, jp);
5141 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005142 INT_ON;
5143
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005144 st = getstatus(jp);
5145#if JOBS
5146 if (jp->jobctl) {
5147 xtcsetpgrp(ttyfd, rootpid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01005148 restore_tty_if_stopped_or_signaled(jp);
5149
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005150 /*
5151 * This is truly gross.
5152 * If we're doing job control, then we did a TIOCSPGRP which
5153 * caused us (the shell) to no longer be in the controlling
5154 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
5155 * intuit from the subprocess exit status whether a SIGINT
5156 * occurred, and if so interrupt ourselves. Yuck. - mycroft
5157 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00005158 if (jp->sigint) /* TODO: do the same with all signals */
5159 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005160 }
5161 if (jp->state == JOBDONE)
5162#endif
5163 freejob(jp);
5164 return st;
5165}
5166
5167/*
5168 * return 1 if there are stopped jobs, otherwise 0
5169 */
5170static int
5171stoppedjobs(void)
5172{
5173 struct job *jp;
5174 int retval;
5175
5176 retval = 0;
5177 if (job_warning)
5178 goto out;
5179 jp = curjob;
5180 if (jp && jp->state == JOBSTOPPED) {
5181 out2str("You have stopped jobs.\n");
5182 job_warning = 2;
5183 retval++;
5184 }
5185 out:
5186 return retval;
5187}
5188
5189
Denys Vlasenko70392332016-10-27 02:31:55 +02005190/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005191 * Code for dealing with input/output redirection.
5192 */
5193
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005194#undef EMPTY
5195#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005196#define EMPTY -2 /* marks an unused slot in redirtab */
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005197#define CLOSED -3 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005198
5199/*
5200 * Open a file in noclobber mode.
5201 * The code was copied from bash.
5202 */
5203static int
5204noclobberopen(const char *fname)
5205{
5206 int r, fd;
5207 struct stat finfo, finfo2;
5208
5209 /*
5210 * If the file exists and is a regular file, return an error
5211 * immediately.
5212 */
5213 r = stat(fname, &finfo);
5214 if (r == 0 && S_ISREG(finfo.st_mode)) {
5215 errno = EEXIST;
5216 return -1;
5217 }
5218
5219 /*
5220 * If the file was not present (r != 0), make sure we open it
5221 * exclusively so that if it is created before we open it, our open
5222 * will fail. Make sure that we do not truncate an existing file.
5223 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5224 * file was not a regular file, we leave O_EXCL off.
5225 */
5226 if (r != 0)
5227 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5228 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5229
5230 /* If the open failed, return the file descriptor right away. */
5231 if (fd < 0)
5232 return fd;
5233
5234 /*
5235 * OK, the open succeeded, but the file may have been changed from a
5236 * non-regular file to a regular file between the stat and the open.
5237 * We are assuming that the O_EXCL open handles the case where FILENAME
5238 * did not exist and is symlinked to an existing file between the stat
5239 * and open.
5240 */
5241
5242 /*
5243 * If we can open it and fstat the file descriptor, and neither check
5244 * revealed that it was a regular file, and the file has not been
5245 * replaced, return the file descriptor.
5246 */
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005247 if (fstat(fd, &finfo2) == 0
5248 && !S_ISREG(finfo2.st_mode)
5249 && finfo.st_dev == finfo2.st_dev
5250 && finfo.st_ino == finfo2.st_ino
5251 ) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005252 return fd;
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005253 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005254
5255 /* The file has been replaced. badness. */
5256 close(fd);
5257 errno = EEXIST;
5258 return -1;
5259}
5260
5261/*
5262 * Handle here documents. Normally we fork off a process to write the
5263 * data to a pipe. If the document is short, we can stuff the data in
5264 * the pipe without forking.
5265 */
5266/* openhere needs this forward reference */
5267static void expandhere(union node *arg, int fd);
5268static int
5269openhere(union node *redir)
5270{
5271 int pip[2];
5272 size_t len = 0;
5273
5274 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005275 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005276 if (redir->type == NHERE) {
5277 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005278 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005279 full_write(pip[1], redir->nhere.doc->narg.text, len);
5280 goto out;
5281 }
5282 }
5283 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005284 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005285 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005286 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5287 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5288 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5289 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005290 signal(SIGPIPE, SIG_DFL);
5291 if (redir->type == NHERE)
5292 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005293 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005294 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005295 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005296 }
5297 out:
5298 close(pip[1]);
5299 return pip[0];
5300}
5301
5302static int
5303openredirect(union node *redir)
5304{
5305 char *fname;
5306 int f;
5307
5308 switch (redir->nfile.type) {
Denys Vlasenko557482c2016-09-25 21:24:04 +02005309/* Can't happen, our single caller does this itself */
5310// case NTOFD:
5311// case NFROMFD:
5312// return -1;
5313 case NHERE:
5314 case NXHERE:
5315 return openhere(redir);
5316 }
5317
5318 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5319 * allocated space. Do it only when we know it is safe.
5320 */
5321 fname = redir->nfile.expfname;
5322
5323 switch (redir->nfile.type) {
5324 default:
5325#if DEBUG
5326 abort();
5327#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005328 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005329 f = open(fname, O_RDONLY);
5330 if (f < 0)
5331 goto eopen;
5332 break;
5333 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005334 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005335 if (f < 0)
5336 goto ecreate;
5337 break;
5338 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005339#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005340 case NTO2:
5341#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005342 /* Take care of noclobber mode. */
5343 if (Cflag) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005344 f = noclobberopen(fname);
5345 if (f < 0)
5346 goto ecreate;
5347 break;
5348 }
5349 /* FALLTHROUGH */
5350 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005351 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5352 if (f < 0)
5353 goto ecreate;
5354 break;
5355 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005356 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5357 if (f < 0)
5358 goto ecreate;
5359 break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005360 }
5361
5362 return f;
5363 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005364 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005365 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005366 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005367}
5368
5369/*
Denys Vlasenko64774602016-10-26 15:24:30 +02005370 * Copy a file descriptor to be >= 10. Throws exception on error.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005371 */
5372static int
Denys Vlasenko64774602016-10-26 15:24:30 +02005373savefd(int from)
5374{
5375 int newfd;
5376 int err;
5377
5378 newfd = fcntl(from, F_DUPFD, 10);
5379 err = newfd < 0 ? errno : 0;
5380 if (err != EBADF) {
5381 if (err)
5382 ash_msg_and_raise_error("%d: %m", from);
5383 close(from);
5384 fcntl(newfd, F_SETFD, FD_CLOEXEC);
5385 }
5386
5387 return newfd;
5388}
5389static int
5390dup2_or_raise(int from, int to)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005391{
5392 int newfd;
5393
Denys Vlasenko64774602016-10-26 15:24:30 +02005394 newfd = (from != to) ? dup2(from, to) : to;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005395 if (newfd < 0) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005396 /* Happens when source fd is not open: try "echo >&99" */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005397 ash_msg_and_raise_error("%d: %m", from);
5398 }
5399 return newfd;
5400}
5401
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005402/* Struct def and variable are moved down to the first usage site */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005403struct two_fd_t {
5404 int orig, copy;
5405};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005406struct redirtab {
5407 struct redirtab *next;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005408 int pair_count;
Denys Vlasenko606291b2009-09-23 23:15:43 +02005409 struct two_fd_t two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005410};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005411#define redirlist (G_var.redirlist)
Denys Vlasenko64774602016-10-26 15:24:30 +02005412enum {
5413 COPYFD_RESTORE = (int)~(INT_MAX),
5414};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005415
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005416static int
5417need_to_remember(struct redirtab *rp, int fd)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005418{
5419 int i;
5420
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005421 if (!rp) /* remembering was not requested */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005422 return 0;
5423
5424 for (i = 0; i < rp->pair_count; i++) {
5425 if (rp->two_fd[i].orig == fd) {
5426 /* already remembered */
5427 return 0;
5428 }
5429 }
5430 return 1;
5431}
5432
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005433/* "hidden" fd is a fd used to read scripts, or a copy of such */
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005434static int
5435is_hidden_fd(struct redirtab *rp, int fd)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005436{
5437 int i;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005438 struct parsefile *pf;
5439
5440 if (fd == -1)
5441 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005442 /* Check open scripts' fds */
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005443 pf = g_parsefile;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005444 while (pf) {
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005445 /* We skip pf_fd == 0 case because of the following case:
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005446 * $ ash # running ash interactively
5447 * $ . ./script.sh
5448 * and in script.sh: "exec 9>&0".
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005449 * Even though top-level pf_fd _is_ 0,
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005450 * it's still ok to use it: "read" builtin uses it,
5451 * why should we cripple "exec" builtin?
5452 */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005453 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005454 return 1;
5455 }
5456 pf = pf->prev;
5457 }
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005458
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005459 if (!rp)
5460 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005461 /* Check saved fds of redirects */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005462 fd |= COPYFD_RESTORE;
5463 for (i = 0; i < rp->pair_count; i++) {
5464 if (rp->two_fd[i].copy == fd) {
5465 return 1;
5466 }
5467 }
5468 return 0;
5469}
5470
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005471/*
5472 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5473 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005474 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005475 */
5476/* flags passed to redirect */
5477#define REDIR_PUSH 01 /* save previous values of file descriptors */
5478#define REDIR_SAVEFD2 03 /* set preverrout */
5479static void
5480redirect(union node *redir, int flags)
5481{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005482 struct redirtab *sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005483 int sv_pos;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005484 int i;
5485 int fd;
5486 int newfd;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005487 int copied_fd2 = -1;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005488
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005489 if (!redir) {
5490 return;
5491 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005492
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005493 sv = NULL;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005494 sv_pos = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005495 INT_OFF;
5496 if (flags & REDIR_PUSH) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005497 union node *tmp = redir;
5498 do {
5499 sv_pos++;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005500#if BASH_REDIR_OUTPUT
Chris Metcalfc3c1fb62010-01-08 13:18:06 +01005501 if (tmp->nfile.type == NTO2)
Denis Vlasenko559691a2008-10-05 18:39:31 +00005502 sv_pos++;
5503#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005504 tmp = tmp->nfile.next;
5505 } while (tmp);
5506 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005507 sv->next = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005508 sv->pair_count = sv_pos;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005509 redirlist = sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005510 while (sv_pos > 0) {
5511 sv_pos--;
5512 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5513 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005514 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005515
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005516 do {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005517 int right_fd = -1;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005518 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005519 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005520 right_fd = redir->ndup.dupfd;
5521 //bb_error_msg("doing %d > %d", fd, right_fd);
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005522 /* redirect from/to same file descriptor? */
5523 if (right_fd == fd)
5524 continue;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005525 /* "echo >&10" and 10 is a fd opened to a sh script? */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005526 if (is_hidden_fd(sv, right_fd)) {
5527 errno = EBADF; /* as if it is closed */
5528 ash_msg_and_raise_error("%d: %m", right_fd);
5529 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005530 newfd = -1;
5531 } else {
5532 newfd = openredirect(redir); /* always >= 0 */
5533 if (fd == newfd) {
5534 /* Descriptor wasn't open before redirect.
5535 * Mark it for close in the future */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005536 if (need_to_remember(sv, fd)) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005537 goto remember_to_close;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005538 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005539 continue;
5540 }
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005541 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005542#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005543 redirect_more:
5544#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005545 if (need_to_remember(sv, fd)) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005546 /* Copy old descriptor */
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005547 /* Careful to not accidentally "save"
5548 * to the same fd as right side fd in N>&M */
5549 int minfd = right_fd < 10 ? 10 : right_fd + 1;
Denys Vlasenko86584e12017-01-07 10:15:01 +01005550#if defined(F_DUPFD_CLOEXEC)
5551 i = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
5552#else
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005553 i = fcntl(fd, F_DUPFD, minfd);
Denys Vlasenko86584e12017-01-07 10:15:01 +01005554#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005555 if (i == -1) {
5556 i = errno;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005557 if (i != EBADF) {
5558 /* Strange error (e.g. "too many files" EMFILE?) */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005559 if (newfd >= 0)
5560 close(newfd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005561 errno = i;
5562 ash_msg_and_raise_error("%d: %m", fd);
5563 /* NOTREACHED */
5564 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005565 /* EBADF: it is not open - good, remember to close it */
5566 remember_to_close:
5567 i = CLOSED;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005568 } else { /* fd is open, save its copy */
Denys Vlasenko86584e12017-01-07 10:15:01 +01005569#if !defined(F_DUPFD_CLOEXEC)
5570 fcntl(i, F_SETFD, FD_CLOEXEC);
5571#endif
Denis Vlasenko22f74142008-07-24 22:34:43 +00005572 /* "exec fd>&-" should not close fds
5573 * which point to script file(s).
5574 * Force them to be restored afterwards */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005575 if (is_hidden_fd(sv, fd))
5576 i |= COPYFD_RESTORE;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005577 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005578 if (fd == 2)
5579 copied_fd2 = i;
5580 sv->two_fd[sv_pos].orig = fd;
5581 sv->two_fd[sv_pos].copy = i;
5582 sv_pos++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005583 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005584 if (newfd < 0) {
5585 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005586 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005587 /* Don't want to trigger debugging */
5588 if (fd != -1)
5589 close(fd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005590 } else {
Denys Vlasenko64774602016-10-26 15:24:30 +02005591 dup2_or_raise(redir->ndup.dupfd, fd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005592 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005593 } else if (fd != newfd) { /* move newfd to fd */
Denys Vlasenko64774602016-10-26 15:24:30 +02005594 dup2_or_raise(newfd, fd);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005595#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005596 if (!(redir->nfile.type == NTO2 && fd == 2))
5597#endif
5598 close(newfd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005599 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005600#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005601 if (redir->nfile.type == NTO2 && fd == 1) {
5602 /* We already redirected it to fd 1, now copy it to 2 */
5603 newfd = 1;
5604 fd = 2;
5605 goto redirect_more;
5606 }
5607#endif
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005608 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005609
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005610 INT_ON;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005611 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5612 preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005613}
5614
5615/*
5616 * Undo the effects of the last redirection.
5617 */
5618static void
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005619popredir(int drop, int restore)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005620{
5621 struct redirtab *rp;
5622 int i;
5623
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02005624 if (redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005625 return;
5626 INT_OFF;
5627 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005628 for (i = 0; i < rp->pair_count; i++) {
5629 int fd = rp->two_fd[i].orig;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005630 int copy = rp->two_fd[i].copy;
5631 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005632 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005633 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005634 continue;
5635 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005636 if (copy != EMPTY) {
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005637 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
Denis Vlasenko22f74142008-07-24 22:34:43 +00005638 copy &= ~COPYFD_RESTORE;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005639 /*close(fd);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02005640 dup2_or_raise(copy, fd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005641 }
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005642 close(copy & ~COPYFD_RESTORE);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005643 }
5644 }
5645 redirlist = rp->next;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005646 free(rp);
5647 INT_ON;
5648}
5649
5650/*
5651 * Undo all redirections. Called on error or interrupt.
5652 */
5653
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005654static int
5655redirectsafe(union node *redir, int flags)
5656{
5657 int err;
5658 volatile int saveint;
5659 struct jmploc *volatile savehandler = exception_handler;
5660 struct jmploc jmploc;
5661
5662 SAVE_INT(saveint);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005663 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5664 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005665 if (!err) {
5666 exception_handler = &jmploc;
5667 redirect(redir, flags);
5668 }
5669 exception_handler = savehandler;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00005670 if (err && exception_type != EXERROR)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005671 longjmp(exception_handler->loc, 1);
5672 RESTORE_INT(saveint);
5673 return err;
5674}
5675
5676
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005677/* ============ Routines to expand arguments to commands
5678 *
5679 * We have to deal with backquotes, shell variables, and file metacharacters.
5680 */
5681
Denys Vlasenko0b883582016-12-23 16:49:07 +01005682#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005683static arith_t
5684ash_arith(const char *s)
5685{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005686 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005687 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005688
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005689 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005690 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005691 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005692
5693 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005694 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005695 if (math_state.errmsg)
5696 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005697 INT_ON;
5698
5699 return result;
5700}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005701#endif
5702
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005703/*
5704 * expandarg flags
5705 */
5706#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5707#define EXP_TILDE 0x2 /* do normal tilde expansion */
5708#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5709#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
Denys Vlasenkodb74c6c2016-10-24 21:12:33 +02005710/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5711 * POSIX says for this case:
5712 * Pathname expansion shall not be performed on the word by a
5713 * non-interactive shell; an interactive shell may perform it, but shall
5714 * do so only when the expansion would result in one word.
5715 * Currently, our code complies to the above rule by never globbing
5716 * redirection filenames.
5717 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5718 * (this means that on a typical Linux distro, bash almost always
5719 * performs globbing, and thus diverges from what we do).
5720 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005721#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Ron Yorston549deab2015-05-18 09:57:51 +02005722#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005723#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5724#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005725#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005726/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005727 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005728 */
5729#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5730#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005731#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5732#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Ron Yorston417622c2015-05-18 09:59:14 +02005733#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005734
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005735/* Add CTLESC when necessary. */
Ron Yorston549deab2015-05-18 09:57:51 +02005736#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005737/* Do not skip NUL characters. */
5738#define QUOTES_KEEPNUL EXP_TILDE
5739
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005740/*
5741 * Structure specifying which parts of the string should be searched
5742 * for IFS characters.
5743 */
5744struct ifsregion {
5745 struct ifsregion *next; /* next region in list */
5746 int begoff; /* offset of start of region */
5747 int endoff; /* offset of end of region */
5748 int nulonly; /* search for nul bytes only */
5749};
5750
5751struct arglist {
5752 struct strlist *list;
5753 struct strlist **lastp;
5754};
5755
5756/* output of current string */
5757static char *expdest;
5758/* list of back quote expressions */
5759static struct nodelist *argbackq;
5760/* first struct in list of ifs regions */
5761static struct ifsregion ifsfirst;
5762/* last struct in list */
5763static struct ifsregion *ifslastp;
5764/* holds expanded arg list */
5765static struct arglist exparg;
5766
5767/*
5768 * Our own itoa().
5769 */
Denys Vlasenko0b883582016-12-23 16:49:07 +01005770#if !ENABLE_FEATURE_SH_MATH
Denys Vlasenko26777aa2010-11-22 23:49:10 +01005771/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5772typedef long arith_t;
5773# define ARITH_FMT "%ld"
5774#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005775static int
5776cvtnum(arith_t num)
5777{
5778 int len;
5779
Denys Vlasenko9c541002015-10-07 15:44:36 +02005780 expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest);
5781 len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005782 STADJUST(len, expdest);
5783 return len;
5784}
5785
Denys Vlasenko455e4222016-10-27 14:45:13 +02005786/*
5787 * Break the argument string into pieces based upon IFS and add the
5788 * strings to the argument list. The regions of the string to be
5789 * searched for IFS characters have been stored by recordregion.
5790 */
5791static void
5792ifsbreakup(char *string, struct arglist *arglist)
5793{
5794 struct ifsregion *ifsp;
5795 struct strlist *sp;
5796 char *start;
5797 char *p;
5798 char *q;
5799 const char *ifs, *realifs;
5800 int ifsspc;
5801 int nulonly;
5802
5803 start = string;
5804 if (ifslastp != NULL) {
5805 ifsspc = 0;
5806 nulonly = 0;
5807 realifs = ifsset() ? ifsval() : defifs;
5808 ifsp = &ifsfirst;
5809 do {
5810 p = string + ifsp->begoff;
5811 nulonly = ifsp->nulonly;
5812 ifs = nulonly ? nullstr : realifs;
5813 ifsspc = 0;
5814 while (p < string + ifsp->endoff) {
5815 q = p;
5816 if ((unsigned char)*p == CTLESC)
5817 p++;
5818 if (!strchr(ifs, *p)) {
5819 p++;
5820 continue;
5821 }
5822 if (!nulonly)
5823 ifsspc = (strchr(defifs, *p) != NULL);
5824 /* Ignore IFS whitespace at start */
5825 if (q == start && ifsspc) {
5826 p++;
5827 start = p;
5828 continue;
5829 }
5830 *q = '\0';
5831 sp = stzalloc(sizeof(*sp));
5832 sp->text = start;
5833 *arglist->lastp = sp;
5834 arglist->lastp = &sp->next;
5835 p++;
5836 if (!nulonly) {
5837 for (;;) {
5838 if (p >= string + ifsp->endoff) {
5839 break;
5840 }
5841 q = p;
5842 if ((unsigned char)*p == CTLESC)
5843 p++;
5844 if (strchr(ifs, *p) == NULL) {
5845 p = q;
5846 break;
5847 }
5848 if (strchr(defifs, *p) == NULL) {
5849 if (ifsspc) {
5850 p++;
5851 ifsspc = 0;
5852 } else {
5853 p = q;
5854 break;
5855 }
5856 } else
5857 p++;
5858 }
5859 }
5860 start = p;
5861 } /* while */
5862 ifsp = ifsp->next;
5863 } while (ifsp != NULL);
5864 if (nulonly)
5865 goto add;
5866 }
5867
5868 if (!*start)
5869 return;
5870
5871 add:
5872 sp = stzalloc(sizeof(*sp));
5873 sp->text = start;
5874 *arglist->lastp = sp;
5875 arglist->lastp = &sp->next;
5876}
5877
5878static void
5879ifsfree(void)
5880{
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005881 struct ifsregion *p = ifsfirst.next;
5882
5883 if (!p)
5884 goto out;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005885
5886 INT_OFF;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005887 do {
5888 struct ifsregion *ifsp;
5889 ifsp = p->next;
5890 free(p);
5891 p = ifsp;
5892 } while (p);
Denys Vlasenko455e4222016-10-27 14:45:13 +02005893 ifsfirst.next = NULL;
5894 INT_ON;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005895 out:
5896 ifslastp = NULL;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005897}
5898
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005899static size_t
5900esclen(const char *start, const char *p)
5901{
5902 size_t esc = 0;
5903
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005904 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005905 esc++;
5906 }
5907 return esc;
5908}
5909
5910/*
5911 * Remove any CTLESC characters from a string.
5912 */
5913static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005914rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005915{
Ron Yorston417622c2015-05-18 09:59:14 +02005916 static const char qchars[] ALIGN1 = {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005917 IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005918
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005919 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005920 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005921 unsigned protect_against_glob;
5922 unsigned globbing;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005923 IF_BASH_PATTERN_SUBST(unsigned slash = flag & RMESCAPE_SLASH;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005924
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005925 p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005926 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005927 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005928
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005929 q = p;
5930 r = str;
5931 if (flag & RMESCAPE_ALLOC) {
5932 size_t len = p - str;
5933 size_t fulllen = len + strlen(p) + 1;
5934
5935 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005936 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005937 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005938 /* p and str may be invalidated by makestrspace */
5939 str = (char *)stackblock() + strloc;
5940 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005941 } else if (flag & RMESCAPE_HEAP) {
5942 r = ckmalloc(fulllen);
5943 } else {
5944 r = stalloc(fulllen);
5945 }
5946 q = r;
5947 if (len > 0) {
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02005948 q = (char *)mempcpy(q, str, len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005949 }
5950 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005951
Ron Yorston549deab2015-05-18 09:57:51 +02005952 inquotes = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005953 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005954 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005955 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005956 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005957// Note: both inquotes and protect_against_glob only affect whether
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02005958// CTLESC,<ch> gets converted to <ch> or to \<ch>
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005959 inquotes = ~inquotes;
5960 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005961 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005962 continue;
5963 }
Ron Yorston549deab2015-05-18 09:57:51 +02005964 if ((unsigned char)*p == CTLESC) {
5965 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02005966#if DEBUG
5967 if (*p == '\0')
5968 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
5969#endif
Ron Yorston549deab2015-05-18 09:57:51 +02005970 if (protect_against_glob) {
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02005971 /*
5972 * We used to trust glob() and fnmatch() to eat
5973 * superfluous escapes (\z where z has no
5974 * special meaning anyway). But this causes
5975 * bugs such as string of one greek letter rho
Denys Vlasenkoed79a632017-07-05 19:20:43 +02005976 * (unicode-encoded as two bytes "cf,81")
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02005977 * getting encoded as "cf,CTLESC,81"
5978 * and here, converted to "cf,\,81" -
5979 * which does not go well with some flavors
Denys Vlasenko92b8d9c2017-07-05 19:13:44 +02005980 * of fnmatch() in unicode locales
5981 * (for example, glibc <= 2.22).
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02005982 *
5983 * Lets add "\" only on the chars which need it.
Denys Vlasenko4142f012017-07-05 22:19:28 +02005984 * Testcases for less obvious chars are shown.
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02005985 */
5986 if (*p == '*'
5987 || *p == '?'
5988 || *p == '['
Denys Vlasenko4142f012017-07-05 22:19:28 +02005989 || *p == '\\' /* case '\' in \\ ) echo ok;; *) echo WRONG;; esac */
5990 || *p == ']' /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */
5991 || *p == '-' /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */
5992 || *p == '!' /* case '!' in [\!] ) echo ok;; *) echo WRONG;; esac */
5993 /* Some libc support [^negate], that's why "^" also needs love */
5994 || *p == '^' /* case '^' in [\^] ) echo ok;; *) echo WRONG;; esac */
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02005995 ) {
5996 *q++ = '\\';
5997 }
Ron Yorston549deab2015-05-18 09:57:51 +02005998 }
5999 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006000 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006001 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006002 goto copy;
6003 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006004#if BASH_PATTERN_SUBST
Ron Yorston417622c2015-05-18 09:59:14 +02006005 else if (*p == '/' && slash) {
6006 /* stop handling globbing and mark location of slash */
6007 globbing = slash = 0;
6008 *p = CTLESC;
6009 }
6010#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006011 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006012 copy:
6013 *q++ = *p++;
6014 }
6015 *q = '\0';
6016 if (flag & RMESCAPE_GROW) {
6017 expdest = r;
6018 STADJUST(q - r + 1, expdest);
6019 }
6020 return r;
6021}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006022#define pmatch(a, b) !fnmatch((a), (b), 0)
6023
6024/*
6025 * Prepare a pattern for a expmeta (internal glob(3)) call.
6026 *
6027 * Returns an stalloced string.
6028 */
6029static char *
Ron Yorston549deab2015-05-18 09:57:51 +02006030preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006031{
Ron Yorston549deab2015-05-18 09:57:51 +02006032 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006033}
6034
6035/*
6036 * Put a string on the stack.
6037 */
6038static void
6039memtodest(const char *p, size_t len, int syntax, int quotes)
6040{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006041 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006042
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006043 if (!len)
6044 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006045
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006046 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
6047
6048 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006049 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006050 if (c) {
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01006051 if (quotes & QUOTES_ESC) {
6052 int n = SIT(c, syntax);
6053 if (n == CCTL
6054 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
6055 && n == CBACK
6056 )
6057 ) {
6058 USTPUTC(CTLESC, q);
6059 }
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006060 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006061 } else if (!(quotes & QUOTES_KEEPNUL))
6062 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006063 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006064 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006065
6066 expdest = q;
6067}
6068
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006069static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006070strtodest(const char *p, int syntax, int quotes)
6071{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006072 size_t len = strlen(p);
6073 memtodest(p, len, syntax, quotes);
6074 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006075}
6076
6077/*
6078 * Record the fact that we have to scan this region of the
6079 * string for IFS characters.
6080 */
6081static void
6082recordregion(int start, int end, int nulonly)
6083{
6084 struct ifsregion *ifsp;
6085
6086 if (ifslastp == NULL) {
6087 ifsp = &ifsfirst;
6088 } else {
6089 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00006090 ifsp = ckzalloc(sizeof(*ifsp));
6091 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006092 ifslastp->next = ifsp;
6093 INT_ON;
6094 }
6095 ifslastp = ifsp;
6096 ifslastp->begoff = start;
6097 ifslastp->endoff = end;
6098 ifslastp->nulonly = nulonly;
6099}
6100
6101static void
6102removerecordregions(int endoff)
6103{
6104 if (ifslastp == NULL)
6105 return;
6106
6107 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006108 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006109 struct ifsregion *ifsp;
6110 INT_OFF;
6111 ifsp = ifsfirst.next->next;
6112 free(ifsfirst.next);
6113 ifsfirst.next = ifsp;
6114 INT_ON;
6115 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006116 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006117 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006118 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006119 ifslastp = &ifsfirst;
6120 ifsfirst.endoff = endoff;
6121 }
6122 return;
6123 }
6124
6125 ifslastp = &ifsfirst;
6126 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006127 ifslastp = ifslastp->next;
6128 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006129 struct ifsregion *ifsp;
6130 INT_OFF;
6131 ifsp = ifslastp->next->next;
6132 free(ifslastp->next);
6133 ifslastp->next = ifsp;
6134 INT_ON;
6135 }
6136 if (ifslastp->endoff > endoff)
6137 ifslastp->endoff = endoff;
6138}
6139
6140static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006141exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006142{
Denys Vlasenkocd716832009-11-28 22:14:02 +01006143 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006144 char *name;
6145 struct passwd *pw;
6146 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006147 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006148
6149 name = p + 1;
6150
6151 while ((c = *++p) != '\0') {
6152 switch (c) {
6153 case CTLESC:
6154 return startp;
6155 case CTLQUOTEMARK:
6156 return startp;
6157 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006158 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006159 goto done;
6160 break;
6161 case '/':
6162 case CTLENDVAR:
6163 goto done;
6164 }
6165 }
6166 done:
6167 *p = '\0';
6168 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02006169 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006170 } else {
6171 pw = getpwnam(name);
6172 if (pw == NULL)
6173 goto lose;
6174 home = pw->pw_dir;
6175 }
6176 if (!home || !*home)
6177 goto lose;
6178 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006179 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006180 return p;
6181 lose:
6182 *p = c;
6183 return startp;
6184}
6185
6186/*
6187 * Execute a command inside back quotes. If it's a builtin command, we
6188 * want to save its output in a block obtained from malloc. Otherwise
6189 * we fork off a subprocess and get the output of the command via a pipe.
6190 * Should be called with interrupts off.
6191 */
6192struct backcmd { /* result of evalbackcmd */
6193 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006194 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00006195 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006196 struct job *jp; /* job structure for command */
6197};
6198
6199/* These forward decls are needed to use "eval" code for backticks handling: */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006200#define EV_EXIT 01 /* exit after evaluating tree */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02006201static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006202
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02006203static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006204evalbackcmd(union node *n, struct backcmd *result)
6205{
Denys Vlasenko579ad102016-10-25 21:10:20 +02006206 int pip[2];
6207 struct job *jp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006208
6209 result->fd = -1;
6210 result->buf = NULL;
6211 result->nleft = 0;
6212 result->jp = NULL;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006213 if (n == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006214 goto out;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006215 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006216
Denys Vlasenko579ad102016-10-25 21:10:20 +02006217 if (pipe(pip) < 0)
6218 ash_msg_and_raise_error("pipe call failed");
6219 jp = makejob(/*n,*/ 1);
6220 if (forkshell(jp, n, FORK_NOJOB) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02006221 /* child */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006222 FORCE_INT_ON;
6223 close(pip[0]);
6224 if (pip[1] != 1) {
6225 /*close(1);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02006226 dup2_or_raise(pip[1], 1);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006227 close(pip[1]);
6228 }
Denys Vlasenko960ca382016-10-25 18:12:15 +02006229/* TODO: eflag clearing makes the following not abort:
6230 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6231 * which is what bash does (unless it is in POSIX mode).
6232 * dash deleted "eflag = 0" line in the commit
6233 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6234 * [EVAL] Don't clear eflag in evalbackcmd
6235 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6236 */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006237 eflag = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006238 ifsfree();
Denys Vlasenko579ad102016-10-25 21:10:20 +02006239 evaltree(n, EV_EXIT); /* actually evaltreenr... */
6240 /* NOTREACHED */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006241 }
Denys Vlasenko70392332016-10-27 02:31:55 +02006242 /* parent */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006243 close(pip[1]);
6244 result->fd = pip[0];
6245 result->jp = jp;
6246
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006247 out:
6248 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6249 result->fd, result->buf, result->nleft, result->jp));
6250}
6251
6252/*
6253 * Expand stuff in backwards quotes.
6254 */
6255static void
Ron Yorston549deab2015-05-18 09:57:51 +02006256expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006257{
6258 struct backcmd in;
6259 int i;
6260 char buf[128];
6261 char *p;
6262 char *dest;
6263 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02006264 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006265 struct stackmark smark;
6266
6267 INT_OFF;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02006268 startloc = expdest - (char *)stackblock();
6269 pushstackmark(&smark, startloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006270 evalbackcmd(cmd, &in);
6271 popstackmark(&smark);
6272
6273 p = in.buf;
6274 i = in.nleft;
6275 if (i == 0)
6276 goto read;
6277 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02006278 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006279 read:
6280 if (in.fd < 0)
6281 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01006282 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006283 TRACE(("expbackq: read returns %d\n", i));
6284 if (i <= 0)
6285 break;
6286 p = buf;
6287 }
6288
Denis Vlasenko60818682007-09-28 22:07:23 +00006289 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006290 if (in.fd >= 0) {
6291 close(in.fd);
6292 back_exitstatus = waitforjob(in.jp);
6293 }
6294 INT_ON;
6295
6296 /* Eat all trailing newlines */
6297 dest = expdest;
6298 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6299 STUNPUTC(dest);
6300 expdest = dest;
6301
Ron Yorston549deab2015-05-18 09:57:51 +02006302 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006303 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006304 TRACE(("evalbackq: size:%d:'%.*s'\n",
6305 (int)((dest - (char *)stackblock()) - startloc),
6306 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006307 stackblock() + startloc));
6308}
6309
Denys Vlasenko0b883582016-12-23 16:49:07 +01006310#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006311/*
6312 * Expand arithmetic expression. Backup to start of expression,
6313 * evaluate, place result in (backed up) result, adjust string position.
6314 */
6315static void
Ron Yorston549deab2015-05-18 09:57:51 +02006316expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006317{
6318 char *p, *start;
6319 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006320 int len;
6321
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006322 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006323
6324 /*
6325 * This routine is slightly over-complicated for
6326 * efficiency. Next we scan backwards looking for the
6327 * start of arithmetic.
6328 */
6329 start = stackblock();
6330 p = expdest - 1;
6331 *p = '\0';
6332 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006333 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006334 int esc;
6335
Denys Vlasenkocd716832009-11-28 22:14:02 +01006336 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006337 p--;
6338#if DEBUG
6339 if (p < start) {
6340 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6341 }
6342#endif
6343 }
6344
6345 esc = esclen(start, p);
6346 if (!(esc % 2)) {
6347 break;
6348 }
6349
6350 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006351 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006352
6353 begoff = p - start;
6354
6355 removerecordregions(begoff);
6356
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006357 expdest = p;
6358
Ron Yorston549deab2015-05-18 09:57:51 +02006359 if (flag & QUOTES_ESC)
6360 rmescapes(p + 1, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006361
Ron Yorston549deab2015-05-18 09:57:51 +02006362 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006363
Ron Yorston549deab2015-05-18 09:57:51 +02006364 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006365 recordregion(begoff, begoff + len, 0);
6366}
6367#endif
6368
6369/* argstr needs it */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006370static char *evalvar(char *p, int flags, struct strlist *var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006371
6372/*
6373 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6374 * characters to allow for further processing. Otherwise treat
6375 * $@ like $* since no splitting will be performed.
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006376 *
6377 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
Denys Vlasenko10ad6222017-04-17 16:13:32 +02006378 * over shell variables. Needed for "A=a B=$A; echo $B" case - we use it
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006379 * for correct expansion of "B=$A" word.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006380 */
6381static void
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006382argstr(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006383{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006384 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006385 '=',
6386 ':',
6387 CTLQUOTEMARK,
6388 CTLENDVAR,
6389 CTLESC,
6390 CTLVAR,
6391 CTLBACKQ,
Denys Vlasenko0b883582016-12-23 16:49:07 +01006392#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006393 CTLENDARI,
6394#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006395 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006396 };
6397 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006398 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006399 int inquotes;
6400 size_t length;
6401 int startloc;
6402
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006403 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006404 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006405 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006406 reject++;
6407 }
6408 inquotes = 0;
6409 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006410 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006411 char *q;
6412
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006413 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006414 tilde:
6415 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006416 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006417 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006418 }
6419 start:
6420 startloc = expdest - (char *)stackblock();
6421 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006422 unsigned char c;
6423
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006424 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006425 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006426 if (c) {
6427 if (!(c & 0x80)
Denys Vlasenko0b883582016-12-23 16:49:07 +01006428 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006429 ) {
6430 /* c == '=' || c == ':' || c == CTLENDARI */
6431 length++;
6432 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006433 }
6434 if (length > 0) {
6435 int newloc;
6436 expdest = stack_nputstr(p, length, expdest);
6437 newloc = expdest - (char *)stackblock();
6438 if (breakall && !inquotes && newloc > startloc) {
6439 recordregion(startloc, newloc, 0);
6440 }
6441 startloc = newloc;
6442 }
6443 p += length + 1;
6444 length = 0;
6445
6446 switch (c) {
6447 case '\0':
6448 goto breakloop;
6449 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006450 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006451 p--;
6452 continue;
6453 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006454 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006455 reject++;
6456 /* fall through */
6457 case ':':
6458 /*
6459 * sort of a hack - expand tildes in variable
6460 * assignments (after the first '=' and after ':'s).
6461 */
6462 if (*--p == '~') {
6463 goto tilde;
6464 }
6465 continue;
6466 }
6467
6468 switch (c) {
6469 case CTLENDVAR: /* ??? */
6470 goto breakloop;
6471 case CTLQUOTEMARK:
Ron Yorston549deab2015-05-18 09:57:51 +02006472 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006473 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006474 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6475 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006476 goto start;
6477 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006478 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006479 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006480 p--;
6481 length++;
6482 startloc++;
6483 }
6484 break;
6485 case CTLESC:
6486 startloc++;
6487 length++;
Ron Yorston549deab2015-05-18 09:57:51 +02006488
6489 /*
6490 * Quoted parameter expansion pattern: remove quote
6491 * unless inside inner quotes or we have a literal
6492 * backslash.
6493 */
6494 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6495 EXP_QPAT && *p != '\\')
6496 break;
6497
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006498 goto addquote;
6499 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006500 TRACE(("argstr: evalvar('%s')\n", p));
Ron Yorston549deab2015-05-18 09:57:51 +02006501 p = evalvar(p, flags | inquotes, var_str_list);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006502 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006503 goto start;
6504 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006505 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006506 argbackq = argbackq->next;
6507 goto start;
Denys Vlasenko0b883582016-12-23 16:49:07 +01006508#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006509 case CTLENDARI:
6510 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006511 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006512 goto start;
6513#endif
6514 }
6515 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006516 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006517}
6518
6519static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006520scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6521 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006522{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006523 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006524 char c;
6525
6526 loc = startp;
6527 loc2 = rmesc;
6528 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006529 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006530 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006531
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006532 c = *loc2;
6533 if (zero) {
6534 *loc2 = '\0';
6535 s = rmesc;
6536 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006537 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006538
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006539 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006540 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006541 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006542 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006543 loc++;
6544 loc++;
6545 loc2++;
6546 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006547 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006548}
6549
6550static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006551scanright(char *startp, char *rmesc, char *rmescend,
6552 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006553{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006554#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6555 int try2optimize = match_at_start;
6556#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006557 int esc = 0;
6558 char *loc;
6559 char *loc2;
6560
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006561 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6562 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6563 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6564 * Logic:
6565 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6566 * and on each iteration they go back two/one char until they reach the beginning.
6567 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6568 */
6569 /* TODO: document in what other circumstances we are called. */
6570
6571 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006572 int match;
6573 char c = *loc2;
6574 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006575 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006576 *loc2 = '\0';
6577 s = rmesc;
6578 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006579 match = pmatch(pattern, s);
6580 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006581 *loc2 = c;
6582 if (match)
6583 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006584#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6585 if (try2optimize) {
6586 /* Maybe we can optimize this:
6587 * if pattern ends with unescaped *, we can avoid checking
Denys Vlasenko10ad6222017-04-17 16:13:32 +02006588 * shorter strings: if "foo*" doesn't match "raw_value_of_v",
6589 * it won't match truncated "raw_value_of_" strings too.
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006590 */
6591 unsigned plen = strlen(pattern);
6592 /* Does it end with "*"? */
6593 if (plen != 0 && pattern[--plen] == '*') {
6594 /* "xxxx*" is not escaped */
6595 /* "xxx\*" is escaped */
6596 /* "xx\\*" is not escaped */
6597 /* "x\\\*" is escaped */
6598 int slashes = 0;
6599 while (plen != 0 && pattern[--plen] == '\\')
6600 slashes++;
6601 if (!(slashes & 1))
6602 break; /* ends with unescaped "*" */
6603 }
6604 try2optimize = 0;
6605 }
6606#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006607 loc--;
6608 if (quotes) {
6609 if (--esc < 0) {
6610 esc = esclen(startp, loc);
6611 }
6612 if (esc % 2) {
6613 esc--;
6614 loc--;
6615 }
6616 }
6617 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006618 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006619}
6620
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006621static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006622static void
6623varunset(const char *end, const char *var, const char *umsg, int varflags)
6624{
6625 const char *msg;
6626 const char *tail;
6627
6628 tail = nullstr;
6629 msg = "parameter not set";
6630 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006631 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006632 if (varflags & VSNUL)
6633 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006634 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006635 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006636 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006637 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006638 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006639}
6640
6641static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006642subevalvar(char *p, char *varname, int strloc, int subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006643 int startloc, int varflags, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006644{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006645 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006646 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006647 char *startp;
6648 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006649 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006650 char *str;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006651 int amount, resetloc;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006652 IF_BASH_PATTERN_SUBST(int workloc;)
6653 IF_BASH_PATTERN_SUBST(char *repl = NULL;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006654 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006655 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006656
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006657 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6658 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006659
Ron Yorstoneb6b48b2015-05-18 09:51:35 +02006660 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
Ron Yorston549deab2015-05-18 09:57:51 +02006661 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6662 var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006663 STPUTC('\0', expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006664 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006665 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006666
6667 switch (subtype) {
6668 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006669 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006670 amount = startp - expdest;
6671 STADJUST(amount, expdest);
6672 return startp;
6673
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006674 case VSQUESTION:
6675 varunset(p, varname, startp, varflags);
6676 /* NOTREACHED */
6677
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006678#if BASH_SUBSTR
Denys Vlasenko826360f2017-07-17 17:49:11 +02006679 case VSSUBSTR: {
6680 int pos, len, orig_len;
6681 char *colon;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006682
Denys Vlasenko826360f2017-07-17 17:49:11 +02006683 loc = str = stackblock() + strloc;
6684
6685# if !ENABLE_FEATURE_SH_MATH
6686# define ash_arith number
6687# endif
6688 /* Read POS in ${var:POS:LEN} */
6689 colon = strchr(loc, ':');
6690 if (colon) *colon = '\0';
6691 pos = ash_arith(loc);
6692 if (colon) *colon = ':';
6693
6694 /* Read LEN in ${var:POS:LEN} */
6695 len = str - startp - 1;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006696 /* *loc != '\0', guaranteed by parser */
6697 if (quotes) {
6698 char *ptr;
6699
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006700 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006701 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006702 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006703 len--;
6704 ptr++;
6705 }
6706 }
6707 }
6708 orig_len = len;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006709 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006710 /* ${var::LEN} */
Denys Vlasenko826360f2017-07-17 17:49:11 +02006711 len = ash_arith(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006712 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006713 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006714 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006715 while (*loc && *loc != ':') {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006716 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006717 }
6718 if (*loc++ == ':') {
Denys Vlasenko826360f2017-07-17 17:49:11 +02006719 len = ash_arith(loc);
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006720 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006721 }
Denys Vlasenko826360f2017-07-17 17:49:11 +02006722# undef ash_arith
6723
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006724 if (pos < 0) {
6725 /* ${VAR:$((-n)):l} starts n chars from the end */
6726 pos = orig_len + pos;
6727 }
6728 if ((unsigned)pos >= orig_len) {
6729 /* apart from obvious ${VAR:999999:l},
6730 * covers ${VAR:$((-9999999)):l} - result is ""
Denys Vlasenko826360f2017-07-17 17:49:11 +02006731 * (bash compat)
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006732 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006733 pos = 0;
6734 len = 0;
6735 }
Denys Vlasenko826360f2017-07-17 17:49:11 +02006736 if (len < 0) {
6737 /* ${VAR:N:-M} sets LEN to strlen()-M */
6738 len = (orig_len - pos) + len;
6739 }
6740 if ((unsigned)len > (orig_len - pos))
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006741 len = orig_len - pos;
6742
6743 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006744 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006745 str++;
6746 }
6747 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006748 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006749 *loc++ = *str++;
6750 *loc++ = *str++;
6751 }
6752 *loc = '\0';
6753 amount = loc - expdest;
6754 STADJUST(amount, expdest);
6755 return loc;
Denys Vlasenko826360f2017-07-17 17:49:11 +02006756 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006757#endif /* BASH_SUBSTR */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006758 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006759
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006760 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006761
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006762#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006763 /* We'll comeback here if we grow the stack while handling
6764 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6765 * stack will need rebasing, and we'll need to remove our work
6766 * areas each time
6767 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006768 restart:
6769#endif
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006770
6771 amount = expdest - ((char *)stackblock() + resetloc);
6772 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006773 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006774
6775 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006776 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006777 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006778 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006779 if (rmesc != startp) {
6780 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006781 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006782 }
6783 }
6784 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006785 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02006786 /*
6787 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6788 * The result is a_\_z_c (not a\_\_z_c)!
6789 *
6790 * The search pattern and replace string treat backslashes differently!
6791 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6792 * and string. It's only used on the first call.
6793 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006794 preglob(str, IF_BASH_PATTERN_SUBST(
Ron Yorston417622c2015-05-18 09:59:14 +02006795 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006796 RMESCAPE_SLASH : ) 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006797
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006798#if BASH_PATTERN_SUBST
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006799 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006800 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenko826360f2017-07-17 17:49:11 +02006801 int len;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006802 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006803
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006804 if (!repl) {
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006805 repl = strchr(str, CTLESC);
6806 if (repl)
Ron Yorston417622c2015-05-18 09:59:14 +02006807 *repl++ = '\0';
6808 else
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006809 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006810 }
Ron Yorston417622c2015-05-18 09:59:14 +02006811 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006812
6813 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006814 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006815 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006816
6817 len = 0;
6818 idx = startp;
6819 end = str - 1;
6820 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006821 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006822 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006823 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006824 if (!loc) {
6825 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006826 char *restart_detect = stackblock();
6827 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006828 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006829 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006830 idx++;
6831 len++;
6832 STPUTC(*idx, expdest);
6833 }
6834 if (stackblock() != restart_detect)
6835 goto restart;
6836 idx++;
6837 len++;
6838 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006839 /* continue; - prone to quadratic behavior, smarter code: */
6840 if (idx >= end)
6841 break;
6842 if (str[0] == '*') {
6843 /* Pattern is "*foo". If "*foo" does not match "long_string",
6844 * it would never match "ong_string" etc, no point in trying.
6845 */
6846 goto skip_matching;
6847 }
6848 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006849 }
6850
6851 if (subtype == VSREPLACEALL) {
6852 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006853 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006854 idx++;
6855 idx++;
6856 rmesc++;
6857 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006858 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006859 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006860 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006861
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006862 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006863 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006864 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006865 if (quotes && *loc == '\\') {
6866 STPUTC(CTLESC, expdest);
6867 len++;
6868 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006869 STPUTC(*loc, expdest);
6870 if (stackblock() != restart_detect)
6871 goto restart;
6872 len++;
6873 }
6874
6875 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006876 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006877 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006878 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006879 STPUTC(*idx, expdest);
6880 if (stackblock() != restart_detect)
6881 goto restart;
6882 len++;
6883 idx++;
6884 }
6885 break;
6886 }
6887 }
6888
6889 /* We've put the replaced text into a buffer at workloc, now
6890 * move it to the right place and adjust the stack.
6891 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006892 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006893 startp = (char *)stackblock() + startloc;
6894 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006895 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006896 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006897 STADJUST(-amount, expdest);
6898 return startp;
6899 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006900#endif /* BASH_PATTERN_SUBST */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006901
6902 subtype -= VSTRIMRIGHT;
6903#if DEBUG
6904 if (subtype < 0 || subtype > 7)
6905 abort();
6906#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006907 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006908 zero = subtype >> 1;
6909 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6910 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6911
6912 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6913 if (loc) {
6914 if (zero) {
6915 memmove(startp, loc, str - loc);
6916 loc = startp + (str - loc) - 1;
6917 }
6918 *loc = '\0';
6919 amount = loc - expdest;
6920 STADJUST(amount, expdest);
6921 }
6922 return loc;
6923}
6924
6925/*
6926 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006927 * name parameter (examples):
6928 * ash -c 'echo $1' name:'1='
6929 * ash -c 'echo $qwe' name:'qwe='
6930 * ash -c 'echo $$' name:'$='
6931 * ash -c 'echo ${$}' name:'$='
6932 * ash -c 'echo ${$##q}' name:'$=q'
6933 * ash -c 'echo ${#$}' name:'$='
6934 * note: examples with bad shell syntax:
6935 * ash -c 'echo ${#$1}' name:'$=1'
6936 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006937 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02006938static NOINLINE ssize_t
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006939varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int *quotedp)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006940{
Mike Frysinger98c52642009-04-02 10:02:37 +00006941 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006942 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006943 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006944 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006945 int sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006946 int quoted = *quotedp;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006947 int subtype = varflags & VSTYPE;
6948 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6949 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006950 int syntax;
6951
6952 sep = (flags & EXP_FULL) << CHAR_BIT;
6953 syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006954
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006955 switch (*name) {
6956 case '$':
6957 num = rootpid;
6958 goto numvar;
6959 case '?':
6960 num = exitstatus;
6961 goto numvar;
6962 case '#':
6963 num = shellparam.nparam;
6964 goto numvar;
6965 case '!':
6966 num = backgndpid;
6967 if (num == 0)
6968 return -1;
6969 numvar:
6970 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006971 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006972 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00006973 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006974 for (i = NOPTS - 1; i >= 0; i--) {
6975 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00006976 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006977 len++;
6978 }
6979 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006980 check_1char_name:
6981#if 0
6982 /* handles cases similar to ${#$1} */
6983 if (name[2] != '\0')
6984 raise_error_syntax("bad substitution");
6985#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006986 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006987 case '@':
6988 if (quoted && sep)
6989 goto param;
6990 /* fall through */
6991 case '*': {
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006992 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006993 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006994
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006995 if (quoted)
6996 sep = 0;
6997 sep |= ifsset() ? ifsval()[0] : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006998 param:
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006999 sepc = sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007000 *quotedp = !sepc;
7001 ap = shellparam.p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007002 if (!ap)
7003 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007004 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007005 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007006
7007 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007008 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007009 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007010 }
7011 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007012 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007013 } /* case '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007014 case '0':
7015 case '1':
7016 case '2':
7017 case '3':
7018 case '4':
7019 case '5':
7020 case '6':
7021 case '7':
7022 case '8':
7023 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02007024 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007025 if (num < 0 || num > shellparam.nparam)
7026 return -1;
7027 p = num ? shellparam.p[num - 1] : arg0;
7028 goto value;
7029 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007030 /* NB: name has form "VAR=..." */
7031
7032 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
7033 * which should be considered before we check variables. */
7034 if (var_str_list) {
7035 unsigned name_len = (strchrnul(name, '=') - name) + 1;
7036 p = NULL;
7037 do {
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00007038 char *str, *eq;
7039 str = var_str_list->text;
7040 eq = strchr(str, '=');
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007041 if (!eq) /* stop at first non-assignment */
7042 break;
7043 eq++;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00007044 if (name_len == (unsigned)(eq - str)
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007045 && strncmp(str, name, name_len) == 0
7046 ) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007047 p = eq;
7048 /* goto value; - WRONG! */
7049 /* think "A=1 A=2 B=$A" */
7050 }
7051 var_str_list = var_str_list->next;
7052 } while (var_str_list);
7053 if (p)
7054 goto value;
7055 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007056 p = lookupvar(name);
7057 value:
7058 if (!p)
7059 return -1;
7060
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007061 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007062#if ENABLE_UNICODE_SUPPORT
7063 if (subtype == VSLENGTH && len > 0) {
7064 reinit_unicode_for_ash();
7065 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00007066 STADJUST(-len, expdest);
7067 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007068 len = unicode_strlen(p);
7069 }
7070 }
7071#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007072 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007073 }
7074
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007075 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007076 STADJUST(-len, expdest);
7077 return len;
7078}
7079
7080/*
7081 * Expand a variable, and return a pointer to the next character in the
7082 * input string.
7083 */
7084static char *
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007085evalvar(char *p, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007086{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007087 char varflags;
7088 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02007089 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007090 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007091 char *var;
7092 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007093 int startloc;
7094 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007095
Denys Vlasenkob0d63382009-09-16 16:18:32 +02007096 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007097 subtype = varflags & VSTYPE;
Denys Vlasenko88e15702016-10-26 01:55:56 +02007098
7099 if (!subtype)
7100 raise_error_syntax("bad substitution");
7101
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007102 quoted = flag & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007103 var = p;
7104 easy = (!quoted || (*var == '@' && shellparam.nparam));
7105 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02007106 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007107
7108 again:
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007109 varlen = varvalue(var, varflags, flag, var_str_list, &quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007110 if (varflags & VSNUL)
7111 varlen--;
7112
7113 if (subtype == VSPLUS) {
7114 varlen = -1 - varlen;
7115 goto vsplus;
7116 }
7117
7118 if (subtype == VSMINUS) {
7119 vsplus:
7120 if (varlen < 0) {
7121 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02007122 p,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007123 flag | EXP_TILDE | EXP_WORD,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007124 var_str_list
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007125 );
7126 goto end;
7127 }
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007128 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007129 }
7130
7131 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007132 if (varlen >= 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007133 goto record;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007134
7135 subevalvar(p, var, 0, subtype, startloc, varflags,
7136 flag & ~QUOTES_ESC, var_str_list);
7137 varflags &= ~VSNUL;
7138 /*
7139 * Remove any recorded regions beyond
7140 * start of variable
7141 */
7142 removerecordregions(startloc);
7143 goto again;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007144 }
7145
7146 if (varlen < 0 && uflag)
7147 varunset(p, var, 0, 0);
7148
7149 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007150 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007151 goto record;
7152 }
7153
7154 if (subtype == VSNORMAL) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007155 record:
7156 if (!easy)
7157 goto end;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007158 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007159 goto end;
7160 }
7161
7162#if DEBUG
7163 switch (subtype) {
7164 case VSTRIMLEFT:
7165 case VSTRIMLEFTMAX:
7166 case VSTRIMRIGHT:
7167 case VSTRIMRIGHTMAX:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007168#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007169 case VSSUBSTR:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007170#endif
7171#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007172 case VSREPLACE:
7173 case VSREPLACEALL:
7174#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007175 break;
7176 default:
7177 abort();
7178 }
7179#endif
7180
7181 if (varlen >= 0) {
7182 /*
7183 * Terminate the string and start recording the pattern
7184 * right after it
7185 */
7186 STPUTC('\0', expdest);
7187 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007188 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007189 startloc, varflags, flag, var_str_list)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007190 int amount = expdest - (
7191 (char *)stackblock() + patloc - 1
7192 );
7193 STADJUST(-amount, expdest);
7194 }
7195 /* Remove any recorded regions beyond start of variable */
7196 removerecordregions(startloc);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007197 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007198 }
7199
7200 end:
7201 if (subtype != VSNORMAL) { /* skip to end of alternative */
7202 int nesting = 1;
7203 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007204 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007205 if (c == CTLESC)
7206 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02007207 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007208 if (varlen >= 0)
7209 argbackq = argbackq->next;
7210 } else if (c == CTLVAR) {
7211 if ((*p++ & VSTYPE) != VSNORMAL)
7212 nesting++;
7213 } else if (c == CTLENDVAR) {
7214 if (--nesting == 0)
7215 break;
7216 }
7217 }
7218 }
7219 return p;
7220}
7221
7222/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007223 * Add a file name to the list.
7224 */
7225static void
7226addfname(const char *name)
7227{
7228 struct strlist *sp;
7229
Denis Vlasenko597906c2008-02-20 16:38:54 +00007230 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02007231 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007232 *exparg.lastp = sp;
7233 exparg.lastp = &sp->next;
7234}
7235
Felix Fietkaub5b21122017-01-31 21:58:55 +01007236/* Avoid glob() (and thus, stat() et al) for words like "echo" */
7237static int
7238hasmeta(const char *p)
7239{
7240 static const char chars[] ALIGN1 = {
7241 '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
7242 };
7243
7244 for (;;) {
7245 p = strpbrk(p, chars);
7246 if (!p)
7247 break;
7248 switch ((unsigned char) *p) {
7249 case CTLQUOTEMARK:
7250 for (;;) {
7251 p++;
7252 if (*p == CTLQUOTEMARK)
7253 break;
7254 if (*p == CTLESC)
7255 p++;
7256 if (*p == '\0') /* huh? */
7257 return 0;
7258 }
7259 break;
7260 case '\\':
7261 case CTLESC:
7262 p++;
7263 if (*p == '\0')
7264 return 0;
7265 break;
7266 case '[':
7267 if (!strchr(p + 1, ']')) {
7268 /* It's not a properly closed [] pattern,
7269 * but other metas may follow. Continue checking.
7270 * my[file* _is_ globbed by bash
7271 * and matches filenames like "my[file1".
7272 */
7273 break;
7274 }
7275 /* fallthrough */
7276 default:
7277 /* case '*': */
7278 /* case '?': */
7279 return 1;
7280 }
7281 p++;
7282 }
7283
7284 return 0;
7285}
7286
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007287/* If we want to use glob() from libc... */
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007288#if !ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007289
7290/* Add the result of glob() to the list */
7291static void
7292addglob(const glob_t *pglob)
7293{
7294 char **p = pglob->gl_pathv;
7295
7296 do {
7297 addfname(*p);
7298 } while (*++p);
7299}
7300static void
7301expandmeta(struct strlist *str /*, int flag*/)
7302{
7303 /* TODO - EXP_REDIR */
7304
7305 while (str) {
7306 char *p;
7307 glob_t pglob;
7308 int i;
7309
7310 if (fflag)
7311 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007312
Felix Fietkaub5b21122017-01-31 21:58:55 +01007313 if (!hasmeta(str->text))
7314 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007315
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007316 INT_OFF;
7317 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007318// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7319// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7320//
7321// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7322// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7323// Which means you need to unescape the string, right? Not so fast:
7324// if there _is_ a file named "file\?" (with backslash), it is returned
7325// as "file\?" too (whichever pattern you used to find it, say, "file*").
Denys Vlasenko10ad6222017-04-17 16:13:32 +02007326// You DON'T KNOW by looking at the result whether you need to unescape it.
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007327//
7328// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7329// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7330// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7331// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7332// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7333// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7334 i = glob(p, 0, NULL, &pglob);
7335 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007336 if (p != str->text)
7337 free(p);
7338 switch (i) {
7339 case 0:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007340#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007341 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7342 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7343 goto nometa2;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007344#endif
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007345 addglob(&pglob);
7346 globfree(&pglob);
7347 INT_ON;
7348 break;
7349 case GLOB_NOMATCH:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007350 //nometa2:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007351 globfree(&pglob);
7352 INT_ON;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007353 nometa:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007354 *exparg.lastp = str;
7355 rmescapes(str->text, 0);
7356 exparg.lastp = &str->next;
7357 break;
7358 default: /* GLOB_NOSPACE */
7359 globfree(&pglob);
7360 INT_ON;
7361 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7362 }
7363 str = str->next;
7364 }
7365}
7366
7367#else
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007368/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007369
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007370/*
7371 * Do metacharacter (i.e. *, ?, [...]) expansion.
7372 */
7373static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007374expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007375{
7376 char *p;
7377 const char *cp;
7378 char *start;
7379 char *endname;
7380 int metaflag;
7381 struct stat statb;
7382 DIR *dirp;
7383 struct dirent *dp;
7384 int atend;
7385 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007386 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007387
7388 metaflag = 0;
7389 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007390 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007391 if (*p == '*' || *p == '?')
7392 metaflag = 1;
7393 else if (*p == '[') {
7394 char *q = p + 1;
7395 if (*q == '!')
7396 q++;
7397 for (;;) {
7398 if (*q == '\\')
7399 q++;
7400 if (*q == '/' || *q == '\0')
7401 break;
7402 if (*++q == ']') {
7403 metaflag = 1;
7404 break;
7405 }
7406 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007407 } else {
7408 if (*p == '\\')
7409 esc++;
7410 if (p[esc] == '/') {
7411 if (metaflag)
7412 break;
7413 start = p + esc + 1;
7414 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007415 }
7416 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007417 if (metaflag == 0) { /* we've reached the end of the file name */
7418 if (enddir != expdir)
7419 metaflag++;
7420 p = name;
7421 do {
7422 if (*p == '\\')
7423 p++;
7424 *enddir++ = *p;
7425 } while (*p++);
7426 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7427 addfname(expdir);
7428 return;
7429 }
7430 endname = p;
7431 if (name < start) {
7432 p = name;
7433 do {
7434 if (*p == '\\')
7435 p++;
7436 *enddir++ = *p++;
7437 } while (p < start);
7438 }
7439 if (enddir == expdir) {
7440 cp = ".";
7441 } else if (enddir == expdir + 1 && *expdir == '/') {
7442 cp = "/";
7443 } else {
7444 cp = expdir;
7445 enddir[-1] = '\0';
7446 }
7447 dirp = opendir(cp);
7448 if (dirp == NULL)
7449 return;
7450 if (enddir != expdir)
7451 enddir[-1] = '/';
7452 if (*endname == 0) {
7453 atend = 1;
7454 } else {
7455 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007456 *endname = '\0';
7457 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007458 }
7459 matchdot = 0;
7460 p = start;
7461 if (*p == '\\')
7462 p++;
7463 if (*p == '.')
7464 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007465 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007466 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007467 continue;
7468 if (pmatch(start, dp->d_name)) {
7469 if (atend) {
7470 strcpy(enddir, dp->d_name);
7471 addfname(expdir);
7472 } else {
7473 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7474 continue;
7475 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007476 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007477 }
7478 }
7479 }
7480 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007481 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007482 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007483}
7484
7485static struct strlist *
7486msort(struct strlist *list, int len)
7487{
7488 struct strlist *p, *q = NULL;
7489 struct strlist **lpp;
7490 int half;
7491 int n;
7492
7493 if (len <= 1)
7494 return list;
7495 half = len >> 1;
7496 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007497 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007498 q = p;
7499 p = p->next;
7500 }
7501 q->next = NULL; /* terminate first half of list */
7502 q = msort(list, half); /* sort first half of list */
7503 p = msort(p, len - half); /* sort second half */
7504 lpp = &list;
7505 for (;;) {
7506#if ENABLE_LOCALE_SUPPORT
7507 if (strcoll(p->text, q->text) < 0)
7508#else
7509 if (strcmp(p->text, q->text) < 0)
7510#endif
7511 {
7512 *lpp = p;
7513 lpp = &p->next;
7514 p = *lpp;
7515 if (p == NULL) {
7516 *lpp = q;
7517 break;
7518 }
7519 } else {
7520 *lpp = q;
7521 lpp = &q->next;
7522 q = *lpp;
7523 if (q == NULL) {
7524 *lpp = p;
7525 break;
7526 }
7527 }
7528 }
7529 return list;
7530}
7531
7532/*
7533 * Sort the results of file name expansion. It calculates the number of
7534 * strings to sort and then calls msort (short for merge sort) to do the
7535 * work.
7536 */
7537static struct strlist *
7538expsort(struct strlist *str)
7539{
7540 int len;
7541 struct strlist *sp;
7542
7543 len = 0;
7544 for (sp = str; sp; sp = sp->next)
7545 len++;
7546 return msort(str, len);
7547}
7548
7549static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007550expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007551{
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007552 /* TODO - EXP_REDIR */
7553
7554 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007555 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007556 struct strlist **savelastp;
7557 struct strlist *sp;
7558 char *p;
7559
7560 if (fflag)
7561 goto nometa;
Felix Fietkaub5b21122017-01-31 21:58:55 +01007562 if (!hasmeta(str->text))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007563 goto nometa;
7564 savelastp = exparg.lastp;
7565
7566 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007567 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007568 {
7569 int i = strlen(str->text);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007570//BUGGY estimation of how long expanded name can be
7571 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007572 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007573 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007574 free(expdir);
7575 if (p != str->text)
7576 free(p);
7577 INT_ON;
7578 if (exparg.lastp == savelastp) {
7579 /*
7580 * no matches
7581 */
7582 nometa:
7583 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007584 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007585 exparg.lastp = &str->next;
7586 } else {
7587 *exparg.lastp = NULL;
7588 *savelastp = sp = expsort(*savelastp);
7589 while (sp->next != NULL)
7590 sp = sp->next;
7591 exparg.lastp = &sp->next;
7592 }
7593 str = str->next;
7594 }
7595}
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007596#endif /* ENABLE_ASH_INTERNAL_GLOB */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007597
7598/*
7599 * Perform variable substitution and command substitution on an argument,
7600 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7601 * perform splitting and file name expansion. When arglist is NULL, perform
7602 * here document expansion.
7603 */
7604static void
7605expandarg(union node *arg, struct arglist *arglist, int flag)
7606{
7607 struct strlist *sp;
7608 char *p;
7609
7610 argbackq = arg->narg.backquote;
7611 STARTSTACKSTR(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007612 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007613 argstr(arg->narg.text, flag,
7614 /* var_str_list: */ arglist ? arglist->list : NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007615 p = _STPUTC('\0', expdest);
7616 expdest = p - 1;
7617 if (arglist == NULL) {
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007618 /* here document expanded */
7619 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007620 }
7621 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007622 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007623 exparg.lastp = &exparg.list;
7624 /*
7625 * TODO - EXP_REDIR
7626 */
7627 if (flag & EXP_FULL) {
7628 ifsbreakup(p, &exparg);
7629 *exparg.lastp = NULL;
7630 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007631 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007632 } else {
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007633 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007634 rmescapes(p, 0);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007635 TRACE(("expandarg: rmescapes:'%s'\n", p));
7636 }
Denis Vlasenko597906c2008-02-20 16:38:54 +00007637 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007638 sp->text = p;
7639 *exparg.lastp = sp;
7640 exparg.lastp = &sp->next;
7641 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007642 *exparg.lastp = NULL;
7643 if (exparg.list) {
7644 *arglist->lastp = exparg.list;
7645 arglist->lastp = exparg.lastp;
7646 }
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007647
7648 out:
7649 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007650}
7651
7652/*
7653 * Expand shell variables and backquotes inside a here document.
7654 */
7655static void
7656expandhere(union node *arg, int fd)
7657{
Ron Yorston549deab2015-05-18 09:57:51 +02007658 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007659 full_write(fd, stackblock(), expdest - (char *)stackblock());
7660}
7661
7662/*
7663 * Returns true if the pattern matches the string.
7664 */
7665static int
7666patmatch(char *pattern, const char *string)
7667{
Denys Vlasenkobd43c672017-07-05 23:12:15 +02007668 char *p = preglob(pattern, 0);
7669 //bb_error_msg("fnmatch(pattern:'%s',str:'%s')", p, string);
7670 return pmatch(p, string);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007671}
7672
7673/*
7674 * See if a pattern matches in a case statement.
7675 */
7676static int
7677casematch(union node *pattern, char *val)
7678{
7679 struct stackmark smark;
7680 int result;
7681
7682 setstackmark(&smark);
7683 argbackq = pattern->narg.backquote;
7684 STARTSTACKSTR(expdest);
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007685 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7686 /* var_str_list: */ NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007687 STACKSTRNUL(expdest);
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007688 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007689 result = patmatch(stackblock(), val);
7690 popstackmark(&smark);
7691 return result;
7692}
7693
7694
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007695/* ============ find_command */
7696
7697struct builtincmd {
7698 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007699 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007700 /* unsigned flags; */
7701};
7702#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007703/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007704 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007705#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007706#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007707
7708struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007709 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007710 union param {
7711 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007712 /* index >= 0 for commands without path (slashes) */
7713 /* (TODO: what exactly does the value mean? PATH position?) */
7714 /* index == -1 for commands with slashes */
7715 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007716 const struct builtincmd *cmd;
7717 struct funcnode *func;
7718 } u;
7719};
7720/* values of cmdtype */
7721#define CMDUNKNOWN -1 /* no entry in table for command */
7722#define CMDNORMAL 0 /* command is an executable program */
7723#define CMDFUNCTION 1 /* command is a shell function */
7724#define CMDBUILTIN 2 /* command is a shell builtin */
7725
7726/* action to find_command() */
7727#define DO_ERR 0x01 /* prints errors */
7728#define DO_ABS 0x02 /* checks absolute paths */
7729#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7730#define DO_ALTPATH 0x08 /* using alternate path */
7731#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7732
7733static void find_command(char *, struct cmdentry *, int, const char *);
7734
7735
7736/* ============ Hashing commands */
7737
7738/*
7739 * When commands are first encountered, they are entered in a hash table.
7740 * This ensures that a full path search will not have to be done for them
7741 * on each invocation.
7742 *
7743 * We should investigate converting to a linear search, even though that
7744 * would make the command name "hash" a misnomer.
7745 */
7746
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007747struct tblentry {
7748 struct tblentry *next; /* next entry in hash chain */
7749 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007750 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007751 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007752 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007753};
7754
Denis Vlasenko01631112007-12-16 17:20:38 +00007755static struct tblentry **cmdtable;
7756#define INIT_G_cmdtable() do { \
7757 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7758} while (0)
7759
7760static int builtinloc = -1; /* index in path of %builtin, or -1 */
7761
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007762
7763static void
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007764tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007765{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007766#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007767 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007768 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007769 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007770 while (*envp)
7771 putenv(*envp++);
Denys Vlasenko69a5ec92017-07-07 19:08:56 +02007772 run_applet_no_and_exit(applet_no, cmd, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007773 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007774 /* re-exec ourselves with the new arguments */
7775 execve(bb_busybox_exec_path, argv, envp);
7776 /* If they called chroot or otherwise made the binary no longer
7777 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007778 }
7779#endif
7780
7781 repeat:
7782#ifdef SYSV
7783 do {
7784 execve(cmd, argv, envp);
7785 } while (errno == EINTR);
7786#else
7787 execve(cmd, argv, envp);
7788#endif
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007789 if (cmd != (char*) bb_busybox_exec_path && errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007790 /* Run "cmd" as a shell script:
7791 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7792 * "If the execve() function fails with ENOEXEC, the shell
7793 * shall execute a command equivalent to having a shell invoked
7794 * with the command name as its first operand,
7795 * with any remaining arguments passed to the new shell"
7796 *
7797 * That is, do not use $SHELL, user's shell, or /bin/sh;
7798 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007799 *
7800 * Note that bash reads ~80 chars of the file, and if it sees
7801 * a zero byte before it sees newline, it doesn't try to
7802 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007803 * message and exit code 126. For one, this prevents attempts
7804 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007805 */
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007806 argv[0] = cmd;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007807 cmd = (char*) bb_busybox_exec_path;
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007808 /* NB: this is only possible because all callers of shellexec()
7809 * ensure that the argv[-1] slot exists!
7810 */
7811 argv--;
7812 argv[0] = (char*) "ash";
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007813 goto repeat;
7814 }
7815}
7816
7817/*
7818 * Exec a program. Never returns. If you change this routine, you may
7819 * have to change the find_command routine as well.
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007820 * argv[-1] must exist and be writable! See tryexec() for why.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007821 */
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007822static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN;
7823static void shellexec(char *prog, char **argv, const char *path, int idx)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007824{
7825 char *cmdname;
7826 int e;
7827 char **envp;
7828 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007829 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007830
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007831 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007832 if (strchr(prog, '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007833#if ENABLE_FEATURE_SH_STANDALONE
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007834 || (applet_no = find_applet_by_name(prog)) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007835#endif
7836 ) {
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007837 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007838 if (applet_no >= 0) {
7839 /* We tried execing ourself, but it didn't work.
7840 * Maybe /proc/self/exe doesn't exist?
7841 * Try $PATH search.
7842 */
7843 goto try_PATH;
7844 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007845 e = errno;
7846 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007847 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007848 e = ENOENT;
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007849 while ((cmdname = path_advance(&path, prog)) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007850 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007851 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007852 if (errno != ENOENT && errno != ENOTDIR)
7853 e = errno;
7854 }
7855 stunalloc(cmdname);
7856 }
7857 }
7858
7859 /* Map to POSIX errors */
7860 switch (e) {
7861 case EACCES:
7862 exerrno = 126;
7863 break;
7864 case ENOENT:
7865 exerrno = 127;
7866 break;
7867 default:
7868 exerrno = 2;
7869 break;
7870 }
7871 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007872 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007873 prog, e, suppress_int));
7874 ash_msg_and_raise(EXEXIT, "%s: %s", prog, errmsg(e, "not found"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007875 /* NOTREACHED */
7876}
7877
7878static void
7879printentry(struct tblentry *cmdp)
7880{
7881 int idx;
7882 const char *path;
7883 char *name;
7884
7885 idx = cmdp->param.index;
7886 path = pathval();
7887 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007888 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007889 stunalloc(name);
7890 } while (--idx >= 0);
7891 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7892}
7893
7894/*
7895 * Clear out command entries. The argument specifies the first entry in
7896 * PATH which has changed.
7897 */
7898static void
7899clearcmdentry(int firstchange)
7900{
7901 struct tblentry **tblp;
7902 struct tblentry **pp;
7903 struct tblentry *cmdp;
7904
7905 INT_OFF;
7906 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7907 pp = tblp;
7908 while ((cmdp = *pp) != NULL) {
7909 if ((cmdp->cmdtype == CMDNORMAL &&
7910 cmdp->param.index >= firstchange)
7911 || (cmdp->cmdtype == CMDBUILTIN &&
7912 builtinloc >= firstchange)
7913 ) {
7914 *pp = cmdp->next;
7915 free(cmdp);
7916 } else {
7917 pp = &cmdp->next;
7918 }
7919 }
7920 }
7921 INT_ON;
7922}
7923
7924/*
7925 * Locate a command in the command hash table. If "add" is nonzero,
7926 * add the command to the table if it is not already present. The
7927 * variable "lastcmdentry" is set to point to the address of the link
7928 * pointing to the entry, so that delete_cmd_entry can delete the
7929 * entry.
7930 *
7931 * Interrupts must be off if called with add != 0.
7932 */
7933static struct tblentry **lastcmdentry;
7934
7935static struct tblentry *
7936cmdlookup(const char *name, int add)
7937{
7938 unsigned int hashval;
7939 const char *p;
7940 struct tblentry *cmdp;
7941 struct tblentry **pp;
7942
7943 p = name;
7944 hashval = (unsigned char)*p << 4;
7945 while (*p)
7946 hashval += (unsigned char)*p++;
7947 hashval &= 0x7FFF;
7948 pp = &cmdtable[hashval % CMDTABLESIZE];
7949 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7950 if (strcmp(cmdp->cmdname, name) == 0)
7951 break;
7952 pp = &cmdp->next;
7953 }
7954 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007955 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7956 + strlen(name)
7957 /* + 1 - already done because
7958 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007959 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007960 cmdp->cmdtype = CMDUNKNOWN;
7961 strcpy(cmdp->cmdname, name);
7962 }
7963 lastcmdentry = pp;
7964 return cmdp;
7965}
7966
7967/*
7968 * Delete the command entry returned on the last lookup.
7969 */
7970static void
7971delete_cmd_entry(void)
7972{
7973 struct tblentry *cmdp;
7974
7975 INT_OFF;
7976 cmdp = *lastcmdentry;
7977 *lastcmdentry = cmdp->next;
7978 if (cmdp->cmdtype == CMDFUNCTION)
7979 freefunc(cmdp->param.func);
7980 free(cmdp);
7981 INT_ON;
7982}
7983
7984/*
7985 * Add a new command entry, replacing any existing command entry for
7986 * the same name - except special builtins.
7987 */
7988static void
7989addcmdentry(char *name, struct cmdentry *entry)
7990{
7991 struct tblentry *cmdp;
7992
7993 cmdp = cmdlookup(name, 1);
7994 if (cmdp->cmdtype == CMDFUNCTION) {
7995 freefunc(cmdp->param.func);
7996 }
7997 cmdp->cmdtype = entry->cmdtype;
7998 cmdp->param = entry->u;
7999 cmdp->rehash = 0;
8000}
8001
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008002static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008003hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008004{
8005 struct tblentry **pp;
8006 struct tblentry *cmdp;
8007 int c;
8008 struct cmdentry entry;
8009 char *name;
8010
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008011 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008012 clearcmdentry(0);
8013 return 0;
8014 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008015
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008016 if (*argptr == NULL) {
8017 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8018 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8019 if (cmdp->cmdtype == CMDNORMAL)
8020 printentry(cmdp);
8021 }
8022 }
8023 return 0;
8024 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008025
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008026 c = 0;
8027 while ((name = *argptr) != NULL) {
8028 cmdp = cmdlookup(name, 0);
8029 if (cmdp != NULL
8030 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008031 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
8032 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008033 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008034 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008035 find_command(name, &entry, DO_ERR, pathval());
8036 if (entry.cmdtype == CMDUNKNOWN)
8037 c = 1;
8038 argptr++;
8039 }
8040 return c;
8041}
8042
8043/*
8044 * Called when a cd is done. Marks all commands so the next time they
8045 * are executed they will be rehashed.
8046 */
8047static void
8048hashcd(void)
8049{
8050 struct tblentry **pp;
8051 struct tblentry *cmdp;
8052
8053 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8054 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008055 if (cmdp->cmdtype == CMDNORMAL
8056 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02008057 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008058 && builtinloc > 0)
8059 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008060 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008061 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008062 }
8063 }
8064}
8065
8066/*
8067 * Fix command hash table when PATH changed.
8068 * Called before PATH is changed. The argument is the new value of PATH;
8069 * pathval() still returns the old value at this point.
8070 * Called with interrupts off.
8071 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008072static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008073changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008074{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008075 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008076 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008077 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008078 int idx_bltin;
8079
8080 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008081 firstchange = 9999; /* assume no change */
8082 idx = 0;
8083 idx_bltin = -1;
8084 for (;;) {
8085 if (*old != *new) {
8086 firstchange = idx;
8087 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008088 || (*old == ':' && *new == '\0')
8089 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008090 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008091 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008092 old = new; /* ignore subsequent differences */
8093 }
8094 if (*new == '\0')
8095 break;
8096 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
8097 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008098 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008099 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008100 new++;
8101 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008102 }
8103 if (builtinloc < 0 && idx_bltin >= 0)
8104 builtinloc = idx_bltin; /* zap builtins */
8105 if (builtinloc >= 0 && idx_bltin < 0)
8106 firstchange = 0;
8107 clearcmdentry(firstchange);
8108 builtinloc = idx_bltin;
8109}
Ron Yorston95ebcf72015-11-03 09:42:23 +00008110enum {
8111 TEOF,
8112 TNL,
8113 TREDIR,
8114 TWORD,
8115 TSEMI,
8116 TBACKGND,
8117 TAND,
8118 TOR,
8119 TPIPE,
8120 TLP,
8121 TRP,
8122 TENDCASE,
8123 TENDBQUOTE,
8124 TNOT,
8125 TCASE,
8126 TDO,
8127 TDONE,
8128 TELIF,
8129 TELSE,
8130 TESAC,
8131 TFI,
8132 TFOR,
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008133#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +00008134 TFUNCTION,
8135#endif
8136 TIF,
8137 TIN,
8138 TTHEN,
8139 TUNTIL,
8140 TWHILE,
8141 TBEGIN,
8142 TEND
8143};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008144typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008145
Denys Vlasenko888527c2016-10-02 16:54:17 +02008146/* Nth bit indicates if token marks the end of a list */
8147enum {
8148 tokendlist = 0
8149 /* 0 */ | (1u << TEOF)
8150 /* 1 */ | (0u << TNL)
8151 /* 2 */ | (0u << TREDIR)
8152 /* 3 */ | (0u << TWORD)
8153 /* 4 */ | (0u << TSEMI)
8154 /* 5 */ | (0u << TBACKGND)
8155 /* 6 */ | (0u << TAND)
8156 /* 7 */ | (0u << TOR)
8157 /* 8 */ | (0u << TPIPE)
8158 /* 9 */ | (0u << TLP)
8159 /* 10 */ | (1u << TRP)
8160 /* 11 */ | (1u << TENDCASE)
8161 /* 12 */ | (1u << TENDBQUOTE)
8162 /* 13 */ | (0u << TNOT)
8163 /* 14 */ | (0u << TCASE)
8164 /* 15 */ | (1u << TDO)
8165 /* 16 */ | (1u << TDONE)
8166 /* 17 */ | (1u << TELIF)
8167 /* 18 */ | (1u << TELSE)
8168 /* 19 */ | (1u << TESAC)
8169 /* 20 */ | (1u << TFI)
8170 /* 21 */ | (0u << TFOR)
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008171#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008172 /* 22 */ | (0u << TFUNCTION)
Denys Vlasenko80729a42016-10-02 22:33:15 +02008173#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008174 /* 23 */ | (0u << TIF)
8175 /* 24 */ | (0u << TIN)
8176 /* 25 */ | (1u << TTHEN)
8177 /* 26 */ | (0u << TUNTIL)
8178 /* 27 */ | (0u << TWHILE)
8179 /* 28 */ | (0u << TBEGIN)
8180 /* 29 */ | (1u << TEND)
8181 , /* thus far 29 bits used */
8182};
8183
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008184static const char *const tokname_array[] = {
Denys Vlasenko888527c2016-10-02 16:54:17 +02008185 "end of file",
8186 "newline",
8187 "redirection",
8188 "word",
8189 ";",
8190 "&",
8191 "&&",
8192 "||",
8193 "|",
8194 "(",
8195 ")",
8196 ";;",
8197 "`",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008198#define KWDOFFSET 13
8199 /* the following are keywords */
Denys Vlasenko888527c2016-10-02 16:54:17 +02008200 "!",
8201 "case",
8202 "do",
8203 "done",
8204 "elif",
8205 "else",
8206 "esac",
8207 "fi",
8208 "for",
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008209#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008210 "function",
Ron Yorston95ebcf72015-11-03 09:42:23 +00008211#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008212 "if",
8213 "in",
8214 "then",
8215 "until",
8216 "while",
8217 "{",
8218 "}",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008219};
8220
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008221/* Wrapper around strcmp for qsort/bsearch/... */
8222static int
8223pstrcmp(const void *a, const void *b)
8224{
Denys Vlasenko888527c2016-10-02 16:54:17 +02008225 return strcmp((char*)a, *(char**)b);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008226}
8227
8228static const char *const *
8229findkwd(const char *s)
8230{
8231 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00008232 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8233 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008234}
8235
8236/*
8237 * Locate and print what a word is...
8238 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008239static int
Ron Yorston3f221112015-08-03 13:47:33 +01008240describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008241{
8242 struct cmdentry entry;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008243#if ENABLE_ASH_ALIAS
8244 const struct alias *ap;
8245#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008246
8247 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008248
8249 if (describe_command_verbose) {
8250 out1str(command);
8251 }
8252
8253 /* First look at the keywords */
8254 if (findkwd(command)) {
8255 out1str(describe_command_verbose ? " is a shell keyword" : command);
8256 goto out;
8257 }
8258
8259#if ENABLE_ASH_ALIAS
8260 /* Then look at the aliases */
8261 ap = lookupalias(command, 0);
8262 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008263 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008264 out1str("alias ");
8265 printalias(ap);
8266 return 0;
8267 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00008268 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008269 goto out;
8270 }
8271#endif
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008272 /* Brute force */
8273 find_command(command, &entry, DO_ABS, path);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008274
8275 switch (entry.cmdtype) {
8276 case CMDNORMAL: {
8277 int j = entry.u.index;
8278 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008279 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008280 p = command;
8281 } else {
8282 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008283 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008284 stunalloc(p);
8285 } while (--j >= 0);
8286 }
8287 if (describe_command_verbose) {
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008288 out1fmt(" is %s", p);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008289 } else {
8290 out1str(p);
8291 }
8292 break;
8293 }
8294
8295 case CMDFUNCTION:
8296 if (describe_command_verbose) {
8297 out1str(" is a shell function");
8298 } else {
8299 out1str(command);
8300 }
8301 break;
8302
8303 case CMDBUILTIN:
8304 if (describe_command_verbose) {
8305 out1fmt(" is a %sshell builtin",
8306 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8307 "special " : nullstr
8308 );
8309 } else {
8310 out1str(command);
8311 }
8312 break;
8313
8314 default:
8315 if (describe_command_verbose) {
8316 out1str(": not found\n");
8317 }
8318 return 127;
8319 }
8320 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008321 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008322 return 0;
8323}
8324
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008325static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008326typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008327{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008328 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008329 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008330 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008331
Denis Vlasenko46846e22007-05-20 13:08:31 +00008332 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008333 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008334 i++;
8335 verbose = 0;
8336 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008337 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008338 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008339 }
8340 return err;
8341}
8342
8343#if ENABLE_ASH_CMDCMD
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008344/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8345static char **
8346parse_command_args(char **argv, const char **path)
8347{
8348 char *cp, c;
8349
8350 for (;;) {
8351 cp = *++argv;
8352 if (!cp)
8353 return NULL;
8354 if (*cp++ != '-')
8355 break;
8356 c = *cp++;
8357 if (!c)
8358 break;
8359 if (c == '-' && !*cp) {
8360 if (!*++argv)
8361 return NULL;
8362 break;
8363 }
8364 do {
8365 switch (c) {
8366 case 'p':
8367 *path = bb_default_path;
8368 break;
8369 default:
8370 /* run 'typecmd' for other options */
8371 return NULL;
8372 }
8373 c = *cp++;
8374 } while (c);
8375 }
8376 return argv;
8377}
8378
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008379static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008380commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008381{
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008382 char *cmd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008383 int c;
8384 enum {
8385 VERIFY_BRIEF = 1,
8386 VERIFY_VERBOSE = 2,
8387 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008388 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008389
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008390 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8391 * never reaches this function.
8392 */
8393
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008394 while ((c = nextopt("pvV")) != '\0')
8395 if (c == 'V')
8396 verify |= VERIFY_VERBOSE;
8397 else if (c == 'v')
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008398 /*verify |= VERIFY_BRIEF*/;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008399#if DEBUG
8400 else if (c != 'p')
8401 abort();
8402#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008403 else
8404 path = bb_default_path;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008405
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008406 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008407 cmd = *argptr;
8408 if (/*verify && */ cmd)
8409 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008410
8411 return 0;
8412}
8413#endif
8414
8415
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008416/*static int funcblocksize; // size of structures in function */
8417/*static int funcstringsize; // size of strings in node */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008418static void *funcblock; /* block to allocate function from */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008419static char *funcstring_end; /* end of block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008420
Eric Andersencb57d552001-06-28 07:25:16 +00008421/* flags in argument to evaltree */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008422#define EV_EXIT 01 /* exit after evaluating tree */
8423#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Eric Andersencb57d552001-06-28 07:25:16 +00008424
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008425static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008426 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8427 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8428 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8429 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8430 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8431 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8432 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8433 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8434 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8435 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8436 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8437 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8438 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8439 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8440 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8441 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8442 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008443#if BASH_REDIR_OUTPUT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008444 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008445#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008446 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8447 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8448 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8449 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8450 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8451 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8452 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8453 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8454 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008455};
8456
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008457static int calcsize(int funcblocksize, union node *n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008458
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008459static int
8460sizenodelist(int funcblocksize, struct nodelist *lp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008461{
8462 while (lp) {
8463 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008464 funcblocksize = calcsize(funcblocksize, lp->n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008465 lp = lp->next;
8466 }
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008467 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008468}
8469
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008470static int
8471calcsize(int funcblocksize, union node *n)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008472{
8473 if (n == NULL)
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008474 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008475 funcblocksize += nodesize[n->type];
8476 switch (n->type) {
8477 case NCMD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008478 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8479 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8480 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008481 break;
8482 case NPIPE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008483 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008484 break;
8485 case NREDIR:
8486 case NBACKGND:
8487 case NSUBSHELL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008488 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8489 funcblocksize = calcsize(funcblocksize, n->nredir.n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008490 break;
8491 case NAND:
8492 case NOR:
8493 case NSEMI:
8494 case NWHILE:
8495 case NUNTIL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008496 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8497 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008498 break;
8499 case NIF:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008500 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8501 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8502 funcblocksize = calcsize(funcblocksize, n->nif.test);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008503 break;
8504 case NFOR:
Denys Vlasenko561639a2016-10-07 04:28:33 +02008505 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008506 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8507 funcblocksize = calcsize(funcblocksize, n->nfor.args);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008508 break;
8509 case NCASE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008510 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8511 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008512 break;
8513 case NCLIST:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008514 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8515 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8516 funcblocksize = calcsize(funcblocksize, n->nclist.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008517 break;
8518 case NDEFUN:
8519 case NARG:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008520 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
Denys Vlasenko561639a2016-10-07 04:28:33 +02008521 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008522 funcblocksize = calcsize(funcblocksize, n->narg.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008523 break;
8524 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008525#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008526 case NTO2:
8527#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008528 case NCLOBBER:
8529 case NFROM:
8530 case NFROMTO:
8531 case NAPPEND:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008532 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8533 funcblocksize = calcsize(funcblocksize, n->nfile.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008534 break;
8535 case NTOFD:
8536 case NFROMFD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008537 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8538 funcblocksize = calcsize(funcblocksize, n->ndup.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008539 break;
8540 case NHERE:
8541 case NXHERE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008542 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8543 funcblocksize = calcsize(funcblocksize, n->nhere.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008544 break;
8545 case NNOT:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008546 funcblocksize = calcsize(funcblocksize, n->nnot.com);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008547 break;
8548 };
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008549 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008550}
8551
8552static char *
8553nodeckstrdup(char *s)
8554{
Denys Vlasenko561639a2016-10-07 04:28:33 +02008555 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008556 return strcpy(funcstring_end, s);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008557}
8558
8559static union node *copynode(union node *);
8560
8561static struct nodelist *
8562copynodelist(struct nodelist *lp)
8563{
8564 struct nodelist *start;
8565 struct nodelist **lpp;
8566
8567 lpp = &start;
8568 while (lp) {
8569 *lpp = funcblock;
8570 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8571 (*lpp)->n = copynode(lp->n);
8572 lp = lp->next;
8573 lpp = &(*lpp)->next;
8574 }
8575 *lpp = NULL;
8576 return start;
8577}
8578
8579static union node *
8580copynode(union node *n)
8581{
8582 union node *new;
8583
8584 if (n == NULL)
8585 return NULL;
8586 new = funcblock;
8587 funcblock = (char *) funcblock + nodesize[n->type];
8588
8589 switch (n->type) {
8590 case NCMD:
8591 new->ncmd.redirect = copynode(n->ncmd.redirect);
8592 new->ncmd.args = copynode(n->ncmd.args);
8593 new->ncmd.assign = copynode(n->ncmd.assign);
8594 break;
8595 case NPIPE:
8596 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008597 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008598 break;
8599 case NREDIR:
8600 case NBACKGND:
8601 case NSUBSHELL:
8602 new->nredir.redirect = copynode(n->nredir.redirect);
8603 new->nredir.n = copynode(n->nredir.n);
8604 break;
8605 case NAND:
8606 case NOR:
8607 case NSEMI:
8608 case NWHILE:
8609 case NUNTIL:
8610 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8611 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8612 break;
8613 case NIF:
8614 new->nif.elsepart = copynode(n->nif.elsepart);
8615 new->nif.ifpart = copynode(n->nif.ifpart);
8616 new->nif.test = copynode(n->nif.test);
8617 break;
8618 case NFOR:
8619 new->nfor.var = nodeckstrdup(n->nfor.var);
8620 new->nfor.body = copynode(n->nfor.body);
8621 new->nfor.args = copynode(n->nfor.args);
8622 break;
8623 case NCASE:
8624 new->ncase.cases = copynode(n->ncase.cases);
8625 new->ncase.expr = copynode(n->ncase.expr);
8626 break;
8627 case NCLIST:
8628 new->nclist.body = copynode(n->nclist.body);
8629 new->nclist.pattern = copynode(n->nclist.pattern);
8630 new->nclist.next = copynode(n->nclist.next);
8631 break;
8632 case NDEFUN:
8633 case NARG:
8634 new->narg.backquote = copynodelist(n->narg.backquote);
8635 new->narg.text = nodeckstrdup(n->narg.text);
8636 new->narg.next = copynode(n->narg.next);
8637 break;
8638 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008639#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008640 case NTO2:
8641#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008642 case NCLOBBER:
8643 case NFROM:
8644 case NFROMTO:
8645 case NAPPEND:
8646 new->nfile.fname = copynode(n->nfile.fname);
8647 new->nfile.fd = n->nfile.fd;
8648 new->nfile.next = copynode(n->nfile.next);
8649 break;
8650 case NTOFD:
8651 case NFROMFD:
8652 new->ndup.vname = copynode(n->ndup.vname);
8653 new->ndup.dupfd = n->ndup.dupfd;
8654 new->ndup.fd = n->ndup.fd;
8655 new->ndup.next = copynode(n->ndup.next);
8656 break;
8657 case NHERE:
8658 case NXHERE:
8659 new->nhere.doc = copynode(n->nhere.doc);
8660 new->nhere.fd = n->nhere.fd;
8661 new->nhere.next = copynode(n->nhere.next);
8662 break;
8663 case NNOT:
8664 new->nnot.com = copynode(n->nnot.com);
8665 break;
8666 };
8667 new->type = n->type;
8668 return new;
8669}
8670
8671/*
8672 * Make a copy of a parse tree.
8673 */
8674static struct funcnode *
8675copyfunc(union node *n)
8676{
8677 struct funcnode *f;
8678 size_t blocksize;
8679
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008680 /*funcstringsize = 0;*/
8681 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8682 f = ckzalloc(blocksize /* + funcstringsize */);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008683 funcblock = (char *) f + offsetof(struct funcnode, n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008684 funcstring_end = (char *) f + blocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008685 copynode(n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008686 /* f->count = 0; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008687 return f;
8688}
8689
8690/*
8691 * Define a shell function.
8692 */
8693static void
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008694defun(union node *func)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008695{
8696 struct cmdentry entry;
8697
8698 INT_OFF;
8699 entry.cmdtype = CMDFUNCTION;
8700 entry.u.func = copyfunc(func);
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008701 addcmdentry(func->narg.text, &entry);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008702 INT_ON;
8703}
8704
Denis Vlasenko4b875702009-03-19 13:30:04 +00008705/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008706#define SKIPBREAK (1 << 0)
8707#define SKIPCONT (1 << 1)
8708#define SKIPFUNC (1 << 2)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008709static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008710static int skipcount; /* number of levels to skip */
8711static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008712static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008713
Denis Vlasenko4b875702009-03-19 13:30:04 +00008714/* Forward decl way out to parsing code - dotrap needs it */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008715static int evalstring(char *s, int flags);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008716
Denis Vlasenko4b875702009-03-19 13:30:04 +00008717/* Called to execute a trap.
8718 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008719 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008720 *
8721 * Perhaps we should avoid entering new trap handlers
8722 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008723 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008724static void
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008725dotrap(void)
8726{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008727 uint8_t *g;
8728 int sig;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008729 uint8_t last_status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008730
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008731 if (!pending_sig)
8732 return;
8733
8734 last_status = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008735 pending_sig = 0;
Denys Vlasenkode892052016-10-02 01:49:13 +02008736 barrier();
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008737
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008738 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008739 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008740 char *p;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008741
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008742 if (!*g)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008743 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008744
8745 if (evalskip) {
8746 pending_sig = sig;
8747 break;
8748 }
8749
8750 p = trap[sig];
Denis Vlasenko4b875702009-03-19 13:30:04 +00008751 /* non-trapped SIGINT is handled separately by raise_interrupt,
8752 * don't upset it by resetting gotsig[SIGINT-1] */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008753 if (sig == SIGINT && !p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008754 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008755
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008756 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008757 *g = 0;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008758 if (!p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008759 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008760 evalstring(p, 0);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008761 }
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008762 exitstatus = last_status;
8763 TRACE(("dotrap returns\n"));
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008764}
8765
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008766/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008767static int evalloop(union node *, int);
8768static int evalfor(union node *, int);
8769static int evalcase(union node *, int);
8770static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008771static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008772static int evalpipe(union node *, int);
8773static int evalcommand(union node *, int);
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008774static int evalbltin(const struct builtincmd *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008775static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008776
Eric Andersen62483552001-07-10 06:09:16 +00008777/*
Eric Andersenc470f442003-07-28 09:56:35 +00008778 * Evaluate a parse tree. The value is left in the global variable
8779 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008780 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008781static int
Eric Andersenc470f442003-07-28 09:56:35 +00008782evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008783{
Eric Andersenc470f442003-07-28 09:56:35 +00008784 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008785 int (*evalfn)(union node *, int);
8786 int status = 0;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008787
Eric Andersenc470f442003-07-28 09:56:35 +00008788 if (n == NULL) {
8789 TRACE(("evaltree(NULL) called\n"));
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02008790 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00008791 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008792 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008793
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008794 dotrap();
8795
Eric Andersenc470f442003-07-28 09:56:35 +00008796 switch (n->type) {
8797 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008798#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008799 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008800 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008801 break;
8802#endif
8803 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008804 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008805 goto setstatus;
8806 case NREDIR:
8807 expredir(n->nredir.redirect);
8808 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8809 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008810 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008811 }
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02008812 if (n->nredir.redirect)
8813 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
Eric Andersenc470f442003-07-28 09:56:35 +00008814 goto setstatus;
8815 case NCMD:
8816 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008817 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008818 if (eflag && !(flags & EV_TESTED))
8819 checkexit = ~0;
8820 goto calleval;
8821 case NFOR:
8822 evalfn = evalfor;
8823 goto calleval;
8824 case NWHILE:
8825 case NUNTIL:
8826 evalfn = evalloop;
8827 goto calleval;
8828 case NSUBSHELL:
8829 case NBACKGND:
8830 evalfn = evalsubshell;
Denys Vlasenkocf98b0c2016-10-25 18:19:39 +02008831 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00008832 case NPIPE:
8833 evalfn = evalpipe;
8834 goto checkexit;
8835 case NCASE:
8836 evalfn = evalcase;
8837 goto calleval;
8838 case NAND:
8839 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008840 case NSEMI: {
8841
Eric Andersenc470f442003-07-28 09:56:35 +00008842#if NAND + 1 != NOR
8843#error NAND + 1 != NOR
8844#endif
8845#if NOR + 1 != NSEMI
8846#error NOR + 1 != NSEMI
8847#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008848 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008849 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00008850 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008851 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008852 );
Denys Vlasenkobc1a0082016-10-02 15:31:33 +02008853 if ((!status) == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00008854 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008855 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008856 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008857 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008858 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008859 status = evalfn(n, flags);
8860 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008861 }
Eric Andersenc470f442003-07-28 09:56:35 +00008862 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008863 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008864 if (evalskip)
8865 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008866 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00008867 n = n->nif.ifpart;
8868 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008869 }
8870 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008871 n = n->nif.elsepart;
8872 goto evaln;
8873 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008874 status = 0;
8875 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00008876 case NDEFUN:
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008877 defun(n);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008878 /* Not necessary. To test it:
8879 * "false; f() { qwerty; }; echo $?" should print 0.
8880 */
8881 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008882 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00008883 exitstatus = status;
8884 break;
8885 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008886 out:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008887 /* Order of checks below is important:
8888 * signal handlers trigger before exit caused by "set -e".
8889 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008890 dotrap();
8891
8892 if (checkexit & status)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008893 raise_exception(EXEXIT);
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008894 if (flags & EV_EXIT)
8895 raise_exception(EXEXIT);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008896
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008897 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008898 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00008899}
8900
Eric Andersenc470f442003-07-28 09:56:35 +00008901#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8902static
8903#endif
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008904int evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
Eric Andersenc470f442003-07-28 09:56:35 +00008905
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02008906static int
8907skiploop(void)
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008908{
8909 int skip = evalskip;
8910
8911 switch (skip) {
8912 case 0:
8913 break;
8914 case SKIPBREAK:
8915 case SKIPCONT:
8916 if (--skipcount <= 0) {
8917 evalskip = 0;
8918 break;
8919 }
8920 skip = SKIPBREAK;
8921 break;
8922 }
8923 return skip;
8924}
8925
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008926static int
Eric Andersenc470f442003-07-28 09:56:35 +00008927evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008928{
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008929 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00008930 int status;
8931
8932 loopnest++;
8933 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008934 flags &= EV_TESTED;
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008935 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008936 int i;
8937
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008938 i = evaltree(n->nbinary.ch1, EV_TESTED);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008939 skip = skiploop();
8940 if (skip == SKIPFUNC)
8941 status = i;
8942 if (skip)
8943 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00008944 if (n->type != NWHILE)
8945 i = !i;
8946 if (i != 0)
8947 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008948 status = evaltree(n->nbinary.ch2, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008949 skip = skiploop();
8950 } while (!(skip & ~SKIPCONT));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008951 loopnest--;
8952
8953 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008954}
8955
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008956static int
Eric Andersenc470f442003-07-28 09:56:35 +00008957evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008958{
8959 struct arglist arglist;
8960 union node *argp;
8961 struct strlist *sp;
8962 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008963 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008964
8965 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008966 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008967 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008968 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02008969 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersencb57d552001-06-28 07:25:16 +00008970 }
8971 *arglist.lastp = NULL;
8972
Eric Andersencb57d552001-06-28 07:25:16 +00008973 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008974 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008975 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008976 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008977 status = evaltree(n->nfor.body, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008978 if (skiploop() & ~SKIPCONT)
Eric Andersencb57d552001-06-28 07:25:16 +00008979 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008980 }
8981 loopnest--;
Eric Andersencb57d552001-06-28 07:25:16 +00008982 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008983
8984 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008985}
8986
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008987static int
Eric Andersenc470f442003-07-28 09:56:35 +00008988evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008989{
8990 union node *cp;
8991 union node *patp;
8992 struct arglist arglist;
8993 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008994 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008995
8996 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008997 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008998 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00008999 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009000 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
9001 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00009002 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009003 /* Ensure body is non-empty as otherwise
9004 * EV_EXIT may prevent us from setting the
9005 * exit status.
9006 */
9007 if (evalskip == 0 && cp->nclist.body) {
9008 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00009009 }
9010 goto out;
9011 }
9012 }
9013 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009014 out:
Eric Andersencb57d552001-06-28 07:25:16 +00009015 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009016
9017 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009018}
9019
Eric Andersenc470f442003-07-28 09:56:35 +00009020/*
9021 * Kick off a subshell to evaluate a tree.
9022 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009023static int
Eric Andersenc470f442003-07-28 09:56:35 +00009024evalsubshell(union node *n, int flags)
9025{
9026 struct job *jp;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009027 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
Eric Andersenc470f442003-07-28 09:56:35 +00009028 int status;
9029
9030 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02009031 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00009032 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009033 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009034 if (backgnd == FORK_FG)
9035 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009036 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009037 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009038 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009039 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009040 flags |= EV_EXIT;
9041 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02009042 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00009043 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00009044 redirect(n->nredir.redirect, 0);
9045 evaltreenr(n->nredir.n, flags);
9046 /* never returns */
9047 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009048 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00009049 status = 0;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009050 if (backgnd == FORK_FG)
Eric Andersenc470f442003-07-28 09:56:35 +00009051 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009052 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009053 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009054}
9055
Eric Andersenc470f442003-07-28 09:56:35 +00009056/*
9057 * Compute the names of the files in a redirection list.
9058 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009059static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00009060static void
9061expredir(union node *n)
9062{
9063 union node *redir;
9064
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009065 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009066 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009067
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009068 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009069 fn.lastp = &fn.list;
9070 switch (redir->type) {
9071 case NFROMTO:
9072 case NFROM:
9073 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009074#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009075 case NTO2:
9076#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009077 case NCLOBBER:
9078 case NAPPEND:
9079 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02009080 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009081#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009082 store_expfname:
9083#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009084#if 0
9085// By the design of stack allocator, the loop of this kind:
9086// while true; do while true; do break; done </dev/null; done
9087// will look like a memory leak: ash plans to free expfname's
9088// of "/dev/null" as soon as it finishes running the loop
9089// (in this case, never).
9090// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01009091 if (redir->nfile.expfname)
9092 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009093// It results in corrupted state of stacked allocations.
9094#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009095 redir->nfile.expfname = fn.list->text;
9096 break;
9097 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00009098 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00009099 if (redir->ndup.vname) {
9100 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009101 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009102 ash_msg_and_raise_error("redir error");
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009103#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009104//FIXME: we used expandarg with different args!
9105 if (!isdigit_str9(fn.list->text)) {
9106 /* >&file, not >&fd */
9107 if (redir->nfile.fd != 1) /* 123>&file - BAD */
9108 ash_msg_and_raise_error("redir error");
9109 redir->type = NTO2;
9110 goto store_expfname;
9111 }
9112#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009113 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009114 }
9115 break;
9116 }
9117 }
9118}
9119
Eric Andersencb57d552001-06-28 07:25:16 +00009120/*
Eric Andersencb57d552001-06-28 07:25:16 +00009121 * Evaluate a pipeline. All the processes in the pipeline are children
9122 * of the process creating the pipeline. (This differs from some versions
9123 * of the shell, which make the last process in a pipeline the parent
9124 * of all the rest.)
9125 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009126static int
Eric Andersenc470f442003-07-28 09:56:35 +00009127evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009128{
9129 struct job *jp;
9130 struct nodelist *lp;
9131 int pipelen;
9132 int prevfd;
9133 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009134 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009135
Eric Andersenc470f442003-07-28 09:56:35 +00009136 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00009137 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009138 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00009139 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009140 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009141 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009142 if (n->npipe.pipe_backgnd == 0)
9143 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009144 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00009145 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009146 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009147 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00009148 pip[1] = -1;
9149 if (lp->next) {
9150 if (pipe(pip) < 0) {
9151 close(prevfd);
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00009152 ash_msg_and_raise_error("pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00009153 }
9154 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009155 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02009156 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009157 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00009158 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009159 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00009160 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009161 if (prevfd > 0) {
9162 dup2(prevfd, 0);
9163 close(prevfd);
9164 }
9165 if (pip[1] > 1) {
9166 dup2(pip[1], 1);
9167 close(pip[1]);
9168 }
Eric Andersenc470f442003-07-28 09:56:35 +00009169 evaltreenr(lp->n, flags);
9170 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00009171 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009172 /* parent */
Eric Andersencb57d552001-06-28 07:25:16 +00009173 if (prevfd >= 0)
9174 close(prevfd);
9175 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00009176 /* Don't want to trigger debugging */
9177 if (pip[1] != -1)
9178 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009179 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009180 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009181 status = waitforjob(jp);
9182 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00009183 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009184 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009185
9186 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009187}
9188
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009189/*
9190 * Controls whether the shell is interactive or not.
9191 */
9192static void
9193setinteractive(int on)
9194{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009195 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009196
9197 if (++on == is_interactive)
9198 return;
9199 is_interactive = on;
9200 setsignal(SIGINT);
9201 setsignal(SIGQUIT);
9202 setsignal(SIGTERM);
9203#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9204 if (is_interactive > 1) {
9205 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009206 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009207
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009208 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009209 /* note: ash and hush share this string */
9210 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009211 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9212 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009213 bb_banner,
9214 "built-in shell (ash)"
9215 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009216 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009217 }
9218 }
9219#endif
9220}
9221
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009222static void
9223optschanged(void)
9224{
9225#if DEBUG
9226 opentrace();
9227#endif
9228 setinteractive(iflag);
9229 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009230#if ENABLE_FEATURE_EDITING_VI
9231 if (viflag)
9232 line_input_state->flags |= VI_MODE;
9233 else
9234 line_input_state->flags &= ~VI_MODE;
9235#else
9236 viflag = 0; /* forcibly keep the option off */
9237#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009238}
9239
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009240static struct localvar *localvars;
9241
9242/*
9243 * Called after a function returns.
9244 * Interrupts must be off.
9245 */
9246static void
9247poplocalvars(void)
9248{
9249 struct localvar *lvp;
9250 struct var *vp;
9251
9252 while ((lvp = localvars) != NULL) {
9253 localvars = lvp->next;
9254 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02009255 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009256 if (vp == NULL) { /* $- saved */
9257 memcpy(optlist, lvp->text, sizeof(optlist));
9258 free((char*)lvp->text);
9259 optschanged();
9260 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009261 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009262 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009263 if (vp->var_func)
9264 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009265 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009266 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009267 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009268 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009269 }
9270 free(lvp);
9271 }
9272}
9273
9274static int
9275evalfun(struct funcnode *func, int argc, char **argv, int flags)
9276{
9277 volatile struct shparam saveparam;
9278 struct localvar *volatile savelocalvars;
9279 struct jmploc *volatile savehandler;
9280 struct jmploc jmploc;
9281 int e;
9282
9283 saveparam = shellparam;
9284 savelocalvars = localvars;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009285 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009286 e = setjmp(jmploc.loc);
9287 if (e) {
9288 goto funcdone;
9289 }
9290 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009291 exception_handler = &jmploc;
9292 localvars = NULL;
Denis Vlasenko01631112007-12-16 17:20:38 +00009293 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009294 func->count++;
9295 funcnest++;
9296 INT_ON;
9297 shellparam.nparam = argc - 1;
9298 shellparam.p = argv + 1;
9299#if ENABLE_ASH_GETOPTS
9300 shellparam.optind = 1;
9301 shellparam.optoff = -1;
9302#endif
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009303 evaltree(func->n.narg.next, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00009304 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009305 INT_OFF;
9306 funcnest--;
9307 freefunc(func);
9308 poplocalvars();
9309 localvars = savelocalvars;
9310 freeparam(&shellparam);
9311 shellparam = saveparam;
9312 exception_handler = savehandler;
9313 INT_ON;
9314 evalskip &= ~SKIPFUNC;
9315 return e;
9316}
9317
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009318/*
9319 * Make a variable a local variable. When a variable is made local, it's
9320 * value and flags are saved in a localvar structure. The saved values
9321 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009322 * "-" as a special case: it makes changes to "set +-options" local
9323 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009324 */
9325static void
9326mklocal(char *name)
9327{
9328 struct localvar *lvp;
9329 struct var **vpp;
9330 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009331 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009332
9333 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009334 /* Cater for duplicate "local". Examples:
9335 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9336 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9337 */
9338 lvp = localvars;
9339 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009340 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009341 if (eq)
9342 setvareq(name, 0);
9343 /* else:
9344 * it's a duplicate "local VAR" declaration, do nothing
9345 */
Denys Vlasenko06b11492016-11-04 16:43:18 +01009346 goto ret;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009347 }
9348 lvp = lvp->next;
9349 }
9350
9351 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009352 if (LONE_DASH(name)) {
9353 char *p;
9354 p = ckmalloc(sizeof(optlist));
9355 lvp->text = memcpy(p, optlist, sizeof(optlist));
9356 vp = NULL;
9357 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009358 vpp = hashvar(name);
9359 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009360 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009361 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009362 if (eq)
9363 setvareq(name, VSTRFIXED);
9364 else
9365 setvar(name, NULL, VSTRFIXED);
9366 vp = *vpp; /* the new variable */
9367 lvp->flags = VUNSET;
9368 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009369 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009370 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009371 /* make sure neither "struct var" nor string gets freed
9372 * during (un)setting:
9373 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009374 vp->flags |= VSTRFIXED|VTEXTFIXED;
9375 if (eq)
9376 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009377 else
9378 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009379 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009380 }
9381 }
9382 lvp->vp = vp;
9383 lvp->next = localvars;
9384 localvars = lvp;
Denys Vlasenko06b11492016-11-04 16:43:18 +01009385 ret:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009386 INT_ON;
9387}
9388
9389/*
9390 * The "local" command.
9391 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009392static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009393localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009394{
9395 char *name;
9396
Ron Yorstonef2386b2015-10-29 16:19:14 +00009397 if (!funcnest)
9398 ash_msg_and_raise_error("not in a function");
9399
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009400 argv = argptr;
9401 while ((name = *argv++) != NULL) {
9402 mklocal(name);
9403 }
9404 return 0;
9405}
9406
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009407static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009408falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009409{
9410 return 1;
9411}
9412
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009413static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009414truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009415{
9416 return 0;
9417}
9418
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009419static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009420execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009421{
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009422 optionarg = NULL;
9423 while (nextopt("a:") != '\0')
9424 /* nextopt() sets optionarg to "-a ARGV0" */;
9425
9426 argv = argptr;
9427 if (argv[0]) {
9428 char *prog;
9429
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009430 iflag = 0; /* exit on error */
9431 mflag = 0;
9432 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009433 /* We should set up signals for "exec CMD"
9434 * the same way as for "CMD" without "exec".
9435 * But optschanged->setinteractive->setsignal
9436 * still thought we are a root shell. Therefore, for example,
9437 * SIGQUIT is still set to IGN. Fix it:
9438 */
9439 shlvl++;
9440 setsignal(SIGQUIT);
9441 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9442 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9443 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9444
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009445 prog = argv[0];
9446 if (optionarg)
9447 argv[0] = optionarg;
9448 shellexec(prog, argv, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009449 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009450 }
9451 return 0;
9452}
9453
9454/*
9455 * The return command.
9456 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009457static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009458returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009459{
9460 /*
9461 * If called outside a function, do what ksh does;
9462 * skip the rest of the file.
9463 */
Denys Vlasenko6a0710e2016-09-30 14:18:34 +02009464 evalskip = SKIPFUNC;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009465 return argv[1] ? number(argv[1]) : exitstatus;
9466}
9467
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009468/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009469static int breakcmd(int, char **) FAST_FUNC;
9470static int dotcmd(int, char **) FAST_FUNC;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009471static int evalcmd(int, char **, int) FAST_FUNC;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009472static int exitcmd(int, char **) FAST_FUNC;
9473static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009474#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009475static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009476#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009477#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009478static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009479#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009480#if MAX_HISTORY
9481static int historycmd(int, char **) FAST_FUNC;
9482#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009483#if ENABLE_FEATURE_SH_MATH
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009484static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009485#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009486static int readcmd(int, char **) FAST_FUNC;
9487static int setcmd(int, char **) FAST_FUNC;
9488static int shiftcmd(int, char **) FAST_FUNC;
9489static int timescmd(int, char **) FAST_FUNC;
9490static int trapcmd(int, char **) FAST_FUNC;
9491static int umaskcmd(int, char **) FAST_FUNC;
9492static int unsetcmd(int, char **) FAST_FUNC;
9493static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009494
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009495#define BUILTIN_NOSPEC "0"
9496#define BUILTIN_SPECIAL "1"
9497#define BUILTIN_REGULAR "2"
9498#define BUILTIN_SPEC_REG "3"
9499#define BUILTIN_ASSIGN "4"
9500#define BUILTIN_SPEC_ASSG "5"
9501#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009502#define BUILTIN_SPEC_REG_ASSG "7"
9503
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009504/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko265062d2017-01-10 15:13:30 +01009505#if ENABLE_ASH_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009506static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009507#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009508#if ENABLE_ASH_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009509static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009510#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009511#if ENABLE_ASH_TEST || BASH_TEST2
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009512static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009513#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009514
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009515/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009516static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009517 { BUILTIN_SPEC_REG "." , dotcmd },
9518 { BUILTIN_SPEC_REG ":" , truecmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009519#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009520 { BUILTIN_REGULAR "[" , testcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009521#endif
9522#if BASH_TEST2
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009523 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009524#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009525#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009526 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009527#endif
9528#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009529 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009530#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009531 { BUILTIN_SPEC_REG "break" , breakcmd },
9532 { BUILTIN_REGULAR "cd" , cdcmd },
9533 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009534#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009535 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009536#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009537 { BUILTIN_SPEC_REG "continue", breakcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009538#if ENABLE_ASH_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009539 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009540#endif
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009541 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009542 { BUILTIN_SPEC_REG "exec" , execcmd },
9543 { BUILTIN_SPEC_REG "exit" , exitcmd },
9544 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9545 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009546#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009547 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009548#endif
9549#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009550 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009551#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009552 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009553#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009554 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009555#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009556#if MAX_HISTORY
9557 { BUILTIN_NOSPEC "history" , historycmd },
9558#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009559#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009560 { BUILTIN_REGULAR "jobs" , jobscmd },
9561 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009562#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009563#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009564 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009565#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009566 { BUILTIN_ASSIGN "local" , localcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009567#if ENABLE_ASH_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009568 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009569#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009570 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9571 { BUILTIN_REGULAR "read" , readcmd },
9572 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9573 { BUILTIN_SPEC_REG "return" , returncmd },
9574 { BUILTIN_SPEC_REG "set" , setcmd },
9575 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009576#if BASH_SOURCE
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009577 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009578#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009579#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009580 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009581#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009582 { BUILTIN_SPEC_REG "times" , timescmd },
9583 { BUILTIN_SPEC_REG "trap" , trapcmd },
9584 { BUILTIN_REGULAR "true" , truecmd },
9585 { BUILTIN_NOSPEC "type" , typecmd },
9586 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9587 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009588#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009589 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009590#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009591 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9592 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009593};
9594
Denis Vlasenko80591b02008-03-25 07:49:43 +00009595/* Should match the above table! */
9596#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009597 /* . : */ 2 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009598 /* [ */ 1 * ENABLE_ASH_TEST + \
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009599 /* [[ */ 1 * BASH_TEST2 + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009600 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9601 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9602 /* break cd cddir */ 3)
9603#define EVALCMD (COMMANDCMD + \
9604 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9605 /* continue */ 1 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009606 /* echo */ 1 * ENABLE_ASH_ECHO + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009607 0)
9608#define EXECCMD (EVALCMD + \
9609 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009610
9611/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009612 * Search the table of builtin commands.
9613 */
Denys Vlasenko888527c2016-10-02 16:54:17 +02009614static int
9615pstrcmp1(const void *a, const void *b)
9616{
9617 return strcmp((char*)a, *(char**)b + 1);
9618}
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009619static struct builtincmd *
9620find_builtin(const char *name)
9621{
9622 struct builtincmd *bp;
9623
9624 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009625 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denys Vlasenko888527c2016-10-02 16:54:17 +02009626 pstrcmp1
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009627 );
9628 return bp;
9629}
9630
9631/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009632 * Execute a simple command.
9633 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009634static int
9635isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009636{
9637 const char *q = endofname(p);
9638 if (p == q)
9639 return 0;
9640 return *q == '=';
9641}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009642static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009643bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009644{
9645 /* Preserve exitstatus of a previous possible redirection
9646 * as POSIX mandates */
9647 return back_exitstatus;
9648}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009649static int
Eric Andersenc470f442003-07-28 09:56:35 +00009650evalcommand(union node *cmd, int flags)
9651{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009652 static const struct builtincmd null_bltin = {
9653 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009654 };
Eric Andersenc470f442003-07-28 09:56:35 +00009655 struct stackmark smark;
9656 union node *argp;
9657 struct arglist arglist;
9658 struct arglist varlist;
9659 char **argv;
9660 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009661 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009662 struct cmdentry cmdentry;
9663 struct job *jp;
9664 char *lastarg;
9665 const char *path;
9666 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009667 int status;
9668 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00009669 struct builtincmd *bcmd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009670 smallint cmd_is_exec;
9671 smallint pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009672
9673 /* First expand the arguments. */
9674 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9675 setstackmark(&smark);
9676 back_exitstatus = 0;
9677
9678 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009679 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009680 varlist.lastp = &varlist.list;
9681 *varlist.lastp = NULL;
9682 arglist.lastp = &arglist.list;
9683 *arglist.lastp = NULL;
9684
9685 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009686 if (cmd->ncmd.args) {
Paul Foxc3850c82005-07-20 18:23:39 +00009687 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9688 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9689 }
9690
Eric Andersenc470f442003-07-28 09:56:35 +00009691 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9692 struct strlist **spp;
9693
9694 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00009695 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00009696 expandarg(argp, &arglist, EXP_VARTILDE);
9697 else
9698 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9699
Eric Andersenc470f442003-07-28 09:56:35 +00009700 for (sp = *spp; sp; sp = sp->next)
9701 argc++;
9702 }
9703
Denys Vlasenko65a8b852016-10-26 22:29:11 +02009704 /* Reserve one extra spot at the front for shellexec. */
9705 nargv = stalloc(sizeof(char *) * (argc + 2));
9706 argv = ++nargv;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009707 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009708 TRACE(("evalcommand arg: %s\n", sp->text));
9709 *nargv++ = sp->text;
9710 }
9711 *nargv = NULL;
9712
9713 lastarg = NULL;
9714 if (iflag && funcnest == 0 && argc > 0)
9715 lastarg = nargv[-1];
9716
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009717 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009718 expredir(cmd->ncmd.redirect);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009719 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009720
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009721 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009722 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9723 struct strlist **spp;
9724 char *p;
9725
9726 spp = varlist.lastp;
9727 expandarg(argp, &varlist, EXP_VARTILDE);
9728
9729 /*
9730 * Modify the command lookup path, if a PATH= assignment
9731 * is present
9732 */
9733 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009734 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009735 path = p;
9736 }
9737
9738 /* Print the command if xflag is set. */
9739 if (xflag) {
Denys Vlasenko42ba7572017-07-21 13:20:14 +02009740 const char *pfx = "";
Eric Andersenc470f442003-07-28 09:56:35 +00009741
Denys Vlasenko42ba7572017-07-21 13:20:14 +02009742 fdprintf(preverrout_fd, "%s", expandstr(ps4val()));
9743
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009744 sp = varlist.list;
Denys Vlasenko42ba7572017-07-21 13:20:14 +02009745 while (sp) {
9746 char *varval = sp->text;
9747 char *eq = strchrnul(varval, '=');
9748 if (*eq)
9749 eq++;
9750 fdprintf(preverrout_fd, "%s%.*s%s",
9751 pfx,
9752 (int)(eq - varval), varval,
9753 maybe_single_quote(eq)
9754 );
9755 sp = sp->next;
9756 pfx = " ";
9757 }
9758
9759 sp = arglist.list;
9760 while (sp) {
9761 fdprintf(preverrout_fd, "%s%s",
9762 pfx,
9763 /* always quote if matches reserved word: */
9764 findkwd(sp->text)
9765 ? single_quote(sp->text)
9766 : maybe_single_quote(sp->text)
9767 );
9768 sp = sp->next;
9769 pfx = " ";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009770 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009771 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009772 }
9773
9774 cmd_is_exec = 0;
9775 spclbltin = -1;
9776
9777 /* Now locate the command. */
9778 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009779 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02009780#if ENABLE_ASH_CMDCMD
9781 const char *oldpath = path + 5;
9782#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009783 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009784 for (;;) {
9785 find_command(argv[0], &cmdentry, cmd_flag, path);
9786 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009787 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009788 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009789 goto bail;
9790 }
9791
9792 /* implement bltin and command here */
9793 if (cmdentry.cmdtype != CMDBUILTIN)
9794 break;
9795 if (spclbltin < 0)
9796 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9797 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009798 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009799#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009800 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009801 path = oldpath;
9802 nargv = parse_command_args(argv, &path);
9803 if (!nargv)
9804 break;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02009805 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
9806 * nargv => "PROG". path is updated if -p.
9807 */
Eric Andersenc470f442003-07-28 09:56:35 +00009808 argc -= nargv - argv;
9809 argv = nargv;
9810 cmd_flag |= DO_NOFUNC;
9811 } else
9812#endif
9813 break;
9814 }
9815 }
9816
9817 if (status) {
Ron Yorstonea7d2f62017-01-03 11:18:23 +01009818 bail:
9819 exitstatus = status;
9820
Eric Andersenc470f442003-07-28 09:56:35 +00009821 /* We have a redirection error. */
9822 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009823 raise_exception(EXERROR);
Ron Yorstonea7d2f62017-01-03 11:18:23 +01009824
Eric Andersenc470f442003-07-28 09:56:35 +00009825 goto out;
9826 }
9827
9828 /* Execute the command. */
9829 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009830 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009831
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009832#if ENABLE_FEATURE_SH_NOFORK
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009833/* (1) BUG: if variables are set, we need to fork, or save/restore them
9834 * around run_nofork_applet() call.
9835 * (2) Should this check also be done in forkshell()?
9836 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9837 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009838 /* find_command() encodes applet_no as (-2 - applet_no) */
9839 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009840 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009841 listsetvar(varlist.list, VEXPORT|VSTACK);
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009842 /* run <applet>_main() */
Ron Yorston5ccb0e92016-10-20 12:24:02 +01009843 status = run_nofork_applet(applet_no, argv);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009844 break;
9845 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009846#endif
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009847 /* Can we avoid forking off? For example, very last command
9848 * in a script or a subshell does not need forking,
9849 * we can just exec it.
9850 */
Denys Vlasenko238bf182010-05-18 15:49:07 +02009851 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009852 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009853 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009854 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009855 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009856 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009857 /* parent */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009858 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009859 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009860 TRACE(("forked child exited with %d\n", status));
Eric Andersenc470f442003-07-28 09:56:35 +00009861 break;
9862 }
Denys Vlasenko238bf182010-05-18 15:49:07 +02009863 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009864 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +02009865 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +00009866 }
9867 listsetvar(varlist.list, VEXPORT|VSTACK);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02009868 shellexec(argv[0], argv, path, cmdentry.u.index);
Eric Andersenc470f442003-07-28 09:56:35 +00009869 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009870 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +00009871 case CMDBUILTIN:
9872 cmdenviron = varlist.list;
9873 if (cmdenviron) {
9874 struct strlist *list = cmdenviron;
9875 int i = VNOSET;
9876 if (spclbltin > 0 || argc == 0) {
9877 i = 0;
9878 if (cmd_is_exec && argc > 1)
9879 i = VEXPORT;
9880 }
9881 listsetvar(list, i);
9882 }
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009883 /* Tight loop with builtins only:
9884 * "while kill -0 $child; do true; done"
9885 * will never exit even if $child died, unless we do this
9886 * to reap the zombie and make kill detect that it's gone: */
9887 dowait(DOWAIT_NONBLOCK, NULL);
9888
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009889 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009890 if (exception_type == EXERROR && spclbltin <= 0) {
9891 FORCE_INT_ON;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02009892 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009893 }
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009894 raise:
9895 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009896 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009897 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009898
9899 case CMDFUNCTION:
9900 listsetvar(varlist.list, 0);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009901 /* See above for the rationale */
9902 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009903 if (evalfun(cmdentry.u.func, argc, argv, flags))
9904 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009905 readstatus:
9906 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009907 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009908 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +00009909
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009910 out:
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02009911 if (cmd->ncmd.redirect)
9912 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009913 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +00009914 /* dsl: I think this is intended to be used to support
9915 * '_' in 'vi' command mode during line editing...
9916 * However I implemented that within libedit itself.
9917 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009918 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009919 }
Eric Andersenc470f442003-07-28 09:56:35 +00009920 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009921
9922 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009923}
9924
9925static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009926evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009927{
Eric Andersenc470f442003-07-28 09:56:35 +00009928 char *volatile savecmdname;
9929 struct jmploc *volatile savehandler;
9930 struct jmploc jmploc;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009931 int status;
Eric Andersenc470f442003-07-28 09:56:35 +00009932 int i;
9933
9934 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009935 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009936 i = setjmp(jmploc.loc);
9937 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +00009938 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009939 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00009940 commandname = argv[0];
9941 argptr = argv + 1;
9942 optptr = NULL; /* initialize nextopt */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009943 if (cmd == EVALCMD)
9944 status = evalcmd(argc, argv, flags);
9945 else
9946 status = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009947 flush_stdout_stderr();
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009948 status |= ferror(stdout);
9949 exitstatus = status;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009950 cmddone:
Rob Landleyf296f0b2006-07-06 01:09:21 +00009951 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009952 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009953 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +00009954
9955 return i;
9956}
9957
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009958static int
9959goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009960{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02009961 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009962}
9963
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009964
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009965/*
9966 * Search for a command. This is called before we fork so that the
9967 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009968 * the child. The check for "goodname" is an overly conservative
9969 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009970 */
Eric Andersenc470f442003-07-28 09:56:35 +00009971static void
9972prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009973{
9974 struct cmdentry entry;
9975
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009976 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9977 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009978}
9979
Eric Andersencb57d552001-06-28 07:25:16 +00009980
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009981/* ============ Builtin commands
9982 *
9983 * Builtin commands whose functions are closely tied to evaluation
9984 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +00009985 */
9986
9987/*
Eric Andersencb57d552001-06-28 07:25:16 +00009988 * Handle break and continue commands. Break, continue, and return are
9989 * all handled by setting the evalskip flag. The evaluation routines
9990 * above all check this flag, and if it is set they start skipping
9991 * commands rather than executing them. The variable skipcount is
9992 * the number of loops to break/continue, or the number of function
9993 * levels to return. (The latter is always 1.) It should probably
9994 * be an error to break out of more loops than exist, but it isn't
9995 * in the standard shell so we don't make it one here.
9996 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009997static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009998breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009999{
Denis Vlasenko68404f12008-03-17 09:00:54 +000010000 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010001
Aaron Lehmann2aef3a62001-12-31 06:03:12 +000010002 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +020010003 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +000010004 if (n > loopnest)
10005 n = loopnest;
10006 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000010007 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +000010008 skipcount = n;
10009 }
10010 return 0;
10011}
10012
Eric Andersenc470f442003-07-28 09:56:35 +000010013
Denys Vlasenko70392332016-10-27 02:31:55 +020010014/*
Eric Andersen90898442003-08-06 11:20:52 +000010015 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +000010016 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010017
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010018enum {
10019 INPUT_PUSH_FILE = 1,
10020 INPUT_NOFILE_OK = 2,
10021};
Eric Andersencb57d552001-06-28 07:25:16 +000010022
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010023static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010024/* values of checkkwd variable */
10025#define CHKALIAS 0x1
10026#define CHKKWD 0x2
10027#define CHKNL 0x4
10028
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010029/*
10030 * Push a string back onto the input at this current parsefile level.
10031 * We handle aliases this way.
10032 */
10033#if !ENABLE_ASH_ALIAS
10034#define pushstring(s, ap) pushstring(s)
10035#endif
10036static void
10037pushstring(char *s, struct alias *ap)
10038{
10039 struct strpush *sp;
10040 int len;
10041
10042 len = strlen(s);
10043 INT_OFF;
10044 if (g_parsefile->strpush) {
10045 sp = ckzalloc(sizeof(*sp));
10046 sp->prev = g_parsefile->strpush;
10047 } else {
10048 sp = &(g_parsefile->basestrpush);
10049 }
10050 g_parsefile->strpush = sp;
10051 sp->prev_string = g_parsefile->next_to_pgetc;
10052 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010053 sp->unget = g_parsefile->unget;
10054 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010055#if ENABLE_ASH_ALIAS
10056 sp->ap = ap;
10057 if (ap) {
10058 ap->flag |= ALIASINUSE;
10059 sp->string = s;
10060 }
10061#endif
10062 g_parsefile->next_to_pgetc = s;
10063 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010064 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010065 INT_ON;
10066}
10067
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010068static void
10069popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010070{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010071 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +000010072
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010073 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010074#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010075 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010076 if (g_parsefile->next_to_pgetc[-1] == ' '
10077 || g_parsefile->next_to_pgetc[-1] == '\t'
10078 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010079 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010080 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010081 if (sp->string != sp->ap->val) {
10082 free(sp->string);
10083 }
10084 sp->ap->flag &= ~ALIASINUSE;
10085 if (sp->ap->flag & ALIASDEAD) {
10086 unalias(sp->ap->name);
10087 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010088 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010089#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010090 g_parsefile->next_to_pgetc = sp->prev_string;
10091 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010092 g_parsefile->unget = sp->unget;
10093 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010094 g_parsefile->strpush = sp->prev;
10095 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010096 free(sp);
10097 INT_ON;
10098}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010099
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010100static int
10101preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010102{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010103 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +000010104 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010105
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010106 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +000010107#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +000010108 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010109 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +010010110 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010111 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010112 int timeout = -1;
10113# if ENABLE_ASH_IDLE_TIMEOUT
10114 if (iflag) {
10115 const char *tmout_var = lookupvar("TMOUT");
10116 if (tmout_var) {
10117 timeout = atoi(tmout_var) * 1000;
10118 if (timeout <= 0)
10119 timeout = -1;
10120 }
10121 }
10122# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010123# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010124 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010125# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +020010126 reinit_unicode_for_ash();
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010127 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010128 if (nr == 0) {
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010129 /* ^C pressed, "convert" to SIGINT */
10130 write(STDOUT_FILENO, "^C", 2);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010131 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010132 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010133 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010134 raise(SIGINT);
10135 return 1;
10136 }
Denys Vlasenko8660aeb2016-11-24 17:44:02 +010010137 exitstatus = 128 + SIGINT;
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010138 bb_putchar('\n');
Eric Andersenc470f442003-07-28 09:56:35 +000010139 goto retry;
10140 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010141 if (nr < 0) {
10142 if (errno == 0) {
10143 /* Ctrl+D pressed */
10144 nr = 0;
10145 }
10146# if ENABLE_ASH_IDLE_TIMEOUT
10147 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +020010148 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010149 exitshell();
10150 }
10151# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010152 }
Eric Andersencb57d552001-06-28 07:25:16 +000010153 }
10154#else
Ron Yorston61d6ae22015-04-19 10:50:25 +010010155 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +000010156#endif
10157
Denys Vlasenko80c5b682011-05-08 21:21:10 +020010158#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +000010159 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010160 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +000010161 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +000010162 if (flags >= 0 && (flags & O_NONBLOCK)) {
10163 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +000010164 if (fcntl(0, F_SETFL, flags) >= 0) {
10165 out2str("sh: turning off NDELAY mode\n");
10166 goto retry;
10167 }
10168 }
10169 }
10170 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +000010171#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010172 return nr;
10173}
10174
10175/*
10176 * Refill the input buffer and return the next input character:
10177 *
10178 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010179 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
10180 * or we are reading from a string so we can't refill the buffer,
10181 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +020010182 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +000010183 * 4) Process input up to the next newline, deleting nul characters.
10184 */
Denis Vlasenko727752d2008-11-28 03:41:47 +000010185//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
10186#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010187static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010188static int
Eric Andersenc470f442003-07-28 09:56:35 +000010189preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010190{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010191 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010192 int more;
Eric Andersencb57d552001-06-28 07:25:16 +000010193
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010194 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000010195#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010196 if (g_parsefile->left_in_line == -1
10197 && g_parsefile->strpush->ap
10198 && g_parsefile->next_to_pgetc[-1] != ' '
10199 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +000010200 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010201 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +000010202 return PEOA;
10203 }
Eric Andersen2870d962001-07-02 17:27:21 +000010204#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010205 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010206 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010207 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010208 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010209 * "pgetc" needs refilling.
10210 */
10211
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010212 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010213 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010214 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010215 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010216 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010217 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010218 /* even in failure keep left_in_line and next_to_pgetc
10219 * in lock step, for correct multi-layer pungetc.
10220 * left_in_line was decremented before preadbuffer(),
10221 * must inc next_to_pgetc: */
10222 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010223 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010224 }
Eric Andersencb57d552001-06-28 07:25:16 +000010225
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010226 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010227 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010228 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010229 again:
10230 more = preadfd();
10231 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010232 /* don't try reading again */
10233 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010234 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010235 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010236 return PEOF;
10237 }
10238 }
10239
Denis Vlasenko727752d2008-11-28 03:41:47 +000010240 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010241 * Set g_parsefile->left_in_line
10242 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010243 * NUL chars are deleted.
10244 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010245 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010246 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010247 char c;
Eric Andersencb57d552001-06-28 07:25:16 +000010248
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010249 more--;
Eric Andersenc470f442003-07-28 09:56:35 +000010250
Denis Vlasenko727752d2008-11-28 03:41:47 +000010251 c = *q;
10252 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010253 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010254 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010255 q++;
10256 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010257 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010258 break;
10259 }
Eric Andersencb57d552001-06-28 07:25:16 +000010260 }
10261
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010262 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010263 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10264 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010265 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010266 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010267 }
10268 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010269 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +000010270
Eric Andersencb57d552001-06-28 07:25:16 +000010271 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010272 char save = *q;
10273 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010274 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010275 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +000010276 }
10277
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010278 pgetc_debug("preadbuffer at %d:%p'%s'",
10279 g_parsefile->left_in_line,
10280 g_parsefile->next_to_pgetc,
10281 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +010010282 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010283}
10284
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010285static void
10286nlprompt(void)
10287{
10288 g_parsefile->linno++;
10289 setprompt_if(doprompt, 2);
10290}
10291static void
10292nlnoprompt(void)
10293{
10294 g_parsefile->linno++;
10295 needprompt = doprompt;
10296}
10297
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010298static int
10299pgetc(void)
10300{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010301 int c;
10302
10303 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010304 g_parsefile->left_in_line,
10305 g_parsefile->next_to_pgetc,
10306 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010307 if (g_parsefile->unget)
10308 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010309
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010310 if (--g_parsefile->left_in_line >= 0)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +010010311 c = (unsigned char)*g_parsefile->next_to_pgetc++;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010312 else
10313 c = preadbuffer();
10314
10315 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10316 g_parsefile->lastc[0] = c;
10317
10318 return c;
10319}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010320
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010321#if ENABLE_ASH_ALIAS
10322static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010323pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010324{
10325 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010326 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010327 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010328 g_parsefile->left_in_line,
10329 g_parsefile->next_to_pgetc,
10330 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010331 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010332 } while (c == PEOA);
10333 return c;
10334}
10335#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010336# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010337#endif
10338
10339/*
10340 * Read a line from the script.
10341 */
10342static char *
10343pfgets(char *line, int len)
10344{
10345 char *p = line;
10346 int nleft = len;
10347 int c;
10348
10349 while (--nleft > 0) {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010350 c = pgetc_without_PEOA();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010351 if (c == PEOF) {
10352 if (p == line)
10353 return NULL;
10354 break;
10355 }
10356 *p++ = c;
10357 if (c == '\n')
10358 break;
10359 }
10360 *p = '\0';
10361 return line;
10362}
10363
Eric Andersenc470f442003-07-28 09:56:35 +000010364/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010365 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010366 * PEOF may be pushed back.
10367 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010368static void
Eric Andersenc470f442003-07-28 09:56:35 +000010369pungetc(void)
10370{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010371 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010372}
10373
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010374/* This one eats backslash+newline */
10375static int
10376pgetc_eatbnl(void)
10377{
10378 int c;
10379
10380 while ((c = pgetc()) == '\\') {
10381 if (pgetc() != '\n') {
10382 pungetc();
10383 break;
10384 }
10385
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010386 nlprompt();
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010387 }
10388
10389 return c;
10390}
10391
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010392/*
10393 * To handle the "." command, a stack of input files is used. Pushfile
10394 * adds a new entry to the stack and popfile restores the previous level.
10395 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010396static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010397pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010398{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010399 struct parsefile *pf;
10400
Denis Vlasenko597906c2008-02-20 16:38:54 +000010401 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010402 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010403 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010404 /*pf->strpush = NULL; - ckzalloc did it */
10405 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010406 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010407 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010408}
10409
10410static void
10411popfile(void)
10412{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010413 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010414
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010010415 if (pf == &basepf)
10416 return;
10417
Denis Vlasenkob012b102007-02-19 22:43:01 +000010418 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010419 if (pf->pf_fd >= 0)
10420 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010421 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010422 while (pf->strpush)
10423 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010424 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010425 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010426 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010427}
10428
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010429/*
10430 * Return to top level.
10431 */
10432static void
10433popallfiles(void)
10434{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010435 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010436 popfile();
10437}
10438
10439/*
10440 * Close the file(s) that the shell is reading commands from. Called
10441 * after a fork is done.
10442 */
10443static void
10444closescript(void)
10445{
10446 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010447 if (g_parsefile->pf_fd > 0) {
10448 close(g_parsefile->pf_fd);
10449 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010450 }
10451}
10452
10453/*
10454 * Like setinputfile, but takes an open file descriptor. Call this with
10455 * interrupts off.
10456 */
10457static void
10458setinputfd(int fd, int push)
10459{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010460 if (push) {
10461 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010462 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010463 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010464 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010465 if (g_parsefile->buf == NULL)
10466 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010467 g_parsefile->left_in_buffer = 0;
10468 g_parsefile->left_in_line = 0;
10469 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010470}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010471
Eric Andersenc470f442003-07-28 09:56:35 +000010472/*
10473 * Set the input to take input from a file. If push is set, push the
10474 * old input onto the stack first.
10475 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010476static int
10477setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010478{
10479 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010480
Denis Vlasenkob012b102007-02-19 22:43:01 +000010481 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010482 fd = open(fname, O_RDONLY);
10483 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010484 if (flags & INPUT_NOFILE_OK)
10485 goto out;
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010486 exitstatus = 127;
Denis Vlasenko9604e1b2009-03-03 18:47:56 +000010487 ash_msg_and_raise_error("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010488 }
Denys Vlasenko64774602016-10-26 15:24:30 +020010489 if (fd < 10)
10490 fd = savefd(fd);
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020010491 else
10492 close_on_exec_on(fd);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010493 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010494 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010495 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010496 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010497}
10498
Eric Andersencb57d552001-06-28 07:25:16 +000010499/*
10500 * Like setinputfile, but takes input from a string.
10501 */
Eric Andersenc470f442003-07-28 09:56:35 +000010502static void
10503setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010504{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010505 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010506 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010507 g_parsefile->next_to_pgetc = string;
10508 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010509 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010510 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010511 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010512}
10513
10514
Denys Vlasenko70392332016-10-27 02:31:55 +020010515/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010516 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010517 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010518
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010519#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010520
Denys Vlasenko23841622015-10-09 15:52:03 +020010521/* Hash of mtimes of mailboxes */
10522static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010523/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010524static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010525
Eric Andersencb57d552001-06-28 07:25:16 +000010526/*
Eric Andersenc470f442003-07-28 09:56:35 +000010527 * Print appropriate message(s) if mail has arrived.
10528 * If mail_var_path_changed is set,
10529 * then the value of MAIL has mail_var_path_changed,
10530 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010531 */
Eric Andersenc470f442003-07-28 09:56:35 +000010532static void
10533chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010534{
Eric Andersencb57d552001-06-28 07:25:16 +000010535 const char *mpath;
10536 char *p;
10537 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010538 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010539 struct stackmark smark;
10540 struct stat statb;
10541
Eric Andersencb57d552001-06-28 07:25:16 +000010542 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010543 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010544 new_hash = 0;
10545 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010546 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010547 if (p == NULL)
10548 break;
10549 if (*p == '\0')
10550 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010551 for (q = p; *q; q++)
10552 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010553#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010554 if (q[-1] != '/')
10555 abort();
10556#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010557 q[-1] = '\0'; /* delete trailing '/' */
10558 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010559 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010560 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010561 /* Very simplistic "hash": just a sum of all mtimes */
10562 new_hash += (unsigned)statb.st_mtime;
10563 }
10564 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010565 if (mailtime_hash != 0)
10566 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010567 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010568 }
Eric Andersenc470f442003-07-28 09:56:35 +000010569 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010570 popstackmark(&smark);
10571}
Eric Andersencb57d552001-06-28 07:25:16 +000010572
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010573static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010574changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010575{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010576 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010577}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010578
Denis Vlasenko131ae172007-02-18 13:00:19 +000010579#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010580
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010581
10582/* ============ ??? */
10583
Eric Andersencb57d552001-06-28 07:25:16 +000010584/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010585 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010586 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010587static void
10588setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010589{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010590 char **newparam;
10591 char **ap;
10592 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010593
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010594 for (nparam = 0; argv[nparam]; nparam++)
10595 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010596 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10597 while (*argv) {
10598 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010599 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010600 *ap = NULL;
10601 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010602 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010603 shellparam.nparam = nparam;
10604 shellparam.p = newparam;
10605#if ENABLE_ASH_GETOPTS
10606 shellparam.optind = 1;
10607 shellparam.optoff = -1;
10608#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010609}
10610
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010611/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010612 * Process shell options. The global variable argptr contains a pointer
10613 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010614 *
10615 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10616 * For a non-interactive shell, an error condition encountered
10617 * by a special built-in ... shall cause the shell to write a diagnostic message
10618 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010619 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010620 * ...
10621 * Utility syntax error (option or operand error) Shall exit
10622 * ...
10623 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10624 * we see that bash does not do that (set "finishes" with error code 1 instead,
10625 * and shell continues), and people rely on this behavior!
10626 * Testcase:
10627 * set -o barfoo 2>/dev/null
10628 * echo $?
10629 *
10630 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010631 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010632static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010633plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010634{
10635 int i;
10636
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010637 if (name) {
10638 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010639 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010640 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010641 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010642 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010643 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010644 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010645 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010646 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010647 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010648 if (val) {
10649 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10650 } else {
10651 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10652 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010653 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010654 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010655}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010656static void
10657setoption(int flag, int val)
10658{
10659 int i;
10660
10661 for (i = 0; i < NOPTS; i++) {
10662 if (optletters(i) == flag) {
10663 optlist[i] = val;
10664 return;
10665 }
10666 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010667 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010668 /* NOTREACHED */
10669}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010670static int
Eric Andersenc470f442003-07-28 09:56:35 +000010671options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +000010672{
10673 char *p;
10674 int val;
10675 int c;
10676
10677 if (cmdline)
10678 minusc = NULL;
10679 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010680 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010681 if (c != '-' && c != '+')
10682 break;
10683 argptr++;
10684 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010685 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010686 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010687 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010688 if (!cmdline) {
10689 /* "-" means turn off -x and -v */
10690 if (p[0] == '\0')
10691 xflag = vflag = 0;
10692 /* "--" means reset params */
10693 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010694 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010695 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010696 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010697 }
Eric Andersencb57d552001-06-28 07:25:16 +000010698 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010699 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010700 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010701 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010702 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010703 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010704 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010705 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010706 /* it already printed err message */
10707 return 1; /* error */
10708 }
Eric Andersencb57d552001-06-28 07:25:16 +000010709 if (*argptr)
10710 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010711 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10712 isloginsh = 1;
10713 /* bash does not accept +-login, we also won't */
10714 } else if (cmdline && val && (c == '-')) { /* long options */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010715 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +000010716 isloginsh = 1;
10717 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010718 } else {
10719 setoption(c, val);
10720 }
10721 }
10722 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010723 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010724}
10725
Eric Andersencb57d552001-06-28 07:25:16 +000010726/*
Eric Andersencb57d552001-06-28 07:25:16 +000010727 * The shift builtin command.
10728 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010729static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010730shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010731{
10732 int n;
10733 char **ap1, **ap2;
10734
10735 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010736 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010737 n = number(argv[1]);
10738 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010739 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010740 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010741 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010742 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010743 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010744 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010745 }
10746 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010747 while ((*ap2++ = *ap1++) != NULL)
10748 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010749#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010750 shellparam.optind = 1;
10751 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010752#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010753 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010754 return 0;
10755}
10756
Eric Andersencb57d552001-06-28 07:25:16 +000010757/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010758 * POSIX requires that 'set' (but not export or readonly) output the
10759 * variables in lexicographic order - by the locale's collating order (sigh).
10760 * Maybe we could keep them in an ordered balanced binary tree
10761 * instead of hashed lists.
10762 * For now just roll 'em through qsort for printing...
10763 */
10764static int
10765showvars(const char *sep_prefix, int on, int off)
10766{
10767 const char *sep;
10768 char **ep, **epend;
10769
10770 ep = listvars(on, off, &epend);
10771 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10772
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010773 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010774
10775 for (; ep < epend; ep++) {
10776 const char *p;
10777 const char *q;
10778
10779 p = strchrnul(*ep, '=');
10780 q = nullstr;
10781 if (*p)
10782 q = single_quote(++p);
10783 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10784 }
10785 return 0;
10786}
10787
10788/*
Eric Andersencb57d552001-06-28 07:25:16 +000010789 * The set command builtin.
10790 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010791static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010792setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010793{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010794 int retval;
10795
Denis Vlasenko68404f12008-03-17 09:00:54 +000010796 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010797 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010798
Denis Vlasenkob012b102007-02-19 22:43:01 +000010799 INT_OFF;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010800 retval = options(/*cmdline:*/ 0);
10801 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010802 optschanged();
10803 if (*argptr != NULL) {
10804 setparam(argptr);
10805 }
Eric Andersencb57d552001-06-28 07:25:16 +000010806 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010807 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010808 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010809}
10810
Denis Vlasenko131ae172007-02-18 13:00:19 +000010811#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010812static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010813change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010814{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010815 uint32_t t;
10816
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010817 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010818 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010819 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010820 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010821 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010822 vrandom.flags &= ~VNOFUNC;
10823 } else {
10824 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010825 t = strtoul(value, NULL, 10);
10826 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010827 }
Eric Andersenef02f822004-03-11 13:34:24 +000010828}
Eric Andersen16767e22004-03-16 05:14:10 +000010829#endif
10830
Denis Vlasenko131ae172007-02-18 13:00:19 +000010831#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010832static int
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010833getopts(char *optstr, char *optvar, char **optfirst)
Eric Andersencb57d552001-06-28 07:25:16 +000010834{
10835 char *p, *q;
10836 char c = '?';
10837 int done = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010838 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000010839 char **optnext;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010840 int ind = shellparam.optind;
10841 int off = shellparam.optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010842
Denys Vlasenko9c541002015-10-07 15:44:36 +020010843 sbuf[1] = '\0';
10844
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010845 shellparam.optind = -1;
10846 optnext = optfirst + ind - 1;
Eric Andersena48b0a32003-10-22 10:56:47 +000010847
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010848 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
Eric Andersencb57d552001-06-28 07:25:16 +000010849 p = NULL;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010850 else
10851 p = optnext[-1] + off;
Eric Andersencb57d552001-06-28 07:25:16 +000010852 if (p == NULL || *p == '\0') {
10853 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010854 p = *optnext;
10855 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010856 atend:
Eric Andersencb57d552001-06-28 07:25:16 +000010857 p = NULL;
10858 done = 1;
10859 goto out;
10860 }
10861 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010862 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010863 goto atend;
10864 }
10865
10866 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010867 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010868 if (*q == '\0') {
10869 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010870 sbuf[0] = c;
10871 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010872 setvar0("OPTARG", sbuf);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010873 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010874 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010875 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010876 }
10877 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010878 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010879 }
10880 if (*++q == ':')
10881 q++;
10882 }
10883
10884 if (*++q == ':') {
10885 if (*p == '\0' && (p = *optnext) == NULL) {
10886 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010887 sbuf[0] = c;
10888 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010889 setvar0("OPTARG", sbuf);
Eric Andersencb57d552001-06-28 07:25:16 +000010890 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010891 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010892 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010893 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010894 c = '?';
10895 }
Eric Andersenc470f442003-07-28 09:56:35 +000010896 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010897 }
10898
10899 if (p == *optnext)
10900 optnext++;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010901 setvar0("OPTARG", p);
Eric Andersencb57d552001-06-28 07:25:16 +000010902 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010903 } else
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010904 setvar0("OPTARG", nullstr);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010905 out:
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010906 ind = optnext - optfirst + 1;
10907 setvar("OPTIND", itoa(ind), VNOFUNC);
Denys Vlasenko9c541002015-10-07 15:44:36 +020010908 sbuf[0] = c;
10909 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010910 setvar0(optvar, sbuf);
10911
10912 shellparam.optoff = p ? p - *(optnext - 1) : -1;
10913 shellparam.optind = ind;
10914
Eric Andersencb57d552001-06-28 07:25:16 +000010915 return done;
10916}
Eric Andersenc470f442003-07-28 09:56:35 +000010917
10918/*
10919 * The getopts builtin. Shellparam.optnext points to the next argument
10920 * to be processed. Shellparam.optptr points to the next character to
10921 * be processed in the current argument. If shellparam.optnext is NULL,
10922 * then it's the first time getopts has been called.
10923 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010924static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000010925getoptscmd(int argc, char **argv)
10926{
10927 char **optbase;
10928
10929 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010930 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010931 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000010932 optbase = shellparam.p;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010933 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
Eric Andersenc470f442003-07-28 09:56:35 +000010934 shellparam.optind = 1;
10935 shellparam.optoff = -1;
10936 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010937 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010938 optbase = &argv[3];
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010939 if ((unsigned)shellparam.optind > argc - 2) {
Eric Andersenc470f442003-07-28 09:56:35 +000010940 shellparam.optind = 1;
10941 shellparam.optoff = -1;
10942 }
10943 }
10944
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010945 return getopts(argv[1], argv[2], optbase);
Eric Andersenc470f442003-07-28 09:56:35 +000010946}
Denis Vlasenko131ae172007-02-18 13:00:19 +000010947#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000010948
Eric Andersencb57d552001-06-28 07:25:16 +000010949
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010950/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000010951
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010952struct heredoc {
10953 struct heredoc *next; /* next here document in list */
10954 union node *here; /* redirection node */
10955 char *eofmark; /* string indicating end of input */
10956 smallint striptabs; /* if set, strip leading tabs */
10957};
10958
10959static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010960static smallint quoteflag; /* set if (part of) last token was quoted */
10961static token_id_t lasttoken; /* last token read (integer id Txxx) */
10962static struct heredoc *heredoclist; /* list of here documents to read */
10963static char *wordtext; /* text of last word returned by readtoken */
10964static struct nodelist *backquotelist;
10965static union node *redirnode;
10966static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010967
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010968static const char *
10969tokname(char *buf, int tok)
10970{
10971 if (tok < TSEMI)
Denys Vlasenko888527c2016-10-02 16:54:17 +020010972 return tokname_array[tok];
10973 sprintf(buf, "\"%s\"", tokname_array[tok]);
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010974 return buf;
10975}
10976
10977/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010978 * Called when an unexpected token is read during the parse. The argument
10979 * is the token that is expected, or -1 if more than one type of token can
10980 * occur at this point.
10981 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010982static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010983static void
10984raise_error_unexpected_syntax(int token)
10985{
10986 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010987 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010988 int l;
10989
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010990 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010991 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010992 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010993 raise_error_syntax(msg);
10994 /* NOTREACHED */
10995}
Eric Andersencb57d552001-06-28 07:25:16 +000010996
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010997#define EOFMARKLEN 79
Eric Andersencb57d552001-06-28 07:25:16 +000010998
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010999/* parsing is heavily cross-recursive, need these forward decls */
11000static union node *andor(void);
11001static union node *pipeline(void);
11002static union node *parse_command(void);
11003static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000011004static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011005static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000011006
Eric Andersenc470f442003-07-28 09:56:35 +000011007static union node *
11008list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000011009{
11010 union node *n1, *n2, *n3;
11011 int tok;
11012
Eric Andersencb57d552001-06-28 07:25:16 +000011013 n1 = NULL;
11014 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011015 switch (peektoken()) {
11016 case TNL:
11017 if (!(nlflag & 1))
11018 break;
11019 parseheredoc();
11020 return n1;
11021
11022 case TEOF:
11023 if (!n1 && (nlflag & 1))
11024 n1 = NODE_EOF;
11025 parseheredoc();
11026 return n1;
11027 }
11028
11029 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko888527c2016-10-02 16:54:17 +020011030 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
Ron Yorstonc0e00762015-10-29 11:30:55 +000011031 return n1;
11032 nlflag |= 2;
11033
Eric Andersencb57d552001-06-28 07:25:16 +000011034 n2 = andor();
11035 tok = readtoken();
11036 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000011037 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011038 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011039 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011040 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011041 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000011042 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011043 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011044 n2 = n3;
11045 }
11046 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000011047 }
11048 }
11049 if (n1 == NULL) {
11050 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011051 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011052 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011053 n3->type = NSEMI;
11054 n3->nbinary.ch1 = n1;
11055 n3->nbinary.ch2 = n2;
11056 n1 = n3;
11057 }
11058 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011059 case TNL:
11060 case TEOF:
11061 tokpushback = 1;
11062 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000011063 case TBACKGND:
11064 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000011065 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011066 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000011067 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011068 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011069 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011070 return n1;
11071 }
11072 }
11073}
11074
Eric Andersenc470f442003-07-28 09:56:35 +000011075static union node *
11076andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011077{
Eric Andersencb57d552001-06-28 07:25:16 +000011078 union node *n1, *n2, *n3;
11079 int t;
11080
Eric Andersencb57d552001-06-28 07:25:16 +000011081 n1 = pipeline();
11082 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011083 t = readtoken();
11084 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000011085 t = NAND;
11086 } else if (t == TOR) {
11087 t = NOR;
11088 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011089 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011090 return n1;
11091 }
Eric Andersenc470f442003-07-28 09:56:35 +000011092 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011093 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011094 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011095 n3->type = t;
11096 n3->nbinary.ch1 = n1;
11097 n3->nbinary.ch2 = n2;
11098 n1 = n3;
11099 }
11100}
11101
Eric Andersenc470f442003-07-28 09:56:35 +000011102static union node *
11103pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011104{
Eric Andersencb57d552001-06-28 07:25:16 +000011105 union node *n1, *n2, *pipenode;
11106 struct nodelist *lp, *prev;
11107 int negate;
11108
11109 negate = 0;
11110 TRACE(("pipeline: entered\n"));
11111 if (readtoken() == TNOT) {
11112 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000011113 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011114 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011115 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011116 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011117 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011118 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000011119 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011120 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011121 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000011122 pipenode->npipe.cmdlist = lp;
11123 lp->n = n1;
11124 do {
11125 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011126 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000011127 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011128 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011129 prev->next = lp;
11130 } while (readtoken() == TPIPE);
11131 lp->next = NULL;
11132 n1 = pipenode;
11133 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011134 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011135 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011136 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000011137 n2->type = NNOT;
11138 n2->nnot.com = n1;
11139 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011140 }
11141 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000011142}
11143
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011144static union node *
11145makename(void)
11146{
11147 union node *n;
11148
Denis Vlasenko597906c2008-02-20 16:38:54 +000011149 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011150 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011151 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011152 n->narg.text = wordtext;
11153 n->narg.backquote = backquotelist;
11154 return n;
11155}
11156
11157static void
11158fixredir(union node *n, const char *text, int err)
11159{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011160 int fd;
11161
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011162 TRACE(("Fix redir %s %d\n", text, err));
11163 if (!err)
11164 n->ndup.vname = NULL;
11165
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011166 fd = bb_strtou(text, NULL, 10);
11167 if (!errno && fd >= 0)
11168 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011169 else if (LONE_DASH(text))
11170 n->ndup.dupfd = -1;
11171 else {
11172 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011173 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011174 n->ndup.vname = makename();
11175 }
11176}
11177
11178/*
11179 * Returns true if the text contains nothing to expand (no dollar signs
11180 * or backquotes).
11181 */
11182static int
Denis Vlasenko68819d12008-12-15 11:26:36 +000011183noexpand(const char *text)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011184{
Denys Vlasenkocd716832009-11-28 22:14:02 +010011185 unsigned char c;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011186
Denys Vlasenkocd716832009-11-28 22:14:02 +010011187 while ((c = *text++) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011188 if (c == CTLQUOTEMARK)
11189 continue;
11190 if (c == CTLESC)
Denys Vlasenkocd716832009-11-28 22:14:02 +010011191 text++;
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011192 else if (SIT(c, BASESYNTAX) == CCTL)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011193 return 0;
11194 }
11195 return 1;
11196}
11197
11198static void
11199parsefname(void)
11200{
11201 union node *n = redirnode;
11202
11203 if (readtoken() != TWORD)
11204 raise_error_unexpected_syntax(-1);
11205 if (n->type == NHERE) {
11206 struct heredoc *here = heredoc;
11207 struct heredoc *p;
11208 int i;
11209
11210 if (quoteflag == 0)
11211 n->type = NXHERE;
11212 TRACE(("Here document %d\n", n->type));
11213 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011214 raise_error_syntax("illegal eof marker for << redirection");
Denys Vlasenkob6c84342009-08-29 20:23:20 +020011215 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011216 here->eofmark = wordtext;
11217 here->next = NULL;
11218 if (heredoclist == NULL)
11219 heredoclist = here;
11220 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011221 for (p = heredoclist; p->next; p = p->next)
11222 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011223 p->next = here;
11224 }
11225 } else if (n->type == NTOFD || n->type == NFROMFD) {
11226 fixredir(n, wordtext, 0);
11227 } else {
11228 n->nfile.fname = makename();
11229 }
11230}
Eric Andersencb57d552001-06-28 07:25:16 +000011231
Eric Andersenc470f442003-07-28 09:56:35 +000011232static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011233simplecmd(void)
11234{
11235 union node *args, **app;
11236 union node *n = NULL;
11237 union node *vars, **vpp;
11238 union node **rpp, *redir;
11239 int savecheckkwd;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011240#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011241 smallint double_brackets_flag = 0;
11242#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011243 IF_BASH_FUNCTION(smallint function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011244
11245 args = NULL;
11246 app = &args;
11247 vars = NULL;
11248 vpp = &vars;
11249 redir = NULL;
11250 rpp = &redir;
11251
11252 savecheckkwd = CHKALIAS;
11253 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000011254 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011255 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011256 t = readtoken();
11257 switch (t) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011258#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011259 case TFUNCTION:
11260 if (peektoken() != TWORD)
11261 raise_error_unexpected_syntax(TWORD);
11262 function_flag = 1;
11263 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011264#endif
11265#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011266 case TAND: /* "&&" */
11267 case TOR: /* "||" */
11268 if (!double_brackets_flag) {
11269 tokpushback = 1;
11270 goto out;
11271 }
11272 wordtext = (char *) (t == TAND ? "-a" : "-o");
11273#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011274 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011275 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011276 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011277 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011278 n->narg.text = wordtext;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011279#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011280 if (strcmp("[[", wordtext) == 0)
11281 double_brackets_flag = 1;
11282 else if (strcmp("]]", wordtext) == 0)
11283 double_brackets_flag = 0;
11284#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011285 n->narg.backquote = backquotelist;
11286 if (savecheckkwd && isassignment(wordtext)) {
11287 *vpp = n;
11288 vpp = &n->narg.next;
11289 } else {
11290 *app = n;
11291 app = &n->narg.next;
11292 savecheckkwd = 0;
11293 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011294#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011295 if (function_flag) {
11296 checkkwd = CHKNL | CHKKWD;
11297 switch (peektoken()) {
11298 case TBEGIN:
11299 case TIF:
11300 case TCASE:
11301 case TUNTIL:
11302 case TWHILE:
11303 case TFOR:
11304 goto do_func;
11305 case TLP:
11306 function_flag = 0;
11307 break;
11308 case TWORD:
11309 if (strcmp("[[", wordtext) == 0)
11310 goto do_func;
11311 /* fall through */
11312 default:
11313 raise_error_unexpected_syntax(-1);
11314 }
11315 }
11316#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011317 break;
11318 case TREDIR:
11319 *rpp = n = redirnode;
11320 rpp = &n->nfile.next;
11321 parsefname(); /* read name of redirection file */
11322 break;
11323 case TLP:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011324 IF_BASH_FUNCTION(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011325 if (args && app == &args->narg.next
11326 && !vars && !redir
11327 ) {
11328 struct builtincmd *bcmd;
11329 const char *name;
11330
11331 /* We have a function */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011332 if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011333 raise_error_unexpected_syntax(TRP);
11334 name = n->narg.text;
11335 if (!goodname(name)
11336 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11337 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011338 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011339 }
11340 n->type = NDEFUN;
11341 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11342 n->narg.next = parse_command();
11343 return n;
11344 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011345 IF_BASH_FUNCTION(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011346 /* fall through */
11347 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011348 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011349 goto out;
11350 }
11351 }
11352 out:
11353 *app = NULL;
11354 *vpp = NULL;
11355 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011356 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011357 n->type = NCMD;
11358 n->ncmd.args = args;
11359 n->ncmd.assign = vars;
11360 n->ncmd.redirect = redir;
11361 return n;
11362}
11363
11364static union node *
11365parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011366{
Eric Andersencb57d552001-06-28 07:25:16 +000011367 union node *n1, *n2;
11368 union node *ap, **app;
11369 union node *cp, **cpp;
11370 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011371 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011372 int t;
11373
11374 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011375 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011376
Eric Andersencb57d552001-06-28 07:25:16 +000011377 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011378 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011379 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011380 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011381 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011382 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011383 n1->type = NIF;
11384 n1->nif.test = list(0);
11385 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011386 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011387 n1->nif.ifpart = list(0);
11388 n2 = n1;
11389 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011390 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011391 n2 = n2->nif.elsepart;
11392 n2->type = NIF;
11393 n2->nif.test = list(0);
11394 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011395 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011396 n2->nif.ifpart = list(0);
11397 }
11398 if (lasttoken == TELSE)
11399 n2->nif.elsepart = list(0);
11400 else {
11401 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011402 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011403 }
Eric Andersenc470f442003-07-28 09:56:35 +000011404 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011405 break;
11406 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011407 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011408 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011409 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011410 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011411 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011412 got = readtoken();
11413 if (got != TDO) {
Denys Vlasenko888527c2016-10-02 16:54:17 +020011414 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
Denis Vlasenko131ae172007-02-18 13:00:19 +000011415 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011416 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011417 }
11418 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011419 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011420 break;
11421 }
11422 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011423 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011424 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011425 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011426 n1->type = NFOR;
11427 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011428 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011429 if (readtoken() == TIN) {
11430 app = &ap;
11431 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011432 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011433 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011434 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011435 n2->narg.text = wordtext;
11436 n2->narg.backquote = backquotelist;
11437 *app = n2;
11438 app = &n2->narg.next;
11439 }
11440 *app = NULL;
11441 n1->nfor.args = ap;
11442 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011443 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011444 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011445 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011446 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011447 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011448 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011449 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011450 n1->nfor.args = n2;
11451 /*
11452 * Newline or semicolon here is optional (but note
11453 * that the original Bourne shell only allowed NL).
11454 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011455 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011456 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011457 }
Eric Andersenc470f442003-07-28 09:56:35 +000011458 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011459 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011460 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011461 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011462 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011463 break;
11464 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011465 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011466 n1->type = NCASE;
11467 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011468 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011469 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011470 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011471 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011472 n2->narg.text = wordtext;
11473 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011474 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11475 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011476 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011477 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011478 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011479 checkkwd = CHKNL | CHKKWD;
11480 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011481 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011482 if (lasttoken == TLP)
11483 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011484 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011485 cp->type = NCLIST;
11486 app = &cp->nclist.pattern;
11487 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011488 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011489 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011490 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011491 ap->narg.text = wordtext;
11492 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011493 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011494 break;
11495 app = &ap->narg.next;
11496 readtoken();
11497 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011498 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011499 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011500 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011501 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011502
Eric Andersenc470f442003-07-28 09:56:35 +000011503 cpp = &cp->nclist.next;
11504
11505 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011506 t = readtoken();
11507 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011508 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011509 raise_error_unexpected_syntax(TENDCASE);
11510 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011511 }
Eric Andersenc470f442003-07-28 09:56:35 +000011512 }
Eric Andersencb57d552001-06-28 07:25:16 +000011513 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011514 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011515 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011516 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011517 n1->type = NSUBSHELL;
11518 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011519 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011520 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011521 break;
11522 case TBEGIN:
11523 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011524 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011525 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011526 IF_BASH_FUNCTION(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011527 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011528 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011529 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011530 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011531 }
11532
Eric Andersenc470f442003-07-28 09:56:35 +000011533 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011534 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011535
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011536 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011537 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011538 checkkwd = CHKKWD | CHKALIAS;
11539 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011540 while (readtoken() == TREDIR) {
11541 *rpp = n2 = redirnode;
11542 rpp = &n2->nfile.next;
11543 parsefname();
11544 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011545 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011546 *rpp = NULL;
11547 if (redir) {
11548 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011549 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011550 n2->type = NREDIR;
11551 n2->nredir.n = n1;
11552 n1 = n2;
11553 }
11554 n1->nredir.redirect = redir;
11555 }
Eric Andersencb57d552001-06-28 07:25:16 +000011556 return n1;
11557}
11558
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011559#if BASH_DOLLAR_SQUOTE
Denys Vlasenko37dc08b2016-10-02 04:38:07 +020011560static int
11561decode_dollar_squote(void)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011562{
11563 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11564 int c, cnt;
11565 char *p;
11566 char buf[4];
11567
11568 c = pgetc();
11569 p = strchr(C_escapes, c);
11570 if (p) {
11571 buf[0] = c;
11572 p = buf;
11573 cnt = 3;
11574 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11575 do {
11576 c = pgetc();
11577 *++p = c;
11578 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11579 pungetc();
11580 } else if (c == 'x') { /* \xHH */
11581 do {
11582 c = pgetc();
11583 *++p = c;
11584 } while (isxdigit(c) && --cnt);
11585 pungetc();
11586 if (cnt == 3) { /* \x but next char is "bad" */
11587 c = 'x';
11588 goto unrecognized;
11589 }
11590 } else { /* simple seq like \\ or \t */
11591 p++;
11592 }
11593 *p = '\0';
11594 p = buf;
11595 c = bb_process_escape_sequence((void*)&p);
11596 } else { /* unrecognized "\z": print both chars unless ' or " */
11597 if (c != '\'' && c != '"') {
11598 unrecognized:
11599 c |= 0x100; /* "please encode \, then me" */
11600 }
11601 }
11602 return c;
11603}
11604#endif
11605
Eric Andersencb57d552001-06-28 07:25:16 +000011606/*
11607 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11608 * is not NULL, read a here document. In the latter case, eofmark is the
11609 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011610 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011611 * is the first character of the input token or document.
11612 *
11613 * Because C does not have internal subroutines, I have simulated them
11614 * using goto's to implement the subroutine linkage. The following macros
11615 * will run code that appears at the end of readtoken1.
11616 */
Eric Andersen2870d962001-07-02 17:27:21 +000011617#define CHECKEND() {goto checkend; checkend_return:;}
11618#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11619#define PARSESUB() {goto parsesub; parsesub_return:;}
11620#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11621#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11622#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011623static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011624readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011625{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011626 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011627 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011628 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020011629 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +000011630 char line[EOFMARKLEN + 1];
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011631 struct nodelist *bqlist;
11632 smallint quotef;
11633 smallint dblquote;
11634 smallint oldstyle;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011635 IF_FEATURE_SH_MATH(smallint prevsyntax;) /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011636 smallint pssyntax; /* we are expanding a prompt string */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011637 int varnest; /* levels of variables expansion */
Denys Vlasenko0b883582016-12-23 16:49:07 +010011638 IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */
11639 IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011640 int dqvarnest; /* levels of variables expansion within double quotes */
11641
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011642 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011643
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011644 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011645 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011646 quotef = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011647 IF_FEATURE_SH_MATH(prevsyntax = 0;)
Denis Vlasenko46a53062007-09-24 18:30:02 +000011648 pssyntax = (syntax == PSSYNTAX);
11649 if (pssyntax)
11650 syntax = DQSYNTAX;
Denis Vlasenko46a53062007-09-24 18:30:02 +000011651 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011652 varnest = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011653 IF_FEATURE_SH_MATH(arinest = 0;)
11654 IF_FEATURE_SH_MATH(parenlevel = 0;)
Eric Andersencb57d552001-06-28 07:25:16 +000011655 dqvarnest = 0;
11656
11657 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011658 loop:
11659 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011660 CHECKEND(); /* set c to PEOF if at end of here document */
11661 for (;;) { /* until end of line or end of word */
11662 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11663 switch (SIT(c, syntax)) {
11664 case CNL: /* '\n' */
11665 if (syntax == BASESYNTAX)
11666 goto endword; /* exit outer loop */
11667 USTPUTC(c, out);
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011668 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011669 c = pgetc();
11670 goto loop; /* continue outer loop */
11671 case CWORD:
11672 USTPUTC(c, out);
11673 break;
11674 case CCTL:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011675#if BASH_DOLLAR_SQUOTE
Denys Vlasenko958581a2010-09-12 15:04:27 +020011676 if (c == '\\' && bash_dollar_squote) {
11677 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020011678 if (c == '\0') {
11679 /* skip $'\000', $'\x00' (like bash) */
11680 break;
11681 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011682 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020011683 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011684 c = (unsigned char)c;
Denys Vlasenko13f20912016-09-25 20:54:25 +020011685 if (eofmark == NULL || dblquote)
11686 USTPUTC(CTLESC, out);
11687 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011688 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011689 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011690#endif
Denys Vlasenko13f20912016-09-25 20:54:25 +020011691 if (eofmark == NULL || dblquote)
11692 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011693 USTPUTC(c, out);
11694 break;
11695 case CBACK: /* backslash */
11696 c = pgetc_without_PEOA();
11697 if (c == PEOF) {
11698 USTPUTC(CTLESC, out);
11699 USTPUTC('\\', out);
11700 pungetc();
11701 } else if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011702 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011703 } else {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011704 if (c == '$' && pssyntax) {
Eric Andersenc470f442003-07-28 09:56:35 +000011705 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011706 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011707 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011708 /* Backslash is retained if we are in "str" and next char isn't special */
11709 if (dblquote
11710 && c != '\\'
11711 && c != '`'
11712 && c != '$'
11713 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011714 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011715 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011716 }
Ron Yorston549deab2015-05-18 09:57:51 +020011717 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011718 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011719 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011720 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011721 break;
11722 case CSQUOTE:
11723 syntax = SQSYNTAX;
11724 quotemark:
11725 if (eofmark == NULL) {
11726 USTPUTC(CTLQUOTEMARK, out);
11727 }
11728 break;
11729 case CDQUOTE:
11730 syntax = DQSYNTAX;
11731 dblquote = 1;
11732 goto quotemark;
11733 case CENDQUOTE:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011734 IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020011735 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011736 USTPUTC(c, out);
11737 } else {
11738 if (dqvarnest == 0) {
11739 syntax = BASESYNTAX;
11740 dblquote = 0;
11741 }
11742 quotef = 1;
11743 goto quotemark;
11744 }
11745 break;
11746 case CVAR: /* '$' */
11747 PARSESUB(); /* parse substitution */
11748 break;
11749 case CENDVAR: /* '}' */
11750 if (varnest > 0) {
11751 varnest--;
11752 if (dqvarnest > 0) {
11753 dqvarnest--;
11754 }
11755 c = CTLENDVAR;
11756 }
11757 USTPUTC(c, out);
11758 break;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011759#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko958581a2010-09-12 15:04:27 +020011760 case CLP: /* '(' in arithmetic */
11761 parenlevel++;
11762 USTPUTC(c, out);
11763 break;
11764 case CRP: /* ')' in arithmetic */
11765 if (parenlevel > 0) {
11766 parenlevel--;
11767 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011768 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020011769 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011770 if (--arinest == 0) {
11771 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011772 }
11773 } else {
11774 /*
11775 * unbalanced parens
11776 * (don't 2nd guess - no error)
11777 */
11778 pungetc();
11779 }
11780 }
11781 USTPUTC(c, out);
11782 break;
11783#endif
11784 case CBQUOTE: /* '`' */
11785 PARSEBACKQOLD();
11786 break;
11787 case CENDFILE:
11788 goto endword; /* exit outer loop */
11789 case CIGN:
11790 break;
11791 default:
11792 if (varnest == 0) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011793#if BASH_REDIR_OUTPUT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011794 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011795//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020011796 if (pgetc() == '>')
11797 c = 0x100 + '>'; /* flag &> */
11798 pungetc();
11799 }
11800#endif
11801 goto endword; /* exit outer loop */
11802 }
11803 IF_ASH_ALIAS(if (c != PEOA))
11804 USTPUTC(c, out);
11805 }
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020011806 c = pgetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011807 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011808 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011809
Denys Vlasenko0b883582016-12-23 16:49:07 +010011810#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000011811 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011812 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011813#endif
Ron Yorston0e056f72015-07-01 16:45:40 +010011814 if (syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011815 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011816 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011817 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011818 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011819 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011820 }
11821 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011822 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011823 out = stackblock();
11824 if (eofmark == NULL) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011825 if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011826 && quotef == 0
11827 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011828 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011829 PARSEREDIR(); /* passed as params: out, c */
11830 lasttoken = TREDIR;
11831 return lasttoken;
11832 }
11833 /* else: non-number X seen, interpret it
11834 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011835 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011836 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011837 }
11838 quoteflag = quotef;
11839 backquotelist = bqlist;
11840 grabstackblock(len);
11841 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011842 lasttoken = TWORD;
11843 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011844/* end of readtoken routine */
11845
Eric Andersencb57d552001-06-28 07:25:16 +000011846/*
11847 * Check to see whether we are at the end of the here document. When this
11848 * is called, c is set to the first character of the next input line. If
11849 * we are at the end of the here document, this routine sets the c to PEOF.
11850 */
Eric Andersenc470f442003-07-28 09:56:35 +000011851checkend: {
11852 if (eofmark) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000011853#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011854 if (c == PEOA)
11855 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011856#endif
11857 if (striptabs) {
11858 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011859 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011860 }
Eric Andersenc470f442003-07-28 09:56:35 +000011861 }
11862 if (c == *eofmark) {
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011863 if (pfgets(line, sizeof(line)) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000011864 char *p, *q;
Denys Vlasenko350e6862016-10-26 16:26:45 +020011865 int cc;
Eric Andersencb57d552001-06-28 07:25:16 +000011866
Eric Andersenc470f442003-07-28 09:56:35 +000011867 p = line;
Denys Vlasenko350e6862016-10-26 16:26:45 +020011868 for (q = eofmark + 1;; p++, q++) {
11869 cc = *p;
11870 if (cc == '\n')
11871 cc = 0;
11872 if (!*q || cc != *q)
11873 break;
11874 }
11875 if (cc == *q) {
Eric Andersenc470f442003-07-28 09:56:35 +000011876 c = PEOF;
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011877 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011878 } else {
11879 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011880 }
11881 }
11882 }
11883 }
Eric Andersenc470f442003-07-28 09:56:35 +000011884 goto checkend_return;
11885}
Eric Andersencb57d552001-06-28 07:25:16 +000011886
Eric Andersencb57d552001-06-28 07:25:16 +000011887/*
11888 * Parse a redirection operator. The variable "out" points to a string
11889 * specifying the fd to be redirected. The variable "c" contains the
11890 * first character of the redirection operator.
11891 */
Eric Andersenc470f442003-07-28 09:56:35 +000011892parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011893 /* out is already checked to be a valid number or "" */
11894 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000011895 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000011896
Denis Vlasenko597906c2008-02-20 16:38:54 +000011897 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000011898 if (c == '>') {
11899 np->nfile.fd = 1;
11900 c = pgetc();
11901 if (c == '>')
11902 np->type = NAPPEND;
11903 else if (c == '|')
11904 np->type = NCLOBBER;
11905 else if (c == '&')
11906 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011907 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000011908 else {
11909 np->type = NTO;
11910 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011911 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000011912 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011913#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000011914 else if (c == 0x100 + '>') { /* this flags &> redirection */
11915 np->nfile.fd = 1;
11916 pgetc(); /* this is '>', no need to check */
11917 np->type = NTO2;
11918 }
11919#endif
11920 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000011921 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011922 c = pgetc();
11923 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000011924 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011925 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011926 np = stzalloc(sizeof(struct nhere));
11927 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011928 }
11929 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011930 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000011931 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011932 c = pgetc();
11933 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000011934 heredoc->striptabs = 1;
11935 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011936 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011937 pungetc();
11938 }
11939 break;
11940
11941 case '&':
11942 np->type = NFROMFD;
11943 break;
11944
11945 case '>':
11946 np->type = NFROMTO;
11947 break;
11948
11949 default:
11950 np->type = NFROM;
11951 pungetc();
11952 break;
11953 }
Eric Andersencb57d552001-06-28 07:25:16 +000011954 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011955 if (fd >= 0)
11956 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011957 redirnode = np;
11958 goto parseredir_return;
11959}
Eric Andersencb57d552001-06-28 07:25:16 +000011960
Eric Andersencb57d552001-06-28 07:25:16 +000011961/*
11962 * Parse a substitution. At this point, we have read the dollar sign
11963 * and nothing else.
11964 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000011965
11966/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11967 * (assuming ascii char codes, as the original implementation did) */
11968#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011969 (((unsigned)(c) - 33 < 32) \
11970 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000011971parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010011972 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011973 int typeloc;
Eric Andersencb57d552001-06-28 07:25:16 +000011974
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011975 c = pgetc_eatbnl();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011976 if (c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011977 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000011978 ) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011979#if BASH_DOLLAR_SQUOTE
Ron Yorston84ba50c2016-04-03 22:43:14 +010011980 if (syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011981 bash_dollar_squote = 1;
11982 else
11983#endif
11984 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011985 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011986 } else if (c == '(') {
11987 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011988 if (pgetc_eatbnl() == '(') {
Denys Vlasenko0b883582016-12-23 16:49:07 +010011989#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000011990 PARSEARITH();
11991#else
Denys Vlasenko4f8079d2017-07-17 17:11:48 +020011992 raise_error_syntax("support for $((arith)) is disabled");
Eric Andersenc470f442003-07-28 09:56:35 +000011993#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011994 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011995 pungetc();
11996 PARSEBACKQNEW();
11997 }
11998 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011999 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000012000 USTPUTC(CTLVAR, out);
12001 typeloc = out - (char *)stackblock();
Denys Vlasenko3df14102016-10-26 16:41:13 +020012002 STADJUST(1, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012003 subtype = VSNORMAL;
12004 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012005 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012006 subtype = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000012007 }
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012008 varname:
Denys Vlasenko3df14102016-10-26 16:41:13 +020012009 if (is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012010 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000012011 do {
12012 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012013 c = pgetc_eatbnl();
Denys Vlasenko3df14102016-10-26 16:41:13 +020012014 } while (is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012015 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012016 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000012017 do {
12018 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012019 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012020 } while (isdigit(c));
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012021 } else if (is_special(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012022 /* $[{[#]]<specialchar>[}] */
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012023 int cc = c;
12024
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012025 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012026 if (!subtype && cc == '#') {
12027 subtype = VSLENGTH;
12028 if (c == '_' || isalnum(c))
12029 goto varname;
12030 cc = c;
12031 c = pgetc_eatbnl();
12032 if (cc == '}' || c != '}') {
12033 pungetc();
12034 subtype = 0;
12035 c = cc;
12036 cc = '#';
12037 }
12038 }
12039 USTPUTC(cc, out);
Denis Vlasenko559691a2008-10-05 18:39:31 +000012040 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020012041 goto badsub;
Denis Vlasenko559691a2008-10-05 18:39:31 +000012042 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012043 if (c != '}' && subtype == VSLENGTH) {
12044 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020012045 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012046 }
Eric Andersencb57d552001-06-28 07:25:16 +000012047
Eric Andersenc470f442003-07-28 09:56:35 +000012048 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012049 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012050 /* ${VAR...} but not $VAR or ${#VAR} */
12051 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000012052 switch (c) {
12053 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012054 c = pgetc_eatbnl();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012055#if BASH_SUBSTR
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012056 /* This check is only needed to not misinterpret
12057 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
12058 * constructs.
12059 */
12060 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012061 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012062 pungetc();
Denys Vlasenko88e15702016-10-26 01:55:56 +020012063 break; /* "goto badsub" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012064 }
12065#endif
Denys Vlasenko3df14102016-10-26 16:41:13 +020012066 subtype = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000012067 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012068 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012069 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000012070 if (p == NULL)
Denys Vlasenko88e15702016-10-26 01:55:56 +020012071 break;
Denys Vlasenko3df14102016-10-26 16:41:13 +020012072 subtype |= p - types + VSNORMAL;
Eric Andersenc470f442003-07-28 09:56:35 +000012073 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012074 }
Eric Andersenc470f442003-07-28 09:56:35 +000012075 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012076 case '#': {
12077 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012078 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012079 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012080 if (c != cc)
Denys Vlasenko88e15702016-10-26 01:55:56 +020012081 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012082 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012083 break;
12084 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012085#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012086 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020012087 /* ${v/[/]pattern/repl} */
12088//TODO: encode pattern and repl separately.
12089// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012090 subtype = VSREPLACE;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012091 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012092 if (c != '/')
Denys Vlasenko88e15702016-10-26 01:55:56 +020012093 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012094 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012095 break;
12096#endif
Eric Andersencb57d552001-06-28 07:25:16 +000012097 }
Eric Andersenc470f442003-07-28 09:56:35 +000012098 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020012099 badsub:
Eric Andersenc470f442003-07-28 09:56:35 +000012100 pungetc();
12101 }
Denys Vlasenko3df14102016-10-26 16:41:13 +020012102 ((unsigned char *)stackblock())[typeloc] = subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012103 if (subtype != VSNORMAL) {
12104 varnest++;
Denys Vlasenko3df14102016-10-26 16:41:13 +020012105 if (dblquote)
Eric Andersenc470f442003-07-28 09:56:35 +000012106 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000012107 }
Denys Vlasenko88e15702016-10-26 01:55:56 +020012108 STPUTC('=', out);
Eric Andersencb57d552001-06-28 07:25:16 +000012109 }
Eric Andersenc470f442003-07-28 09:56:35 +000012110 goto parsesub_return;
12111}
Eric Andersencb57d552001-06-28 07:25:16 +000012112
Eric Andersencb57d552001-06-28 07:25:16 +000012113/*
12114 * Called to parse command substitutions. Newstyle is set if the command
12115 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
12116 * list of commands (passed by reference), and savelen is the number of
12117 * characters on the top of the stack which must be preserved.
12118 */
Eric Andersenc470f442003-07-28 09:56:35 +000012119parsebackq: {
12120 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012121 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010012122 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000012123 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012124 smallint saveprompt = 0;
12125
Eric Andersenc470f442003-07-28 09:56:35 +000012126 str = NULL;
12127 savelen = out - (char *)stackblock();
12128 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012129 /*
12130 * FIXME: this can allocate very large block on stack and SEGV.
12131 * Example:
12132 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020012133 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012134 * a hundred command substitutions stack overflows.
12135 * With larger prepended string, SEGV happens sooner.
12136 */
Ron Yorston072fc602015-07-01 16:46:18 +010012137 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000012138 memcpy(str, stackblock(), savelen);
12139 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012140
Eric Andersenc470f442003-07-28 09:56:35 +000012141 if (oldstyle) {
12142 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010012143 * treatment to some slashes, and then push the string and
12144 * reread it as input, interpreting it normally.
12145 */
Eric Andersenc470f442003-07-28 09:56:35 +000012146 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000012147 size_t psavelen;
12148 char *pstr;
12149
Eric Andersenc470f442003-07-28 09:56:35 +000012150 STARTSTACKSTR(pout);
12151 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012152 int pc;
12153
12154 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012155 pc = pgetc();
12156 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000012157 case '`':
12158 goto done;
12159
12160 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012161 pc = pgetc();
12162 if (pc == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012163 nlprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012164 /*
12165 * If eating a newline, avoid putting
12166 * the newline into the new character
12167 * stream (via the STPUTC after the
12168 * switch).
12169 */
12170 continue;
12171 }
12172 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012173 && (!dblquote || pc != '"')
12174 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000012175 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012176 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010012177 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000012178 break;
12179 }
12180 /* fall through */
12181
12182 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012183 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012184 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012185 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000012186
12187 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012188 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012189 break;
12190
12191 default:
12192 break;
12193 }
12194 STPUTC(pc, pout);
12195 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012196 done:
Eric Andersenc470f442003-07-28 09:56:35 +000012197 STPUTC('\0', pout);
12198 psavelen = pout - (char *)stackblock();
12199 if (psavelen > 0) {
12200 pstr = grabstackstr(pout);
12201 setinputstring(pstr);
12202 }
12203 }
12204 nlpp = &bqlist;
12205 while (*nlpp)
12206 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012207 *nlpp = stzalloc(sizeof(**nlpp));
12208 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012209
12210 if (oldstyle) {
12211 saveprompt = doprompt;
12212 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012213 }
12214
Eric Andersenc470f442003-07-28 09:56:35 +000012215 n = list(2);
12216
12217 if (oldstyle)
12218 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012219 else if (readtoken() != TRP)
12220 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000012221
12222 (*nlpp)->n = n;
12223 if (oldstyle) {
12224 /*
12225 * Start reading from old file again, ignoring any pushed back
12226 * tokens left from the backquote parsing
12227 */
12228 popfile();
12229 tokpushback = 0;
12230 }
12231 while (stackblocksize() <= savelen)
12232 growstackblock();
12233 STARTSTACKSTR(out);
12234 if (str) {
12235 memcpy(out, str, savelen);
12236 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012237 }
Ron Yorston549deab2015-05-18 09:57:51 +020012238 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012239 if (oldstyle)
12240 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012241 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000012242}
12243
Denys Vlasenko0b883582016-12-23 16:49:07 +010012244#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000012245/*
12246 * Parse an arithmetic expansion (indicate start of one and set state)
12247 */
Eric Andersenc470f442003-07-28 09:56:35 +000012248parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000012249 if (++arinest == 1) {
12250 prevsyntax = syntax;
12251 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000012252 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020012253 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012254 goto parsearith_return;
12255}
12256#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012257} /* end of readtoken */
12258
Eric Andersencb57d552001-06-28 07:25:16 +000012259/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012260 * Read the next input token.
12261 * If the token is a word, we set backquotelist to the list of cmds in
12262 * backquotes. We set quoteflag to true if any part of the word was
12263 * quoted.
12264 * If the token is TREDIR, then we set redirnode to a structure containing
12265 * the redirection.
12266 * In all cases, the variable startlinno is set to the number of the line
12267 * on which the token starts.
12268 *
12269 * [Change comment: here documents and internal procedures]
12270 * [Readtoken shouldn't have any arguments. Perhaps we should make the
12271 * word parsing code into a separate routine. In this case, readtoken
12272 * doesn't need to have any internal procedures, but parseword does.
12273 * We could also make parseoperator in essence the main routine, and
12274 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000012275 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012276#define NEW_xxreadtoken
12277#ifdef NEW_xxreadtoken
12278/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012279static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000012280 '\n', '(', ')', /* singles */
12281 '&', '|', ';', /* doubles */
12282 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012283};
Eric Andersencb57d552001-06-28 07:25:16 +000012284
Denis Vlasenko834dee72008-10-07 09:18:30 +000012285#define xxreadtoken_singles 3
12286#define xxreadtoken_doubles 3
12287
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012288static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012289 TNL, TLP, TRP, /* only single occurrence allowed */
12290 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12291 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012292 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012293};
12294
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012295static int
12296xxreadtoken(void)
12297{
12298 int c;
12299
12300 if (tokpushback) {
12301 tokpushback = 0;
12302 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012303 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012304 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012305 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012306 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012307 c = pgetc();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000012308 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012309 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012310
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012311 if (c == '#') {
12312 while ((c = pgetc()) != '\n' && c != PEOF)
12313 continue;
12314 pungetc();
12315 } else if (c == '\\') {
12316 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012317 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012318 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012319 }
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012320 nlprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012321 } else {
12322 const char *p;
12323
12324 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12325 if (c != PEOF) {
12326 if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012327 nlnoprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012328 }
12329
12330 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000012331 if (p == NULL)
12332 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012333
Denis Vlasenko834dee72008-10-07 09:18:30 +000012334 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12335 int cc = pgetc();
12336 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012337 p += xxreadtoken_doubles + 1;
12338 } else {
12339 pungetc();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012340#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012341 if (c == '&' && cc == '>') /* &> */
12342 break; /* return readtoken1(...) */
12343#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012344 }
12345 }
12346 }
12347 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12348 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012349 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012350 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012351
12352 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012353}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012354#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012355#define RETURN(token) return lasttoken = token
12356static int
12357xxreadtoken(void)
12358{
12359 int c;
12360
12361 if (tokpushback) {
12362 tokpushback = 0;
12363 return lasttoken;
12364 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012365 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012366 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012367 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012368 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012369 switch (c) {
12370 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012371 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012372 continue;
12373 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012374 while ((c = pgetc()) != '\n' && c != PEOF)
12375 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012376 pungetc();
12377 continue;
12378 case '\\':
12379 if (pgetc() == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012380 nlprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012381 continue;
12382 }
12383 pungetc();
12384 goto breakloop;
12385 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012386 nlnoprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012387 RETURN(TNL);
12388 case PEOF:
12389 RETURN(TEOF);
12390 case '&':
12391 if (pgetc() == '&')
12392 RETURN(TAND);
12393 pungetc();
12394 RETURN(TBACKGND);
12395 case '|':
12396 if (pgetc() == '|')
12397 RETURN(TOR);
12398 pungetc();
12399 RETURN(TPIPE);
12400 case ';':
12401 if (pgetc() == ';')
12402 RETURN(TENDCASE);
12403 pungetc();
12404 RETURN(TSEMI);
12405 case '(':
12406 RETURN(TLP);
12407 case ')':
12408 RETURN(TRP);
12409 default:
12410 goto breakloop;
12411 }
12412 }
12413 breakloop:
12414 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12415#undef RETURN
12416}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012417#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012418
12419static int
12420readtoken(void)
12421{
12422 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012423 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012424#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012425 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012426#endif
12427
12428#if ENABLE_ASH_ALIAS
12429 top:
12430#endif
12431
12432 t = xxreadtoken();
12433
12434 /*
12435 * eat newlines
12436 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012437 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012438 while (t == TNL) {
12439 parseheredoc();
12440 t = xxreadtoken();
12441 }
12442 }
12443
12444 if (t != TWORD || quoteflag) {
12445 goto out;
12446 }
12447
12448 /*
12449 * check for keywords
12450 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012451 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012452 const char *const *pp;
12453
12454 pp = findkwd(wordtext);
12455 if (pp) {
12456 lasttoken = t = pp - tokname_array;
Denys Vlasenko888527c2016-10-02 16:54:17 +020012457 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012458 goto out;
12459 }
12460 }
12461
12462 if (checkkwd & CHKALIAS) {
12463#if ENABLE_ASH_ALIAS
12464 struct alias *ap;
12465 ap = lookupalias(wordtext, 1);
12466 if (ap != NULL) {
12467 if (*ap->val) {
12468 pushstring(ap->val, ap);
12469 }
12470 goto top;
12471 }
12472#endif
12473 }
12474 out:
12475 checkkwd = 0;
12476#if DEBUG
12477 if (!alreadyseen)
Denys Vlasenko888527c2016-10-02 16:54:17 +020012478 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012479 else
Denys Vlasenko888527c2016-10-02 16:54:17 +020012480 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012481#endif
12482 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012483}
12484
Ron Yorstonc0e00762015-10-29 11:30:55 +000012485static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012486peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012487{
12488 int t;
12489
12490 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012491 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012492 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012493}
Eric Andersencb57d552001-06-28 07:25:16 +000012494
12495/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012496 * Read and parse a command. Returns NODE_EOF on end of file.
12497 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012498 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012499static union node *
12500parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012501{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012502 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012503 checkkwd = 0;
12504 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012505 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012506 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012507 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012508 return list(1);
12509}
12510
12511/*
12512 * Input any here documents.
12513 */
12514static void
12515parseheredoc(void)
12516{
12517 struct heredoc *here;
12518 union node *n;
12519
12520 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012521 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012522
12523 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012524 setprompt_if(needprompt, 2);
12525 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012526 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012527 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012528 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012529 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012530 n->narg.text = wordtext;
12531 n->narg.backquote = backquotelist;
12532 here->here->nhere.doc = n;
12533 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012534 }
Eric Andersencb57d552001-06-28 07:25:16 +000012535}
12536
12537
12538/*
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012539 * called by editline -- any expansions to the prompt should be added here.
Eric Andersencb57d552001-06-28 07:25:16 +000012540 */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012541static const char *
12542expandstr(const char *ps)
12543{
12544 union node n;
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012545 int saveprompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012546
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000012547 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12548 * and token processing _can_ alter it (delete NULs etc). */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012549 setinputstring((char *)ps);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012550
12551 saveprompt = doprompt;
12552 doprompt = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000012553 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012554 doprompt = saveprompt;
12555
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012556 popfile();
12557
12558 n.narg.type = NARG;
12559 n.narg.next = NULL;
12560 n.narg.text = wordtext;
12561 n.narg.backquote = backquotelist;
12562
Ron Yorston549deab2015-05-18 09:57:51 +020012563 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012564 return stackblock();
12565}
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012566
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012567/*
12568 * Execute a command or commands contained in a string.
12569 */
12570static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012571evalstring(char *s, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000012572{
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012573 struct jmploc *volatile savehandler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012574 struct jmploc jmploc;
12575 int ex;
12576
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012577 union node *n;
12578 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012579 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012580
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012581 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012582 setinputstring(s);
12583 setstackmark(&smark);
12584
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012585 status = 0;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012586 /* On exception inside execution loop, we must popfile().
12587 * Try interactively:
12588 * readonly a=a
12589 * command eval "a=b" # throws "is read only" error
12590 * "command BLTIN" is not supposed to abort (even in non-interactive use).
12591 * But if we skip popfile(), we hit EOF in eval's string, and exit.
12592 */
12593 savehandler = exception_handler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012594 ex = setjmp(jmploc.loc);
12595 if (ex)
12596 goto out;
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012597 exception_handler = &jmploc;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012598
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012599 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012600 int i;
12601
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012602 i = evaltree(n, flags);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012603 if (n)
12604 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012605 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012606 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012607 break;
12608 }
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012609 out:
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012610 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012611 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012612 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012613
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012614 exception_handler = savehandler;
12615 if (ex)
12616 longjmp(exception_handler->loc, ex);
12617
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012618 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000012619}
12620
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012621/*
12622 * The eval command.
12623 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012624static int FAST_FUNC
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012625evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012626{
12627 char *p;
12628 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012629
Denis Vlasenko68404f12008-03-17 09:00:54 +000012630 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012631 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012632 argv += 2;
12633 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012634 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012635 for (;;) {
12636 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012637 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012638 if (p == NULL)
12639 break;
12640 STPUTC(' ', concat);
12641 }
12642 STPUTC('\0', concat);
12643 p = grabstackstr(concat);
12644 }
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012645 return evalstring(p, flags & EV_TESTED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012646 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012647 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012648}
12649
12650/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012651 * Read and execute commands.
12652 * "Top" is nonzero for the top level command loop;
12653 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012654 */
12655static int
12656cmdloop(int top)
12657{
12658 union node *n;
12659 struct stackmark smark;
12660 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012661 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012662 int numeof = 0;
12663
12664 TRACE(("cmdloop(%d) called\n", top));
12665 for (;;) {
12666 int skip;
12667
12668 setstackmark(&smark);
12669#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012670 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020012671 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012672#endif
12673 inter = 0;
12674 if (iflag && top) {
12675 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012676 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012677 }
12678 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012679#if DEBUG
12680 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012681 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012682#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012683 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012684 if (!top || numeof >= 50)
12685 break;
12686 if (!stoppedjobs()) {
12687 if (!Iflag)
12688 break;
12689 out2str("\nUse \"exit\" to leave shell.\n");
12690 }
12691 numeof++;
12692 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012693 int i;
12694
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012695 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12696 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012697 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012698 i = evaltree(n, 0);
12699 if (n)
12700 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012701 }
12702 popstackmark(&smark);
12703 skip = evalskip;
12704
12705 if (skip) {
Denys Vlasenko6a0710e2016-09-30 14:18:34 +020012706 evalskip &= ~SKIPFUNC;
Denys Vlasenko0840c912016-10-01 15:27:44 +020012707 break;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012708 }
12709 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012710 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012711}
12712
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012713/*
12714 * Take commands from a file. To be compatible we should do a path
12715 * search for the file, which is necessary to find sub-commands.
12716 */
12717static char *
12718find_dot_file(char *name)
12719{
12720 char *fullname;
12721 const char *path = pathval();
12722 struct stat statb;
12723
12724 /* don't try this for absolute or relative paths */
12725 if (strchr(name, '/'))
12726 return name;
12727
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012728 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012729 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12730 /*
12731 * Don't bother freeing here, since it will
12732 * be freed by the caller.
12733 */
12734 return fullname;
12735 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012736 if (fullname != name)
12737 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012738 }
12739
12740 /* not found in the PATH */
12741 ash_msg_and_raise_error("%s: not found", name);
12742 /* NOTREACHED */
12743}
12744
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012745static int FAST_FUNC
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012746dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012747{
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012748 /* "false; . empty_file; echo $?" should print 0, not 1: */
12749 int status = 0;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012750 char *fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012751 char **argv;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012752 char *args_need_save;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012753 struct strlist *sp;
12754 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012755
12756 for (sp = cmdenviron; sp; sp = sp->next)
Denis Vlasenko4222ae42007-02-25 02:37:49 +000012757 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012758
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012759 nextopt(nullstr); /* handle possible "--" */
12760 argv = argptr;
12761
12762 if (!argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012763 /* bash says: "bash: .: filename argument required" */
12764 return 2; /* bash compat */
12765 }
12766
Denys Vlasenko091f8312013-03-17 14:25:22 +010012767 /* This aborts if file isn't found, which is POSIXly correct.
12768 * bash returns exitcode 1 instead.
12769 */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012770 fullname = find_dot_file(argv[0]);
12771 argv++;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012772 args_need_save = argv[0];
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010012773 if (args_need_save) { /* ". FILE ARGS", and ARGS are not empty */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012774 int argc;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012775 saveparam = shellparam;
12776 shellparam.malloced = 0;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012777 argc = 1;
12778 while (argv[argc])
12779 argc++;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012780 shellparam.nparam = argc;
12781 shellparam.p = argv;
12782 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012783
Denys Vlasenko091f8312013-03-17 14:25:22 +010012784 /* This aborts if file can't be opened, which is POSIXly correct.
12785 * bash returns exitcode 1 instead.
12786 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012787 setinputfile(fullname, INPUT_PUSH_FILE);
12788 commandname = fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012789 status = cmdloop(0);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012790 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012791
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012792 if (args_need_save) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012793 freeparam(&shellparam);
12794 shellparam = saveparam;
12795 };
12796
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012797 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012798}
12799
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012800static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012801exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012802{
12803 if (stoppedjobs())
12804 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012805 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012806 exitstatus = number(argv[1]);
12807 raise_exception(EXEXIT);
12808 /* NOTREACHED */
12809}
12810
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012811/*
12812 * Read a file containing shell functions.
12813 */
12814static void
12815readcmdfile(char *name)
12816{
12817 setinputfile(name, INPUT_PUSH_FILE);
12818 cmdloop(0);
12819 popfile();
12820}
12821
12822
Denis Vlasenkocc571512007-02-23 21:10:35 +000012823/* ============ find_command inplementation */
12824
12825/*
12826 * Resolve a command name. If you change this routine, you may have to
12827 * change the shellexec routine as well.
12828 */
12829static void
12830find_command(char *name, struct cmdentry *entry, int act, const char *path)
12831{
12832 struct tblentry *cmdp;
12833 int idx;
12834 int prev;
12835 char *fullname;
12836 struct stat statb;
12837 int e;
12838 int updatetbl;
12839 struct builtincmd *bcmd;
12840
12841 /* If name contains a slash, don't use PATH or hash table */
12842 if (strchr(name, '/') != NULL) {
12843 entry->u.index = -1;
12844 if (act & DO_ABS) {
12845 while (stat(name, &statb) < 0) {
12846#ifdef SYSV
12847 if (errno == EINTR)
12848 continue;
12849#endif
12850 entry->cmdtype = CMDUNKNOWN;
12851 return;
12852 }
12853 }
12854 entry->cmdtype = CMDNORMAL;
12855 return;
12856 }
12857
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012858/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012859
12860 updatetbl = (path == pathval());
12861 if (!updatetbl) {
12862 act |= DO_ALTPATH;
12863 if (strstr(path, "%builtin") != NULL)
12864 act |= DO_ALTBLTIN;
12865 }
12866
12867 /* If name is in the table, check answer will be ok */
12868 cmdp = cmdlookup(name, 0);
12869 if (cmdp != NULL) {
12870 int bit;
12871
12872 switch (cmdp->cmdtype) {
12873 default:
12874#if DEBUG
12875 abort();
12876#endif
12877 case CMDNORMAL:
12878 bit = DO_ALTPATH;
12879 break;
12880 case CMDFUNCTION:
12881 bit = DO_NOFUNC;
12882 break;
12883 case CMDBUILTIN:
12884 bit = DO_ALTBLTIN;
12885 break;
12886 }
12887 if (act & bit) {
12888 updatetbl = 0;
12889 cmdp = NULL;
12890 } else if (cmdp->rehash == 0)
12891 /* if not invalidated by cd, we're done */
12892 goto success;
12893 }
12894
12895 /* If %builtin not in path, check for builtin next */
12896 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012897 if (bcmd) {
12898 if (IS_BUILTIN_REGULAR(bcmd))
12899 goto builtin_success;
12900 if (act & DO_ALTPATH) {
12901 if (!(act & DO_ALTBLTIN))
12902 goto builtin_success;
12903 } else if (builtinloc <= 0) {
12904 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000012905 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012906 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000012907
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012908#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000012909 {
12910 int applet_no = find_applet_by_name(name);
12911 if (applet_no >= 0) {
12912 entry->cmdtype = CMDNORMAL;
12913 entry->u.index = -2 - applet_no;
12914 return;
12915 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012916 }
12917#endif
12918
Denis Vlasenkocc571512007-02-23 21:10:35 +000012919 /* We have to search path. */
12920 prev = -1; /* where to start */
12921 if (cmdp && cmdp->rehash) { /* doing a rehash */
12922 if (cmdp->cmdtype == CMDBUILTIN)
12923 prev = builtinloc;
12924 else
12925 prev = cmdp->param.index;
12926 }
12927
12928 e = ENOENT;
12929 idx = -1;
12930 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012931 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000012932 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012933 /* NB: code below will still use fullname
12934 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012935 idx++;
12936 if (pathopt) {
12937 if (prefix(pathopt, "builtin")) {
12938 if (bcmd)
12939 goto builtin_success;
12940 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000012941 }
12942 if ((act & DO_NOFUNC)
12943 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020012944 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012945 continue;
12946 }
12947 }
12948 /* if rehash, don't redo absolute path names */
12949 if (fullname[0] == '/' && idx <= prev) {
12950 if (idx < prev)
12951 continue;
12952 TRACE(("searchexec \"%s\": no change\n", name));
12953 goto success;
12954 }
12955 while (stat(fullname, &statb) < 0) {
12956#ifdef SYSV
12957 if (errno == EINTR)
12958 continue;
12959#endif
12960 if (errno != ENOENT && errno != ENOTDIR)
12961 e = errno;
12962 goto loop;
12963 }
12964 e = EACCES; /* if we fail, this will be the error */
12965 if (!S_ISREG(statb.st_mode))
12966 continue;
12967 if (pathopt) { /* this is a %func directory */
12968 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012969 /* NB: stalloc will return space pointed by fullname
12970 * (because we don't have any intervening allocations
12971 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012972 readcmdfile(fullname);
12973 cmdp = cmdlookup(name, 0);
12974 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12975 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12976 stunalloc(fullname);
12977 goto success;
12978 }
12979 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12980 if (!updatetbl) {
12981 entry->cmdtype = CMDNORMAL;
12982 entry->u.index = idx;
12983 return;
12984 }
12985 INT_OFF;
12986 cmdp = cmdlookup(name, 1);
12987 cmdp->cmdtype = CMDNORMAL;
12988 cmdp->param.index = idx;
12989 INT_ON;
12990 goto success;
12991 }
12992
12993 /* We failed. If there was an entry for this command, delete it */
12994 if (cmdp && updatetbl)
12995 delete_cmd_entry();
12996 if (act & DO_ERR)
12997 ash_msg("%s: %s", name, errmsg(e, "not found"));
12998 entry->cmdtype = CMDUNKNOWN;
12999 return;
13000
13001 builtin_success:
13002 if (!updatetbl) {
13003 entry->cmdtype = CMDBUILTIN;
13004 entry->u.cmd = bcmd;
13005 return;
13006 }
13007 INT_OFF;
13008 cmdp = cmdlookup(name, 1);
13009 cmdp->cmdtype = CMDBUILTIN;
13010 cmdp->param.cmd = bcmd;
13011 INT_ON;
13012 success:
13013 cmdp->rehash = 0;
13014 entry->cmdtype = cmdp->cmdtype;
13015 entry->u = cmdp->param;
13016}
13017
13018
Eric Andersencb57d552001-06-28 07:25:16 +000013019/*
Eric Andersencb57d552001-06-28 07:25:16 +000013020 * The trap builtin.
13021 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013022static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013023trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013024{
13025 char *action;
13026 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013027 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013028
Eric Andersenc470f442003-07-28 09:56:35 +000013029 nextopt(nullstr);
13030 ap = argptr;
13031 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013032 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013033 char *tr = trap_ptr[signo];
13034 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013035 /* note: bash adds "SIG", but only if invoked
13036 * as "bash". If called as "sh", or if set -o posix,
13037 * then it prints short signal names.
13038 * We are printing short names: */
13039 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013040 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013041 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013042 /* trap_ptr != trap only if we are in special-cased `trap` code.
13043 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013044 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013045 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000013046 }
13047 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013048 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013049 if (trap_ptr != trap) {
13050 free(trap_ptr);
13051 trap_ptr = trap;
13052 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013053 */
Eric Andersencb57d552001-06-28 07:25:16 +000013054 return 0;
13055 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013056
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013057 action = NULL;
13058 if (ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000013059 action = *ap++;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013060 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013061 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000013062 signo = get_signum(*ap);
Denys Vlasenkoe9aba3e2017-07-01 21:09:27 +020013063 if (signo < 0 || signo >= NSIG) {
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013064 /* Mimic bash message exactly */
13065 ash_msg("%s: invalid signal specification", *ap);
13066 exitcode = 1;
13067 goto next;
13068 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000013069 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000013070 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000013071 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000013072 action = NULL;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013073 else {
13074 if (action[0]) /* not NULL and not "" and not "-" */
13075 may_have_traps = 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013076 action = ckstrdup(action);
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013077 }
Eric Andersencb57d552001-06-28 07:25:16 +000013078 }
Denis Vlasenko60818682007-09-28 22:07:23 +000013079 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000013080 trap[signo] = action;
13081 if (signo != 0)
13082 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013083 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013084 next:
Eric Andersencb57d552001-06-28 07:25:16 +000013085 ap++;
13086 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013087 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013088}
13089
Eric Andersenc470f442003-07-28 09:56:35 +000013090
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013091/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000013092
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013093#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013094static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013095helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013096{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000013097 unsigned col;
13098 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000013099
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020013100 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000013101 "Built-in commands:\n"
13102 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000013103 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013104 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000013105 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013106 if (col > 60) {
13107 out1fmt("\n");
13108 col = 0;
13109 }
13110 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013111# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000013112 {
13113 const char *a = applet_names;
13114 while (*a) {
13115 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
13116 if (col > 60) {
13117 out1fmt("\n");
13118 col = 0;
13119 }
Ron Yorston2b919582016-04-08 11:57:20 +010013120 while (*a++ != '\0')
13121 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013122 }
13123 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013124# endif
Denys Vlasenkoebedb942016-10-02 18:45:09 +020013125 newline_and_flush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000013126 return EXIT_SUCCESS;
13127}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013128#endif
Eric Andersenc470f442003-07-28 09:56:35 +000013129
Flemming Madsend96ffda2013-04-07 18:47:24 +020013130#if MAX_HISTORY
13131static int FAST_FUNC
13132historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13133{
13134 show_history(line_input_state);
13135 return EXIT_SUCCESS;
13136}
13137#endif
13138
Eric Andersencb57d552001-06-28 07:25:16 +000013139/*
Eric Andersencb57d552001-06-28 07:25:16 +000013140 * The export and readonly commands.
13141 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013142static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013143exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000013144{
13145 struct var *vp;
13146 char *name;
13147 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000013148 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020013149 char opt;
13150 int flag;
13151 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000013152
Denys Vlasenkod5275882012-10-01 13:41:17 +020013153 /* "readonly" in bash accepts, but ignores -n.
13154 * We do the same: it saves a conditional in nextopt's param.
13155 */
13156 flag_off = 0;
13157 while ((opt = nextopt("np")) != '\0') {
13158 if (opt == 'n')
13159 flag_off = VEXPORT;
13160 }
13161 flag = VEXPORT;
13162 if (argv[0][0] == 'r') {
13163 flag = VREADONLY;
13164 flag_off = 0; /* readonly ignores -n */
13165 }
13166 flag_off = ~flag_off;
13167
Denys Vlasenko10ad6222017-04-17 16:13:32 +020013168 /*if (opt_p_not_specified) - bash doesn't check this. Try "export -p NAME" */
Denys Vlasenkod5275882012-10-01 13:41:17 +020013169 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013170 aptr = argptr;
13171 name = *aptr;
13172 if (name) {
13173 do {
13174 p = strchr(name, '=');
13175 if (p != NULL) {
13176 p++;
13177 } else {
13178 vp = *findvar(hashvar(name), name);
13179 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020013180 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013181 continue;
13182 }
Eric Andersencb57d552001-06-28 07:25:16 +000013183 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013184 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013185 } while ((name = *++aptr) != NULL);
13186 return 0;
13187 }
Eric Andersencb57d552001-06-28 07:25:16 +000013188 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013189
13190 /* No arguments. Show the list of exported or readonly vars.
13191 * -n is ignored.
13192 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013193 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000013194 return 0;
13195}
13196
Eric Andersencb57d552001-06-28 07:25:16 +000013197/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013198 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000013199 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013200static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013201unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000013202{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013203 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000013204
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013205 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013206 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013207 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000013208}
13209
Eric Andersencb57d552001-06-28 07:25:16 +000013210/*
Eric Andersencb57d552001-06-28 07:25:16 +000013211 * The unset builtin command. We unset the function before we unset the
13212 * variable to allow a function to be unset when there is a readonly variable
13213 * with the same name.
13214 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013215static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013216unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013217{
13218 char **ap;
13219 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013220 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013221 int ret = 0;
13222
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013223 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000013224 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000013225 }
Eric Andersencb57d552001-06-28 07:25:16 +000013226
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013227 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013228 if (flag != 'f') {
13229 i = unsetvar(*ap);
13230 ret |= i;
13231 if (!(i & 2))
13232 continue;
13233 }
13234 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000013235 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000013236 }
Eric Andersenc470f442003-07-28 09:56:35 +000013237 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000013238}
13239
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000013240static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013241 ' ', offsetof(struct tms, tms_utime),
13242 '\n', offsetof(struct tms, tms_stime),
13243 ' ', offsetof(struct tms, tms_cutime),
13244 '\n', offsetof(struct tms, tms_cstime),
13245 0
13246};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013247static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013248timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013249{
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020013250 unsigned long clk_tck, s, t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013251 const unsigned char *p;
13252 struct tms buf;
13253
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020013254 clk_tck = bb_clk_tck();
Eric Andersencb57d552001-06-28 07:25:16 +000013255 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013256
13257 p = timescmd_str;
13258 do {
13259 t = *(clock_t *)(((char *) &buf) + p[1]);
13260 s = t / clk_tck;
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020013261 t = t % clk_tck;
13262 out1fmt("%lum%lu.%03lus%c",
13263 s / 60, s % 60,
13264 (t * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013265 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013266 p += 2;
13267 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013268
Eric Andersencb57d552001-06-28 07:25:16 +000013269 return 0;
13270}
13271
Denys Vlasenko0b883582016-12-23 16:49:07 +010013272#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000013273/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013274 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013275 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000013276 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013277 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000013278 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013279static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013280letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013281{
Denis Vlasenko68404f12008-03-17 09:00:54 +000013282 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000013283
Denis Vlasenko68404f12008-03-17 09:00:54 +000013284 argv++;
13285 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000013286 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000013287 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013288 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013289 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013290
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000013291 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000013292}
Eric Andersenc470f442003-07-28 09:56:35 +000013293#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013294
Eric Andersenc470f442003-07-28 09:56:35 +000013295/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013296 * The read builtin. Options:
13297 * -r Do not interpret '\' specially
13298 * -s Turn off echo (tty only)
13299 * -n NCHARS Read NCHARS max
13300 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13301 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13302 * -u FD Read from given FD instead of fd 0
Eric Andersenc470f442003-07-28 09:56:35 +000013303 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013304 * TODO: bash also has:
13305 * -a ARRAY Read into array[0],[1],etc
13306 * -d DELIM End on DELIM char, not newline
13307 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000013308 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013309static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013310readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013311{
Denys Vlasenko73067272010-01-12 22:11:24 +010013312 char *opt_n = NULL;
13313 char *opt_p = NULL;
13314 char *opt_t = NULL;
13315 char *opt_u = NULL;
13316 int read_flags = 0;
13317 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000013318 int i;
13319
Denys Vlasenko73067272010-01-12 22:11:24 +010013320 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000013321 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000013322 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010013323 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013324 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013325 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010013326 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013327 break;
13328 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010013329 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000013330 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013331 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010013332 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013333 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013334 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010013335 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000013336 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013337 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010013338 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013339 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013340 default:
13341 break;
13342 }
Eric Andersenc470f442003-07-28 09:56:35 +000013343 }
Paul Fox02eb9342005-09-07 16:56:02 +000013344
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013345 /* "read -s" needs to save/restore termios, can't allow ^C
13346 * to jump out of it.
13347 */
Denys Vlasenkof5470412017-05-22 19:34:45 +020013348 again:
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013349 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013350 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010013351 argptr,
13352 bltinlookup("IFS"), /* can be NULL */
13353 read_flags,
13354 opt_n,
13355 opt_p,
13356 opt_t,
13357 opt_u
13358 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013359 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000013360
Denys Vlasenkof5470412017-05-22 19:34:45 +020013361 if ((uintptr_t)r == 1 && errno == EINTR) {
13362 /* to get SIGCHLD: sleep 1 & read x; echo $x */
13363 if (pending_sig == 0)
13364 goto again;
13365 }
13366
Denys Vlasenko73067272010-01-12 22:11:24 +010013367 if ((uintptr_t)r > 1)
13368 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000013369
Denys Vlasenko73067272010-01-12 22:11:24 +010013370 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000013371}
13372
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013373static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020013374umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013375{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013376 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000013377
Eric Andersenc470f442003-07-28 09:56:35 +000013378 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000013379 int symbolic_mode = 0;
13380
13381 while (nextopt("S") != '\0') {
13382 symbolic_mode = 1;
13383 }
13384
Denis Vlasenkob012b102007-02-19 22:43:01 +000013385 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013386 mask = umask(0);
13387 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013388 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013389
Denys Vlasenko6283f982015-10-07 16:56:20 +020013390 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013391 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013392 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013393 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013394 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013395
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013396 i = 2;
13397 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013398 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013399 *p++ = permuser[i];
13400 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013401 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013402 if (!(mask & 0400)) *p++ = 'r';
13403 if (!(mask & 0200)) *p++ = 'w';
13404 if (!(mask & 0100)) *p++ = 'x';
13405 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013406 if (--i < 0)
13407 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013408 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013409 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013410 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013411 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013412 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013413 }
13414 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013415 char *modestr = *argptr;
13416 /* numeric umasks are taken as-is */
13417 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
13418 if (!isdigit(modestr[0]))
13419 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013420 mask = bb_parse_mode(modestr, mask);
13421 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013422 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013423 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013424 if (!isdigit(modestr[0]))
13425 mask ^= 0777;
13426 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013427 }
13428 return 0;
13429}
13430
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013431static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013432ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013433{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013434 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013435}
13436
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013437/* ============ main() and helpers */
13438
13439/*
13440 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013441 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013442static void
13443exitshell(void)
13444{
13445 struct jmploc loc;
13446 char *p;
13447 int status;
13448
Denys Vlasenkobede2152011-09-04 16:12:33 +020013449#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13450 save_history(line_input_state);
13451#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013452 status = exitstatus;
13453 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13454 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013455 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013456 status = exitstatus;
13457 goto out;
13458 }
13459 exception_handler = &loc;
13460 p = trap[0];
13461 if (p) {
13462 trap[0] = NULL;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013463 evalskip = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013464 evalstring(p, 0);
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013465 /*free(p); - we'll exit soon */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013466 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013467 out:
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013468 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13469 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13470 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013471 setjobctl(0);
Denys Vlasenkocaee80c2016-10-25 20:49:53 +020013472 flush_stdout_stderr();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013473 _exit(status);
13474 /* NOTREACHED */
13475}
13476
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013477static void
13478init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013479{
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013480 /* we will never free this */
13481 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013482
Denys Vlasenko458c1f22016-10-27 23:51:19 +020013483 sigmode[SIGCHLD - 1] = S_DFL;
13484 setsignal(SIGCHLD);
13485
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013486 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13487 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13488 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013489 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013490
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013491 {
13492 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013493 const char *p;
13494 struct stat st1, st2;
13495
13496 initvar();
13497 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenkob6838b52016-09-30 11:33:47 +020013498 p = endofname(*envp);
13499 if (p != *envp && *p == '=') {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013500 setvareq(*envp, VEXPORT|VTEXTFIXED);
13501 }
13502 }
13503
Denys Vlasenkoe627ac92016-09-30 14:36:59 +020013504 setvareq((char*)defoptindvar, VTEXTFIXED);
13505
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013506 setvar0("PPID", utoa(getppid()));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013507#if BASH_SHLVL_VAR
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013508 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013509 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013510#endif
13511#if BASH_HOSTNAME_VAR
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013512 if (!lookupvar("HOSTNAME")) {
13513 struct utsname uts;
13514 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013515 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013516 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013517#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013518 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013519 if (p) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013520 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013521 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13522 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013523 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013524 }
13525 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013526 setpwd(p, 0);
13527 }
13528}
13529
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013530
13531//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013532//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013533//usage:#define ash_full_usage "\n\n"
13534//usage: "Unix shell interpreter"
13535
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013536/*
13537 * Process the shell command line arguments.
13538 */
13539static void
Denis Vlasenko68404f12008-03-17 09:00:54 +000013540procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013541{
13542 int i;
13543 const char *xminusc;
13544 char **xargv;
13545
13546 xargv = argv;
13547 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013548 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013549 xargv++;
13550 for (i = 0; i < NOPTS; i++)
13551 optlist[i] = 2;
13552 argptr = xargv;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013553 if (options(/*cmdline:*/ 1)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013554 /* it already printed err message */
13555 raise_exception(EXERROR);
13556 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013557 xargv = argptr;
13558 xminusc = minusc;
13559 if (*xargv == NULL) {
13560 if (xminusc)
13561 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13562 sflag = 1;
13563 }
13564 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13565 iflag = 1;
13566 if (mflag == 2)
13567 mflag = iflag;
13568 for (i = 0; i < NOPTS; i++)
13569 if (optlist[i] == 2)
13570 optlist[i] = 0;
13571#if DEBUG == 2
13572 debug = 1;
13573#endif
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013574 /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013575 if (xminusc) {
13576 minusc = *xargv++;
13577 if (*xargv)
13578 goto setarg0;
13579 } else if (!sflag) {
13580 setinputfile(*xargv, 0);
13581 setarg0:
13582 arg0 = *xargv++;
13583 commandname = arg0;
13584 }
13585
13586 shellparam.p = xargv;
13587#if ENABLE_ASH_GETOPTS
13588 shellparam.optind = 1;
13589 shellparam.optoff = -1;
13590#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013591 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013592 while (*xargv) {
13593 shellparam.nparam++;
13594 xargv++;
13595 }
13596 optschanged();
13597}
13598
13599/*
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013600 * Read /etc/profile, ~/.profile, $ENV.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013601 */
13602static void
13603read_profile(const char *name)
13604{
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013605 name = expandstr(name);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013606 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13607 return;
Denys Vlasenko0840c912016-10-01 15:27:44 +020013608 cmdloop(0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013609 popfile();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013610}
13611
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013612/*
13613 * This routine is called when an error or an interrupt occurs in an
13614 * interactive shell and control is returned to the main command loop.
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013615 * (In dash, this function is auto-generated by build machinery).
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013616 */
13617static void
13618reset(void)
13619{
13620 /* from eval.c: */
13621 evalskip = 0;
13622 loopnest = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013623
13624 /* from expand.c: */
13625 ifsfree();
13626
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013627 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013628 g_parsefile->left_in_buffer = 0;
13629 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013630 popallfiles();
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013631
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013632 /* from redir.c: */
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020013633 while (redirlist)
13634 popredir(/*drop:*/ 0, /*restore:*/ 0);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013635}
13636
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013637#if PROFILE
13638static short profile_buf[16384];
13639extern int etext();
13640#endif
13641
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013642/*
13643 * Main routine. We initialize things, parse the arguments, execute
13644 * profiles if we're a login shell, and then call cmdloop to execute
13645 * commands. The setjmp call sets up the location to jump to when an
13646 * exception occurs. When an exception occurs the variable "state"
13647 * is used to figure out how far we had gotten.
13648 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013649int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013650int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013651{
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013652 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013653 struct jmploc jmploc;
13654 struct stackmark smark;
13655
Denis Vlasenko01631112007-12-16 17:20:38 +000013656 /* Initialize global data */
13657 INIT_G_misc();
13658 INIT_G_memstack();
13659 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013660#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013661 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013662#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013663 INIT_G_cmdtable();
13664
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013665#if PROFILE
13666 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13667#endif
13668
13669#if ENABLE_FEATURE_EDITING
13670 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13671#endif
13672 state = 0;
13673 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013674 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013675 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013676
13677 reset();
13678
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013679 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013680 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013681 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013682 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013683 }
13684 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020013685 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013686 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013687
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013688 popstackmark(&smark);
13689 FORCE_INT_ON; /* enable interrupts */
13690 if (s == 1)
13691 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013692 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013693 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013694 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013695 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013696 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013697 }
13698 exception_handler = &jmploc;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013699 rootpid = getpid();
13700
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013701 init();
13702 setstackmark(&smark);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013703 procargs(argv);
Denys Vlasenko474ed062016-10-30 18:30:29 +010013704#if DEBUG
13705 TRACE(("Shell args: "));
13706 trace_puts_args(argv);
13707#endif
Denis Vlasenko68404f12008-03-17 09:00:54 +000013708
Denys Vlasenko6088e132010-12-25 23:58:42 +010013709 if (argv[0] && argv[0][0] == '-')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013710 isloginsh = 1;
13711 if (isloginsh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013712 const char *hp;
13713
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013714 state = 1;
13715 read_profile("/etc/profile");
13716 state1:
13717 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013718 hp = lookupvar("HOME");
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013719 if (hp)
13720 read_profile("$HOME/.profile");
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013721 }
13722 state2:
13723 state = 3;
13724 if (
13725#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013726 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013727#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013728 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013729 ) {
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013730 const char *shinit = lookupvar("ENV");
13731 if (shinit != NULL && *shinit != '\0')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013732 read_profile(shinit);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013733 }
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013734 popstackmark(&smark);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013735 state3:
13736 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013737 if (minusc) {
13738 /* evalstring pushes parsefile stack.
13739 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013740 * is one of stacked source fds.
13741 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013742 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013743 // ^^ not necessary since now we special-case fd 0
13744 // in is_hidden_fd() to not be considered "hidden fd"
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013745 evalstring(minusc, 0);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013746 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013747
13748 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020013749#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013750 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013751 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013752 if (!hp) {
13753 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013754 if (hp) {
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013755 INT_OFF;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013756 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013757 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013758 free((char*)hp);
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013759 INT_ON;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013760 hp = lookupvar("HISTFILE");
13761 }
13762 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013763 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013764 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013765# if ENABLE_FEATURE_SH_HISTFILESIZE
13766 hp = lookupvar("HISTFILESIZE");
13767 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13768# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013769 }
13770#endif
13771 state4: /* XXX ??? - why isn't this before the "if" statement */
13772 cmdloop(1);
13773 }
13774#if PROFILE
13775 monitor(0);
13776#endif
13777#ifdef GPROF
13778 {
13779 extern void _mcleanup(void);
13780 _mcleanup();
13781 }
13782#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013783 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013784 exitshell();
13785 /* NOTREACHED */
13786}
13787
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013788
Eric Andersendf82f612001-06-28 07:46:40 +000013789/*-
13790 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013791 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013792 *
13793 * This code is derived from software contributed to Berkeley by
13794 * Kenneth Almquist.
13795 *
13796 * Redistribution and use in source and binary forms, with or without
13797 * modification, are permitted provided that the following conditions
13798 * are met:
13799 * 1. Redistributions of source code must retain the above copyright
13800 * notice, this list of conditions and the following disclaimer.
13801 * 2. Redistributions in binary form must reproduce the above copyright
13802 * notice, this list of conditions and the following disclaimer in the
13803 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013804 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013805 * may be used to endorse or promote products derived from this software
13806 * without specific prior written permission.
13807 *
13808 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13809 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13810 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13811 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13812 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13813 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13814 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13815 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13816 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13817 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13818 * SUCH DAMAGE.
13819 */