blob: 6d46e3719bba33e03fd36f67315264bc12526178 [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
19//config: bool "ash"
20//config: default y
21//config: depends on !NOMMU
22//config: help
23//config: Tha 'ash' shell adds about 60k in the default configuration and is
24//config: the most complete and most pedantically correct shell included with
25//config: busybox. This shell is actually a derivative of the Debian 'dash'
26//config: shell (by Herbert Xu), which was created by porting the 'ash' shell
27//config: (written by Kenneth Almquist) from NetBSD.
28//config:
Kang-Che Sung6cd02942017-01-06 17:02:03 +010029//config:# ash options
30//config:# note: Don't remove !NOMMU part in the next line; it would break
31//config:# menuconfig's indenting.
32//config:if !NOMMU && (ASH || SH_IS_ASH || BASH_IS_ASH)
33//config:
Denys Vlasenko514b51d2016-10-01 14:33:08 +020034//config:config ASH_OPTIMIZE_FOR_SIZE
35//config: bool "Optimize for size instead of speed"
36//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010037//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020038//config:
39//config:config ASH_INTERNAL_GLOB
40//config: bool "Use internal glob() implementation"
Denys Vlasenko326edc32016-12-22 14:36:49 +010041//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 +010042//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020043//config: help
44//config: Do not use glob() function from libc, use internal implementation.
45//config: Use this if you are getting "glob.h: No such file or directory"
46//config: or similar build errors.
Denys Vlasenkof5604222017-01-10 14:58:54 +010047//config: Note that as of now (2017-01), uclibc and musl glob() both have bugs
48//config: which would break ash if you select N here.
49//config:
50//config:config ASH_BASH_COMPAT
51//config: bool "bash-compatible extensions"
52//config: default y
53//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
54//config:
55//config:config ASH_JOB_CONTROL
56//config: bool "Job control"
57//config: default y
58//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
59//config:
60//config:config ASH_ALIAS
61//config: bool "Alias support"
62//config: default y
63//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020064//config:
65//config:config ASH_RANDOM_SUPPORT
66//config: bool "Pseudorandom generator and $RANDOM variable"
67//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010068//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020069//config: help
70//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
71//config: Each read of "$RANDOM" will generate a new pseudorandom value.
72//config: You can reset the generator by using a specified start value.
73//config: After "unset RANDOM" the generator will switch off and this
74//config: variable will no longer have special treatment.
75//config:
76//config:config ASH_EXPAND_PRMT
77//config: bool "Expand prompt string"
78//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010079//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020080//config: help
Denys Vlasenkof5604222017-01-10 14:58:54 +010081//config: $PS# may contain volatile content, such as backquote commands.
Denys Vlasenko514b51d2016-10-01 14:33:08 +020082//config: This option recreates the prompt string from the environment
83//config: variable each time it is displayed.
84//config:
Denys Vlasenko046341e2011-02-04 17:53:59 +010085//config:config ASH_IDLE_TIMEOUT
Denys Vlasenkof5604222017-01-10 14:58:54 +010086//config: bool "Idle timeout variable $TMOUT"
Denys Vlasenko771f1992010-07-16 14:31:34 +020087//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010088//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +020089//config: help
Denys Vlasenkof5604222017-01-10 14:58:54 +010090//config: Enable bash-like auto-logout after $TMOUT seconds of idle time.
Denys Vlasenko771f1992010-07-16 14:31:34 +020091//config:
Denys Vlasenkof5604222017-01-10 14:58:54 +010092//config:config ASH_MAIL
93//config: bool "Check for new mail in interactive shell"
Denys Vlasenko771f1992010-07-16 14:31:34 +020094//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010095//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +020096//config: help
Denys Vlasenkof5604222017-01-10 14:58:54 +010097//config: Enable "check for new mail" function:
98//config: if set, $MAIL file and $MAILPATH list of files
99//config: are checked for mtime changes, and "you have mail"
100//config: message is printed if change is detected.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200101//config:
Denys Vlasenko265062d2017-01-10 15:13:30 +0100102//config:config ASH_ECHO
Denys Vlasenkof5604222017-01-10 14:58:54 +0100103//config: bool "echo builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200104//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100105//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200106//config:
Denys Vlasenko265062d2017-01-10 15:13:30 +0100107//config:config ASH_PRINTF
Denys Vlasenkof5604222017-01-10 14:58:54 +0100108//config: bool "printf builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200109//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100110//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200111//config:
Denys Vlasenko265062d2017-01-10 15:13:30 +0100112//config:config ASH_TEST
Denys Vlasenkof5604222017-01-10 14:58:54 +0100113//config: bool "test builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200114//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100115//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200116//config:
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200117//config:config ASH_HELP
118//config: bool "help builtin"
119//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100120//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenkof5604222017-01-10 14:58:54 +0100121//config:
122//config:config ASH_GETOPTS
123//config: bool "getopts builtin"
124//config: default y
125//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200126//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200127//config:config ASH_CMDCMD
Denys Vlasenkof5604222017-01-10 14:58:54 +0100128//config: bool "command builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200129//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100130//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200131//config: help
Denys Vlasenkof5604222017-01-10 14:58:54 +0100132//config: Enable support for the 'command' builtin, which allows
133//config: you to run the specified command or builtin,
134//config: even when there is a function with the same name.
Kang-Che Sung6cd02942017-01-06 17:02:03 +0100135//config:
136//config:endif # ash options
Denys Vlasenko771f1992010-07-16 14:31:34 +0200137
Denys Vlasenko20704f02011-03-23 17:59:27 +0100138//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
Denys Vlasenko205d48e2017-01-29 14:57:33 +0100139// APPLET_ODDNAME:name main location suid_type help
140//applet:IF_SH_IS_ASH( APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
Denys Vlasenko0b883582016-12-23 16:49:07 +0100141//applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
Denys Vlasenko20704f02011-03-23 17:59:27 +0100142
143//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
Denys Vlasenko0b883582016-12-23 16:49:07 +0100144//kbuild:lib-$(CONFIG_SH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
145//kbuild:lib-$(CONFIG_BASH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
Denys Vlasenko20704f02011-03-23 17:59:27 +0100146//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
147
Denys Vlasenko67047462016-12-22 15:21:58 +0100148/*
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100149 * DEBUG=1 to compile in debugging ('set -o debug' turns on)
150 * DEBUG=2 to compile in and turn on debugging.
151 * When debugging is on ("set -o debug" was executed, or DEBUG=2),
152 * debugging info is written to ./trace, quit signal generates core dump.
Denys Vlasenko67047462016-12-22 15:21:58 +0100153 */
154#define DEBUG 0
155/* Tweak debug output verbosity here */
156#define DEBUG_TIME 0
157#define DEBUG_PID 1
158#define DEBUG_SIG 1
159#define DEBUG_INTONOFF 0
160
161#define PROFILE 0
162
163#define JOBS ENABLE_ASH_JOB_CONTROL
164
165#include <setjmp.h>
166#include <fnmatch.h>
167#include <sys/times.h>
168#include <sys/utsname.h> /* for setting $HOSTNAME */
Denys Vlasenko67047462016-12-22 15:21:58 +0100169#include "busybox.h" /* for applet_names */
170
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100171/* So far, all bash compat is controlled by one config option */
172/* Separate defines document which part of code implements what */
173/* function keyword */
174#define BASH_FUNCTION ENABLE_ASH_BASH_COMPAT
175#define IF_BASH_FUNCTION IF_ASH_BASH_COMPAT
176/* &>file */
177#define BASH_REDIR_OUTPUT ENABLE_ASH_BASH_COMPAT
178#define IF_BASH_REDIR_OUTPUT IF_ASH_BASH_COMPAT
179/* $'...' */
180#define BASH_DOLLAR_SQUOTE ENABLE_ASH_BASH_COMPAT
181#define IF_BASH_DOLLAR_SQUOTE IF_ASH_BASH_COMPAT
182#define BASH_PATTERN_SUBST ENABLE_ASH_BASH_COMPAT
183#define IF_BASH_PATTERN_SUBST IF_ASH_BASH_COMPAT
184#define BASH_SUBSTR ENABLE_ASH_BASH_COMPAT
185#define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT
186/* [[ EXPR ]] */
187#define BASH_TEST2 (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST)
188#define BASH_SOURCE ENABLE_ASH_BASH_COMPAT
189#define BASH_PIPEFAIL ENABLE_ASH_BASH_COMPAT
190#define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT
191#define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT
192
Denys Vlasenko67047462016-12-22 15:21:58 +0100193#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
194/* Bionic at least up to version 24 has no glob() */
195# undef ENABLE_ASH_INTERNAL_GLOB
196# define ENABLE_ASH_INTERNAL_GLOB 1
197#endif
198
199#if !ENABLE_ASH_INTERNAL_GLOB && defined(__UCLIBC__)
200# error uClibc glob() is buggy, use ASH_INTERNAL_GLOB.
201# error The bug is: for "$PWD"/<pattern> ash will escape e.g. dashes in "$PWD"
202# error with backslash, even ones which do not need to be: "/a-b" -> "/a\-b"
203# error glob() should unbackslash them and match. uClibc does not unbackslash,
204# error fails to match dirname, subsequently not expanding <pattern> in it.
205// Testcase:
206// if (glob("/etc/polkit\\-1", 0, NULL, &pglob)) - this returns 0 on uclibc, no bug
207// if (glob("/etc/polkit\\-1/*", 0, NULL, &pglob)) printf("uclibc bug!\n");
208#endif
209
210#if !ENABLE_ASH_INTERNAL_GLOB
211# include <glob.h>
212#endif
213
214#include "unicode.h"
215#include "shell_common.h"
Denys Vlasenko0b883582016-12-23 16:49:07 +0100216#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko67047462016-12-22 15:21:58 +0100217# include "math.h"
218#endif
219#if ENABLE_ASH_RANDOM_SUPPORT
220# include "random.h"
221#else
222# define CLEAR_RANDOM_T(rnd) ((void)0)
223#endif
224
225#include "NUM_APPLETS.h"
226#if NUM_APPLETS == 1
227/* STANDALONE does not make sense, and won't compile */
228# undef CONFIG_FEATURE_SH_STANDALONE
229# undef ENABLE_FEATURE_SH_STANDALONE
230# undef IF_FEATURE_SH_STANDALONE
231# undef IF_NOT_FEATURE_SH_STANDALONE
232# define ENABLE_FEATURE_SH_STANDALONE 0
233# define IF_FEATURE_SH_STANDALONE(...)
234# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
235#endif
236
237#ifndef PIPE_BUF
238# define PIPE_BUF 4096 /* amount of buffering in a pipe */
239#endif
240
241#if !BB_MMU
242# error "Do not even bother, ash will not run on NOMMU machine"
243#endif
244
Denis Vlasenkob012b102007-02-19 22:43:01 +0000245
Denis Vlasenko01631112007-12-16 17:20:38 +0000246/* ============ Hash table sizes. Configurable. */
247
248#define VTABSIZE 39
249#define ATABSIZE 39
250#define CMDTABLESIZE 31 /* should be prime */
251
252
Denis Vlasenkob012b102007-02-19 22:43:01 +0000253/* ============ Shell options */
254
255static const char *const optletters_optnames[] = {
256 "e" "errexit",
257 "f" "noglob",
258 "I" "ignoreeof",
259 "i" "interactive",
260 "m" "monitor",
261 "n" "noexec",
262 "s" "stdin",
263 "x" "xtrace",
264 "v" "verbose",
265 "C" "noclobber",
266 "a" "allexport",
267 "b" "notify",
268 "u" "nounset",
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100269 "\0" "vi"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100270#if BASH_PIPEFAIL
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100271 ,"\0" "pipefail"
Michael Abbott359da5e2009-12-04 23:03:29 +0100272#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000273#if DEBUG
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000274 ,"\0" "nolog"
275 ,"\0" "debug"
Denis Vlasenkob012b102007-02-19 22:43:01 +0000276#endif
277};
278
Denys Vlasenko285ad152009-12-04 23:02:27 +0100279#define optletters(n) optletters_optnames[n][0]
280#define optnames(n) (optletters_optnames[n] + 1)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000281
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000282enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
Denis Vlasenkob012b102007-02-19 22:43:01 +0000283
Eric Andersenc470f442003-07-28 09:56:35 +0000284
Denis Vlasenkob012b102007-02-19 22:43:01 +0000285/* ============ Misc data */
Eric Andersenc470f442003-07-28 09:56:35 +0000286
Denys Vlasenkoea8b2522010-06-02 12:57:26 +0200287#define msg_illnum "Illegal number: %s"
Denis Vlasenkoaa744452007-02-23 01:04:22 +0000288
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +0000289/*
Eric Andersenc470f442003-07-28 09:56:35 +0000290 * We enclose jmp_buf in a structure so that we can declare pointers to
291 * jump locations. The global variable handler contains the location to
Denis Vlasenkof1733952009-03-19 23:21:55 +0000292 * jump to when an exception occurs, and the global variable exception_type
Eric Andersenaff114c2004-04-14 17:51:38 +0000293 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000294 * exception handlers, the user should save the value of handler on entry
295 * to an inner scope, set handler to point to a jmploc structure for the
296 * inner scope, and restore handler on exit from the scope.
297 */
Eric Andersenc470f442003-07-28 09:56:35 +0000298struct jmploc {
299 jmp_buf loc;
300};
Denis Vlasenko01631112007-12-16 17:20:38 +0000301
302struct globals_misc {
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200303 uint8_t exitstatus; /* exit status of last command */
304 uint8_t back_exitstatus;/* exit status of backquoted command */
305 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
306 int rootpid; /* pid of main shell */
Denis Vlasenko01631112007-12-16 17:20:38 +0000307 /* shell level: 0 for the main shell, 1 for its children, and so on */
308 int shlvl;
309#define rootshell (!shlvl)
310 char *minusc; /* argument to -c option */
311
312 char *curdir; // = nullstr; /* current working directory */
313 char *physdir; // = nullstr; /* physical working directory */
314
315 char *arg0; /* value of $0 */
316
317 struct jmploc *exception_handler;
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000318
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200319 volatile int suppress_int; /* counter */
320 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200321 volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +0200322 volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000323 smallint exception_type; /* kind of exception (0..5) */
Denis Vlasenko01631112007-12-16 17:20:38 +0000324 /* exceptions */
Eric Andersenc470f442003-07-28 09:56:35 +0000325#define EXINT 0 /* SIGINT received */
326#define EXERROR 1 /* a generic error */
Eric Andersenc470f442003-07-28 09:56:35 +0000327#define EXEXIT 4 /* exit the shell */
Eric Andersen2870d962001-07-02 17:27:21 +0000328
Denis Vlasenko01631112007-12-16 17:20:38 +0000329 smallint isloginsh;
Denis Vlasenkob07a4962008-06-22 13:16:23 +0000330 char nullstr[1]; /* zero length string */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000331
332 char optlist[NOPTS];
333#define eflag optlist[0]
334#define fflag optlist[1]
335#define Iflag optlist[2]
336#define iflag optlist[3]
337#define mflag optlist[4]
338#define nflag optlist[5]
339#define sflag optlist[6]
340#define xflag optlist[7]
341#define vflag optlist[8]
342#define Cflag optlist[9]
343#define aflag optlist[10]
344#define bflag optlist[11]
345#define uflag optlist[12]
346#define viflag optlist[13]
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100347#if BASH_PIPEFAIL
Michael Abbott359da5e2009-12-04 23:03:29 +0100348# define pipefail optlist[14]
349#else
350# define pipefail 0
351#endif
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000352#if DEBUG
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100353# define nolog optlist[14 + BASH_PIPEFAIL]
354# define debug optlist[15 + BASH_PIPEFAIL]
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000355#endif
356
357 /* trap handler commands */
Denis Vlasenko01631112007-12-16 17:20:38 +0000358 /*
359 * Sigmode records the current value of the signal handlers for the various
360 * modes. A value of zero means that the current handler is not known.
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000361 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
Denis Vlasenko01631112007-12-16 17:20:38 +0000362 */
363 char sigmode[NSIG - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000364#define S_DFL 1 /* default signal handling (SIG_DFL) */
365#define S_CATCH 2 /* signal is caught */
366#define S_IGN 3 /* signal is ignored (SIG_IGN) */
Denys Vlasenkoe5814a52016-07-16 18:33:55 +0200367#define S_HARD_IGN 4 /* signal is ignored permanently */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000368
Denis Vlasenko01631112007-12-16 17:20:38 +0000369 /* indicates specified signal received */
Denis Vlasenko4b875702009-03-19 13:30:04 +0000370 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
Denys Vlasenko238bf182010-05-18 15:49:07 +0200371 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000372 char *trap[NSIG];
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200373 char **trap_ptr; /* used only by "trap hack" */
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000374
375 /* Rarely referenced stuff */
376#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200377 random_t random_gen;
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000378#endif
379 pid_t backgndpid; /* pid of last background process */
Denis Vlasenko01631112007-12-16 17:20:38 +0000380};
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000381extern struct globals_misc *const ash_ptr_to_globals_misc;
382#define G_misc (*ash_ptr_to_globals_misc)
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200383#define exitstatus (G_misc.exitstatus )
384#define back_exitstatus (G_misc.back_exitstatus )
385#define job_warning (G_misc.job_warning)
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000386#define rootpid (G_misc.rootpid )
387#define shlvl (G_misc.shlvl )
388#define minusc (G_misc.minusc )
389#define curdir (G_misc.curdir )
390#define physdir (G_misc.physdir )
391#define arg0 (G_misc.arg0 )
Denis Vlasenko01631112007-12-16 17:20:38 +0000392#define exception_handler (G_misc.exception_handler)
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000393#define exception_type (G_misc.exception_type )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200394#define suppress_int (G_misc.suppress_int )
395#define pending_int (G_misc.pending_int )
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200396#define got_sigchld (G_misc.got_sigchld )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200397#define pending_sig (G_misc.pending_sig )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000398#define isloginsh (G_misc.isloginsh )
399#define nullstr (G_misc.nullstr )
400#define optlist (G_misc.optlist )
401#define sigmode (G_misc.sigmode )
402#define gotsig (G_misc.gotsig )
Denys Vlasenko238bf182010-05-18 15:49:07 +0200403#define may_have_traps (G_misc.may_have_traps )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000404#define trap (G_misc.trap )
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200405#define trap_ptr (G_misc.trap_ptr )
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200406#define random_gen (G_misc.random_gen )
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000407#define backgndpid (G_misc.backgndpid )
Denis Vlasenko01631112007-12-16 17:20:38 +0000408#define INIT_G_misc() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000409 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
410 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +0000411 curdir = nullstr; \
412 physdir = nullstr; \
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200413 trap_ptr = trap; \
Denis Vlasenko01631112007-12-16 17:20:38 +0000414} while (0)
415
416
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000417/* ============ DEBUG */
418#if DEBUG
419static void trace_printf(const char *fmt, ...);
420static void trace_vprintf(const char *fmt, va_list va);
421# define TRACE(param) trace_printf param
422# define TRACEV(param) trace_vprintf param
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000423# define close(fd) do { \
424 int dfd = (fd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000425 if (close(dfd) < 0) \
Denys Vlasenko883cea42009-07-11 15:31:59 +0200426 bb_error_msg("bug on %d: closing %d(0x%x)", \
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000427 __LINE__, dfd, dfd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000428} while (0)
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000429#else
430# define TRACE(param)
431# define TRACEV(param)
432#endif
433
434
Denis Vlasenko559691a2008-10-05 18:39:31 +0000435/* ============ Utility functions */
Denys Vlasenko1961aea2013-02-26 00:36:53 +0100436#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
437#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
438
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200439static int
440isdigit_str9(const char *str)
Denis Vlasenko559691a2008-10-05 18:39:31 +0000441{
442 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
443 while (--maxlen && isdigit(*str))
444 str++;
445 return (*str == '\0');
446}
Denis Vlasenko01631112007-12-16 17:20:38 +0000447
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200448static const char *
449var_end(const char *var)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +0200450{
451 while (*var)
452 if (*var++ == '=')
453 break;
454 return var;
455}
456
Denis Vlasenko559691a2008-10-05 18:39:31 +0000457
458/* ============ Interrupts / exceptions */
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100459
460static void exitshell(void) NORETURN;
461
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000462/*
Eric Andersen2870d962001-07-02 17:27:21 +0000463 * These macros allow the user to suspend the handling of interrupt signals
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000464 * over a period of time. This is similar to SIGHOLD or to sigblock, but
Eric Andersen2870d962001-07-02 17:27:21 +0000465 * much more efficient and portable. (But hacking the kernel is so much
466 * more fun than worrying about efficiency and portability. :-))
467 */
Denys Vlasenko06b11492016-11-04 16:43:18 +0100468#if DEBUG_INTONOFF
469# define INT_OFF do { \
470 TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200471 suppress_int++; \
Denys Vlasenkode892052016-10-02 01:49:13 +0200472 barrier(); \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000473} while (0)
Denys Vlasenko06b11492016-11-04 16:43:18 +0100474#else
475# define INT_OFF do { \
476 suppress_int++; \
477 barrier(); \
478} while (0)
479#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000480
481/*
482 * Called to raise an exception. Since C doesn't include exceptions, we
483 * just do a longjmp to the exception handler. The type of exception is
Denis Vlasenko4b875702009-03-19 13:30:04 +0000484 * stored in the global variable "exception_type".
Denis Vlasenkob012b102007-02-19 22:43:01 +0000485 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000486static void raise_exception(int) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000487static void
488raise_exception(int e)
489{
490#if DEBUG
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000491 if (exception_handler == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000492 abort();
493#endif
494 INT_OFF;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000495 exception_type = e;
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000496 longjmp(exception_handler->loc, 1);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000497}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000498#if DEBUG
499#define raise_exception(e) do { \
500 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
501 raise_exception(e); \
502} while (0)
503#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000504
505/*
Denys Vlasenkof37e1152016-10-07 03:17:28 +0200506 * Called when a SIGINT is received. (If the user specifies
Denis Vlasenkob012b102007-02-19 22:43:01 +0000507 * that SIGINT is to be trapped or ignored using the trap builtin, then
508 * this routine is not called.) Suppressint is nonzero when interrupts
509 * are held using the INT_OFF macro. (The test for iflag is just
510 * defensive programming.)
511 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000512static void raise_interrupt(void) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000513static void
514raise_interrupt(void)
515{
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200516 pending_int = 0;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000517 /* Signal is not automatically unmasked after it is raised,
518 * do it ourself - unmask all signals */
Denis Vlasenko3f165fa2008-03-17 08:29:08 +0000519 sigprocmask_allsigs(SIG_UNBLOCK);
Denys Vlasenko238bf182010-05-18 15:49:07 +0200520 /* pending_sig = 0; - now done in signal_handler() */
Denis Vlasenko7c139b42007-03-21 20:17:27 +0000521
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200522 if (!(rootshell && iflag)) {
523 /* Kill ourself with SIGINT */
524 signal(SIGINT, SIG_DFL);
525 raise(SIGINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000526 }
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200527 /* bash: ^C even on empty command line sets $? */
528 exitstatus = SIGINT + 128;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200529 raise_exception(EXINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000530 /* NOTREACHED */
531}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000532#if DEBUG
533#define raise_interrupt() do { \
534 TRACE(("raising interrupt on line %d\n", __LINE__)); \
535 raise_interrupt(); \
536} while (0)
537#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000538
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000539static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000540int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000541{
Denys Vlasenkode892052016-10-02 01:49:13 +0200542 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200543 if (--suppress_int == 0 && pending_int) {
Denis Vlasenkob012b102007-02-19 22:43:01 +0000544 raise_interrupt();
545 }
546}
Denys Vlasenko06b11492016-11-04 16:43:18 +0100547#if DEBUG_INTONOFF
548# define INT_ON do { \
549 TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
550 int_on(); \
551} while (0)
552#else
553# define INT_ON int_on()
554#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000555static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000556force_int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000557{
Denys Vlasenkode892052016-10-02 01:49:13 +0200558 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200559 suppress_int = 0;
560 if (pending_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000561 raise_interrupt();
562}
563#define FORCE_INT_ON force_int_on()
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000564
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200565#define SAVE_INT(v) ((v) = suppress_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000566
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000567#define RESTORE_INT(v) do { \
Denys Vlasenkode892052016-10-02 01:49:13 +0200568 barrier(); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200569 suppress_int = (v); \
570 if (suppress_int == 0 && pending_int) \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000571 raise_interrupt(); \
572} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000573
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000574
Denis Vlasenkobc54cff2007-02-23 01:05:52 +0000575/* ============ Stdout/stderr output */
Eric Andersenc470f442003-07-28 09:56:35 +0000576
Eric Andersenc470f442003-07-28 09:56:35 +0000577static void
Denis Vlasenkob012b102007-02-19 22:43:01 +0000578outstr(const char *p, FILE *file)
Denis Vlasenkoe5570da2007-02-19 22:41:55 +0000579{
Denis Vlasenkob012b102007-02-19 22:43:01 +0000580 INT_OFF;
581 fputs(p, file);
582 INT_ON;
583}
584
585static void
586flush_stdout_stderr(void)
587{
588 INT_OFF;
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100589 fflush_all();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000590 INT_ON;
591}
592
Denys Vlasenko9c541002015-10-07 15:44:36 +0200593/* Was called outcslow(c,FILE*), but c was always '\n' */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000594static void
Denys Vlasenko9c541002015-10-07 15:44:36 +0200595newline_and_flush(FILE *dest)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000596{
597 INT_OFF;
Denys Vlasenko9c541002015-10-07 15:44:36 +0200598 putc('\n', dest);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000599 fflush(dest);
600 INT_ON;
601}
602
603static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
604static int
605out1fmt(const char *fmt, ...)
606{
607 va_list ap;
608 int r;
609
610 INT_OFF;
611 va_start(ap, fmt);
612 r = vprintf(fmt, ap);
613 va_end(ap);
614 INT_ON;
615 return r;
616}
617
618static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
619static int
620fmtstr(char *outbuf, size_t length, const char *fmt, ...)
621{
622 va_list ap;
623 int ret;
624
625 va_start(ap, fmt);
626 INT_OFF;
627 ret = vsnprintf(outbuf, length, fmt, ap);
628 va_end(ap);
629 INT_ON;
630 return ret;
631}
632
633static void
634out1str(const char *p)
635{
636 outstr(p, stdout);
637}
638
639static void
640out2str(const char *p)
641{
642 outstr(p, stderr);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100643 flush_stdout_stderr();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000644}
645
646
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000647/* ============ Parser structures */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +0000648
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000649/* control characters in argument strings */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100650#define CTL_FIRST CTLESC
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200651#define CTLESC ((unsigned char)'\201') /* escape next character */
652#define CTLVAR ((unsigned char)'\202') /* variable defn */
653#define CTLENDVAR ((unsigned char)'\203')
654#define CTLBACKQ ((unsigned char)'\204')
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200655#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
656#define CTLENDARI ((unsigned char)'\207')
657#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100658#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000659
660/* variable substitution byte (follows CTLVAR) */
661#define VSTYPE 0x0f /* type of variable substitution */
662#define VSNUL 0x10 /* colon--treat the empty string as unset */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000663
664/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000665#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
666#define VSMINUS 0x2 /* ${var-text} */
667#define VSPLUS 0x3 /* ${var+text} */
668#define VSQUESTION 0x4 /* ${var?message} */
669#define VSASSIGN 0x5 /* ${var=text} */
670#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
671#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
672#define VSTRIMLEFT 0x8 /* ${var#pattern} */
673#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
674#define VSLENGTH 0xa /* ${#var} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100675#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000676#define VSSUBSTR 0xc /* ${var:position:length} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100677#endif
678#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000679#define VSREPLACE 0xd /* ${var/pattern/replacement} */
680#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
681#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000682
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000683static const char dolatstr[] ALIGN1 = {
Ron Yorston549deab2015-05-18 09:57:51 +0200684 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000685};
Ron Yorston549deab2015-05-18 09:57:51 +0200686#define DOLATSTRLEN 6
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000687
Denis Vlasenko559691a2008-10-05 18:39:31 +0000688#define NCMD 0
689#define NPIPE 1
690#define NREDIR 2
691#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000692#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000693#define NAND 5
694#define NOR 6
695#define NSEMI 7
696#define NIF 8
697#define NWHILE 9
698#define NUNTIL 10
699#define NFOR 11
700#define NCASE 12
701#define NCLIST 13
702#define NDEFUN 14
703#define NARG 15
704#define NTO 16
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100705#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +0000706#define NTO2 17
707#endif
708#define NCLOBBER 18
709#define NFROM 19
710#define NFROMTO 20
711#define NAPPEND 21
712#define NTOFD 22
713#define NFROMFD 23
714#define NHERE 24
715#define NXHERE 25
716#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000717#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000718
719union node;
720
721struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000722 smallint type; /* Nxxxx */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000723 union node *assign;
724 union node *args;
725 union node *redirect;
726};
727
728struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000729 smallint type;
730 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000731 struct nodelist *cmdlist;
732};
733
734struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000735 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000736 union node *n;
737 union node *redirect;
738};
739
740struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000741 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000742 union node *ch1;
743 union node *ch2;
744};
745
746struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000747 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000748 union node *test;
749 union node *ifpart;
750 union node *elsepart;
751};
752
753struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000754 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000755 union node *args;
756 union node *body;
757 char *var;
758};
759
760struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000761 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000762 union node *expr;
763 union node *cases;
764};
765
766struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000767 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000768 union node *next;
769 union node *pattern;
770 union node *body;
771};
772
773struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000774 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000775 union node *next;
776 char *text;
777 struct nodelist *backquote;
778};
779
Denis Vlasenko559691a2008-10-05 18:39:31 +0000780/* nfile and ndup layout must match!
781 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
782 * that it is actually NTO2 (>&file), and change its type.
783 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000784struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000785 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000786 union node *next;
787 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000788 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000789 union node *fname;
790 char *expfname;
791};
792
793struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000794 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000795 union node *next;
796 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000797 int dupfd;
798 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000799 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000800};
801
802struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000803 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000804 union node *next;
805 int fd;
806 union node *doc;
807};
808
809struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000810 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000811 union node *com;
812};
813
814union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000815 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000816 struct ncmd ncmd;
817 struct npipe npipe;
818 struct nredir nredir;
819 struct nbinary nbinary;
820 struct nif nif;
821 struct nfor nfor;
822 struct ncase ncase;
823 struct nclist nclist;
824 struct narg narg;
825 struct nfile nfile;
826 struct ndup ndup;
827 struct nhere nhere;
828 struct nnot nnot;
829};
830
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200831/*
832 * NODE_EOF is returned by parsecmd when it encounters an end of file.
833 * It must be distinct from NULL.
834 */
835#define NODE_EOF ((union node *) -1L)
836
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000837struct nodelist {
838 struct nodelist *next;
839 union node *n;
840};
841
842struct funcnode {
843 int count;
844 union node n;
845};
846
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000847/*
848 * Free a parse tree.
849 */
850static void
851freefunc(struct funcnode *f)
852{
853 if (f && --f->count < 0)
854 free(f);
855}
856
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000857
858/* ============ Debugging output */
859
860#if DEBUG
861
862static FILE *tracefile;
863
864static void
865trace_printf(const char *fmt, ...)
866{
867 va_list va;
868
869 if (debug != 1)
870 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000871 if (DEBUG_TIME)
872 fprintf(tracefile, "%u ", (int) time(NULL));
873 if (DEBUG_PID)
874 fprintf(tracefile, "[%u] ", (int) getpid());
875 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200876 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000877 va_start(va, fmt);
878 vfprintf(tracefile, fmt, va);
879 va_end(va);
880}
881
882static void
883trace_vprintf(const char *fmt, va_list va)
884{
885 if (debug != 1)
886 return;
887 vfprintf(tracefile, fmt, va);
Denys Vlasenko474ed062016-10-30 18:30:29 +0100888 fprintf(tracefile, "\n");
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000889}
890
891static void
892trace_puts(const char *s)
893{
894 if (debug != 1)
895 return;
896 fputs(s, tracefile);
897}
898
899static void
900trace_puts_quoted(char *s)
901{
902 char *p;
903 char c;
904
905 if (debug != 1)
906 return;
907 putc('"', tracefile);
908 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100909 switch ((unsigned char)*p) {
910 case '\n': c = 'n'; goto backslash;
911 case '\t': c = 't'; goto backslash;
912 case '\r': c = 'r'; goto backslash;
913 case '\"': c = '\"'; goto backslash;
914 case '\\': c = '\\'; goto backslash;
915 case CTLESC: c = 'e'; goto backslash;
916 case CTLVAR: c = 'v'; goto backslash;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100917 case CTLBACKQ: c = 'q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000918 backslash:
919 putc('\\', tracefile);
920 putc(c, tracefile);
921 break;
922 default:
923 if (*p >= ' ' && *p <= '~')
924 putc(*p, tracefile);
925 else {
926 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +0100927 putc((*p >> 6) & 03, tracefile);
928 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000929 putc(*p & 07, tracefile);
930 }
931 break;
932 }
933 }
934 putc('"', tracefile);
935}
936
937static void
938trace_puts_args(char **ap)
939{
940 if (debug != 1)
941 return;
942 if (!*ap)
943 return;
944 while (1) {
945 trace_puts_quoted(*ap);
946 if (!*++ap) {
947 putc('\n', tracefile);
948 break;
949 }
950 putc(' ', tracefile);
951 }
952}
953
954static void
955opentrace(void)
956{
957 char s[100];
958#ifdef O_APPEND
959 int flags;
960#endif
961
962 if (debug != 1) {
963 if (tracefile)
964 fflush(tracefile);
965 /* leave open because libedit might be using it */
966 return;
967 }
968 strcpy(s, "./trace");
969 if (tracefile) {
970 if (!freopen(s, "a", tracefile)) {
971 fprintf(stderr, "Can't re-open %s\n", s);
972 debug = 0;
973 return;
974 }
975 } else {
976 tracefile = fopen(s, "a");
977 if (tracefile == NULL) {
978 fprintf(stderr, "Can't open %s\n", s);
979 debug = 0;
980 return;
981 }
982 }
983#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000984 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000985 if (flags >= 0)
986 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
987#endif
988 setlinebuf(tracefile);
989 fputs("\nTracing started.\n", tracefile);
990}
991
992static void
993indent(int amount, char *pfx, FILE *fp)
994{
995 int i;
996
997 for (i = 0; i < amount; i++) {
998 if (pfx && i == amount - 1)
999 fputs(pfx, fp);
1000 putc('\t', fp);
1001 }
1002}
1003
1004/* little circular references here... */
1005static void shtree(union node *n, int ind, char *pfx, FILE *fp);
1006
1007static void
1008sharg(union node *arg, FILE *fp)
1009{
1010 char *p;
1011 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001012 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001013
1014 if (arg->type != NARG) {
1015 out1fmt("<node type %d>\n", arg->type);
1016 abort();
1017 }
1018 bqlist = arg->narg.backquote;
1019 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01001020 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001021 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -07001022 p++;
1023 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001024 break;
1025 case CTLVAR:
1026 putc('$', fp);
1027 putc('{', fp);
1028 subtype = *++p;
1029 if (subtype == VSLENGTH)
1030 putc('#', fp);
1031
Dan Fandrich77d48722010-09-07 23:38:28 -07001032 while (*p != '=') {
1033 putc(*p, fp);
1034 p++;
1035 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001036
1037 if (subtype & VSNUL)
1038 putc(':', fp);
1039
1040 switch (subtype & VSTYPE) {
1041 case VSNORMAL:
1042 putc('}', fp);
1043 break;
1044 case VSMINUS:
1045 putc('-', fp);
1046 break;
1047 case VSPLUS:
1048 putc('+', fp);
1049 break;
1050 case VSQUESTION:
1051 putc('?', fp);
1052 break;
1053 case VSASSIGN:
1054 putc('=', fp);
1055 break;
1056 case VSTRIMLEFT:
1057 putc('#', fp);
1058 break;
1059 case VSTRIMLEFTMAX:
1060 putc('#', fp);
1061 putc('#', fp);
1062 break;
1063 case VSTRIMRIGHT:
1064 putc('%', fp);
1065 break;
1066 case VSTRIMRIGHTMAX:
1067 putc('%', fp);
1068 putc('%', fp);
1069 break;
1070 case VSLENGTH:
1071 break;
1072 default:
1073 out1fmt("<subtype %d>", subtype);
1074 }
1075 break;
1076 case CTLENDVAR:
1077 putc('}', fp);
1078 break;
1079 case CTLBACKQ:
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001080 putc('$', fp);
1081 putc('(', fp);
1082 shtree(bqlist->n, -1, NULL, fp);
1083 putc(')', fp);
1084 break;
1085 default:
1086 putc(*p, fp);
1087 break;
1088 }
1089 }
1090}
1091
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001092static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001093shcmd(union node *cmd, FILE *fp)
1094{
1095 union node *np;
1096 int first;
1097 const char *s;
1098 int dftfd;
1099
1100 first = 1;
1101 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001102 if (!first)
1103 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001104 sharg(np, fp);
1105 first = 0;
1106 }
1107 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001108 if (!first)
1109 putc(' ', fp);
1110 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001111 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001112 case NTO: s = ">>"+1; dftfd = 1; break;
1113 case NCLOBBER: s = ">|"; dftfd = 1; break;
1114 case NAPPEND: s = ">>"; dftfd = 1; break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01001115#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00001116 case NTO2:
1117#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001118 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001119 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001120 case NFROMFD: s = "<&"; break;
1121 case NFROMTO: s = "<>"; break;
1122 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001123 }
1124 if (np->nfile.fd != dftfd)
1125 fprintf(fp, "%d", np->nfile.fd);
1126 fputs(s, fp);
1127 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1128 fprintf(fp, "%d", np->ndup.dupfd);
1129 } else {
1130 sharg(np->nfile.fname, fp);
1131 }
1132 first = 0;
1133 }
1134}
1135
1136static void
1137shtree(union node *n, int ind, char *pfx, FILE *fp)
1138{
1139 struct nodelist *lp;
1140 const char *s;
1141
1142 if (n == NULL)
1143 return;
1144
1145 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001146
1147 if (n == NODE_EOF) {
1148 fputs("<EOF>", fp);
1149 return;
1150 }
1151
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001152 switch (n->type) {
1153 case NSEMI:
1154 s = "; ";
1155 goto binop;
1156 case NAND:
1157 s = " && ";
1158 goto binop;
1159 case NOR:
1160 s = " || ";
1161 binop:
1162 shtree(n->nbinary.ch1, ind, NULL, fp);
1163 /* if (ind < 0) */
1164 fputs(s, fp);
1165 shtree(n->nbinary.ch2, ind, NULL, fp);
1166 break;
1167 case NCMD:
1168 shcmd(n, fp);
1169 if (ind >= 0)
1170 putc('\n', fp);
1171 break;
1172 case NPIPE:
1173 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001174 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001175 if (lp->next)
1176 fputs(" | ", fp);
1177 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001178 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001179 fputs(" &", fp);
1180 if (ind >= 0)
1181 putc('\n', fp);
1182 break;
1183 default:
1184 fprintf(fp, "<node type %d>", n->type);
1185 if (ind >= 0)
1186 putc('\n', fp);
1187 break;
1188 }
1189}
1190
1191static void
1192showtree(union node *n)
1193{
1194 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001195 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001196}
1197
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001198#endif /* DEBUG */
1199
1200
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001201/* ============ Parser data */
1202
1203/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001204 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1205 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001206struct strlist {
1207 struct strlist *next;
1208 char *text;
1209};
1210
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001211struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001212
Denis Vlasenkob012b102007-02-19 22:43:01 +00001213struct strpush {
1214 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001215 char *prev_string;
1216 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001217#if ENABLE_ASH_ALIAS
1218 struct alias *ap; /* if push was associated with an alias */
1219#endif
1220 char *string; /* remember the string since it may change */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001221
1222 /* Remember last two characters for pungetc. */
1223 int lastc[2];
1224
1225 /* Number of outstanding calls to pungetc. */
1226 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001227};
1228
1229struct parsefile {
1230 struct parsefile *prev; /* preceding file on stack */
1231 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001232 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001233 int left_in_line; /* number of chars left in this line */
1234 int left_in_buffer; /* number of chars left in this buffer past the line */
1235 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001236 char *buf; /* input buffer */
1237 struct strpush *strpush; /* for pushing strings at this level */
1238 struct strpush basestrpush; /* so pushing one is fast */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001239
1240 /* Remember last two characters for pungetc. */
1241 int lastc[2];
1242
1243 /* Number of outstanding calls to pungetc. */
1244 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001245};
1246
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001247static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001248static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001249static int startlinno; /* line # where last token started */
1250static char *commandname; /* currently executing command */
1251static struct strlist *cmdenviron; /* environment for builtin command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001252
1253
1254/* ============ Message printing */
1255
1256static void
1257ash_vmsg(const char *msg, va_list ap)
1258{
1259 fprintf(stderr, "%s: ", arg0);
1260 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001261 if (strcmp(arg0, commandname))
1262 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001263 if (!iflag || g_parsefile->pf_fd > 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001264 fprintf(stderr, "line %d: ", startlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001265 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001266 vfprintf(stderr, msg, ap);
Denys Vlasenko9c541002015-10-07 15:44:36 +02001267 newline_and_flush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001268}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001269
1270/*
1271 * Exverror is called to raise the error exception. If the second argument
1272 * is not NULL then error prints an error message using printf style
1273 * formatting. It then raises the error exception.
1274 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001275static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001276static void
1277ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001278{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001279#if DEBUG
1280 if (msg) {
Denys Vlasenko474ed062016-10-30 18:30:29 +01001281 TRACE(("ash_vmsg_and_raise(%d):", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001282 TRACEV((msg, ap));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001283 } else
Denys Vlasenko474ed062016-10-30 18:30:29 +01001284 TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001285 if (msg)
1286#endif
1287 ash_vmsg(msg, ap);
1288
1289 flush_stdout_stderr();
1290 raise_exception(cond);
1291 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001292}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001293
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001294static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001295static void
1296ash_msg_and_raise_error(const char *msg, ...)
1297{
1298 va_list ap;
1299
Ron Yorstonea7d2f62017-01-03 11:18:23 +01001300 exitstatus = 2;
1301
Denis Vlasenkob012b102007-02-19 22:43:01 +00001302 va_start(ap, msg);
1303 ash_vmsg_and_raise(EXERROR, msg, ap);
1304 /* NOTREACHED */
1305 va_end(ap);
1306}
1307
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001308static void raise_error_syntax(const char *) NORETURN;
1309static void
1310raise_error_syntax(const char *msg)
1311{
1312 ash_msg_and_raise_error("syntax error: %s", msg);
1313 /* NOTREACHED */
1314}
1315
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001316static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001317static void
1318ash_msg_and_raise(int cond, const char *msg, ...)
1319{
1320 va_list ap;
1321
1322 va_start(ap, msg);
1323 ash_vmsg_and_raise(cond, msg, ap);
1324 /* NOTREACHED */
1325 va_end(ap);
1326}
1327
1328/*
1329 * error/warning routines for external builtins
1330 */
1331static void
1332ash_msg(const char *fmt, ...)
1333{
1334 va_list ap;
1335
1336 va_start(ap, fmt);
1337 ash_vmsg(fmt, ap);
1338 va_end(ap);
1339}
1340
1341/*
1342 * Return a string describing an error. The returned string may be a
1343 * pointer to a static buffer that will be overwritten on the next call.
1344 * Action describes the operation that got the error.
1345 */
1346static const char *
1347errmsg(int e, const char *em)
1348{
1349 if (e == ENOENT || e == ENOTDIR) {
1350 return em;
1351 }
1352 return strerror(e);
1353}
1354
1355
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001356/* ============ Memory allocation */
1357
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001358#if 0
1359/* I consider these wrappers nearly useless:
1360 * ok, they return you to nearest exception handler, but
1361 * how much memory do you leak in the process, making
1362 * memory starvation worse?
1363 */
1364static void *
1365ckrealloc(void * p, size_t nbytes)
1366{
1367 p = realloc(p, nbytes);
1368 if (!p)
1369 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1370 return p;
1371}
1372
1373static void *
1374ckmalloc(size_t nbytes)
1375{
1376 return ckrealloc(NULL, nbytes);
1377}
1378
1379static void *
1380ckzalloc(size_t nbytes)
1381{
1382 return memset(ckmalloc(nbytes), 0, nbytes);
1383}
1384
1385static char *
1386ckstrdup(const char *s)
1387{
1388 char *p = strdup(s);
1389 if (!p)
1390 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1391 return p;
1392}
1393#else
1394/* Using bbox equivalents. They exit if out of memory */
1395# define ckrealloc xrealloc
1396# define ckmalloc xmalloc
1397# define ckzalloc xzalloc
1398# define ckstrdup xstrdup
1399#endif
1400
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001401/*
1402 * It appears that grabstackstr() will barf with such alignments
1403 * because stalloc() will return a string allocated in a new stackblock.
1404 */
1405#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1406enum {
1407 /* Most machines require the value returned from malloc to be aligned
1408 * in some way. The following macro will get this right
1409 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001410 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001411 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001412 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001413};
1414
1415struct stack_block {
1416 struct stack_block *prev;
1417 char space[MINSIZE];
1418};
1419
1420struct stackmark {
1421 struct stack_block *stackp;
1422 char *stacknxt;
1423 size_t stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001424};
1425
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001426
Denis Vlasenko01631112007-12-16 17:20:38 +00001427struct globals_memstack {
1428 struct stack_block *g_stackp; // = &stackbase;
Denis Vlasenko01631112007-12-16 17:20:38 +00001429 char *g_stacknxt; // = stackbase.space;
1430 char *sstrend; // = stackbase.space + MINSIZE;
1431 size_t g_stacknleft; // = MINSIZE;
Denis Vlasenko01631112007-12-16 17:20:38 +00001432 struct stack_block stackbase;
1433};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001434extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1435#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001436#define g_stackp (G_memstack.g_stackp )
Denis Vlasenko01631112007-12-16 17:20:38 +00001437#define g_stacknxt (G_memstack.g_stacknxt )
1438#define sstrend (G_memstack.sstrend )
1439#define g_stacknleft (G_memstack.g_stacknleft)
Denis Vlasenko01631112007-12-16 17:20:38 +00001440#define stackbase (G_memstack.stackbase )
1441#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001442 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1443 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001444 g_stackp = &stackbase; \
1445 g_stacknxt = stackbase.space; \
1446 g_stacknleft = MINSIZE; \
1447 sstrend = stackbase.space + MINSIZE; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001448} while (0)
1449
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001450
Denis Vlasenko01631112007-12-16 17:20:38 +00001451#define stackblock() ((void *)g_stacknxt)
1452#define stackblocksize() g_stacknleft
1453
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001454/*
1455 * Parse trees for commands are allocated in lifo order, so we use a stack
1456 * to make this more efficient, and also to avoid all sorts of exception
1457 * handling code to handle interrupts in the middle of a parse.
1458 *
1459 * The size 504 was chosen because the Ultrix malloc handles that size
1460 * well.
1461 */
1462static void *
1463stalloc(size_t nbytes)
1464{
1465 char *p;
1466 size_t aligned;
1467
1468 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001469 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001470 size_t len;
1471 size_t blocksize;
1472 struct stack_block *sp;
1473
1474 blocksize = aligned;
1475 if (blocksize < MINSIZE)
1476 blocksize = MINSIZE;
1477 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1478 if (len < blocksize)
1479 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1480 INT_OFF;
1481 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001482 sp->prev = g_stackp;
1483 g_stacknxt = sp->space;
1484 g_stacknleft = blocksize;
1485 sstrend = g_stacknxt + blocksize;
1486 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001487 INT_ON;
1488 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001489 p = g_stacknxt;
1490 g_stacknxt += aligned;
1491 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001492 return p;
1493}
1494
Denis Vlasenko597906c2008-02-20 16:38:54 +00001495static void *
1496stzalloc(size_t nbytes)
1497{
1498 return memset(stalloc(nbytes), 0, nbytes);
1499}
1500
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001501static void
1502stunalloc(void *p)
1503{
1504#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001505 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001506 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001507 abort();
1508 }
1509#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001510 g_stacknleft += g_stacknxt - (char *)p;
1511 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001512}
1513
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001514/*
1515 * Like strdup but works with the ash stack.
1516 */
1517static char *
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02001518sstrdup(const char *p)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001519{
1520 size_t len = strlen(p) + 1;
1521 return memcpy(stalloc(len), p, len);
1522}
1523
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001524static inline void
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001525grabstackblock(size_t len)
1526{
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001527 stalloc(len);
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001528}
1529
1530static void
1531pushstackmark(struct stackmark *mark, size_t len)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001532{
Denis Vlasenko01631112007-12-16 17:20:38 +00001533 mark->stackp = g_stackp;
1534 mark->stacknxt = g_stacknxt;
1535 mark->stacknleft = g_stacknleft;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001536 grabstackblock(len);
1537}
1538
1539static void
1540setstackmark(struct stackmark *mark)
1541{
1542 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001543}
1544
1545static void
1546popstackmark(struct stackmark *mark)
1547{
1548 struct stack_block *sp;
1549
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001550 if (!mark->stackp)
1551 return;
1552
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001553 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001554 while (g_stackp != mark->stackp) {
1555 sp = g_stackp;
1556 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001557 free(sp);
1558 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001559 g_stacknxt = mark->stacknxt;
1560 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001561 sstrend = mark->stacknxt + mark->stacknleft;
1562 INT_ON;
1563}
1564
1565/*
1566 * When the parser reads in a string, it wants to stick the string on the
1567 * stack and only adjust the stack pointer when it knows how big the
1568 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1569 * of space on top of the stack and stackblocklen returns the length of
1570 * this block. Growstackblock will grow this space by at least one byte,
1571 * possibly moving it (like realloc). Grabstackblock actually allocates the
1572 * part of the block that has been used.
1573 */
1574static void
1575growstackblock(void)
1576{
1577 size_t newlen;
1578
Denis Vlasenko01631112007-12-16 17:20:38 +00001579 newlen = g_stacknleft * 2;
1580 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001581 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1582 if (newlen < 128)
1583 newlen += 128;
1584
Denis Vlasenko01631112007-12-16 17:20:38 +00001585 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001586 struct stack_block *sp;
1587 struct stack_block *prevstackp;
1588 size_t grosslen;
1589
1590 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001591 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001592 prevstackp = sp->prev;
1593 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1594 sp = ckrealloc(sp, grosslen);
1595 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001596 g_stackp = sp;
1597 g_stacknxt = sp->space;
1598 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001599 sstrend = sp->space + newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001600 INT_ON;
1601 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001602 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001603 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001604 char *p = stalloc(newlen);
1605
1606 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001607 g_stacknxt = memcpy(p, oldspace, oldlen);
1608 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001609 }
1610}
1611
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001612/*
1613 * The following routines are somewhat easier to use than the above.
1614 * The user declares a variable of type STACKSTR, which may be declared
1615 * to be a register. The macro STARTSTACKSTR initializes things. Then
1616 * the user uses the macro STPUTC to add characters to the string. In
1617 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1618 * grown as necessary. When the user is done, she can just leave the
1619 * string there and refer to it using stackblock(). Or she can allocate
1620 * the space for it using grabstackstr(). If it is necessary to allow
1621 * someone else to use the stack temporarily and then continue to grow
1622 * the string, the user should use grabstack to allocate the space, and
1623 * then call ungrabstr(p) to return to the previous mode of operation.
1624 *
1625 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1626 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1627 * is space for at least one character.
1628 */
1629static void *
1630growstackstr(void)
1631{
1632 size_t len = stackblocksize();
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001633 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001634 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001635}
1636
1637/*
1638 * Called from CHECKSTRSPACE.
1639 */
1640static char *
1641makestrspace(size_t newlen, char *p)
1642{
Denis Vlasenko01631112007-12-16 17:20:38 +00001643 size_t len = p - g_stacknxt;
Denys Vlasenko53d6e032016-09-30 11:24:12 +02001644 size_t size;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001645
1646 for (;;) {
1647 size_t nleft;
1648
1649 size = stackblocksize();
1650 nleft = size - len;
1651 if (nleft >= newlen)
1652 break;
1653 growstackblock();
1654 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001655 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001656}
1657
1658static char *
1659stack_nputstr(const char *s, size_t n, char *p)
1660{
1661 p = makestrspace(n, p);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001662 p = (char *)memcpy(p, s, n) + n;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001663 return p;
1664}
1665
1666static char *
1667stack_putstr(const char *s, char *p)
1668{
1669 return stack_nputstr(s, strlen(s), p);
1670}
1671
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001672static char *
1673_STPUTC(int c, char *p)
1674{
1675 if (p == sstrend)
1676 p = growstackstr();
1677 *p++ = c;
1678 return p;
1679}
1680
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001681#define STARTSTACKSTR(p) ((p) = stackblock())
1682#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001683#define CHECKSTRSPACE(n, p) do { \
1684 char *q = (p); \
1685 size_t l = (n); \
1686 size_t m = sstrend - q; \
1687 if (l > m) \
1688 (p) = makestrspace(l, q); \
1689} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001690#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001691#define STACKSTRNUL(p) do { \
1692 if ((p) == sstrend) \
1693 (p) = growstackstr(); \
1694 *(p) = '\0'; \
1695} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001696#define STUNPUTC(p) (--(p))
1697#define STTOPC(p) ((p)[-1])
1698#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001699
1700#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001701#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001702#define stackstrend() ((void *)sstrend)
1703
1704
1705/* ============ String helpers */
1706
1707/*
1708 * prefix -- see if pfx is a prefix of string.
1709 */
1710static char *
1711prefix(const char *string, const char *pfx)
1712{
1713 while (*pfx) {
1714 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001715 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001716 }
1717 return (char *) string;
1718}
1719
1720/*
1721 * Check for a valid number. This should be elsewhere.
1722 */
1723static int
1724is_number(const char *p)
1725{
1726 do {
1727 if (!isdigit(*p))
1728 return 0;
1729 } while (*++p != '\0');
1730 return 1;
1731}
1732
1733/*
1734 * Convert a string of digits to an integer, printing an error message on
1735 * failure.
1736 */
1737static int
1738number(const char *s)
1739{
1740 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001741 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001742 return atoi(s);
1743}
1744
1745/*
1746 * Produce a possibly single quoted string suitable as input to the shell.
1747 * The return string is allocated on the stack.
1748 */
1749static char *
1750single_quote(const char *s)
1751{
1752 char *p;
1753
1754 STARTSTACKSTR(p);
1755
1756 do {
1757 char *q;
1758 size_t len;
1759
1760 len = strchrnul(s, '\'') - s;
1761
1762 q = p = makestrspace(len + 3, p);
1763
1764 *q++ = '\'';
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001765 q = (char *)memcpy(q, s, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001766 *q++ = '\'';
1767 s += len;
1768
1769 STADJUST(q - p, p);
1770
Denys Vlasenkocd716832009-11-28 22:14:02 +01001771 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001772 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001773 len = 0;
1774 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001775
1776 q = p = makestrspace(len + 3, p);
1777
1778 *q++ = '"';
Denys Vlasenkocd716832009-11-28 22:14:02 +01001779 q = (char *)memcpy(q, s - len, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001780 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001781
1782 STADJUST(q - p, p);
1783 } while (*s);
1784
Denys Vlasenkocd716832009-11-28 22:14:02 +01001785 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001786
1787 return stackblock();
1788}
1789
1790
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001791/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001792
1793static char **argptr; /* argument list for builtin commands */
1794static char *optionarg; /* set by nextopt (like getopt) */
1795static char *optptr; /* used by nextopt */
1796
1797/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001798 * XXX - should get rid of. Have all builtins use getopt(3).
1799 * The library getopt must have the BSD extension static variable
1800 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001801 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001802 * Standard option processing (a la getopt) for builtin routines.
1803 * The only argument that is passed to nextopt is the option string;
1804 * the other arguments are unnecessary. It returns the character,
1805 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001806 */
1807static int
1808nextopt(const char *optstring)
1809{
1810 char *p;
1811 const char *q;
1812 char c;
1813
1814 p = optptr;
1815 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001816 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001817 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001818 if (p == NULL)
1819 return '\0';
1820 if (*p != '-')
1821 return '\0';
1822 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001823 return '\0';
1824 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001825 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001826 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001827 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001828 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001829 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001830 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001831 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001832 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001833 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001834 if (*++q == ':')
1835 q++;
1836 }
1837 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001838 if (*p == '\0') {
1839 p = *argptr++;
1840 if (p == NULL)
1841 ash_msg_and_raise_error("no arg for -%c option", c);
1842 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001843 optionarg = p;
1844 p = NULL;
1845 }
1846 optptr = p;
1847 return c;
1848}
1849
1850
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001851/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001852
Denis Vlasenko01631112007-12-16 17:20:38 +00001853/*
1854 * The parsefile structure pointed to by the global variable parsefile
1855 * contains information about the current file being read.
1856 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001857struct shparam {
1858 int nparam; /* # of positional parameters (without $0) */
1859#if ENABLE_ASH_GETOPTS
1860 int optind; /* next parameter to be processed by getopts */
1861 int optoff; /* used by getopts */
1862#endif
1863 unsigned char malloced; /* if parameter list dynamically allocated */
1864 char **p; /* parameter list */
1865};
1866
1867/*
1868 * Free the list of positional parameters.
1869 */
1870static void
1871freeparam(volatile struct shparam *param)
1872{
Denis Vlasenko01631112007-12-16 17:20:38 +00001873 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001874 char **ap, **ap1;
1875 ap = ap1 = param->p;
1876 while (*ap)
1877 free(*ap++);
1878 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001879 }
1880}
1881
1882#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001883static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001884#endif
1885
1886struct var {
1887 struct var *next; /* next entry in hash list */
1888 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001889 const char *var_text; /* name=value */
1890 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001891 /* the variable gets set/unset */
1892};
1893
1894struct localvar {
1895 struct localvar *next; /* next local variable in list */
1896 struct var *vp; /* the variable that was made local */
1897 int flags; /* saved flags */
1898 const char *text; /* saved text */
1899};
1900
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001901/* flags */
1902#define VEXPORT 0x01 /* variable is exported */
1903#define VREADONLY 0x02 /* variable cannot be modified */
1904#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1905#define VTEXTFIXED 0x08 /* text is statically allocated */
1906#define VSTACK 0x10 /* text is allocated on the stack */
1907#define VUNSET 0x20 /* the variable is not set */
1908#define VNOFUNC 0x40 /* don't call the callback function */
1909#define VNOSET 0x80 /* do not set variable - just readonly test */
1910#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001911#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001912# define VDYNAMIC 0x200 /* dynamic variable */
1913#else
1914# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001915#endif
1916
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001917
Denis Vlasenko01631112007-12-16 17:20:38 +00001918/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001919#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001920static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001921change_lc_all(const char *value)
1922{
1923 if (value && *value != '\0')
1924 setlocale(LC_ALL, value);
1925}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001926static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001927change_lc_ctype(const char *value)
1928{
1929 if (value && *value != '\0')
1930 setlocale(LC_CTYPE, value);
1931}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001932#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001933#if ENABLE_ASH_MAIL
1934static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01001935static void changemail(const char *var_value) FAST_FUNC;
1936#else
1937# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001938#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001939static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001940#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001941static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001942#endif
1943
Denis Vlasenko01631112007-12-16 17:20:38 +00001944static const struct {
1945 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001946 const char *var_text;
1947 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00001948} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02001949 /*
1950 * Note: VEXPORT would not work correctly here for NOFORK applets:
1951 * some environment strings may be constant.
1952 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001953 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001954#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001955 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
1956 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001957#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001958 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1959 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1960 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1961 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001962#if ENABLE_ASH_GETOPTS
Denys Vlasenkoe627ac92016-09-30 14:36:59 +02001963 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001964#endif
1965#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001966 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001967#endif
1968#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001969 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
1970 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001971#endif
1972#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001973 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001974#endif
1975};
1976
Denis Vlasenko0b769642008-07-24 07:54:57 +00001977struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00001978
1979struct globals_var {
1980 struct shparam shellparam; /* $@ current positional parameters */
1981 struct redirtab *redirlist;
Denis Vlasenko01631112007-12-16 17:20:38 +00001982 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1983 struct var *vartab[VTABSIZE];
1984 struct var varinit[ARRAY_SIZE(varinit_data)];
1985};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001986extern struct globals_var *const ash_ptr_to_globals_var;
1987#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00001988#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00001989//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00001990#define preverrout_fd (G_var.preverrout_fd)
1991#define vartab (G_var.vartab )
1992#define varinit (G_var.varinit )
1993#define INIT_G_var() do { \
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00001994 unsigned i; \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001995 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1996 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001997 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001998 varinit[i].flags = varinit_data[i].flags; \
1999 varinit[i].var_text = varinit_data[i].var_text; \
2000 varinit[i].var_func = varinit_data[i].var_func; \
Denis Vlasenko01631112007-12-16 17:20:38 +00002001 } \
2002} while (0)
2003
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002004#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002005#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002006# define vmail (&vifs)[1]
2007# define vmpath (&vmail)[1]
2008# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002009#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002010# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002011#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002012#define vps1 (&vpath)[1]
2013#define vps2 (&vps1)[1]
2014#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002015#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002016# define voptind (&vps4)[1]
2017# if ENABLE_ASH_RANDOM_SUPPORT
2018# define vrandom (&voptind)[1]
2019# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002020#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002021# if ENABLE_ASH_RANDOM_SUPPORT
2022# define vrandom (&vps4)[1]
2023# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002024#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002025
2026/*
2027 * The following macros access the values of the above variables.
2028 * They have to skip over the name. They return the null string
2029 * for unset variables.
2030 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002031#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002032#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002033#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002034# define mailval() (vmail.var_text + 5)
2035# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002036# define mpathset() ((vmpath.flags & VUNSET) == 0)
2037#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002038#define pathval() (vpath.var_text + 5)
2039#define ps1val() (vps1.var_text + 4)
2040#define ps2val() (vps2.var_text + 4)
2041#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002042#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002043# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002044#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002045
Denis Vlasenko01631112007-12-16 17:20:38 +00002046#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002047static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002048getoptsreset(const char *value)
2049{
Denys Vlasenkoa513bf32016-10-26 02:03:37 +02002050 shellparam.optind = number(value) ?: 1;
Denis Vlasenko01631112007-12-16 17:20:38 +00002051 shellparam.optoff = -1;
2052}
2053#endif
2054
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002055/*
2056 * Compares two strings up to the first = or '\0'. The first
2057 * string must be terminated by '='; the second may be terminated by
2058 * either '=' or '\0'.
2059 */
2060static int
2061varcmp(const char *p, const char *q)
2062{
2063 int c, d;
2064
2065 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002066 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002067 goto out;
2068 p++;
2069 q++;
2070 }
2071 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002072 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002073 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002074 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002075 out:
2076 return c - d;
2077}
2078
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002079/*
2080 * Find the appropriate entry in the hash table from the name.
2081 */
2082static struct var **
2083hashvar(const char *p)
2084{
2085 unsigned hashval;
2086
2087 hashval = ((unsigned char) *p) << 4;
2088 while (*p && *p != '=')
2089 hashval += (unsigned char) *p++;
2090 return &vartab[hashval % VTABSIZE];
2091}
2092
2093static int
2094vpcmp(const void *a, const void *b)
2095{
2096 return varcmp(*(const char **)a, *(const char **)b);
2097}
2098
2099/*
2100 * This routine initializes the builtin variables.
2101 */
2102static void
2103initvar(void)
2104{
2105 struct var *vp;
2106 struct var *end;
2107 struct var **vpp;
2108
2109 /*
2110 * PS1 depends on uid
2111 */
2112#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002113 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002114#else
2115 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002116 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002117#endif
2118 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002119 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002120 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002121 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002122 vp->next = *vpp;
2123 *vpp = vp;
2124 } while (++vp < end);
2125}
2126
2127static struct var **
2128findvar(struct var **vpp, const char *name)
2129{
2130 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002131 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002132 break;
2133 }
2134 }
2135 return vpp;
2136}
2137
2138/*
2139 * Find the value of a variable. Returns NULL if not set.
2140 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002141static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002142lookupvar(const char *name)
2143{
2144 struct var *v;
2145
2146 v = *findvar(hashvar(name), name);
2147 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002148#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002149 /*
2150 * Dynamic variables are implemented roughly the same way they are
2151 * in bash. Namely, they're "special" so long as they aren't unset.
2152 * As soon as they're unset, they're no longer dynamic, and dynamic
2153 * lookup will no longer happen at that point. -- PFM.
2154 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002155 if (v->flags & VDYNAMIC)
2156 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002157#endif
2158 if (!(v->flags & VUNSET))
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002159 return var_end(v->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002160 }
2161 return NULL;
2162}
2163
Denys Vlasenko0b883582016-12-23 16:49:07 +01002164#if ENABLE_UNICODE_SUPPORT
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02002165static void
2166reinit_unicode_for_ash(void)
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002167{
2168 /* Unicode support should be activated even if LANG is set
2169 * _during_ shell execution, not only if it was set when
2170 * shell was started. Therefore, re-check LANG every time:
2171 */
2172 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2173 || ENABLE_UNICODE_USING_LOCALE
2174 ) {
2175 const char *s = lookupvar("LC_ALL");
2176 if (!s) s = lookupvar("LC_CTYPE");
2177 if (!s) s = lookupvar("LANG");
2178 reinit_unicode(s);
2179 }
2180}
Denys Vlasenko0b883582016-12-23 16:49:07 +01002181#else
2182# define reinit_unicode_for_ash() ((void)0)
2183#endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002184
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002185/*
2186 * Search the environment of a builtin command.
2187 */
Mike Frysinger98c52642009-04-02 10:02:37 +00002188static const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002189bltinlookup(const char *name)
2190{
2191 struct strlist *sp;
2192
2193 for (sp = cmdenviron; sp; sp = sp->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002194 if (varcmp(sp->text, name) == 0)
2195 return var_end(sp->text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002196 }
2197 return lookupvar(name);
2198}
2199
2200/*
2201 * Same as setvar except that the variable and value are passed in
2202 * the first argument as name=value. Since the first argument will
2203 * be actually stored in the table, it should not be a string that
2204 * will go away.
2205 * Called with interrupts off.
2206 */
2207static void
2208setvareq(char *s, int flags)
2209{
2210 struct var *vp, **vpp;
2211
2212 vpp = hashvar(s);
2213 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2214 vp = *findvar(vpp, s);
2215 if (vp) {
2216 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2217 const char *n;
2218
2219 if (flags & VNOSAVE)
2220 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002221 n = vp->var_text;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02002222 exitstatus = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002223 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2224 }
2225
2226 if (flags & VNOSET)
2227 return;
2228
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002229 if (vp->var_func && !(flags & VNOFUNC))
2230 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002231
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002232 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2233 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002234
2235 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2236 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002237 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002238 if (flags & VNOSET)
2239 return;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002240 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002241 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002242 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002243 *vpp = vp;
2244 }
2245 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2246 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002247 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002248 vp->flags = flags;
2249}
2250
2251/*
2252 * Set the value of a variable. The flags argument is ored with the
2253 * flags of the variable. If val is NULL, the variable is unset.
2254 */
2255static void
2256setvar(const char *name, const char *val, int flags)
2257{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002258 const char *q;
2259 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002260 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002261 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002262 size_t vallen;
2263
2264 q = endofname(name);
2265 p = strchrnul(q, '=');
2266 namelen = p - name;
2267 if (!namelen || p != q)
2268 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2269 vallen = 0;
2270 if (val == NULL) {
2271 flags |= VUNSET;
2272 } else {
2273 vallen = strlen(val);
2274 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002275
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002276 INT_OFF;
2277 nameeq = ckmalloc(namelen + vallen + 2);
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002278 p = memcpy(nameeq, name, namelen) + namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002279 if (val) {
2280 *p++ = '=';
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002281 p = memcpy(p, val, vallen) + vallen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002282 }
2283 *p = '\0';
2284 setvareq(nameeq, flags | VNOSAVE);
2285 INT_ON;
2286}
2287
Denys Vlasenko03dad222010-01-12 23:29:57 +01002288static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002289setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002290{
2291 setvar(name, val, 0);
2292}
2293
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002294/*
2295 * Unset the specified variable.
2296 */
2297static int
2298unsetvar(const char *s)
2299{
2300 struct var **vpp;
2301 struct var *vp;
2302 int retval;
2303
2304 vpp = findvar(hashvar(s), s);
2305 vp = *vpp;
2306 retval = 2;
2307 if (vp) {
2308 int flags = vp->flags;
2309
2310 retval = 1;
2311 if (flags & VREADONLY)
2312 goto out;
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002313#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002314 vp->flags &= ~VDYNAMIC;
2315#endif
2316 if (flags & VUNSET)
2317 goto ok;
2318 if ((flags & VSTRFIXED) == 0) {
2319 INT_OFF;
2320 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002321 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002322 *vpp = vp->next;
2323 free(vp);
2324 INT_ON;
2325 } else {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002326 setvar0(s, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002327 vp->flags &= ~VEXPORT;
2328 }
2329 ok:
2330 retval = 0;
2331 }
2332 out:
2333 return retval;
2334}
2335
2336/*
2337 * Process a linked list of variable assignments.
2338 */
2339static void
2340listsetvar(struct strlist *list_set_var, int flags)
2341{
2342 struct strlist *lp = list_set_var;
2343
2344 if (!lp)
2345 return;
2346 INT_OFF;
2347 do {
2348 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002349 lp = lp->next;
2350 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002351 INT_ON;
2352}
2353
2354/*
2355 * Generate a list of variables satisfying the given conditions.
2356 */
2357static char **
2358listvars(int on, int off, char ***end)
2359{
2360 struct var **vpp;
2361 struct var *vp;
2362 char **ep;
2363 int mask;
2364
2365 STARTSTACKSTR(ep);
2366 vpp = vartab;
2367 mask = on | off;
2368 do {
2369 for (vp = *vpp; vp; vp = vp->next) {
2370 if ((vp->flags & mask) == on) {
2371 if (ep == stackstrend())
2372 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002373 *ep++ = (char*)vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002374 }
2375 }
2376 } while (++vpp < vartab + VTABSIZE);
2377 if (ep == stackstrend())
2378 ep = growstackstr();
2379 if (end)
2380 *end = ep;
2381 *ep++ = NULL;
2382 return grabstackstr(ep);
2383}
2384
2385
2386/* ============ Path search helper
2387 *
2388 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002389 * of the path before the first call; path_advance will update
2390 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002391 * the possible path expansions in sequence. If an option (indicated by
2392 * a percent sign) appears in the path entry then the global variable
2393 * pathopt will be set to point to it; otherwise pathopt will be set to
2394 * NULL.
2395 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002396static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002397
2398static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002399path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002400{
2401 const char *p;
2402 char *q;
2403 const char *start;
2404 size_t len;
2405
2406 if (*path == NULL)
2407 return NULL;
2408 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002409 for (p = start; *p && *p != ':' && *p != '%'; p++)
2410 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002411 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2412 while (stackblocksize() < len)
2413 growstackblock();
2414 q = stackblock();
2415 if (p != start) {
2416 memcpy(q, start, p - start);
2417 q += p - start;
2418 *q++ = '/';
2419 }
2420 strcpy(q, name);
2421 pathopt = NULL;
2422 if (*p == '%') {
2423 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002424 while (*p && *p != ':')
2425 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002426 }
2427 if (*p == ':')
2428 *path = p + 1;
2429 else
2430 *path = NULL;
2431 return stalloc(len);
2432}
2433
2434
2435/* ============ Prompt */
2436
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002437static smallint doprompt; /* if set, prompt the user */
2438static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002439
2440#if ENABLE_FEATURE_EDITING
2441static line_input_t *line_input_state;
2442static const char *cmdedit_prompt;
2443static void
2444putprompt(const char *s)
2445{
2446 if (ENABLE_ASH_EXPAND_PRMT) {
2447 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002448 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002449 return;
2450 }
2451 cmdedit_prompt = s;
2452}
2453#else
2454static void
2455putprompt(const char *s)
2456{
2457 out2str(s);
2458}
2459#endif
2460
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002461/* expandstr() needs parsing machinery, so it is far away ahead... */
2462static const char *expandstr(const char *ps);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002463
2464static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002465setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002466{
2467 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002468 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2469
2470 if (!do_set)
2471 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002472
2473 needprompt = 0;
2474
2475 switch (whichprompt) {
2476 case 1:
2477 prompt = ps1val();
2478 break;
2479 case 2:
2480 prompt = ps2val();
2481 break;
2482 default: /* 0 */
2483 prompt = nullstr;
2484 }
2485#if ENABLE_ASH_EXPAND_PRMT
Denys Vlasenko60ca8342016-09-30 11:21:21 +02002486 pushstackmark(&smark, stackblocksize());
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002487 putprompt(expandstr(prompt));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002488 popstackmark(&smark);
Denys Vlasenko48c803a2017-07-01 23:24:48 +02002489#else
2490 putprompt(prompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002491#endif
2492}
2493
2494
2495/* ============ The cd and pwd commands */
2496
2497#define CD_PHYSICAL 1
2498#define CD_PRINT 2
2499
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002500static int
2501cdopt(void)
2502{
2503 int flags = 0;
2504 int i, j;
2505
2506 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002507 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002508 if (i != j) {
2509 flags ^= CD_PHYSICAL;
2510 j = i;
2511 }
2512 }
2513
2514 return flags;
2515}
2516
2517/*
2518 * Update curdir (the name of the current directory) in response to a
2519 * cd command.
2520 */
2521static const char *
2522updatepwd(const char *dir)
2523{
2524 char *new;
2525 char *p;
2526 char *cdcomppath;
2527 const char *lim;
2528
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02002529 cdcomppath = sstrdup(dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002530 STARTSTACKSTR(new);
2531 if (*dir != '/') {
2532 if (curdir == nullstr)
2533 return 0;
2534 new = stack_putstr(curdir, new);
2535 }
2536 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002537 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002538 if (*dir != '/') {
2539 if (new[-1] != '/')
2540 USTPUTC('/', new);
2541 if (new > lim && *lim == '/')
2542 lim++;
2543 } else {
2544 USTPUTC('/', new);
2545 cdcomppath++;
2546 if (dir[1] == '/' && dir[2] != '/') {
2547 USTPUTC('/', new);
2548 cdcomppath++;
2549 lim++;
2550 }
2551 }
2552 p = strtok(cdcomppath, "/");
2553 while (p) {
2554 switch (*p) {
2555 case '.':
2556 if (p[1] == '.' && p[2] == '\0') {
2557 while (new > lim) {
2558 STUNPUTC(new);
2559 if (new[-1] == '/')
2560 break;
2561 }
2562 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002563 }
2564 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002565 break;
2566 /* fall through */
2567 default:
2568 new = stack_putstr(p, new);
2569 USTPUTC('/', new);
2570 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002571 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002572 }
2573 if (new > lim)
2574 STUNPUTC(new);
2575 *new = 0;
2576 return stackblock();
2577}
2578
2579/*
2580 * Find out what the current directory is. If we already know the current
2581 * directory, this routine returns immediately.
2582 */
2583static char *
2584getpwd(void)
2585{
Denis Vlasenko01631112007-12-16 17:20:38 +00002586 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002587 return dir ? dir : nullstr;
2588}
2589
2590static void
2591setpwd(const char *val, int setold)
2592{
2593 char *oldcur, *dir;
2594
2595 oldcur = dir = curdir;
2596
2597 if (setold) {
2598 setvar("OLDPWD", oldcur, VEXPORT);
2599 }
2600 INT_OFF;
2601 if (physdir != nullstr) {
2602 if (physdir != oldcur)
2603 free(physdir);
2604 physdir = nullstr;
2605 }
2606 if (oldcur == val || !val) {
2607 char *s = getpwd();
2608 physdir = s;
2609 if (!val)
2610 dir = s;
2611 } else
2612 dir = ckstrdup(val);
2613 if (oldcur != dir && oldcur != nullstr) {
2614 free(oldcur);
2615 }
2616 curdir = dir;
2617 INT_ON;
2618 setvar("PWD", dir, VEXPORT);
2619}
2620
2621static void hashcd(void);
2622
2623/*
Denys Vlasenko70392332016-10-27 02:31:55 +02002624 * Actually do the chdir. We also call hashcd to let other routines
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002625 * know that the current directory has changed.
2626 */
2627static int
2628docd(const char *dest, int flags)
2629{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002630 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002631 int err;
2632
2633 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2634
2635 INT_OFF;
2636 if (!(flags & CD_PHYSICAL)) {
2637 dir = updatepwd(dest);
2638 if (dir)
2639 dest = dir;
2640 }
2641 err = chdir(dest);
2642 if (err)
2643 goto out;
2644 setpwd(dir, 1);
2645 hashcd();
2646 out:
2647 INT_ON;
2648 return err;
2649}
2650
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002651static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002652cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002653{
2654 const char *dest;
2655 const char *path;
2656 const char *p;
2657 char c;
2658 struct stat statb;
2659 int flags;
2660
2661 flags = cdopt();
2662 dest = *argptr;
2663 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002664 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002665 else if (LONE_DASH(dest)) {
2666 dest = bltinlookup("OLDPWD");
2667 flags |= CD_PRINT;
2668 }
2669 if (!dest)
2670 dest = nullstr;
2671 if (*dest == '/')
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002672 goto step6;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002673 if (*dest == '.') {
2674 c = dest[1];
2675 dotdot:
2676 switch (c) {
2677 case '\0':
2678 case '/':
2679 goto step6;
2680 case '.':
2681 c = dest[2];
2682 if (c != '.')
2683 goto dotdot;
2684 }
2685 }
2686 if (!*dest)
2687 dest = ".";
2688 path = bltinlookup("CDPATH");
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002689 while (path) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002690 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002691 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002692 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2693 if (c && c != ':')
2694 flags |= CD_PRINT;
2695 docd:
2696 if (!docd(p, flags))
2697 goto out;
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002698 goto err;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002699 }
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002700 }
2701
2702 step6:
2703 p = dest;
2704 goto docd;
2705
2706 err:
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002707 ash_msg_and_raise_error("can't cd to %s", dest);
2708 /* NOTREACHED */
2709 out:
2710 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002711 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002712 return 0;
2713}
2714
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002715static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002716pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002717{
2718 int flags;
2719 const char *dir = curdir;
2720
2721 flags = cdopt();
2722 if (flags) {
2723 if (physdir == nullstr)
2724 setpwd(dir, 0);
2725 dir = physdir;
2726 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002727 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002728 return 0;
2729}
2730
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002731
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002732/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002733
Denis Vlasenko834dee72008-10-07 09:18:30 +00002734
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002735#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002736
Eric Andersenc470f442003-07-28 09:56:35 +00002737/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002738#define CWORD 0 /* character is nothing special */
2739#define CNL 1 /* newline character */
2740#define CBACK 2 /* a backslash character */
2741#define CSQUOTE 3 /* single quote */
2742#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002743#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002744#define CBQUOTE 6 /* backwards single quote */
2745#define CVAR 7 /* a dollar sign */
2746#define CENDVAR 8 /* a '}' character */
2747#define CLP 9 /* a left paren in arithmetic */
2748#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002749#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002750#define CCTL 12 /* like CWORD, except it must be escaped */
2751#define CSPCL 13 /* these terminate a word */
2752#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002753
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002754#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002755#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002756# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002757#endif
2758
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002759#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002760
Denys Vlasenko0b883582016-12-23 16:49:07 +01002761#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002762# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002763#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002764# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002765#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002766static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002767#if ENABLE_ASH_ALIAS
2768 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2769#endif
2770 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2771 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2772 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2773 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2774 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2775 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2776 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2777 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2778 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2779 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2780 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002781#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002782 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2783 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2784 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2785#endif
2786#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002787};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002788/* Constants below must match table above */
2789enum {
2790#if ENABLE_ASH_ALIAS
2791 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2792#endif
2793 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2794 CNL_CNL_CNL_CNL , /* 2 */
2795 CWORD_CCTL_CCTL_CWORD , /* 3 */
2796 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2797 CVAR_CVAR_CWORD_CVAR , /* 5 */
2798 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2799 CSPCL_CWORD_CWORD_CLP , /* 7 */
2800 CSPCL_CWORD_CWORD_CRP , /* 8 */
2801 CBACK_CBACK_CCTL_CBACK , /* 9 */
2802 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2803 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2804 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2805 CWORD_CWORD_CWORD_CWORD , /* 13 */
2806 CCTL_CCTL_CCTL_CCTL , /* 14 */
2807};
Eric Andersen2870d962001-07-02 17:27:21 +00002808
Denys Vlasenkocd716832009-11-28 22:14:02 +01002809/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2810 * caller must ensure proper cast on it if c is *char_ptr!
2811 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002812/* Values for syntax param */
2813#define BASESYNTAX 0 /* not in quotes */
2814#define DQSYNTAX 1 /* in double quotes */
2815#define SQSYNTAX 2 /* in single quotes */
2816#define ARISYNTAX 3 /* in arithmetic */
2817#define PSSYNTAX 4 /* prompt. never passed to SIT() */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002818
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002819#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002820
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002821static int
2822SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002823{
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002824 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2825 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2826 /*
2827 * This causes '/' to be prepended with CTLESC in dquoted string,
2828 * making "./file"* treated incorrectly because we feed
2829 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2830 * The "homegrown" glob implementation is okay with that,
2831 * but glibc one isn't. With '/' always treated as CWORD,
2832 * both work fine.
2833 */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002834# if ENABLE_ASH_ALIAS
2835 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002836 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002837 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002838 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2839 11, 3 /* "}~" */
2840 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002841# else
2842 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002843 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002844 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002845 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2846 10, 2 /* "}~" */
2847 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002848# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002849 const char *s;
2850 int indx;
2851
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002852 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002853 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002854# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002855 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002856 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002857 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002858# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002859 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002860 /* Cast is purely for paranoia here,
2861 * just in case someone passed signed char to us */
2862 if ((unsigned char)c >= CTL_FIRST
2863 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002864 ) {
2865 return CCTL;
2866 }
2867 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002868 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002869 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002870 indx = syntax_index_table[s - spec_symbls];
2871 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002872 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002873}
2874
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002875#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002876
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002877static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002878 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002879 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2889 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2890 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2891 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2892 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2893 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2894 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2895 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2896 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2897 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2898 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2899 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2900 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2901 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2902 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2903 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2904 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2905 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2906 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2907 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2908 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2909 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2910 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2911 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2912 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2913 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2914 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2915 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2916 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2917 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2918 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2919 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2920 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2921 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2922 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2923 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2924 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2925 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002926/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
2927 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkocd716832009-11-28 22:14:02 +01002928 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2929 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2939 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2940 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2941 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2942 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2943 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2944 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2972 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2973 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2974 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2977 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2983 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2986 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2987 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2988 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2989 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2990 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2991 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2992 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2993 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2994 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2995 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2996 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2997 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2998 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2999 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
3000 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
3001 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
3002 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
3003 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
3004 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
3005 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3006 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
3007 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
3008 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
3009 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
3010 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
3011 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
3012 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
3013 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
3014 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
3015 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
3016 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3017 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3018 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3019 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3020 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3021 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3029 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3042 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3047 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3112 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3113 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3114 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3115 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3116 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3117 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3118 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3119 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3120 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3121 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3122 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3123 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3124 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3125 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3126 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3127 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3128 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3129 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3130 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3131 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3132 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3133 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3134 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3135 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003136 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003137# if ENABLE_ASH_ALIAS
3138 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3139# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003140};
3141
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003142#if 1
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003143# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003144#else /* debug version, caught one signed char bug */
3145# define SIT(c, syntax) \
3146 ({ \
3147 if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3148 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
Denys Vlasenko0b883582016-12-23 16:49:07 +01003149 if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003150 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3151 ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3152 })
3153#endif
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003154
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003155#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003156
Eric Andersen2870d962001-07-02 17:27:21 +00003157
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003158/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003159
Denis Vlasenko131ae172007-02-18 13:00:19 +00003160#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003161
3162#define ALIASINUSE 1
3163#define ALIASDEAD 2
3164
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003165struct alias {
3166 struct alias *next;
3167 char *name;
3168 char *val;
3169 int flag;
3170};
3171
Denis Vlasenko01631112007-12-16 17:20:38 +00003172
3173static struct alias **atab; // [ATABSIZE];
3174#define INIT_G_alias() do { \
3175 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3176} while (0)
3177
Eric Andersen2870d962001-07-02 17:27:21 +00003178
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003179static struct alias **
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02003180__lookupalias(const char *name)
3181{
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003182 unsigned int hashval;
3183 struct alias **app;
3184 const char *p;
3185 unsigned int ch;
3186
3187 p = name;
3188
3189 ch = (unsigned char)*p;
3190 hashval = ch << 4;
3191 while (ch) {
3192 hashval += ch;
3193 ch = (unsigned char)*++p;
3194 }
3195 app = &atab[hashval % ATABSIZE];
3196
3197 for (; *app; app = &(*app)->next) {
3198 if (strcmp(name, (*app)->name) == 0) {
3199 break;
3200 }
3201 }
3202
3203 return app;
3204}
3205
3206static struct alias *
3207lookupalias(const char *name, int check)
3208{
3209 struct alias *ap = *__lookupalias(name);
3210
3211 if (check && ap && (ap->flag & ALIASINUSE))
3212 return NULL;
3213 return ap;
3214}
3215
3216static struct alias *
3217freealias(struct alias *ap)
3218{
3219 struct alias *next;
3220
3221 if (ap->flag & ALIASINUSE) {
3222 ap->flag |= ALIASDEAD;
3223 return ap;
3224 }
3225
3226 next = ap->next;
3227 free(ap->name);
3228 free(ap->val);
3229 free(ap);
3230 return next;
3231}
Eric Andersencb57d552001-06-28 07:25:16 +00003232
Eric Andersenc470f442003-07-28 09:56:35 +00003233static void
3234setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003235{
3236 struct alias *ap, **app;
3237
3238 app = __lookupalias(name);
3239 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003240 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003241 if (ap) {
3242 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003243 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003244 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003245 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003246 ap->flag &= ~ALIASDEAD;
3247 } else {
3248 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003249 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003250 ap->name = ckstrdup(name);
3251 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003252 /*ap->flag = 0; - ckzalloc did it */
3253 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003254 *app = ap;
3255 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003256 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003257}
3258
Eric Andersenc470f442003-07-28 09:56:35 +00003259static int
3260unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003261{
Eric Andersencb57d552001-06-28 07:25:16 +00003262 struct alias **app;
3263
3264 app = __lookupalias(name);
3265
3266 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003267 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003268 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003269 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003270 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003271 }
3272
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003273 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003274}
3275
Eric Andersenc470f442003-07-28 09:56:35 +00003276static void
3277rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003278{
Eric Andersencb57d552001-06-28 07:25:16 +00003279 struct alias *ap, **app;
3280 int i;
3281
Denis Vlasenkob012b102007-02-19 22:43:01 +00003282 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003283 for (i = 0; i < ATABSIZE; i++) {
3284 app = &atab[i];
3285 for (ap = *app; ap; ap = *app) {
3286 *app = freealias(*app);
3287 if (ap == *app) {
3288 app = &ap->next;
3289 }
3290 }
3291 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003292 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003293}
3294
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003295static void
3296printalias(const struct alias *ap)
3297{
3298 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3299}
3300
Eric Andersencb57d552001-06-28 07:25:16 +00003301/*
3302 * TODO - sort output
3303 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003304static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003305aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003306{
3307 char *n, *v;
3308 int ret = 0;
3309 struct alias *ap;
3310
Denis Vlasenko68404f12008-03-17 09:00:54 +00003311 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003312 int i;
3313
Denis Vlasenko68404f12008-03-17 09:00:54 +00003314 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003315 for (ap = atab[i]; ap; ap = ap->next) {
3316 printalias(ap);
3317 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003318 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003319 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003320 }
3321 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003322 v = strchr(n+1, '=');
3323 if (v == NULL) { /* n+1: funny ksh stuff */
3324 ap = *__lookupalias(n);
3325 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003326 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003327 ret = 1;
3328 } else
3329 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003330 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003331 *v++ = '\0';
3332 setalias(n, v);
3333 }
3334 }
3335
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003336 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003337}
3338
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003339static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003340unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003341{
3342 int i;
3343
Denys Vlasenko6c149f42017-04-12 21:31:32 +02003344 while (nextopt("a") != '\0') {
3345 rmaliases();
3346 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003347 }
3348 for (i = 0; *argptr; argptr++) {
3349 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003350 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003351 i = 1;
3352 }
3353 }
3354
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003355 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003356}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003357
Denis Vlasenko131ae172007-02-18 13:00:19 +00003358#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003359
Eric Andersenc470f442003-07-28 09:56:35 +00003360
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003361/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003362#define FORK_FG 0
3363#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003364#define FORK_NOJOB 2
3365
3366/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003367#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3368#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3369#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003370#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003371
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003372/*
3373 * A job structure contains information about a job. A job is either a
3374 * single process or a set of processes contained in a pipeline. In the
3375 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3376 * array of pids.
3377 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003378struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003379 pid_t ps_pid; /* process id */
3380 int ps_status; /* last process status from wait() */
3381 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003382};
3383
3384struct job {
3385 struct procstat ps0; /* status of process */
3386 struct procstat *ps; /* status or processes when more than one */
3387#if JOBS
3388 int stopstatus; /* status of a stopped job */
3389#endif
Denys Vlasenko4c179372017-01-11 18:44:15 +01003390 unsigned nprocs; /* number of processes */
3391
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003392#define JOBRUNNING 0 /* at least one proc running */
3393#define JOBSTOPPED 1 /* all procs are stopped */
3394#define JOBDONE 2 /* all procs are completed */
Denys Vlasenko4c179372017-01-11 18:44:15 +01003395 unsigned
3396 state: 8,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003397#if JOBS
3398 sigint: 1, /* job was killed by SIGINT */
3399 jobctl: 1, /* job running under job control */
3400#endif
3401 waited: 1, /* true if this entry has been waited for */
3402 used: 1, /* true if this entry is in used */
3403 changed: 1; /* true if status has changed */
3404 struct job *prev_job; /* previous job */
3405};
3406
Denis Vlasenko68404f12008-03-17 09:00:54 +00003407static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003408static int forkshell(struct job *, union node *, int);
3409static int waitforjob(struct job *);
3410
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003411#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003412enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003413#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003414#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003415static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003416static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003417#endif
3418
3419/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003420 * Ignore a signal.
3421 */
3422static void
3423ignoresig(int signo)
3424{
3425 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3426 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3427 /* No, need to do it */
3428 signal(signo, SIG_IGN);
3429 }
3430 sigmode[signo - 1] = S_HARD_IGN;
3431}
3432
3433/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003434 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003435 */
3436static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003437signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003438{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003439 if (signo == SIGCHLD) {
3440 got_sigchld = 1;
3441 if (!trap[SIGCHLD])
3442 return;
3443 }
3444
Denis Vlasenko4b875702009-03-19 13:30:04 +00003445 gotsig[signo - 1] = 1;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003446 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003447
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003448 if (signo == SIGINT && !trap[SIGINT]) {
3449 if (!suppress_int) {
3450 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003451 raise_interrupt(); /* does not return */
3452 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003453 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003454 }
3455}
3456
3457/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003458 * Set the signal handler for the specified signal. The routine figures
3459 * out what it should be set to.
3460 */
3461static void
3462setsignal(int signo)
3463{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003464 char *t;
3465 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003466 struct sigaction act;
3467
3468 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003469 new_act = S_DFL;
3470 if (t != NULL) { /* trap for this sig is set */
3471 new_act = S_CATCH;
3472 if (t[0] == '\0') /* trap is "": ignore this sig */
3473 new_act = S_IGN;
3474 }
3475
3476 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003477 switch (signo) {
3478 case SIGINT:
3479 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003480 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003481 break;
3482 case SIGQUIT:
3483#if DEBUG
3484 if (debug)
3485 break;
3486#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003487 /* man bash:
3488 * "In all cases, bash ignores SIGQUIT. Non-builtin
3489 * commands run by bash have signal handlers
3490 * set to the values inherited by the shell
3491 * from its parent". */
3492 new_act = S_IGN;
3493 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003494 case SIGTERM:
3495 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003496 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003497 break;
3498#if JOBS
3499 case SIGTSTP:
3500 case SIGTTOU:
3501 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003502 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003503 break;
3504#endif
3505 }
3506 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003507//TODO: if !rootshell, we reset SIGQUIT to DFL,
3508//whereas we have to restore it to what shell got on entry
3509//from the parent. See comment above
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003510
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003511 if (signo == SIGCHLD)
3512 new_act = S_CATCH;
3513
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003514 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003515 cur_act = *t;
3516 if (cur_act == 0) {
3517 /* current setting is not yet known */
3518 if (sigaction(signo, NULL, &act)) {
3519 /* pretend it worked; maybe we should give a warning,
3520 * but other shells don't. We don't alter sigmode,
3521 * so we retry every time.
3522 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003523 return;
3524 }
3525 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003526 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003527 if (mflag
3528 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3529 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003530 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003531 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003532 }
3533 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003534 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003535 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003536
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003537 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003538 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003539 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003540 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003541 break;
3542 case S_IGN:
3543 act.sa_handler = SIG_IGN;
3544 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003545 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003546
3547 /* flags and mask matter only if !DFL and !IGN, but we do it
3548 * for all cases for more deterministic behavior:
3549 */
3550 act.sa_flags = 0;
3551 sigfillset(&act.sa_mask);
3552
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003553 sigaction_set(signo, &act);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003554
3555 *t = new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003556}
3557
3558/* mode flags for set_curjob */
3559#define CUR_DELETE 2
3560#define CUR_RUNNING 1
3561#define CUR_STOPPED 0
3562
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003563#if JOBS
3564/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003565static int initialpgrp; //references:2
3566static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003567#endif
3568/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003569static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003570/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003571static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003572/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003573static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003574/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003575static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003576
Denys Vlasenko098b7132017-01-11 19:59:03 +01003577#if 0
3578/* Bash has a feature: it restores termios after a successful wait for
3579 * a foreground job which had at least one stopped or sigkilled member.
3580 * The probable rationale is that SIGSTOP and SIGKILL can preclude task from
3581 * properly restoring tty state. Should we do this too?
3582 * A reproducer: ^Z an interactive python:
3583 *
3584 * # python
3585 * Python 2.7.12 (...)
3586 * >>> ^Z
3587 * { python leaves tty in -icanon -echo state. We do survive that... }
3588 * [1]+ Stopped python
3589 * { ...however, next program (python #2) does not survive it well: }
3590 * # python
3591 * Python 2.7.12 (...)
3592 * >>> Traceback (most recent call last):
3593 * { above, I typed "qwerty<CR>", but -echo state is still in effect }
3594 * File "<stdin>", line 1, in <module>
3595 * NameError: name 'qwerty' is not defined
3596 *
3597 * The implementation below is modeled on bash code and seems to work.
3598 * However, I'm not sure we should do this. For one: what if I'd fg
3599 * the stopped python instead? It'll be confused by "restored" tty state.
3600 */
3601static struct termios shell_tty_info;
3602static void
3603get_tty_state(void)
3604{
3605 if (rootshell && ttyfd >= 0)
3606 tcgetattr(ttyfd, &shell_tty_info);
3607}
3608static void
3609set_tty_state(void)
3610{
3611 /* if (rootshell) - caller ensures this */
3612 if (ttyfd >= 0)
3613 tcsetattr(ttyfd, TCSADRAIN, &shell_tty_info);
3614}
3615static int
3616job_signal_status(struct job *jp)
3617{
3618 int status;
3619 unsigned i;
3620 struct procstat *ps = jp->ps;
3621 for (i = 0; i < jp->nprocs; i++) {
3622 status = ps[i].ps_status;
3623 if (WIFSIGNALED(status) || WIFSTOPPED(status))
3624 return status;
3625 }
3626 return 0;
3627}
3628static void
3629restore_tty_if_stopped_or_signaled(struct job *jp)
3630{
3631//TODO: check what happens if we come from waitforjob() in expbackq()
3632 if (rootshell) {
3633 int s = job_signal_status(jp);
3634 if (s) /* WIFSIGNALED(s) || WIFSTOPPED(s) */
3635 set_tty_state();
3636 }
3637}
3638#else
3639# define get_tty_state() ((void)0)
3640# define restore_tty_if_stopped_or_signaled(jp) ((void)0)
3641#endif
3642
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003643static void
3644set_curjob(struct job *jp, unsigned mode)
3645{
3646 struct job *jp1;
3647 struct job **jpp, **curp;
3648
3649 /* first remove from list */
3650 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003651 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003652 jp1 = *jpp;
3653 if (jp1 == jp)
3654 break;
3655 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003656 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003657 *jpp = jp1->prev_job;
3658
3659 /* Then re-insert in correct position */
3660 jpp = curp;
3661 switch (mode) {
3662 default:
3663#if DEBUG
3664 abort();
3665#endif
3666 case CUR_DELETE:
3667 /* job being deleted */
3668 break;
3669 case CUR_RUNNING:
3670 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003671 * put after all stopped jobs.
3672 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003673 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003674 jp1 = *jpp;
3675#if JOBS
3676 if (!jp1 || jp1->state != JOBSTOPPED)
3677#endif
3678 break;
3679 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003680 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003681 /* FALLTHROUGH */
3682#if JOBS
3683 case CUR_STOPPED:
3684#endif
3685 /* newly stopped job - becomes curjob */
3686 jp->prev_job = *jpp;
3687 *jpp = jp;
3688 break;
3689 }
3690}
3691
3692#if JOBS || DEBUG
3693static int
3694jobno(const struct job *jp)
3695{
3696 return jp - jobtab + 1;
3697}
3698#endif
3699
3700/*
3701 * Convert a job name to a job structure.
3702 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003703#if !JOBS
3704#define getjob(name, getctl) getjob(name)
3705#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003706static struct job *
3707getjob(const char *name, int getctl)
3708{
3709 struct job *jp;
3710 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003711 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003712 unsigned num;
3713 int c;
3714 const char *p;
3715 char *(*match)(const char *, const char *);
3716
3717 jp = curjob;
3718 p = name;
3719 if (!p)
3720 goto currentjob;
3721
3722 if (*p != '%')
3723 goto err;
3724
3725 c = *++p;
3726 if (!c)
3727 goto currentjob;
3728
3729 if (!p[1]) {
3730 if (c == '+' || c == '%') {
3731 currentjob:
3732 err_msg = "No current job";
3733 goto check;
3734 }
3735 if (c == '-') {
3736 if (jp)
3737 jp = jp->prev_job;
3738 err_msg = "No previous job";
3739 check:
3740 if (!jp)
3741 goto err;
3742 goto gotit;
3743 }
3744 }
3745
3746 if (is_number(p)) {
3747 num = atoi(p);
Denys Vlasenko46a45ce2016-09-29 01:10:08 +02003748 if (num > 0 && num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003749 jp = jobtab + num - 1;
3750 if (jp->used)
3751 goto gotit;
3752 goto err;
3753 }
3754 }
3755
3756 match = prefix;
3757 if (*p == '?') {
3758 match = strstr;
3759 p++;
3760 }
3761
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003762 found = NULL;
3763 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003764 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003765 if (found)
3766 goto err;
3767 found = jp;
3768 err_msg = "%s: ambiguous";
3769 }
3770 jp = jp->prev_job;
3771 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003772 if (!found)
3773 goto err;
3774 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003775
3776 gotit:
3777#if JOBS
3778 err_msg = "job %s not created under job control";
3779 if (getctl && jp->jobctl == 0)
3780 goto err;
3781#endif
3782 return jp;
3783 err:
3784 ash_msg_and_raise_error(err_msg, name);
3785}
3786
3787/*
3788 * Mark a job structure as unused.
3789 */
3790static void
3791freejob(struct job *jp)
3792{
3793 struct procstat *ps;
3794 int i;
3795
3796 INT_OFF;
3797 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003798 if (ps->ps_cmd != nullstr)
3799 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003800 }
3801 if (jp->ps != &jp->ps0)
3802 free(jp->ps);
3803 jp->used = 0;
3804 set_curjob(jp, CUR_DELETE);
3805 INT_ON;
3806}
3807
3808#if JOBS
3809static void
3810xtcsetpgrp(int fd, pid_t pgrp)
3811{
3812 if (tcsetpgrp(fd, pgrp))
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003813 ash_msg_and_raise_error("can't set tty process group (%m)");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003814}
3815
3816/*
3817 * Turn job control on and off.
3818 *
3819 * Note: This code assumes that the third arg to ioctl is a character
3820 * pointer, which is true on Berkeley systems but not System V. Since
3821 * System V doesn't have job control yet, this isn't a problem now.
3822 *
3823 * Called with interrupts off.
3824 */
3825static void
3826setjobctl(int on)
3827{
3828 int fd;
3829 int pgrp;
3830
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003831 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003832 return;
3833 if (on) {
3834 int ofd;
3835 ofd = fd = open(_PATH_TTY, O_RDWR);
3836 if (fd < 0) {
3837 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3838 * That sometimes helps to acquire controlling tty.
3839 * Obviously, a workaround for bugs when someone
3840 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003841 fd = 2;
3842 while (!isatty(fd))
3843 if (--fd < 0)
3844 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003845 }
Denys Vlasenko64774602016-10-26 15:24:30 +02003846 /* fd is a tty at this point */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003847 fd = fcntl(fd, F_DUPFD, 10);
Denys Vlasenko10ad6222017-04-17 16:13:32 +02003848 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, don't */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003849 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003850 if (fd < 0)
Denys Vlasenko64774602016-10-26 15:24:30 +02003851 goto out; /* F_DUPFD failed */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003852 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003853 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003854 pgrp = tcgetpgrp(fd);
3855 if (pgrp < 0) {
3856 out:
3857 ash_msg("can't access tty; job control turned off");
3858 mflag = on = 0;
3859 goto close;
3860 }
3861 if (pgrp == getpgrp())
3862 break;
3863 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003864 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003865 initialpgrp = pgrp;
3866
3867 setsignal(SIGTSTP);
3868 setsignal(SIGTTOU);
3869 setsignal(SIGTTIN);
3870 pgrp = rootpid;
3871 setpgid(0, pgrp);
3872 xtcsetpgrp(fd, pgrp);
3873 } else {
3874 /* turning job control off */
3875 fd = ttyfd;
3876 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003877 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003878 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003879 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003880 setpgid(0, pgrp);
3881 setsignal(SIGTSTP);
3882 setsignal(SIGTTOU);
3883 setsignal(SIGTTIN);
3884 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003885 if (fd >= 0)
3886 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003887 fd = -1;
3888 }
3889 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003890 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003891}
3892
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003893static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003894killcmd(int argc, char **argv)
3895{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003896 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003897 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003898 do {
3899 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003900 /*
3901 * "kill %N" - job kill
3902 * Converting to pgrp / pid kill
3903 */
3904 struct job *jp;
3905 char *dst;
3906 int j, n;
3907
3908 jp = getjob(argv[i], 0);
3909 /*
3910 * In jobs started under job control, we signal
3911 * entire process group by kill -PGRP_ID.
3912 * This happens, f.e., in interactive shell.
3913 *
3914 * Otherwise, we signal each child via
3915 * kill PID1 PID2 PID3.
3916 * Testcases:
3917 * sh -c 'sleep 1|sleep 1 & kill %1'
3918 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3919 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3920 */
3921 n = jp->nprocs; /* can't be 0 (I hope) */
3922 if (jp->jobctl)
3923 n = 1;
3924 dst = alloca(n * sizeof(int)*4);
3925 argv[i] = dst;
3926 for (j = 0; j < n; j++) {
3927 struct procstat *ps = &jp->ps[j];
3928 /* Skip non-running and not-stopped members
3929 * (i.e. dead members) of the job
3930 */
3931 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3932 continue;
3933 /*
3934 * kill_main has matching code to expect
3935 * leading space. Needed to not confuse
3936 * negative pids with "kill -SIGNAL_NO" syntax
3937 */
3938 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3939 }
3940 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003941 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003942 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003943 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003944 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003945}
3946
3947static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01003948showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003949{
Denys Vlasenko285ad152009-12-04 23:02:27 +01003950 struct procstat *ps;
3951 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003952
Denys Vlasenko285ad152009-12-04 23:02:27 +01003953 psend = jp->ps + jp->nprocs;
3954 for (ps = jp->ps + 1; ps < psend; ps++)
3955 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003956 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003957 flush_stdout_stderr();
3958}
3959
3960
3961static int
3962restartjob(struct job *jp, int mode)
3963{
3964 struct procstat *ps;
3965 int i;
3966 int status;
3967 pid_t pgid;
3968
3969 INT_OFF;
3970 if (jp->state == JOBDONE)
3971 goto out;
3972 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003973 pgid = jp->ps[0].ps_pid;
Denys Vlasenko098b7132017-01-11 19:59:03 +01003974 if (mode == FORK_FG) {
3975 get_tty_state();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003976 xtcsetpgrp(ttyfd, pgid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01003977 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003978 killpg(pgid, SIGCONT);
3979 ps = jp->ps;
3980 i = jp->nprocs;
3981 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003982 if (WIFSTOPPED(ps->ps_status)) {
3983 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003984 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003985 ps++;
3986 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003987 out:
3988 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3989 INT_ON;
3990 return status;
3991}
3992
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003993static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003994fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003995{
3996 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003997 int mode;
3998 int retval;
3999
4000 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
4001 nextopt(nullstr);
4002 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004003 do {
4004 jp = getjob(*argv, 1);
4005 if (mode == FORK_BG) {
4006 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004007 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004008 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004009 out1str(jp->ps[0].ps_cmd);
4010 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004011 retval = restartjob(jp, mode);
4012 } while (*argv && *++argv);
4013 return retval;
4014}
4015#endif
4016
4017static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02004018sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004019{
4020 int col;
4021 int st;
4022
4023 col = 0;
4024 if (!WIFEXITED(status)) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004025 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004026 st = WSTOPSIG(status);
4027 else
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004028 st = WTERMSIG(status);
4029 if (sigonly) {
4030 if (st == SIGINT || st == SIGPIPE)
4031 goto out;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004032 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004033 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004034 }
4035 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01004036//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004037 col = fmtstr(s, 32, strsignal(st));
4038 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004039 strcpy(s + col, " (core dumped)");
4040 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004041 }
4042 } else if (!sigonly) {
4043 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004044 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004045 }
4046 out:
4047 return col;
4048}
4049
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004050static int
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004051wait_block_or_sig(int *status)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004052{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004053 int pid;
4054
4055 do {
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004056 sigset_t mask;
4057
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004058 /* Poll all children for changes in their state */
4059 got_sigchld = 0;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004060 /* if job control is active, accept stopped processes too */
4061 pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004062 if (pid != 0)
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004063 break; /* Error (e.g. EINTR, ECHILD) or pid */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004064
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004065 /* Children exist, but none are ready. Sleep until interesting signal */
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004066#if 1
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004067 sigfillset(&mask);
4068 sigprocmask(SIG_SETMASK, &mask, &mask);
4069 while (!got_sigchld && !pending_sig)
4070 sigsuspend(&mask);
4071 sigprocmask(SIG_SETMASK, &mask, NULL);
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004072#else /* unsafe: a signal can set pending_sig after check, but before pause() */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004073 while (!got_sigchld && !pending_sig)
4074 pause();
4075#endif
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004076
4077 /* If it was SIGCHLD, poll children again */
4078 } while (got_sigchld);
4079
4080 return pid;
4081}
4082
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004083#define DOWAIT_NONBLOCK 0
4084#define DOWAIT_BLOCK 1
4085#define DOWAIT_BLOCK_OR_SIG 2
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004086
4087static int
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004088dowait(int block, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004089{
4090 int pid;
4091 int status;
4092 struct job *jp;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004093 struct job *thisjob = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004094
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004095 TRACE(("dowait(0x%x) called\n", block));
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00004096
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004097 /* It's wrong to call waitpid() outside of INT_OFF region:
4098 * signal can arrive just after syscall return and handler can
4099 * longjmp away, losing stop/exit notification processing.
4100 * Thus, for "jobs" builtin, and for waiting for a fg job,
4101 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4102 *
4103 * However, for "wait" builtin it is wrong to simply call waitpid()
4104 * in INT_OFF region: "wait" needs to wait for any running job
4105 * to change state, but should exit on any trap too.
4106 * In INT_OFF region, a signal just before syscall entry can set
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004107 * pending_sig variables, but we can't check them, and we would
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004108 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004109 *
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004110 * Because of this, we run inside INT_OFF, but use a special routine
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004111 * which combines waitpid() and sigsuspend().
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004112 * This is the reason why we need to have a handler for SIGCHLD:
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004113 * SIG_DFL handler does not wake sigsuspend().
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004114 */
4115 INT_OFF;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004116 if (block == DOWAIT_BLOCK_OR_SIG) {
4117 pid = wait_block_or_sig(&status);
4118 } else {
4119 int wait_flags = 0;
4120 if (block == DOWAIT_NONBLOCK)
4121 wait_flags = WNOHANG;
4122 /* if job control is active, accept stopped processes too */
4123 if (doing_jobctl)
4124 wait_flags |= WUNTRACED;
4125 /* NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004126 pid = waitpid(-1, &status, wait_flags);
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004127 }
Denis Vlasenkob21f3792009-03-19 23:09:58 +00004128 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4129 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004130 if (pid <= 0)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004131 goto out;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004132
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004133 thisjob = NULL;
4134 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004135 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004136 struct procstat *ps;
4137 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004138 if (jp->state == JOBDONE)
4139 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004140 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004141 ps = jp->ps;
4142 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004143 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004144 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004145 TRACE(("Job %d: changing status of proc %d "
4146 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01004147 jobno(jp), pid, ps->ps_status, status));
4148 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004149 thisjob = jp;
4150 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004151 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004152 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004153#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004154 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004155 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004156 if (WIFSTOPPED(ps->ps_status)) {
4157 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004158 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004159 }
4160#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004161 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004162 if (!thisjob)
4163 continue;
4164
4165 /* Found the job where one of its processes changed its state.
4166 * Is there at least one live and running process in this job? */
4167 if (jobstate != JOBRUNNING) {
4168 /* No. All live processes in the job are stopped
4169 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4170 */
4171 thisjob->changed = 1;
4172 if (thisjob->state != jobstate) {
4173 TRACE(("Job %d: changing state from %d to %d\n",
4174 jobno(thisjob), thisjob->state, jobstate));
4175 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004176#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004177 if (jobstate == JOBSTOPPED)
4178 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004179#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004180 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004181 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004182 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004183 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004184 /* The process wasn't found in job list */
4185 if (JOBS && !WIFSTOPPED(status))
4186 jobless--;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004187 out:
4188 INT_ON;
4189
4190 if (thisjob && thisjob == job) {
4191 char s[48 + 1];
4192 int len;
4193
Denys Vlasenko9c541002015-10-07 15:44:36 +02004194 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004195 if (len) {
4196 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004197 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004198 out2str(s);
4199 }
4200 }
4201 return pid;
4202}
4203
4204#if JOBS
4205static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004206showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004207{
4208 struct procstat *ps;
4209 struct procstat *psend;
4210 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004211 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004212 char s[16 + 16 + 48];
4213 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004214
4215 ps = jp->ps;
4216
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004217 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004218 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004219 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004220 return;
4221 }
4222
4223 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004224 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004225
4226 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004227 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004228 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004229 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004230
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004231 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004232 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004233
4234 psend = ps + jp->nprocs;
4235
4236 if (jp->state == JOBRUNNING) {
4237 strcpy(s + col, "Running");
4238 col += sizeof("Running") - 1;
4239 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004240 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004241 if (jp->state == JOBSTOPPED)
4242 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004243 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004244 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004245 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004246
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004247 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4248 * or prints several "PID | <cmdN>" lines,
4249 * depending on SHOW_PIDS bit.
4250 * We do not print status of individual processes
4251 * between PID and <cmdN>. bash does it, but not very well:
4252 * first line shows overall job status, not process status,
4253 * making it impossible to know 1st process status.
4254 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004255 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004256 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004257 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004258 s[0] = '\0';
4259 col = 33;
4260 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004261 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004262 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004263 fprintf(out, "%s%*c%s%s",
4264 s,
4265 33 - col >= 0 ? 33 - col : 0, ' ',
4266 ps == jp->ps ? "" : "| ",
4267 ps->ps_cmd
4268 );
4269 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004270 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004271
4272 jp->changed = 0;
4273
4274 if (jp->state == JOBDONE) {
4275 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4276 freejob(jp);
4277 }
4278}
4279
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004280/*
4281 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4282 * statuses have changed since the last call to showjobs.
4283 */
4284static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004285showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004286{
4287 struct job *jp;
4288
Denys Vlasenko883cea42009-07-11 15:31:59 +02004289 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004290
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004291 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004292 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004293 continue;
4294
4295 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004296 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004297 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004298 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004299 }
4300}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004301
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004302static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004303jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004304{
4305 int mode, m;
4306
4307 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004308 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004309 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004310 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004311 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004312 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004313 }
4314
4315 argv = argptr;
4316 if (*argv) {
4317 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004318 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004319 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004320 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004321 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004322 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004323
4324 return 0;
4325}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004326#endif /* JOBS */
4327
Michael Abbott359da5e2009-12-04 23:03:29 +01004328/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004329static int
4330getstatus(struct job *job)
4331{
4332 int status;
4333 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004334 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004335
Michael Abbott359da5e2009-12-04 23:03:29 +01004336 /* Fetch last member's status */
4337 ps = job->ps + job->nprocs - 1;
4338 status = ps->ps_status;
4339 if (pipefail) {
4340 /* "set -o pipefail" mode: use last _nonzero_ status */
4341 while (status == 0 && --ps >= job->ps)
4342 status = ps->ps_status;
4343 }
4344
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004345 retval = WEXITSTATUS(status);
4346 if (!WIFEXITED(status)) {
4347#if JOBS
4348 retval = WSTOPSIG(status);
4349 if (!WIFSTOPPED(status))
4350#endif
4351 {
4352 /* XXX: limits number of signals */
4353 retval = WTERMSIG(status);
4354#if JOBS
4355 if (retval == SIGINT)
4356 job->sigint = 1;
4357#endif
4358 }
4359 retval += 128;
4360 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004361 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004362 jobno(job), job->nprocs, status, retval));
4363 return retval;
4364}
4365
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004366static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004367waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004368{
4369 struct job *job;
4370 int retval;
4371 struct job *jp;
4372
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004373 nextopt(nullstr);
4374 retval = 0;
4375
4376 argv = argptr;
4377 if (!*argv) {
4378 /* wait for all jobs */
4379 for (;;) {
4380 jp = curjob;
4381 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004382 if (!jp) /* no running procs */
4383 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004384 if (jp->state == JOBRUNNING)
4385 break;
4386 jp->waited = 1;
4387 jp = jp->prev_job;
4388 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004389 /* man bash:
4390 * "When bash is waiting for an asynchronous command via
4391 * the wait builtin, the reception of a signal for which a trap
4392 * has been set will cause the wait builtin to return immediately
4393 * with an exit status greater than 128, immediately after which
4394 * the trap is executed."
Denys Vlasenko69188112016-10-27 20:18:18 +02004395 */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004396 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004397 /* if child sends us a signal *and immediately exits*,
4398 * dowait() returns pid > 0. Check this case,
4399 * not "if (dowait() < 0)"!
4400 */
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004401 if (pending_sig)
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004402 goto sigout;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004403 }
4404 }
4405
4406 retval = 127;
4407 do {
4408 if (**argv != '%') {
4409 pid_t pid = number(*argv);
4410 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004411 while (1) {
4412 if (!job)
4413 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004414 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004415 break;
4416 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004417 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004418 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004419 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004420 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004421 /* loop until process terminated or stopped */
Denys Vlasenko69188112016-10-27 20:18:18 +02004422 while (job->state == JOBRUNNING) {
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004423 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004424 if (pending_sig)
4425 goto sigout;
Denys Vlasenko69188112016-10-27 20:18:18 +02004426 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004427 job->waited = 1;
4428 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004429 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004430 } while (*++argv);
4431
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004432 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004433 return retval;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004434 sigout:
4435 retval = 128 + pending_sig;
4436 return retval;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004437}
4438
4439static struct job *
4440growjobtab(void)
4441{
4442 size_t len;
4443 ptrdiff_t offset;
4444 struct job *jp, *jq;
4445
4446 len = njobs * sizeof(*jp);
4447 jq = jobtab;
4448 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4449
4450 offset = (char *)jp - (char *)jq;
4451 if (offset) {
4452 /* Relocate pointers */
4453 size_t l = len;
4454
4455 jq = (struct job *)((char *)jq + l);
4456 while (l) {
4457 l -= sizeof(*jp);
4458 jq--;
4459#define joff(p) ((struct job *)((char *)(p) + l))
4460#define jmove(p) (p) = (void *)((char *)(p) + offset)
4461 if (joff(jp)->ps == &jq->ps0)
4462 jmove(joff(jp)->ps);
4463 if (joff(jp)->prev_job)
4464 jmove(joff(jp)->prev_job);
4465 }
4466 if (curjob)
4467 jmove(curjob);
4468#undef joff
4469#undef jmove
4470 }
4471
4472 njobs += 4;
4473 jobtab = jp;
4474 jp = (struct job *)((char *)jp + len);
4475 jq = jp + 3;
4476 do {
4477 jq->used = 0;
4478 } while (--jq >= jp);
4479 return jp;
4480}
4481
4482/*
4483 * Return a new job structure.
4484 * Called with interrupts off.
4485 */
4486static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004487makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004488{
4489 int i;
4490 struct job *jp;
4491
4492 for (i = njobs, jp = jobtab; ; jp++) {
4493 if (--i < 0) {
4494 jp = growjobtab();
4495 break;
4496 }
4497 if (jp->used == 0)
4498 break;
4499 if (jp->state != JOBDONE || !jp->waited)
4500 continue;
4501#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004502 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004503 continue;
4504#endif
4505 freejob(jp);
4506 break;
4507 }
4508 memset(jp, 0, sizeof(*jp));
4509#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004510 /* jp->jobctl is a bitfield.
Denys Vlasenko098b7132017-01-11 19:59:03 +01004511 * "jp->jobctl |= doing_jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004512 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004513 jp->jobctl = 1;
4514#endif
4515 jp->prev_job = curjob;
4516 curjob = jp;
4517 jp->used = 1;
4518 jp->ps = &jp->ps0;
4519 if (nprocs > 1) {
4520 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4521 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004522 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004523 jobno(jp)));
4524 return jp;
4525}
4526
4527#if JOBS
4528/*
4529 * Return a string identifying a command (to be printed by the
4530 * jobs command).
4531 */
4532static char *cmdnextc;
4533
4534static void
4535cmdputs(const char *s)
4536{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004537 static const char vstype[VSTYPE + 1][3] = {
4538 "", "}", "-", "+", "?", "=",
4539 "%", "%%", "#", "##"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004540 IF_BASH_SUBSTR(, ":")
4541 IF_BASH_PATTERN_SUBST(, "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004542 };
4543
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004544 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004545 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004546 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004547 unsigned char c;
4548 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004549 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004550
Denys Vlasenko46a14772009-12-10 21:27:13 +01004551 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004552 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4553 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004554 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004555 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004556 switch (c) {
4557 case CTLESC:
4558 c = *p++;
4559 break;
4560 case CTLVAR:
4561 subtype = *p++;
4562 if ((subtype & VSTYPE) == VSLENGTH)
4563 str = "${#";
4564 else
4565 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004566 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004567 case CTLENDVAR:
4568 str = "\"}" + !(quoted & 1);
4569 quoted >>= 1;
4570 subtype = 0;
4571 goto dostr;
4572 case CTLBACKQ:
4573 str = "$(...)";
4574 goto dostr;
Denys Vlasenko0b883582016-12-23 16:49:07 +01004575#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004576 case CTLARI:
4577 str = "$((";
4578 goto dostr;
4579 case CTLENDARI:
4580 str = "))";
4581 goto dostr;
4582#endif
4583 case CTLQUOTEMARK:
4584 quoted ^= 1;
4585 c = '"';
4586 break;
4587 case '=':
4588 if (subtype == 0)
4589 break;
4590 if ((subtype & VSTYPE) != VSNORMAL)
4591 quoted <<= 1;
4592 str = vstype[subtype & VSTYPE];
4593 if (subtype & VSNUL)
4594 c = ':';
4595 else
4596 goto checkstr;
4597 break;
4598 case '\'':
4599 case '\\':
4600 case '"':
4601 case '$':
4602 /* These can only happen inside quotes */
4603 cc[0] = c;
4604 str = cc;
4605 c = '\\';
4606 break;
4607 default:
4608 break;
4609 }
4610 USTPUTC(c, nextc);
4611 checkstr:
4612 if (!str)
4613 continue;
4614 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004615 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004616 USTPUTC(c, nextc);
4617 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004618 } /* while *p++ not NUL */
4619
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004620 if (quoted & 1) {
4621 USTPUTC('"', nextc);
4622 }
4623 *nextc = 0;
4624 cmdnextc = nextc;
4625}
4626
4627/* cmdtxt() and cmdlist() call each other */
4628static void cmdtxt(union node *n);
4629
4630static void
4631cmdlist(union node *np, int sep)
4632{
4633 for (; np; np = np->narg.next) {
4634 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004635 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004636 cmdtxt(np);
4637 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004638 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004639 }
4640}
4641
4642static void
4643cmdtxt(union node *n)
4644{
4645 union node *np;
4646 struct nodelist *lp;
4647 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004648
4649 if (!n)
4650 return;
4651 switch (n->type) {
4652 default:
4653#if DEBUG
4654 abort();
4655#endif
4656 case NPIPE:
4657 lp = n->npipe.cmdlist;
4658 for (;;) {
4659 cmdtxt(lp->n);
4660 lp = lp->next;
4661 if (!lp)
4662 break;
4663 cmdputs(" | ");
4664 }
4665 break;
4666 case NSEMI:
4667 p = "; ";
4668 goto binop;
4669 case NAND:
4670 p = " && ";
4671 goto binop;
4672 case NOR:
4673 p = " || ";
4674 binop:
4675 cmdtxt(n->nbinary.ch1);
4676 cmdputs(p);
4677 n = n->nbinary.ch2;
4678 goto donode;
4679 case NREDIR:
4680 case NBACKGND:
4681 n = n->nredir.n;
4682 goto donode;
4683 case NNOT:
4684 cmdputs("!");
4685 n = n->nnot.com;
4686 donode:
4687 cmdtxt(n);
4688 break;
4689 case NIF:
4690 cmdputs("if ");
4691 cmdtxt(n->nif.test);
4692 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004693 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004694 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004695 cmdputs("; else ");
4696 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004697 } else {
4698 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004699 }
4700 p = "; fi";
4701 goto dotail;
4702 case NSUBSHELL:
4703 cmdputs("(");
4704 n = n->nredir.n;
4705 p = ")";
4706 goto dotail;
4707 case NWHILE:
4708 p = "while ";
4709 goto until;
4710 case NUNTIL:
4711 p = "until ";
4712 until:
4713 cmdputs(p);
4714 cmdtxt(n->nbinary.ch1);
4715 n = n->nbinary.ch2;
4716 p = "; done";
4717 dodo:
4718 cmdputs("; do ");
4719 dotail:
4720 cmdtxt(n);
4721 goto dotail2;
4722 case NFOR:
4723 cmdputs("for ");
4724 cmdputs(n->nfor.var);
4725 cmdputs(" in ");
4726 cmdlist(n->nfor.args, 1);
4727 n = n->nfor.body;
4728 p = "; done";
4729 goto dodo;
4730 case NDEFUN:
4731 cmdputs(n->narg.text);
4732 p = "() { ... }";
4733 goto dotail2;
4734 case NCMD:
4735 cmdlist(n->ncmd.args, 1);
4736 cmdlist(n->ncmd.redirect, 0);
4737 break;
4738 case NARG:
4739 p = n->narg.text;
4740 dotail2:
4741 cmdputs(p);
4742 break;
4743 case NHERE:
4744 case NXHERE:
4745 p = "<<...";
4746 goto dotail2;
4747 case NCASE:
4748 cmdputs("case ");
4749 cmdputs(n->ncase.expr->narg.text);
4750 cmdputs(" in ");
4751 for (np = n->ncase.cases; np; np = np->nclist.next) {
4752 cmdtxt(np->nclist.pattern);
4753 cmdputs(") ");
4754 cmdtxt(np->nclist.body);
4755 cmdputs(";; ");
4756 }
4757 p = "esac";
4758 goto dotail2;
4759 case NTO:
4760 p = ">";
4761 goto redir;
4762 case NCLOBBER:
4763 p = ">|";
4764 goto redir;
4765 case NAPPEND:
4766 p = ">>";
4767 goto redir;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004768#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00004769 case NTO2:
4770#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004771 case NTOFD:
4772 p = ">&";
4773 goto redir;
4774 case NFROM:
4775 p = "<";
4776 goto redir;
4777 case NFROMFD:
4778 p = "<&";
4779 goto redir;
4780 case NFROMTO:
4781 p = "<>";
4782 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004783 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004784 cmdputs(p);
4785 if (n->type == NTOFD || n->type == NFROMFD) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004786 cmdputs(utoa(n->ndup.dupfd));
4787 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004788 }
4789 n = n->nfile.fname;
4790 goto donode;
4791 }
4792}
4793
4794static char *
4795commandtext(union node *n)
4796{
4797 char *name;
4798
4799 STARTSTACKSTR(cmdnextc);
4800 cmdtxt(n);
4801 name = stackblock();
Denys Vlasenko6a94cee2016-10-25 17:40:25 +02004802 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004803 return ckstrdup(name);
4804}
4805#endif /* JOBS */
4806
4807/*
4808 * Fork off a subshell. If we are doing job control, give the subshell its
4809 * own process group. Jp is a job structure that the job is to be added to.
4810 * N is the command that will be evaluated by the child. Both jp and n may
4811 * be NULL. The mode parameter can be one of the following:
4812 * FORK_FG - Fork off a foreground process.
4813 * FORK_BG - Fork off a background process.
4814 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4815 * process group even if job control is on.
4816 *
4817 * When job control is turned off, background processes have their standard
4818 * input redirected to /dev/null (except for the second and later processes
4819 * in a pipeline).
4820 *
4821 * Called with interrupts off.
4822 */
4823/*
4824 * Clear traps on a fork.
4825 */
4826static void
4827clear_traps(void)
4828{
4829 char **tp;
4830
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004831 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004832 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004833 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004834 if (trap_ptr == trap)
4835 free(*tp);
4836 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004837 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004838 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004839 setsignal(tp - trap);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004840 }
4841 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004842 may_have_traps = 0;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004843 INT_ON;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004844}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004845
4846/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004847static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004848
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004849/* Called after fork(), in child */
Denys Vlasenko70392332016-10-27 02:31:55 +02004850/* jp and n are NULL when called by openhere() for heredoc support */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004851static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004852forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004853{
4854 int oldlvl;
4855
4856 TRACE(("Child shell %d\n", getpid()));
4857 oldlvl = shlvl;
4858 shlvl++;
4859
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004860 /* man bash: "Non-builtin commands run by bash have signal handlers
4861 * set to the values inherited by the shell from its parent".
4862 * Do we do it correctly? */
4863
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004864 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004865
4866 if (mode == FORK_NOJOB /* is it `xxx` ? */
4867 && n && n->type == NCMD /* is it single cmd? */
4868 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004869 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004870 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4871 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4872 ) {
4873 TRACE(("Trap hack\n"));
4874 /* Awful hack for `trap` or $(trap).
4875 *
4876 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4877 * contains an example where "trap" is executed in a subshell:
4878 *
4879 * save_traps=$(trap)
4880 * ...
4881 * eval "$save_traps"
4882 *
4883 * Standard does not say that "trap" in subshell shall print
4884 * parent shell's traps. It only says that its output
4885 * must have suitable form, but then, in the above example
4886 * (which is not supposed to be normative), it implies that.
4887 *
4888 * bash (and probably other shell) does implement it
4889 * (traps are reset to defaults, but "trap" still shows them),
4890 * but as a result, "trap" logic is hopelessly messed up:
4891 *
4892 * # trap
4893 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4894 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4895 * # true | trap <--- trap is in subshell - no output (ditto)
4896 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4897 * trap -- 'echo Ho' SIGWINCH
4898 * # echo `(trap)` <--- in subshell in subshell - output
4899 * trap -- 'echo Ho' SIGWINCH
4900 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4901 * trap -- 'echo Ho' SIGWINCH
4902 *
4903 * The rules when to forget and when to not forget traps
4904 * get really complex and nonsensical.
4905 *
4906 * Our solution: ONLY bare $(trap) or `trap` is special.
4907 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004908 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02004909 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004910 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004911 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004912 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004913#if JOBS
4914 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004915 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004916 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004917 pid_t pgrp;
4918
4919 if (jp->nprocs == 0)
4920 pgrp = getpid();
4921 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004922 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004923 /* this can fail because we are doing it in the parent also */
4924 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004925 if (mode == FORK_FG)
4926 xtcsetpgrp(ttyfd, pgrp);
4927 setsignal(SIGTSTP);
4928 setsignal(SIGTTOU);
4929 } else
4930#endif
4931 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004932 /* man bash: "When job control is not in effect,
4933 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004934 ignoresig(SIGINT);
4935 ignoresig(SIGQUIT);
4936 if (jp->nprocs == 0) {
4937 close(0);
4938 if (open(bb_dev_null, O_RDONLY) != 0)
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00004939 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004940 }
4941 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004942 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004943 if (iflag) { /* why if iflag only? */
4944 setsignal(SIGINT);
4945 setsignal(SIGTERM);
4946 }
4947 /* man bash:
4948 * "In all cases, bash ignores SIGQUIT. Non-builtin
4949 * commands run by bash have signal handlers
4950 * set to the values inherited by the shell
4951 * from its parent".
4952 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004953 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004954 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004955#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02004956 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01004957 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004958 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004959 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02004960 /* "jobs": we do not want to clear job list for it,
4961 * instead we remove only _its_ own_ job from job list.
4962 * This makes "jobs .... | cat" more useful.
4963 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004964 freejob(curjob);
4965 return;
4966 }
4967#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004968 for (jp = curjob; jp; jp = jp->prev_job)
4969 freejob(jp);
4970 jobless = 0;
4971}
4972
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004973/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00004974#if !JOBS
4975#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4976#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004977static void
4978forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4979{
4980 TRACE(("In parent shell: child = %d\n", pid));
4981 if (!jp) {
Denys Vlasenko70392332016-10-27 02:31:55 +02004982 /* jp is NULL when called by openhere() for heredoc support */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004983 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4984 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004985 jobless++;
4986 return;
4987 }
4988#if JOBS
4989 if (mode != FORK_NOJOB && jp->jobctl) {
4990 int pgrp;
4991
4992 if (jp->nprocs == 0)
4993 pgrp = pid;
4994 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004995 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004996 /* This can fail because we are doing it in the child also */
4997 setpgid(pid, pgrp);
4998 }
4999#endif
5000 if (mode == FORK_BG) {
5001 backgndpid = pid; /* set $! */
5002 set_curjob(jp, CUR_RUNNING);
5003 }
5004 if (jp) {
5005 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01005006 ps->ps_pid = pid;
5007 ps->ps_status = -1;
5008 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005009#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005010 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01005011 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005012#endif
5013 }
5014}
5015
Denys Vlasenko70392332016-10-27 02:31:55 +02005016/* jp and n are NULL when called by openhere() for heredoc support */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005017static int
5018forkshell(struct job *jp, union node *n, int mode)
5019{
5020 int pid;
5021
5022 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5023 pid = fork();
5024 if (pid < 0) {
5025 TRACE(("Fork failed, errno=%d", errno));
5026 if (jp)
5027 freejob(jp);
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +00005028 ash_msg_and_raise_error("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005029 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02005030 if (pid == 0) {
5031 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005032 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005033 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005034 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005035 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005036 return pid;
5037}
5038
5039/*
5040 * Wait for job to finish.
5041 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005042 * Under job control we have the problem that while a child process
5043 * is running interrupts generated by the user are sent to the child
5044 * but not to the shell. This means that an infinite loop started by
5045 * an interactive user may be hard to kill. With job control turned off,
5046 * an interactive user may place an interactive program inside a loop.
5047 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005048 * these interrupts to also abort the loop. The approach we take here
5049 * is to have the shell ignore interrupt signals while waiting for a
5050 * foreground process to terminate, and then send itself an interrupt
5051 * signal if the child process was terminated by an interrupt signal.
5052 * Unfortunately, some programs want to do a bit of cleanup and then
5053 * exit on interrupt; unless these processes terminate themselves by
5054 * sending a signal to themselves (instead of calling exit) they will
5055 * confuse this approach.
5056 *
5057 * Called with interrupts off.
5058 */
5059static int
5060waitforjob(struct job *jp)
5061{
5062 int st;
5063
5064 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005065
5066 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005067 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005068 /* In non-interactive shells, we _can_ get
5069 * a keyboard signal here and be EINTRed,
5070 * but we just loop back, waiting for command to complete.
5071 *
5072 * man bash:
5073 * "If bash is waiting for a command to complete and receives
5074 * a signal for which a trap has been set, the trap
5075 * will not be executed until the command completes."
5076 *
5077 * Reality is that even if trap is not set, bash
5078 * will not act on the signal until command completes.
5079 * Try this. sleep5intoff.c:
5080 * #include <signal.h>
5081 * #include <unistd.h>
5082 * int main() {
5083 * sigset_t set;
5084 * sigemptyset(&set);
5085 * sigaddset(&set, SIGINT);
5086 * sigaddset(&set, SIGQUIT);
5087 * sigprocmask(SIG_BLOCK, &set, NULL);
5088 * sleep(5);
5089 * return 0;
5090 * }
5091 * $ bash -c './sleep5intoff; echo hi'
5092 * ^C^C^C^C <--- pressing ^C once a second
5093 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005094 * $ bash -c './sleep5intoff; echo hi'
5095 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5096 * $ _
5097 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005098 dowait(DOWAIT_BLOCK, jp);
5099 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005100 INT_ON;
5101
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005102 st = getstatus(jp);
5103#if JOBS
5104 if (jp->jobctl) {
5105 xtcsetpgrp(ttyfd, rootpid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01005106 restore_tty_if_stopped_or_signaled(jp);
5107
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005108 /*
5109 * This is truly gross.
5110 * If we're doing job control, then we did a TIOCSPGRP which
5111 * caused us (the shell) to no longer be in the controlling
5112 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
5113 * intuit from the subprocess exit status whether a SIGINT
5114 * occurred, and if so interrupt ourselves. Yuck. - mycroft
5115 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00005116 if (jp->sigint) /* TODO: do the same with all signals */
5117 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005118 }
5119 if (jp->state == JOBDONE)
5120#endif
5121 freejob(jp);
5122 return st;
5123}
5124
5125/*
5126 * return 1 if there are stopped jobs, otherwise 0
5127 */
5128static int
5129stoppedjobs(void)
5130{
5131 struct job *jp;
5132 int retval;
5133
5134 retval = 0;
5135 if (job_warning)
5136 goto out;
5137 jp = curjob;
5138 if (jp && jp->state == JOBSTOPPED) {
5139 out2str("You have stopped jobs.\n");
5140 job_warning = 2;
5141 retval++;
5142 }
5143 out:
5144 return retval;
5145}
5146
5147
Denys Vlasenko70392332016-10-27 02:31:55 +02005148/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005149 * Code for dealing with input/output redirection.
5150 */
5151
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005152#undef EMPTY
5153#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005154#define EMPTY -2 /* marks an unused slot in redirtab */
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005155#define CLOSED -3 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005156
5157/*
5158 * Open a file in noclobber mode.
5159 * The code was copied from bash.
5160 */
5161static int
5162noclobberopen(const char *fname)
5163{
5164 int r, fd;
5165 struct stat finfo, finfo2;
5166
5167 /*
5168 * If the file exists and is a regular file, return an error
5169 * immediately.
5170 */
5171 r = stat(fname, &finfo);
5172 if (r == 0 && S_ISREG(finfo.st_mode)) {
5173 errno = EEXIST;
5174 return -1;
5175 }
5176
5177 /*
5178 * If the file was not present (r != 0), make sure we open it
5179 * exclusively so that if it is created before we open it, our open
5180 * will fail. Make sure that we do not truncate an existing file.
5181 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5182 * file was not a regular file, we leave O_EXCL off.
5183 */
5184 if (r != 0)
5185 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5186 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5187
5188 /* If the open failed, return the file descriptor right away. */
5189 if (fd < 0)
5190 return fd;
5191
5192 /*
5193 * OK, the open succeeded, but the file may have been changed from a
5194 * non-regular file to a regular file between the stat and the open.
5195 * We are assuming that the O_EXCL open handles the case where FILENAME
5196 * did not exist and is symlinked to an existing file between the stat
5197 * and open.
5198 */
5199
5200 /*
5201 * If we can open it and fstat the file descriptor, and neither check
5202 * revealed that it was a regular file, and the file has not been
5203 * replaced, return the file descriptor.
5204 */
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005205 if (fstat(fd, &finfo2) == 0
5206 && !S_ISREG(finfo2.st_mode)
5207 && finfo.st_dev == finfo2.st_dev
5208 && finfo.st_ino == finfo2.st_ino
5209 ) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005210 return fd;
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005211 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005212
5213 /* The file has been replaced. badness. */
5214 close(fd);
5215 errno = EEXIST;
5216 return -1;
5217}
5218
5219/*
5220 * Handle here documents. Normally we fork off a process to write the
5221 * data to a pipe. If the document is short, we can stuff the data in
5222 * the pipe without forking.
5223 */
5224/* openhere needs this forward reference */
5225static void expandhere(union node *arg, int fd);
5226static int
5227openhere(union node *redir)
5228{
5229 int pip[2];
5230 size_t len = 0;
5231
5232 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005233 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005234 if (redir->type == NHERE) {
5235 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005236 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005237 full_write(pip[1], redir->nhere.doc->narg.text, len);
5238 goto out;
5239 }
5240 }
5241 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005242 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005243 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005244 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5245 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5246 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5247 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005248 signal(SIGPIPE, SIG_DFL);
5249 if (redir->type == NHERE)
5250 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005251 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005252 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005253 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005254 }
5255 out:
5256 close(pip[1]);
5257 return pip[0];
5258}
5259
5260static int
5261openredirect(union node *redir)
5262{
5263 char *fname;
5264 int f;
5265
5266 switch (redir->nfile.type) {
Denys Vlasenko557482c2016-09-25 21:24:04 +02005267/* Can't happen, our single caller does this itself */
5268// case NTOFD:
5269// case NFROMFD:
5270// return -1;
5271 case NHERE:
5272 case NXHERE:
5273 return openhere(redir);
5274 }
5275
5276 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5277 * allocated space. Do it only when we know it is safe.
5278 */
5279 fname = redir->nfile.expfname;
5280
5281 switch (redir->nfile.type) {
5282 default:
5283#if DEBUG
5284 abort();
5285#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005286 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005287 f = open(fname, O_RDONLY);
5288 if (f < 0)
5289 goto eopen;
5290 break;
5291 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005292 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005293 if (f < 0)
5294 goto ecreate;
5295 break;
5296 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005297#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005298 case NTO2:
5299#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005300 /* Take care of noclobber mode. */
5301 if (Cflag) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005302 f = noclobberopen(fname);
5303 if (f < 0)
5304 goto ecreate;
5305 break;
5306 }
5307 /* FALLTHROUGH */
5308 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005309 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5310 if (f < 0)
5311 goto ecreate;
5312 break;
5313 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005314 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5315 if (f < 0)
5316 goto ecreate;
5317 break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005318 }
5319
5320 return f;
5321 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005322 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005323 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005324 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005325}
5326
5327/*
Denys Vlasenko64774602016-10-26 15:24:30 +02005328 * Copy a file descriptor to be >= 10. Throws exception on error.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005329 */
5330static int
Denys Vlasenko64774602016-10-26 15:24:30 +02005331savefd(int from)
5332{
5333 int newfd;
5334 int err;
5335
5336 newfd = fcntl(from, F_DUPFD, 10);
5337 err = newfd < 0 ? errno : 0;
5338 if (err != EBADF) {
5339 if (err)
5340 ash_msg_and_raise_error("%d: %m", from);
5341 close(from);
5342 fcntl(newfd, F_SETFD, FD_CLOEXEC);
5343 }
5344
5345 return newfd;
5346}
5347static int
5348dup2_or_raise(int from, int to)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005349{
5350 int newfd;
5351
Denys Vlasenko64774602016-10-26 15:24:30 +02005352 newfd = (from != to) ? dup2(from, to) : to;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005353 if (newfd < 0) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005354 /* Happens when source fd is not open: try "echo >&99" */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005355 ash_msg_and_raise_error("%d: %m", from);
5356 }
5357 return newfd;
5358}
5359
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005360/* Struct def and variable are moved down to the first usage site */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005361struct two_fd_t {
5362 int orig, copy;
5363};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005364struct redirtab {
5365 struct redirtab *next;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005366 int pair_count;
Denys Vlasenko606291b2009-09-23 23:15:43 +02005367 struct two_fd_t two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005368};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005369#define redirlist (G_var.redirlist)
Denys Vlasenko64774602016-10-26 15:24:30 +02005370enum {
5371 COPYFD_RESTORE = (int)~(INT_MAX),
5372};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005373
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005374static int
5375need_to_remember(struct redirtab *rp, int fd)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005376{
5377 int i;
5378
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005379 if (!rp) /* remembering was not requested */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005380 return 0;
5381
5382 for (i = 0; i < rp->pair_count; i++) {
5383 if (rp->two_fd[i].orig == fd) {
5384 /* already remembered */
5385 return 0;
5386 }
5387 }
5388 return 1;
5389}
5390
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005391/* "hidden" fd is a fd used to read scripts, or a copy of such */
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005392static int
5393is_hidden_fd(struct redirtab *rp, int fd)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005394{
5395 int i;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005396 struct parsefile *pf;
5397
5398 if (fd == -1)
5399 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005400 /* Check open scripts' fds */
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005401 pf = g_parsefile;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005402 while (pf) {
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005403 /* We skip pf_fd == 0 case because of the following case:
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005404 * $ ash # running ash interactively
5405 * $ . ./script.sh
5406 * and in script.sh: "exec 9>&0".
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005407 * Even though top-level pf_fd _is_ 0,
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005408 * it's still ok to use it: "read" builtin uses it,
5409 * why should we cripple "exec" builtin?
5410 */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005411 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005412 return 1;
5413 }
5414 pf = pf->prev;
5415 }
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005416
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005417 if (!rp)
5418 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005419 /* Check saved fds of redirects */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005420 fd |= COPYFD_RESTORE;
5421 for (i = 0; i < rp->pair_count; i++) {
5422 if (rp->two_fd[i].copy == fd) {
5423 return 1;
5424 }
5425 }
5426 return 0;
5427}
5428
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005429/*
5430 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5431 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005432 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005433 */
5434/* flags passed to redirect */
5435#define REDIR_PUSH 01 /* save previous values of file descriptors */
5436#define REDIR_SAVEFD2 03 /* set preverrout */
5437static void
5438redirect(union node *redir, int flags)
5439{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005440 struct redirtab *sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005441 int sv_pos;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005442 int i;
5443 int fd;
5444 int newfd;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005445 int copied_fd2 = -1;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005446
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005447 if (!redir) {
5448 return;
5449 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005450
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005451 sv = NULL;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005452 sv_pos = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005453 INT_OFF;
5454 if (flags & REDIR_PUSH) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005455 union node *tmp = redir;
5456 do {
5457 sv_pos++;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005458#if BASH_REDIR_OUTPUT
Chris Metcalfc3c1fb62010-01-08 13:18:06 +01005459 if (tmp->nfile.type == NTO2)
Denis Vlasenko559691a2008-10-05 18:39:31 +00005460 sv_pos++;
5461#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005462 tmp = tmp->nfile.next;
5463 } while (tmp);
5464 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005465 sv->next = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005466 sv->pair_count = sv_pos;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005467 redirlist = sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005468 while (sv_pos > 0) {
5469 sv_pos--;
5470 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5471 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005472 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005473
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005474 do {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005475 int right_fd = -1;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005476 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005477 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005478 right_fd = redir->ndup.dupfd;
5479 //bb_error_msg("doing %d > %d", fd, right_fd);
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005480 /* redirect from/to same file descriptor? */
5481 if (right_fd == fd)
5482 continue;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005483 /* "echo >&10" and 10 is a fd opened to a sh script? */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005484 if (is_hidden_fd(sv, right_fd)) {
5485 errno = EBADF; /* as if it is closed */
5486 ash_msg_and_raise_error("%d: %m", right_fd);
5487 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005488 newfd = -1;
5489 } else {
5490 newfd = openredirect(redir); /* always >= 0 */
5491 if (fd == newfd) {
5492 /* Descriptor wasn't open before redirect.
5493 * Mark it for close in the future */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005494 if (need_to_remember(sv, fd)) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005495 goto remember_to_close;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005496 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005497 continue;
5498 }
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005499 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005500#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005501 redirect_more:
5502#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005503 if (need_to_remember(sv, fd)) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005504 /* Copy old descriptor */
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005505 /* Careful to not accidentally "save"
5506 * to the same fd as right side fd in N>&M */
5507 int minfd = right_fd < 10 ? 10 : right_fd + 1;
Denys Vlasenko86584e12017-01-07 10:15:01 +01005508#if defined(F_DUPFD_CLOEXEC)
5509 i = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
5510#else
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005511 i = fcntl(fd, F_DUPFD, minfd);
Denys Vlasenko86584e12017-01-07 10:15:01 +01005512#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005513 if (i == -1) {
5514 i = errno;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005515 if (i != EBADF) {
5516 /* Strange error (e.g. "too many files" EMFILE?) */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005517 if (newfd >= 0)
5518 close(newfd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005519 errno = i;
5520 ash_msg_and_raise_error("%d: %m", fd);
5521 /* NOTREACHED */
5522 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005523 /* EBADF: it is not open - good, remember to close it */
5524 remember_to_close:
5525 i = CLOSED;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005526 } else { /* fd is open, save its copy */
Denys Vlasenko86584e12017-01-07 10:15:01 +01005527#if !defined(F_DUPFD_CLOEXEC)
5528 fcntl(i, F_SETFD, FD_CLOEXEC);
5529#endif
Denis Vlasenko22f74142008-07-24 22:34:43 +00005530 /* "exec fd>&-" should not close fds
5531 * which point to script file(s).
5532 * Force them to be restored afterwards */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005533 if (is_hidden_fd(sv, fd))
5534 i |= COPYFD_RESTORE;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005535 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005536 if (fd == 2)
5537 copied_fd2 = i;
5538 sv->two_fd[sv_pos].orig = fd;
5539 sv->two_fd[sv_pos].copy = i;
5540 sv_pos++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005541 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005542 if (newfd < 0) {
5543 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005544 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005545 /* Don't want to trigger debugging */
5546 if (fd != -1)
5547 close(fd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005548 } else {
Denys Vlasenko64774602016-10-26 15:24:30 +02005549 dup2_or_raise(redir->ndup.dupfd, fd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005550 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005551 } else if (fd != newfd) { /* move newfd to fd */
Denys Vlasenko64774602016-10-26 15:24:30 +02005552 dup2_or_raise(newfd, fd);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005553#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005554 if (!(redir->nfile.type == NTO2 && fd == 2))
5555#endif
5556 close(newfd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005557 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005558#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005559 if (redir->nfile.type == NTO2 && fd == 1) {
5560 /* We already redirected it to fd 1, now copy it to 2 */
5561 newfd = 1;
5562 fd = 2;
5563 goto redirect_more;
5564 }
5565#endif
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005566 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005567
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005568 INT_ON;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005569 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5570 preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005571}
5572
5573/*
5574 * Undo the effects of the last redirection.
5575 */
5576static void
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005577popredir(int drop, int restore)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005578{
5579 struct redirtab *rp;
5580 int i;
5581
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02005582 if (redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005583 return;
5584 INT_OFF;
5585 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005586 for (i = 0; i < rp->pair_count; i++) {
5587 int fd = rp->two_fd[i].orig;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005588 int copy = rp->two_fd[i].copy;
5589 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005590 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005591 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005592 continue;
5593 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005594 if (copy != EMPTY) {
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005595 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
Denis Vlasenko22f74142008-07-24 22:34:43 +00005596 copy &= ~COPYFD_RESTORE;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005597 /*close(fd);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02005598 dup2_or_raise(copy, fd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005599 }
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005600 close(copy & ~COPYFD_RESTORE);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005601 }
5602 }
5603 redirlist = rp->next;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005604 free(rp);
5605 INT_ON;
5606}
5607
5608/*
5609 * Undo all redirections. Called on error or interrupt.
5610 */
5611
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005612static int
5613redirectsafe(union node *redir, int flags)
5614{
5615 int err;
5616 volatile int saveint;
5617 struct jmploc *volatile savehandler = exception_handler;
5618 struct jmploc jmploc;
5619
5620 SAVE_INT(saveint);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005621 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5622 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005623 if (!err) {
5624 exception_handler = &jmploc;
5625 redirect(redir, flags);
5626 }
5627 exception_handler = savehandler;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00005628 if (err && exception_type != EXERROR)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005629 longjmp(exception_handler->loc, 1);
5630 RESTORE_INT(saveint);
5631 return err;
5632}
5633
5634
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005635/* ============ Routines to expand arguments to commands
5636 *
5637 * We have to deal with backquotes, shell variables, and file metacharacters.
5638 */
5639
Denys Vlasenko0b883582016-12-23 16:49:07 +01005640#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005641static arith_t
5642ash_arith(const char *s)
5643{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005644 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005645 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005646
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005647 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005648 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005649 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005650
5651 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005652 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005653 if (math_state.errmsg)
5654 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005655 INT_ON;
5656
5657 return result;
5658}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005659#endif
5660
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005661/*
5662 * expandarg flags
5663 */
5664#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5665#define EXP_TILDE 0x2 /* do normal tilde expansion */
5666#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5667#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
Denys Vlasenkodb74c6c2016-10-24 21:12:33 +02005668/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5669 * POSIX says for this case:
5670 * Pathname expansion shall not be performed on the word by a
5671 * non-interactive shell; an interactive shell may perform it, but shall
5672 * do so only when the expansion would result in one word.
5673 * Currently, our code complies to the above rule by never globbing
5674 * redirection filenames.
5675 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5676 * (this means that on a typical Linux distro, bash almost always
5677 * performs globbing, and thus diverges from what we do).
5678 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005679#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Ron Yorston549deab2015-05-18 09:57:51 +02005680#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005681#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5682#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005683#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005684/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005685 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005686 */
5687#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5688#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005689#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5690#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Ron Yorston417622c2015-05-18 09:59:14 +02005691#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005692
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005693/* Add CTLESC when necessary. */
Ron Yorston549deab2015-05-18 09:57:51 +02005694#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005695/* Do not skip NUL characters. */
5696#define QUOTES_KEEPNUL EXP_TILDE
5697
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005698/*
5699 * Structure specifying which parts of the string should be searched
5700 * for IFS characters.
5701 */
5702struct ifsregion {
5703 struct ifsregion *next; /* next region in list */
5704 int begoff; /* offset of start of region */
5705 int endoff; /* offset of end of region */
5706 int nulonly; /* search for nul bytes only */
5707};
5708
5709struct arglist {
5710 struct strlist *list;
5711 struct strlist **lastp;
5712};
5713
5714/* output of current string */
5715static char *expdest;
5716/* list of back quote expressions */
5717static struct nodelist *argbackq;
5718/* first struct in list of ifs regions */
5719static struct ifsregion ifsfirst;
5720/* last struct in list */
5721static struct ifsregion *ifslastp;
5722/* holds expanded arg list */
5723static struct arglist exparg;
5724
5725/*
5726 * Our own itoa().
5727 */
Denys Vlasenko0b883582016-12-23 16:49:07 +01005728#if !ENABLE_FEATURE_SH_MATH
Denys Vlasenko26777aa2010-11-22 23:49:10 +01005729/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5730typedef long arith_t;
5731# define ARITH_FMT "%ld"
5732#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005733static int
5734cvtnum(arith_t num)
5735{
5736 int len;
5737
Denys Vlasenko9c541002015-10-07 15:44:36 +02005738 expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest);
5739 len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005740 STADJUST(len, expdest);
5741 return len;
5742}
5743
Denys Vlasenko455e4222016-10-27 14:45:13 +02005744/*
5745 * Break the argument string into pieces based upon IFS and add the
5746 * strings to the argument list. The regions of the string to be
5747 * searched for IFS characters have been stored by recordregion.
5748 */
5749static void
5750ifsbreakup(char *string, struct arglist *arglist)
5751{
5752 struct ifsregion *ifsp;
5753 struct strlist *sp;
5754 char *start;
5755 char *p;
5756 char *q;
5757 const char *ifs, *realifs;
5758 int ifsspc;
5759 int nulonly;
5760
5761 start = string;
5762 if (ifslastp != NULL) {
5763 ifsspc = 0;
5764 nulonly = 0;
5765 realifs = ifsset() ? ifsval() : defifs;
5766 ifsp = &ifsfirst;
5767 do {
5768 p = string + ifsp->begoff;
5769 nulonly = ifsp->nulonly;
5770 ifs = nulonly ? nullstr : realifs;
5771 ifsspc = 0;
5772 while (p < string + ifsp->endoff) {
5773 q = p;
5774 if ((unsigned char)*p == CTLESC)
5775 p++;
5776 if (!strchr(ifs, *p)) {
5777 p++;
5778 continue;
5779 }
5780 if (!nulonly)
5781 ifsspc = (strchr(defifs, *p) != NULL);
5782 /* Ignore IFS whitespace at start */
5783 if (q == start && ifsspc) {
5784 p++;
5785 start = p;
5786 continue;
5787 }
5788 *q = '\0';
5789 sp = stzalloc(sizeof(*sp));
5790 sp->text = start;
5791 *arglist->lastp = sp;
5792 arglist->lastp = &sp->next;
5793 p++;
5794 if (!nulonly) {
5795 for (;;) {
5796 if (p >= string + ifsp->endoff) {
5797 break;
5798 }
5799 q = p;
5800 if ((unsigned char)*p == CTLESC)
5801 p++;
5802 if (strchr(ifs, *p) == NULL) {
5803 p = q;
5804 break;
5805 }
5806 if (strchr(defifs, *p) == NULL) {
5807 if (ifsspc) {
5808 p++;
5809 ifsspc = 0;
5810 } else {
5811 p = q;
5812 break;
5813 }
5814 } else
5815 p++;
5816 }
5817 }
5818 start = p;
5819 } /* while */
5820 ifsp = ifsp->next;
5821 } while (ifsp != NULL);
5822 if (nulonly)
5823 goto add;
5824 }
5825
5826 if (!*start)
5827 return;
5828
5829 add:
5830 sp = stzalloc(sizeof(*sp));
5831 sp->text = start;
5832 *arglist->lastp = sp;
5833 arglist->lastp = &sp->next;
5834}
5835
5836static void
5837ifsfree(void)
5838{
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005839 struct ifsregion *p = ifsfirst.next;
5840
5841 if (!p)
5842 goto out;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005843
5844 INT_OFF;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005845 do {
5846 struct ifsregion *ifsp;
5847 ifsp = p->next;
5848 free(p);
5849 p = ifsp;
5850 } while (p);
Denys Vlasenko455e4222016-10-27 14:45:13 +02005851 ifsfirst.next = NULL;
5852 INT_ON;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005853 out:
5854 ifslastp = NULL;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005855}
5856
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005857static size_t
5858esclen(const char *start, const char *p)
5859{
5860 size_t esc = 0;
5861
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005862 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005863 esc++;
5864 }
5865 return esc;
5866}
5867
5868/*
5869 * Remove any CTLESC characters from a string.
5870 */
5871static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005872rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005873{
Ron Yorston417622c2015-05-18 09:59:14 +02005874 static const char qchars[] ALIGN1 = {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005875 IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005876
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005877 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005878 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005879 unsigned protect_against_glob;
5880 unsigned globbing;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005881 IF_BASH_PATTERN_SUBST(unsigned slash = flag & RMESCAPE_SLASH;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005882
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005883 p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005884 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005885 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005886
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005887 q = p;
5888 r = str;
5889 if (flag & RMESCAPE_ALLOC) {
5890 size_t len = p - str;
5891 size_t fulllen = len + strlen(p) + 1;
5892
5893 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005894 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005895 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005896 /* p and str may be invalidated by makestrspace */
5897 str = (char *)stackblock() + strloc;
5898 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005899 } else if (flag & RMESCAPE_HEAP) {
5900 r = ckmalloc(fulllen);
5901 } else {
5902 r = stalloc(fulllen);
5903 }
5904 q = r;
5905 if (len > 0) {
Denis Vlasenko29eb3592008-05-18 14:06:08 +00005906 q = (char *)memcpy(q, str, len) + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005907 }
5908 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005909
Ron Yorston549deab2015-05-18 09:57:51 +02005910 inquotes = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005911 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005912 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005913 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005914 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005915// Note: both inquotes and protect_against_glob only affect whether
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005916 inquotes = ~inquotes;
5917 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005918 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005919 continue;
5920 }
Ron Yorston549deab2015-05-18 09:57:51 +02005921 if ((unsigned char)*p == CTLESC) {
5922 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02005923#if DEBUG
5924 if (*p == '\0')
5925 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
5926#endif
Ron Yorston549deab2015-05-18 09:57:51 +02005927 if (protect_against_glob) {
5928 *q++ = '\\';
5929 }
5930 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005931 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005932 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005933 goto copy;
5934 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005935#if BASH_PATTERN_SUBST
Ron Yorston417622c2015-05-18 09:59:14 +02005936 else if (*p == '/' && slash) {
5937 /* stop handling globbing and mark location of slash */
5938 globbing = slash = 0;
5939 *p = CTLESC;
5940 }
5941#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005942 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005943 copy:
5944 *q++ = *p++;
5945 }
5946 *q = '\0';
5947 if (flag & RMESCAPE_GROW) {
5948 expdest = r;
5949 STADJUST(q - r + 1, expdest);
5950 }
5951 return r;
5952}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005953#define pmatch(a, b) !fnmatch((a), (b), 0)
5954
5955/*
5956 * Prepare a pattern for a expmeta (internal glob(3)) call.
5957 *
5958 * Returns an stalloced string.
5959 */
5960static char *
Ron Yorston549deab2015-05-18 09:57:51 +02005961preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005962{
Ron Yorston549deab2015-05-18 09:57:51 +02005963 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005964}
5965
5966/*
5967 * Put a string on the stack.
5968 */
5969static void
5970memtodest(const char *p, size_t len, int syntax, int quotes)
5971{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005972 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005973
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005974 if (!len)
5975 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005976
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005977 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
5978
5979 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005980 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005981 if (c) {
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01005982 if (quotes & QUOTES_ESC) {
5983 int n = SIT(c, syntax);
5984 if (n == CCTL
5985 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
5986 && n == CBACK
5987 )
5988 ) {
5989 USTPUTC(CTLESC, q);
5990 }
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02005991 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005992 } else if (!(quotes & QUOTES_KEEPNUL))
5993 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005994 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005995 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005996
5997 expdest = q;
5998}
5999
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006000static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006001strtodest(const char *p, int syntax, int quotes)
6002{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006003 size_t len = strlen(p);
6004 memtodest(p, len, syntax, quotes);
6005 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006006}
6007
6008/*
6009 * Record the fact that we have to scan this region of the
6010 * string for IFS characters.
6011 */
6012static void
6013recordregion(int start, int end, int nulonly)
6014{
6015 struct ifsregion *ifsp;
6016
6017 if (ifslastp == NULL) {
6018 ifsp = &ifsfirst;
6019 } else {
6020 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00006021 ifsp = ckzalloc(sizeof(*ifsp));
6022 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006023 ifslastp->next = ifsp;
6024 INT_ON;
6025 }
6026 ifslastp = ifsp;
6027 ifslastp->begoff = start;
6028 ifslastp->endoff = end;
6029 ifslastp->nulonly = nulonly;
6030}
6031
6032static void
6033removerecordregions(int endoff)
6034{
6035 if (ifslastp == NULL)
6036 return;
6037
6038 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006039 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006040 struct ifsregion *ifsp;
6041 INT_OFF;
6042 ifsp = ifsfirst.next->next;
6043 free(ifsfirst.next);
6044 ifsfirst.next = ifsp;
6045 INT_ON;
6046 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006047 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006048 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006049 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006050 ifslastp = &ifsfirst;
6051 ifsfirst.endoff = endoff;
6052 }
6053 return;
6054 }
6055
6056 ifslastp = &ifsfirst;
6057 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006058 ifslastp = ifslastp->next;
6059 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006060 struct ifsregion *ifsp;
6061 INT_OFF;
6062 ifsp = ifslastp->next->next;
6063 free(ifslastp->next);
6064 ifslastp->next = ifsp;
6065 INT_ON;
6066 }
6067 if (ifslastp->endoff > endoff)
6068 ifslastp->endoff = endoff;
6069}
6070
6071static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006072exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006073{
Denys Vlasenkocd716832009-11-28 22:14:02 +01006074 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006075 char *name;
6076 struct passwd *pw;
6077 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006078 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006079
6080 name = p + 1;
6081
6082 while ((c = *++p) != '\0') {
6083 switch (c) {
6084 case CTLESC:
6085 return startp;
6086 case CTLQUOTEMARK:
6087 return startp;
6088 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006089 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006090 goto done;
6091 break;
6092 case '/':
6093 case CTLENDVAR:
6094 goto done;
6095 }
6096 }
6097 done:
6098 *p = '\0';
6099 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02006100 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006101 } else {
6102 pw = getpwnam(name);
6103 if (pw == NULL)
6104 goto lose;
6105 home = pw->pw_dir;
6106 }
6107 if (!home || !*home)
6108 goto lose;
6109 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006110 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006111 return p;
6112 lose:
6113 *p = c;
6114 return startp;
6115}
6116
6117/*
6118 * Execute a command inside back quotes. If it's a builtin command, we
6119 * want to save its output in a block obtained from malloc. Otherwise
6120 * we fork off a subprocess and get the output of the command via a pipe.
6121 * Should be called with interrupts off.
6122 */
6123struct backcmd { /* result of evalbackcmd */
6124 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006125 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00006126 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006127 struct job *jp; /* job structure for command */
6128};
6129
6130/* These forward decls are needed to use "eval" code for backticks handling: */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006131#define EV_EXIT 01 /* exit after evaluating tree */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02006132static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006133
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02006134static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006135evalbackcmd(union node *n, struct backcmd *result)
6136{
Denys Vlasenko579ad102016-10-25 21:10:20 +02006137 int pip[2];
6138 struct job *jp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006139
6140 result->fd = -1;
6141 result->buf = NULL;
6142 result->nleft = 0;
6143 result->jp = NULL;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006144 if (n == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006145 goto out;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006146 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006147
Denys Vlasenko579ad102016-10-25 21:10:20 +02006148 if (pipe(pip) < 0)
6149 ash_msg_and_raise_error("pipe call failed");
6150 jp = makejob(/*n,*/ 1);
6151 if (forkshell(jp, n, FORK_NOJOB) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02006152 /* child */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006153 FORCE_INT_ON;
6154 close(pip[0]);
6155 if (pip[1] != 1) {
6156 /*close(1);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02006157 dup2_or_raise(pip[1], 1);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006158 close(pip[1]);
6159 }
Denys Vlasenko960ca382016-10-25 18:12:15 +02006160/* TODO: eflag clearing makes the following not abort:
6161 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6162 * which is what bash does (unless it is in POSIX mode).
6163 * dash deleted "eflag = 0" line in the commit
6164 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6165 * [EVAL] Don't clear eflag in evalbackcmd
6166 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6167 */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006168 eflag = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006169 ifsfree();
Denys Vlasenko579ad102016-10-25 21:10:20 +02006170 evaltree(n, EV_EXIT); /* actually evaltreenr... */
6171 /* NOTREACHED */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006172 }
Denys Vlasenko70392332016-10-27 02:31:55 +02006173 /* parent */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006174 close(pip[1]);
6175 result->fd = pip[0];
6176 result->jp = jp;
6177
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006178 out:
6179 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6180 result->fd, result->buf, result->nleft, result->jp));
6181}
6182
6183/*
6184 * Expand stuff in backwards quotes.
6185 */
6186static void
Ron Yorston549deab2015-05-18 09:57:51 +02006187expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006188{
6189 struct backcmd in;
6190 int i;
6191 char buf[128];
6192 char *p;
6193 char *dest;
6194 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02006195 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006196 struct stackmark smark;
6197
6198 INT_OFF;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02006199 startloc = expdest - (char *)stackblock();
6200 pushstackmark(&smark, startloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006201 evalbackcmd(cmd, &in);
6202 popstackmark(&smark);
6203
6204 p = in.buf;
6205 i = in.nleft;
6206 if (i == 0)
6207 goto read;
6208 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02006209 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006210 read:
6211 if (in.fd < 0)
6212 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01006213 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006214 TRACE(("expbackq: read returns %d\n", i));
6215 if (i <= 0)
6216 break;
6217 p = buf;
6218 }
6219
Denis Vlasenko60818682007-09-28 22:07:23 +00006220 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006221 if (in.fd >= 0) {
6222 close(in.fd);
6223 back_exitstatus = waitforjob(in.jp);
6224 }
6225 INT_ON;
6226
6227 /* Eat all trailing newlines */
6228 dest = expdest;
6229 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6230 STUNPUTC(dest);
6231 expdest = dest;
6232
Ron Yorston549deab2015-05-18 09:57:51 +02006233 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006234 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006235 TRACE(("evalbackq: size:%d:'%.*s'\n",
6236 (int)((dest - (char *)stackblock()) - startloc),
6237 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006238 stackblock() + startloc));
6239}
6240
Denys Vlasenko0b883582016-12-23 16:49:07 +01006241#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006242/*
6243 * Expand arithmetic expression. Backup to start of expression,
6244 * evaluate, place result in (backed up) result, adjust string position.
6245 */
6246static void
Ron Yorston549deab2015-05-18 09:57:51 +02006247expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006248{
6249 char *p, *start;
6250 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006251 int len;
6252
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006253 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006254
6255 /*
6256 * This routine is slightly over-complicated for
6257 * efficiency. Next we scan backwards looking for the
6258 * start of arithmetic.
6259 */
6260 start = stackblock();
6261 p = expdest - 1;
6262 *p = '\0';
6263 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006264 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006265 int esc;
6266
Denys Vlasenkocd716832009-11-28 22:14:02 +01006267 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006268 p--;
6269#if DEBUG
6270 if (p < start) {
6271 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6272 }
6273#endif
6274 }
6275
6276 esc = esclen(start, p);
6277 if (!(esc % 2)) {
6278 break;
6279 }
6280
6281 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006282 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006283
6284 begoff = p - start;
6285
6286 removerecordregions(begoff);
6287
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006288 expdest = p;
6289
Ron Yorston549deab2015-05-18 09:57:51 +02006290 if (flag & QUOTES_ESC)
6291 rmescapes(p + 1, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006292
Ron Yorston549deab2015-05-18 09:57:51 +02006293 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006294
Ron Yorston549deab2015-05-18 09:57:51 +02006295 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006296 recordregion(begoff, begoff + len, 0);
6297}
6298#endif
6299
6300/* argstr needs it */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006301static char *evalvar(char *p, int flags, struct strlist *var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006302
6303/*
6304 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6305 * characters to allow for further processing. Otherwise treat
6306 * $@ like $* since no splitting will be performed.
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006307 *
6308 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
Denys Vlasenko10ad6222017-04-17 16:13:32 +02006309 * over shell variables. Needed for "A=a B=$A; echo $B" case - we use it
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006310 * for correct expansion of "B=$A" word.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006311 */
6312static void
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006313argstr(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006314{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006315 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006316 '=',
6317 ':',
6318 CTLQUOTEMARK,
6319 CTLENDVAR,
6320 CTLESC,
6321 CTLVAR,
6322 CTLBACKQ,
Denys Vlasenko0b883582016-12-23 16:49:07 +01006323#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006324 CTLENDARI,
6325#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006326 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006327 };
6328 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006329 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006330 int inquotes;
6331 size_t length;
6332 int startloc;
6333
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006334 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006335 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006336 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006337 reject++;
6338 }
6339 inquotes = 0;
6340 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006341 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006342 char *q;
6343
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006344 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006345 tilde:
6346 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006347 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006348 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006349 }
6350 start:
6351 startloc = expdest - (char *)stackblock();
6352 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006353 unsigned char c;
6354
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006355 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006356 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006357 if (c) {
6358 if (!(c & 0x80)
Denys Vlasenko0b883582016-12-23 16:49:07 +01006359 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006360 ) {
6361 /* c == '=' || c == ':' || c == CTLENDARI */
6362 length++;
6363 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006364 }
6365 if (length > 0) {
6366 int newloc;
6367 expdest = stack_nputstr(p, length, expdest);
6368 newloc = expdest - (char *)stackblock();
6369 if (breakall && !inquotes && newloc > startloc) {
6370 recordregion(startloc, newloc, 0);
6371 }
6372 startloc = newloc;
6373 }
6374 p += length + 1;
6375 length = 0;
6376
6377 switch (c) {
6378 case '\0':
6379 goto breakloop;
6380 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006381 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006382 p--;
6383 continue;
6384 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006385 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006386 reject++;
6387 /* fall through */
6388 case ':':
6389 /*
6390 * sort of a hack - expand tildes in variable
6391 * assignments (after the first '=' and after ':'s).
6392 */
6393 if (*--p == '~') {
6394 goto tilde;
6395 }
6396 continue;
6397 }
6398
6399 switch (c) {
6400 case CTLENDVAR: /* ??? */
6401 goto breakloop;
6402 case CTLQUOTEMARK:
Ron Yorston549deab2015-05-18 09:57:51 +02006403 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006404 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006405 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6406 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006407 goto start;
6408 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006409 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006410 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006411 p--;
6412 length++;
6413 startloc++;
6414 }
6415 break;
6416 case CTLESC:
6417 startloc++;
6418 length++;
Ron Yorston549deab2015-05-18 09:57:51 +02006419
6420 /*
6421 * Quoted parameter expansion pattern: remove quote
6422 * unless inside inner quotes or we have a literal
6423 * backslash.
6424 */
6425 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6426 EXP_QPAT && *p != '\\')
6427 break;
6428
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006429 goto addquote;
6430 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006431 TRACE(("argstr: evalvar('%s')\n", p));
Ron Yorston549deab2015-05-18 09:57:51 +02006432 p = evalvar(p, flags | inquotes, var_str_list);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006433 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006434 goto start;
6435 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006436 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006437 argbackq = argbackq->next;
6438 goto start;
Denys Vlasenko0b883582016-12-23 16:49:07 +01006439#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006440 case CTLENDARI:
6441 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006442 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006443 goto start;
6444#endif
6445 }
6446 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006447 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006448}
6449
6450static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006451scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6452 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006453{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006454 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006455 char c;
6456
6457 loc = startp;
6458 loc2 = rmesc;
6459 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006460 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006461 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006462
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006463 c = *loc2;
6464 if (zero) {
6465 *loc2 = '\0';
6466 s = rmesc;
6467 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006468 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006469
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006470 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006471 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006472 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006473 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006474 loc++;
6475 loc++;
6476 loc2++;
6477 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006478 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006479}
6480
6481static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006482scanright(char *startp, char *rmesc, char *rmescend,
6483 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006484{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006485#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6486 int try2optimize = match_at_start;
6487#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006488 int esc = 0;
6489 char *loc;
6490 char *loc2;
6491
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006492 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6493 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6494 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6495 * Logic:
6496 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6497 * and on each iteration they go back two/one char until they reach the beginning.
6498 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6499 */
6500 /* TODO: document in what other circumstances we are called. */
6501
6502 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006503 int match;
6504 char c = *loc2;
6505 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006506 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006507 *loc2 = '\0';
6508 s = rmesc;
6509 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006510 match = pmatch(pattern, s);
6511 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006512 *loc2 = c;
6513 if (match)
6514 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006515#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6516 if (try2optimize) {
6517 /* Maybe we can optimize this:
6518 * if pattern ends with unescaped *, we can avoid checking
Denys Vlasenko10ad6222017-04-17 16:13:32 +02006519 * shorter strings: if "foo*" doesn't match "raw_value_of_v",
6520 * it won't match truncated "raw_value_of_" strings too.
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006521 */
6522 unsigned plen = strlen(pattern);
6523 /* Does it end with "*"? */
6524 if (plen != 0 && pattern[--plen] == '*') {
6525 /* "xxxx*" is not escaped */
6526 /* "xxx\*" is escaped */
6527 /* "xx\\*" is not escaped */
6528 /* "x\\\*" is escaped */
6529 int slashes = 0;
6530 while (plen != 0 && pattern[--plen] == '\\')
6531 slashes++;
6532 if (!(slashes & 1))
6533 break; /* ends with unescaped "*" */
6534 }
6535 try2optimize = 0;
6536 }
6537#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006538 loc--;
6539 if (quotes) {
6540 if (--esc < 0) {
6541 esc = esclen(startp, loc);
6542 }
6543 if (esc % 2) {
6544 esc--;
6545 loc--;
6546 }
6547 }
6548 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006549 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006550}
6551
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006552static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006553static void
6554varunset(const char *end, const char *var, const char *umsg, int varflags)
6555{
6556 const char *msg;
6557 const char *tail;
6558
6559 tail = nullstr;
6560 msg = "parameter not set";
6561 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006562 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006563 if (varflags & VSNUL)
6564 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006565 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006566 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006567 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006568 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006569 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006570}
6571
6572static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006573subevalvar(char *p, char *varname, int strloc, int subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006574 int startloc, int varflags, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006575{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006576 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006577 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006578 char *startp;
6579 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006580 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006581 char *str;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006582 IF_BASH_SUBSTR(int pos, len, orig_len;)
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006583 int amount, resetloc;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006584 IF_BASH_PATTERN_SUBST(int workloc;)
6585 IF_BASH_PATTERN_SUBST(char *repl = NULL;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006586 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006587 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006588
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006589 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6590 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006591
Ron Yorstoneb6b48b2015-05-18 09:51:35 +02006592 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
Ron Yorston549deab2015-05-18 09:57:51 +02006593 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6594 var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006595 STPUTC('\0', expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006596 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006597 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006598
6599 switch (subtype) {
6600 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006601 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006602 amount = startp - expdest;
6603 STADJUST(amount, expdest);
6604 return startp;
6605
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006606 case VSQUESTION:
6607 varunset(p, varname, startp, varflags);
6608 /* NOTREACHED */
6609
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006610#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006611 case VSSUBSTR:
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +02006612//TODO: support more general format ${v:EXPR:EXPR},
6613// where EXPR follows $(()) rules
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006614 loc = str = stackblock() + strloc;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006615 /* Read POS in ${var:POS:LEN} */
6616 pos = atoi(loc); /* number(loc) errors out on "1:4" */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006617 len = str - startp - 1;
6618
6619 /* *loc != '\0', guaranteed by parser */
6620 if (quotes) {
6621 char *ptr;
6622
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006623 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006624 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006625 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006626 len--;
6627 ptr++;
6628 }
6629 }
6630 }
6631 orig_len = len;
6632
6633 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006634 /* ${var::LEN} */
6635 len = number(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006636 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006637 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006638 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006639 while (*loc && *loc != ':') {
6640 /* TODO?
6641 * bash complains on: var=qwe; echo ${var:1a:123}
6642 if (!isdigit(*loc))
6643 ash_msg_and_raise_error(msg_illnum, str);
6644 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006645 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006646 }
6647 if (*loc++ == ':') {
6648 len = number(loc);
6649 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006650 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006651 if (pos < 0) {
6652 /* ${VAR:$((-n)):l} starts n chars from the end */
6653 pos = orig_len + pos;
6654 }
6655 if ((unsigned)pos >= orig_len) {
6656 /* apart from obvious ${VAR:999999:l},
6657 * covers ${VAR:$((-9999999)):l} - result is ""
6658 * (bash-compat)
6659 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006660 pos = 0;
6661 len = 0;
6662 }
6663 if (len > (orig_len - pos))
6664 len = orig_len - pos;
6665
6666 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006667 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006668 str++;
6669 }
6670 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006671 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006672 *loc++ = *str++;
6673 *loc++ = *str++;
6674 }
6675 *loc = '\0';
6676 amount = loc - expdest;
6677 STADJUST(amount, expdest);
6678 return loc;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006679#endif /* BASH_SUBSTR */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006680 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006681
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006682 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006683
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006684#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006685 /* We'll comeback here if we grow the stack while handling
6686 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6687 * stack will need rebasing, and we'll need to remove our work
6688 * areas each time
6689 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006690 restart:
6691#endif
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006692
6693 amount = expdest - ((char *)stackblock() + resetloc);
6694 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006695 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006696
6697 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006698 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006699 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006700 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006701 if (rmesc != startp) {
6702 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006703 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006704 }
6705 }
6706 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006707 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02006708 /*
6709 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6710 * The result is a_\_z_c (not a\_\_z_c)!
6711 *
6712 * The search pattern and replace string treat backslashes differently!
6713 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6714 * and string. It's only used on the first call.
6715 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006716 preglob(str, IF_BASH_PATTERN_SUBST(
Ron Yorston417622c2015-05-18 09:59:14 +02006717 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006718 RMESCAPE_SLASH : ) 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006719
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006720#if BASH_PATTERN_SUBST
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006721 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006722 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006723 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006724
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006725 if (!repl) {
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006726 repl = strchr(str, CTLESC);
6727 if (repl)
Ron Yorston417622c2015-05-18 09:59:14 +02006728 *repl++ = '\0';
6729 else
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006730 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006731 }
Ron Yorston417622c2015-05-18 09:59:14 +02006732 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006733
6734 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006735 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006736 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006737
6738 len = 0;
6739 idx = startp;
6740 end = str - 1;
6741 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006742 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006743 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006744 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006745 if (!loc) {
6746 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006747 char *restart_detect = stackblock();
6748 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006749 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006750 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006751 idx++;
6752 len++;
6753 STPUTC(*idx, expdest);
6754 }
6755 if (stackblock() != restart_detect)
6756 goto restart;
6757 idx++;
6758 len++;
6759 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006760 /* continue; - prone to quadratic behavior, smarter code: */
6761 if (idx >= end)
6762 break;
6763 if (str[0] == '*') {
6764 /* Pattern is "*foo". If "*foo" does not match "long_string",
6765 * it would never match "ong_string" etc, no point in trying.
6766 */
6767 goto skip_matching;
6768 }
6769 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006770 }
6771
6772 if (subtype == VSREPLACEALL) {
6773 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006774 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006775 idx++;
6776 idx++;
6777 rmesc++;
6778 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006779 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006780 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006781 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006782
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006783 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006784 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006785 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006786 if (quotes && *loc == '\\') {
6787 STPUTC(CTLESC, expdest);
6788 len++;
6789 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006790 STPUTC(*loc, expdest);
6791 if (stackblock() != restart_detect)
6792 goto restart;
6793 len++;
6794 }
6795
6796 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006797 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006798 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006799 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006800 STPUTC(*idx, expdest);
6801 if (stackblock() != restart_detect)
6802 goto restart;
6803 len++;
6804 idx++;
6805 }
6806 break;
6807 }
6808 }
6809
6810 /* We've put the replaced text into a buffer at workloc, now
6811 * move it to the right place and adjust the stack.
6812 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006813 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006814 startp = (char *)stackblock() + startloc;
6815 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006816 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006817 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006818 STADJUST(-amount, expdest);
6819 return startp;
6820 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006821#endif /* BASH_PATTERN_SUBST */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006822
6823 subtype -= VSTRIMRIGHT;
6824#if DEBUG
6825 if (subtype < 0 || subtype > 7)
6826 abort();
6827#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006828 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006829 zero = subtype >> 1;
6830 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6831 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6832
6833 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6834 if (loc) {
6835 if (zero) {
6836 memmove(startp, loc, str - loc);
6837 loc = startp + (str - loc) - 1;
6838 }
6839 *loc = '\0';
6840 amount = loc - expdest;
6841 STADJUST(amount, expdest);
6842 }
6843 return loc;
6844}
6845
6846/*
6847 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006848 * name parameter (examples):
6849 * ash -c 'echo $1' name:'1='
6850 * ash -c 'echo $qwe' name:'qwe='
6851 * ash -c 'echo $$' name:'$='
6852 * ash -c 'echo ${$}' name:'$='
6853 * ash -c 'echo ${$##q}' name:'$=q'
6854 * ash -c 'echo ${#$}' name:'$='
6855 * note: examples with bad shell syntax:
6856 * ash -c 'echo ${#$1}' name:'$=1'
6857 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006858 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02006859static NOINLINE ssize_t
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006860varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int *quotedp)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006861{
Mike Frysinger98c52642009-04-02 10:02:37 +00006862 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006863 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006864 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006865 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006866 int sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006867 int quoted = *quotedp;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006868 int subtype = varflags & VSTYPE;
6869 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6870 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006871 int syntax;
6872
6873 sep = (flags & EXP_FULL) << CHAR_BIT;
6874 syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006875
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006876 switch (*name) {
6877 case '$':
6878 num = rootpid;
6879 goto numvar;
6880 case '?':
6881 num = exitstatus;
6882 goto numvar;
6883 case '#':
6884 num = shellparam.nparam;
6885 goto numvar;
6886 case '!':
6887 num = backgndpid;
6888 if (num == 0)
6889 return -1;
6890 numvar:
6891 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006892 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006893 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00006894 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006895 for (i = NOPTS - 1; i >= 0; i--) {
6896 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00006897 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006898 len++;
6899 }
6900 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006901 check_1char_name:
6902#if 0
6903 /* handles cases similar to ${#$1} */
6904 if (name[2] != '\0')
6905 raise_error_syntax("bad substitution");
6906#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006907 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006908 case '@':
6909 if (quoted && sep)
6910 goto param;
6911 /* fall through */
6912 case '*': {
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006913 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006914 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006915
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006916 if (quoted)
6917 sep = 0;
6918 sep |= ifsset() ? ifsval()[0] : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006919 param:
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006920 sepc = sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006921 *quotedp = !sepc;
6922 ap = shellparam.p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006923 if (!ap)
6924 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006925 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006926 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006927
6928 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006929 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006930 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006931 }
6932 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006933 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006934 } /* case '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006935 case '0':
6936 case '1':
6937 case '2':
6938 case '3':
6939 case '4':
6940 case '5':
6941 case '6':
6942 case '7':
6943 case '8':
6944 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02006945 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006946 if (num < 0 || num > shellparam.nparam)
6947 return -1;
6948 p = num ? shellparam.p[num - 1] : arg0;
6949 goto value;
6950 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006951 /* NB: name has form "VAR=..." */
6952
6953 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6954 * which should be considered before we check variables. */
6955 if (var_str_list) {
6956 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6957 p = NULL;
6958 do {
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00006959 char *str, *eq;
6960 str = var_str_list->text;
6961 eq = strchr(str, '=');
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006962 if (!eq) /* stop at first non-assignment */
6963 break;
6964 eq++;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00006965 if (name_len == (unsigned)(eq - str)
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006966 && strncmp(str, name, name_len) == 0
6967 ) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006968 p = eq;
6969 /* goto value; - WRONG! */
6970 /* think "A=1 A=2 B=$A" */
6971 }
6972 var_str_list = var_str_list->next;
6973 } while (var_str_list);
6974 if (p)
6975 goto value;
6976 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006977 p = lookupvar(name);
6978 value:
6979 if (!p)
6980 return -1;
6981
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006982 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006983#if ENABLE_UNICODE_SUPPORT
6984 if (subtype == VSLENGTH && len > 0) {
6985 reinit_unicode_for_ash();
6986 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00006987 STADJUST(-len, expdest);
6988 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006989 len = unicode_strlen(p);
6990 }
6991 }
6992#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006993 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006994 }
6995
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006996 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006997 STADJUST(-len, expdest);
6998 return len;
6999}
7000
7001/*
7002 * Expand a variable, and return a pointer to the next character in the
7003 * input string.
7004 */
7005static char *
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007006evalvar(char *p, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007007{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007008 char varflags;
7009 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02007010 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007011 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007012 char *var;
7013 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007014 int startloc;
7015 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007016
Denys Vlasenkob0d63382009-09-16 16:18:32 +02007017 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007018 subtype = varflags & VSTYPE;
Denys Vlasenko88e15702016-10-26 01:55:56 +02007019
7020 if (!subtype)
7021 raise_error_syntax("bad substitution");
7022
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007023 quoted = flag & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007024 var = p;
7025 easy = (!quoted || (*var == '@' && shellparam.nparam));
7026 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02007027 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007028
7029 again:
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007030 varlen = varvalue(var, varflags, flag, var_str_list, &quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007031 if (varflags & VSNUL)
7032 varlen--;
7033
7034 if (subtype == VSPLUS) {
7035 varlen = -1 - varlen;
7036 goto vsplus;
7037 }
7038
7039 if (subtype == VSMINUS) {
7040 vsplus:
7041 if (varlen < 0) {
7042 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02007043 p,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007044 flag | EXP_TILDE | EXP_WORD,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007045 var_str_list
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007046 );
7047 goto end;
7048 }
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007049 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007050 }
7051
7052 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007053 if (varlen >= 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007054 goto record;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007055
7056 subevalvar(p, var, 0, subtype, startloc, varflags,
7057 flag & ~QUOTES_ESC, var_str_list);
7058 varflags &= ~VSNUL;
7059 /*
7060 * Remove any recorded regions beyond
7061 * start of variable
7062 */
7063 removerecordregions(startloc);
7064 goto again;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007065 }
7066
7067 if (varlen < 0 && uflag)
7068 varunset(p, var, 0, 0);
7069
7070 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007071 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007072 goto record;
7073 }
7074
7075 if (subtype == VSNORMAL) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007076 record:
7077 if (!easy)
7078 goto end;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007079 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007080 goto end;
7081 }
7082
7083#if DEBUG
7084 switch (subtype) {
7085 case VSTRIMLEFT:
7086 case VSTRIMLEFTMAX:
7087 case VSTRIMRIGHT:
7088 case VSTRIMRIGHTMAX:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007089#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007090 case VSSUBSTR:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007091#endif
7092#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007093 case VSREPLACE:
7094 case VSREPLACEALL:
7095#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007096 break;
7097 default:
7098 abort();
7099 }
7100#endif
7101
7102 if (varlen >= 0) {
7103 /*
7104 * Terminate the string and start recording the pattern
7105 * right after it
7106 */
7107 STPUTC('\0', expdest);
7108 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007109 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007110 startloc, varflags, flag, var_str_list)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007111 int amount = expdest - (
7112 (char *)stackblock() + patloc - 1
7113 );
7114 STADJUST(-amount, expdest);
7115 }
7116 /* Remove any recorded regions beyond start of variable */
7117 removerecordregions(startloc);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007118 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007119 }
7120
7121 end:
7122 if (subtype != VSNORMAL) { /* skip to end of alternative */
7123 int nesting = 1;
7124 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007125 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007126 if (c == CTLESC)
7127 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02007128 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007129 if (varlen >= 0)
7130 argbackq = argbackq->next;
7131 } else if (c == CTLVAR) {
7132 if ((*p++ & VSTYPE) != VSNORMAL)
7133 nesting++;
7134 } else if (c == CTLENDVAR) {
7135 if (--nesting == 0)
7136 break;
7137 }
7138 }
7139 }
7140 return p;
7141}
7142
7143/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007144 * Add a file name to the list.
7145 */
7146static void
7147addfname(const char *name)
7148{
7149 struct strlist *sp;
7150
Denis Vlasenko597906c2008-02-20 16:38:54 +00007151 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02007152 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007153 *exparg.lastp = sp;
7154 exparg.lastp = &sp->next;
7155}
7156
Felix Fietkaub5b21122017-01-31 21:58:55 +01007157/* Avoid glob() (and thus, stat() et al) for words like "echo" */
7158static int
7159hasmeta(const char *p)
7160{
7161 static const char chars[] ALIGN1 = {
7162 '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
7163 };
7164
7165 for (;;) {
7166 p = strpbrk(p, chars);
7167 if (!p)
7168 break;
7169 switch ((unsigned char) *p) {
7170 case CTLQUOTEMARK:
7171 for (;;) {
7172 p++;
7173 if (*p == CTLQUOTEMARK)
7174 break;
7175 if (*p == CTLESC)
7176 p++;
7177 if (*p == '\0') /* huh? */
7178 return 0;
7179 }
7180 break;
7181 case '\\':
7182 case CTLESC:
7183 p++;
7184 if (*p == '\0')
7185 return 0;
7186 break;
7187 case '[':
7188 if (!strchr(p + 1, ']')) {
7189 /* It's not a properly closed [] pattern,
7190 * but other metas may follow. Continue checking.
7191 * my[file* _is_ globbed by bash
7192 * and matches filenames like "my[file1".
7193 */
7194 break;
7195 }
7196 /* fallthrough */
7197 default:
7198 /* case '*': */
7199 /* case '?': */
7200 return 1;
7201 }
7202 p++;
7203 }
7204
7205 return 0;
7206}
7207
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007208/* If we want to use glob() from libc... */
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007209#if !ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007210
7211/* Add the result of glob() to the list */
7212static void
7213addglob(const glob_t *pglob)
7214{
7215 char **p = pglob->gl_pathv;
7216
7217 do {
7218 addfname(*p);
7219 } while (*++p);
7220}
7221static void
7222expandmeta(struct strlist *str /*, int flag*/)
7223{
7224 /* TODO - EXP_REDIR */
7225
7226 while (str) {
7227 char *p;
7228 glob_t pglob;
7229 int i;
7230
7231 if (fflag)
7232 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007233
Felix Fietkaub5b21122017-01-31 21:58:55 +01007234 if (!hasmeta(str->text))
7235 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007236
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007237 INT_OFF;
7238 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007239// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7240// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7241//
7242// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7243// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7244// Which means you need to unescape the string, right? Not so fast:
7245// if there _is_ a file named "file\?" (with backslash), it is returned
7246// as "file\?" too (whichever pattern you used to find it, say, "file*").
Denys Vlasenko10ad6222017-04-17 16:13:32 +02007247// You DON'T KNOW by looking at the result whether you need to unescape it.
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007248//
7249// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7250// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7251// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7252// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7253// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7254// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7255 i = glob(p, 0, NULL, &pglob);
7256 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007257 if (p != str->text)
7258 free(p);
7259 switch (i) {
7260 case 0:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007261#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007262 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7263 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7264 goto nometa2;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007265#endif
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007266 addglob(&pglob);
7267 globfree(&pglob);
7268 INT_ON;
7269 break;
7270 case GLOB_NOMATCH:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007271 //nometa2:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007272 globfree(&pglob);
7273 INT_ON;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007274 nometa:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007275 *exparg.lastp = str;
7276 rmescapes(str->text, 0);
7277 exparg.lastp = &str->next;
7278 break;
7279 default: /* GLOB_NOSPACE */
7280 globfree(&pglob);
7281 INT_ON;
7282 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7283 }
7284 str = str->next;
7285 }
7286}
7287
7288#else
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007289/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007290
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007291/*
7292 * Do metacharacter (i.e. *, ?, [...]) expansion.
7293 */
7294static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007295expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007296{
7297 char *p;
7298 const char *cp;
7299 char *start;
7300 char *endname;
7301 int metaflag;
7302 struct stat statb;
7303 DIR *dirp;
7304 struct dirent *dp;
7305 int atend;
7306 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007307 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007308
7309 metaflag = 0;
7310 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007311 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007312 if (*p == '*' || *p == '?')
7313 metaflag = 1;
7314 else if (*p == '[') {
7315 char *q = p + 1;
7316 if (*q == '!')
7317 q++;
7318 for (;;) {
7319 if (*q == '\\')
7320 q++;
7321 if (*q == '/' || *q == '\0')
7322 break;
7323 if (*++q == ']') {
7324 metaflag = 1;
7325 break;
7326 }
7327 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007328 } else {
7329 if (*p == '\\')
7330 esc++;
7331 if (p[esc] == '/') {
7332 if (metaflag)
7333 break;
7334 start = p + esc + 1;
7335 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007336 }
7337 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007338 if (metaflag == 0) { /* we've reached the end of the file name */
7339 if (enddir != expdir)
7340 metaflag++;
7341 p = name;
7342 do {
7343 if (*p == '\\')
7344 p++;
7345 *enddir++ = *p;
7346 } while (*p++);
7347 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7348 addfname(expdir);
7349 return;
7350 }
7351 endname = p;
7352 if (name < start) {
7353 p = name;
7354 do {
7355 if (*p == '\\')
7356 p++;
7357 *enddir++ = *p++;
7358 } while (p < start);
7359 }
7360 if (enddir == expdir) {
7361 cp = ".";
7362 } else if (enddir == expdir + 1 && *expdir == '/') {
7363 cp = "/";
7364 } else {
7365 cp = expdir;
7366 enddir[-1] = '\0';
7367 }
7368 dirp = opendir(cp);
7369 if (dirp == NULL)
7370 return;
7371 if (enddir != expdir)
7372 enddir[-1] = '/';
7373 if (*endname == 0) {
7374 atend = 1;
7375 } else {
7376 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007377 *endname = '\0';
7378 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007379 }
7380 matchdot = 0;
7381 p = start;
7382 if (*p == '\\')
7383 p++;
7384 if (*p == '.')
7385 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007386 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007387 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007388 continue;
7389 if (pmatch(start, dp->d_name)) {
7390 if (atend) {
7391 strcpy(enddir, dp->d_name);
7392 addfname(expdir);
7393 } else {
7394 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7395 continue;
7396 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007397 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007398 }
7399 }
7400 }
7401 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007402 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007403 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007404}
7405
7406static struct strlist *
7407msort(struct strlist *list, int len)
7408{
7409 struct strlist *p, *q = NULL;
7410 struct strlist **lpp;
7411 int half;
7412 int n;
7413
7414 if (len <= 1)
7415 return list;
7416 half = len >> 1;
7417 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007418 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007419 q = p;
7420 p = p->next;
7421 }
7422 q->next = NULL; /* terminate first half of list */
7423 q = msort(list, half); /* sort first half of list */
7424 p = msort(p, len - half); /* sort second half */
7425 lpp = &list;
7426 for (;;) {
7427#if ENABLE_LOCALE_SUPPORT
7428 if (strcoll(p->text, q->text) < 0)
7429#else
7430 if (strcmp(p->text, q->text) < 0)
7431#endif
7432 {
7433 *lpp = p;
7434 lpp = &p->next;
7435 p = *lpp;
7436 if (p == NULL) {
7437 *lpp = q;
7438 break;
7439 }
7440 } else {
7441 *lpp = q;
7442 lpp = &q->next;
7443 q = *lpp;
7444 if (q == NULL) {
7445 *lpp = p;
7446 break;
7447 }
7448 }
7449 }
7450 return list;
7451}
7452
7453/*
7454 * Sort the results of file name expansion. It calculates the number of
7455 * strings to sort and then calls msort (short for merge sort) to do the
7456 * work.
7457 */
7458static struct strlist *
7459expsort(struct strlist *str)
7460{
7461 int len;
7462 struct strlist *sp;
7463
7464 len = 0;
7465 for (sp = str; sp; sp = sp->next)
7466 len++;
7467 return msort(str, len);
7468}
7469
7470static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007471expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007472{
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007473 /* TODO - EXP_REDIR */
7474
7475 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007476 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007477 struct strlist **savelastp;
7478 struct strlist *sp;
7479 char *p;
7480
7481 if (fflag)
7482 goto nometa;
Felix Fietkaub5b21122017-01-31 21:58:55 +01007483 if (!hasmeta(str->text))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007484 goto nometa;
7485 savelastp = exparg.lastp;
7486
7487 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007488 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007489 {
7490 int i = strlen(str->text);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007491//BUGGY estimation of how long expanded name can be
7492 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007493 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007494 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007495 free(expdir);
7496 if (p != str->text)
7497 free(p);
7498 INT_ON;
7499 if (exparg.lastp == savelastp) {
7500 /*
7501 * no matches
7502 */
7503 nometa:
7504 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007505 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007506 exparg.lastp = &str->next;
7507 } else {
7508 *exparg.lastp = NULL;
7509 *savelastp = sp = expsort(*savelastp);
7510 while (sp->next != NULL)
7511 sp = sp->next;
7512 exparg.lastp = &sp->next;
7513 }
7514 str = str->next;
7515 }
7516}
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007517#endif /* ENABLE_ASH_INTERNAL_GLOB */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007518
7519/*
7520 * Perform variable substitution and command substitution on an argument,
7521 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7522 * perform splitting and file name expansion. When arglist is NULL, perform
7523 * here document expansion.
7524 */
7525static void
7526expandarg(union node *arg, struct arglist *arglist, int flag)
7527{
7528 struct strlist *sp;
7529 char *p;
7530
7531 argbackq = arg->narg.backquote;
7532 STARTSTACKSTR(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007533 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007534 argstr(arg->narg.text, flag,
7535 /* var_str_list: */ arglist ? arglist->list : NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007536 p = _STPUTC('\0', expdest);
7537 expdest = p - 1;
7538 if (arglist == NULL) {
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007539 /* here document expanded */
7540 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007541 }
7542 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007543 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007544 exparg.lastp = &exparg.list;
7545 /*
7546 * TODO - EXP_REDIR
7547 */
7548 if (flag & EXP_FULL) {
7549 ifsbreakup(p, &exparg);
7550 *exparg.lastp = NULL;
7551 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007552 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007553 } else {
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007554 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007555 rmescapes(p, 0);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007556 TRACE(("expandarg: rmescapes:'%s'\n", p));
7557 }
Denis Vlasenko597906c2008-02-20 16:38:54 +00007558 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007559 sp->text = p;
7560 *exparg.lastp = sp;
7561 exparg.lastp = &sp->next;
7562 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007563 *exparg.lastp = NULL;
7564 if (exparg.list) {
7565 *arglist->lastp = exparg.list;
7566 arglist->lastp = exparg.lastp;
7567 }
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007568
7569 out:
7570 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007571}
7572
7573/*
7574 * Expand shell variables and backquotes inside a here document.
7575 */
7576static void
7577expandhere(union node *arg, int fd)
7578{
Ron Yorston549deab2015-05-18 09:57:51 +02007579 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007580 full_write(fd, stackblock(), expdest - (char *)stackblock());
7581}
7582
7583/*
7584 * Returns true if the pattern matches the string.
7585 */
7586static int
7587patmatch(char *pattern, const char *string)
7588{
Ron Yorston549deab2015-05-18 09:57:51 +02007589 return pmatch(preglob(pattern, 0), string);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007590}
7591
7592/*
7593 * See if a pattern matches in a case statement.
7594 */
7595static int
7596casematch(union node *pattern, char *val)
7597{
7598 struct stackmark smark;
7599 int result;
7600
7601 setstackmark(&smark);
7602 argbackq = pattern->narg.backquote;
7603 STARTSTACKSTR(expdest);
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007604 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7605 /* var_str_list: */ NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007606 STACKSTRNUL(expdest);
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007607 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007608 result = patmatch(stackblock(), val);
7609 popstackmark(&smark);
7610 return result;
7611}
7612
7613
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007614/* ============ find_command */
7615
7616struct builtincmd {
7617 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007618 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007619 /* unsigned flags; */
7620};
7621#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007622/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007623 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007624#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007625#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007626
7627struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007628 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007629 union param {
7630 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007631 /* index >= 0 for commands without path (slashes) */
7632 /* (TODO: what exactly does the value mean? PATH position?) */
7633 /* index == -1 for commands with slashes */
7634 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007635 const struct builtincmd *cmd;
7636 struct funcnode *func;
7637 } u;
7638};
7639/* values of cmdtype */
7640#define CMDUNKNOWN -1 /* no entry in table for command */
7641#define CMDNORMAL 0 /* command is an executable program */
7642#define CMDFUNCTION 1 /* command is a shell function */
7643#define CMDBUILTIN 2 /* command is a shell builtin */
7644
7645/* action to find_command() */
7646#define DO_ERR 0x01 /* prints errors */
7647#define DO_ABS 0x02 /* checks absolute paths */
7648#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7649#define DO_ALTPATH 0x08 /* using alternate path */
7650#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7651
7652static void find_command(char *, struct cmdentry *, int, const char *);
7653
7654
7655/* ============ Hashing commands */
7656
7657/*
7658 * When commands are first encountered, they are entered in a hash table.
7659 * This ensures that a full path search will not have to be done for them
7660 * on each invocation.
7661 *
7662 * We should investigate converting to a linear search, even though that
7663 * would make the command name "hash" a misnomer.
7664 */
7665
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007666struct tblentry {
7667 struct tblentry *next; /* next entry in hash chain */
7668 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007669 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007670 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007671 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007672};
7673
Denis Vlasenko01631112007-12-16 17:20:38 +00007674static struct tblentry **cmdtable;
7675#define INIT_G_cmdtable() do { \
7676 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7677} while (0)
7678
7679static int builtinloc = -1; /* index in path of %builtin, or -1 */
7680
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007681
7682static void
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007683tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007684{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007685#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007686 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007687 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007688 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007689 while (*envp)
7690 putenv(*envp++);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007691 run_applet_no_and_exit(applet_no, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007692 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007693 /* re-exec ourselves with the new arguments */
7694 execve(bb_busybox_exec_path, argv, envp);
7695 /* If they called chroot or otherwise made the binary no longer
7696 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007697 }
7698#endif
7699
7700 repeat:
7701#ifdef SYSV
7702 do {
7703 execve(cmd, argv, envp);
7704 } while (errno == EINTR);
7705#else
7706 execve(cmd, argv, envp);
7707#endif
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007708 if (cmd != (char*) bb_busybox_exec_path && errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007709 /* Run "cmd" as a shell script:
7710 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7711 * "If the execve() function fails with ENOEXEC, the shell
7712 * shall execute a command equivalent to having a shell invoked
7713 * with the command name as its first operand,
7714 * with any remaining arguments passed to the new shell"
7715 *
7716 * That is, do not use $SHELL, user's shell, or /bin/sh;
7717 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007718 *
7719 * Note that bash reads ~80 chars of the file, and if it sees
7720 * a zero byte before it sees newline, it doesn't try to
7721 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007722 * message and exit code 126. For one, this prevents attempts
7723 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007724 */
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007725 argv[0] = cmd;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007726 cmd = (char*) bb_busybox_exec_path;
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007727 /* NB: this is only possible because all callers of shellexec()
7728 * ensure that the argv[-1] slot exists!
7729 */
7730 argv--;
7731 argv[0] = (char*) "ash";
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007732 goto repeat;
7733 }
7734}
7735
7736/*
7737 * Exec a program. Never returns. If you change this routine, you may
7738 * have to change the find_command routine as well.
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007739 * argv[-1] must exist and be writable! See tryexec() for why.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007740 */
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007741static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN;
7742static void shellexec(char *prog, char **argv, const char *path, int idx)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007743{
7744 char *cmdname;
7745 int e;
7746 char **envp;
7747 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007748 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007749
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007750 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007751 if (strchr(prog, '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007752#if ENABLE_FEATURE_SH_STANDALONE
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007753 || (applet_no = find_applet_by_name(prog)) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007754#endif
7755 ) {
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007756 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007757 if (applet_no >= 0) {
7758 /* We tried execing ourself, but it didn't work.
7759 * Maybe /proc/self/exe doesn't exist?
7760 * Try $PATH search.
7761 */
7762 goto try_PATH;
7763 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007764 e = errno;
7765 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007766 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007767 e = ENOENT;
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007768 while ((cmdname = path_advance(&path, prog)) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007769 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007770 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007771 if (errno != ENOENT && errno != ENOTDIR)
7772 e = errno;
7773 }
7774 stunalloc(cmdname);
7775 }
7776 }
7777
7778 /* Map to POSIX errors */
7779 switch (e) {
7780 case EACCES:
7781 exerrno = 126;
7782 break;
7783 case ENOENT:
7784 exerrno = 127;
7785 break;
7786 default:
7787 exerrno = 2;
7788 break;
7789 }
7790 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007791 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007792 prog, e, suppress_int));
7793 ash_msg_and_raise(EXEXIT, "%s: %s", prog, errmsg(e, "not found"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007794 /* NOTREACHED */
7795}
7796
7797static void
7798printentry(struct tblentry *cmdp)
7799{
7800 int idx;
7801 const char *path;
7802 char *name;
7803
7804 idx = cmdp->param.index;
7805 path = pathval();
7806 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007807 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007808 stunalloc(name);
7809 } while (--idx >= 0);
7810 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7811}
7812
7813/*
7814 * Clear out command entries. The argument specifies the first entry in
7815 * PATH which has changed.
7816 */
7817static void
7818clearcmdentry(int firstchange)
7819{
7820 struct tblentry **tblp;
7821 struct tblentry **pp;
7822 struct tblentry *cmdp;
7823
7824 INT_OFF;
7825 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7826 pp = tblp;
7827 while ((cmdp = *pp) != NULL) {
7828 if ((cmdp->cmdtype == CMDNORMAL &&
7829 cmdp->param.index >= firstchange)
7830 || (cmdp->cmdtype == CMDBUILTIN &&
7831 builtinloc >= firstchange)
7832 ) {
7833 *pp = cmdp->next;
7834 free(cmdp);
7835 } else {
7836 pp = &cmdp->next;
7837 }
7838 }
7839 }
7840 INT_ON;
7841}
7842
7843/*
7844 * Locate a command in the command hash table. If "add" is nonzero,
7845 * add the command to the table if it is not already present. The
7846 * variable "lastcmdentry" is set to point to the address of the link
7847 * pointing to the entry, so that delete_cmd_entry can delete the
7848 * entry.
7849 *
7850 * Interrupts must be off if called with add != 0.
7851 */
7852static struct tblentry **lastcmdentry;
7853
7854static struct tblentry *
7855cmdlookup(const char *name, int add)
7856{
7857 unsigned int hashval;
7858 const char *p;
7859 struct tblentry *cmdp;
7860 struct tblentry **pp;
7861
7862 p = name;
7863 hashval = (unsigned char)*p << 4;
7864 while (*p)
7865 hashval += (unsigned char)*p++;
7866 hashval &= 0x7FFF;
7867 pp = &cmdtable[hashval % CMDTABLESIZE];
7868 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7869 if (strcmp(cmdp->cmdname, name) == 0)
7870 break;
7871 pp = &cmdp->next;
7872 }
7873 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007874 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7875 + strlen(name)
7876 /* + 1 - already done because
7877 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007878 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007879 cmdp->cmdtype = CMDUNKNOWN;
7880 strcpy(cmdp->cmdname, name);
7881 }
7882 lastcmdentry = pp;
7883 return cmdp;
7884}
7885
7886/*
7887 * Delete the command entry returned on the last lookup.
7888 */
7889static void
7890delete_cmd_entry(void)
7891{
7892 struct tblentry *cmdp;
7893
7894 INT_OFF;
7895 cmdp = *lastcmdentry;
7896 *lastcmdentry = cmdp->next;
7897 if (cmdp->cmdtype == CMDFUNCTION)
7898 freefunc(cmdp->param.func);
7899 free(cmdp);
7900 INT_ON;
7901}
7902
7903/*
7904 * Add a new command entry, replacing any existing command entry for
7905 * the same name - except special builtins.
7906 */
7907static void
7908addcmdentry(char *name, struct cmdentry *entry)
7909{
7910 struct tblentry *cmdp;
7911
7912 cmdp = cmdlookup(name, 1);
7913 if (cmdp->cmdtype == CMDFUNCTION) {
7914 freefunc(cmdp->param.func);
7915 }
7916 cmdp->cmdtype = entry->cmdtype;
7917 cmdp->param = entry->u;
7918 cmdp->rehash = 0;
7919}
7920
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007921static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007922hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007923{
7924 struct tblentry **pp;
7925 struct tblentry *cmdp;
7926 int c;
7927 struct cmdentry entry;
7928 char *name;
7929
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007930 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007931 clearcmdentry(0);
7932 return 0;
7933 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007934
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007935 if (*argptr == NULL) {
7936 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7937 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7938 if (cmdp->cmdtype == CMDNORMAL)
7939 printentry(cmdp);
7940 }
7941 }
7942 return 0;
7943 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007944
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007945 c = 0;
7946 while ((name = *argptr) != NULL) {
7947 cmdp = cmdlookup(name, 0);
7948 if (cmdp != NULL
7949 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007950 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7951 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007952 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007953 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007954 find_command(name, &entry, DO_ERR, pathval());
7955 if (entry.cmdtype == CMDUNKNOWN)
7956 c = 1;
7957 argptr++;
7958 }
7959 return c;
7960}
7961
7962/*
7963 * Called when a cd is done. Marks all commands so the next time they
7964 * are executed they will be rehashed.
7965 */
7966static void
7967hashcd(void)
7968{
7969 struct tblentry **pp;
7970 struct tblentry *cmdp;
7971
7972 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7973 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007974 if (cmdp->cmdtype == CMDNORMAL
7975 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02007976 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007977 && builtinloc > 0)
7978 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007979 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007980 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007981 }
7982 }
7983}
7984
7985/*
7986 * Fix command hash table when PATH changed.
7987 * Called before PATH is changed. The argument is the new value of PATH;
7988 * pathval() still returns the old value at this point.
7989 * Called with interrupts off.
7990 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007991static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007992changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007993{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007994 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007995 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007996 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007997 int idx_bltin;
7998
7999 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008000 firstchange = 9999; /* assume no change */
8001 idx = 0;
8002 idx_bltin = -1;
8003 for (;;) {
8004 if (*old != *new) {
8005 firstchange = idx;
8006 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008007 || (*old == ':' && *new == '\0')
8008 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008009 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008010 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008011 old = new; /* ignore subsequent differences */
8012 }
8013 if (*new == '\0')
8014 break;
8015 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
8016 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008017 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008018 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008019 new++;
8020 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008021 }
8022 if (builtinloc < 0 && idx_bltin >= 0)
8023 builtinloc = idx_bltin; /* zap builtins */
8024 if (builtinloc >= 0 && idx_bltin < 0)
8025 firstchange = 0;
8026 clearcmdentry(firstchange);
8027 builtinloc = idx_bltin;
8028}
Ron Yorston95ebcf72015-11-03 09:42:23 +00008029enum {
8030 TEOF,
8031 TNL,
8032 TREDIR,
8033 TWORD,
8034 TSEMI,
8035 TBACKGND,
8036 TAND,
8037 TOR,
8038 TPIPE,
8039 TLP,
8040 TRP,
8041 TENDCASE,
8042 TENDBQUOTE,
8043 TNOT,
8044 TCASE,
8045 TDO,
8046 TDONE,
8047 TELIF,
8048 TELSE,
8049 TESAC,
8050 TFI,
8051 TFOR,
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008052#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +00008053 TFUNCTION,
8054#endif
8055 TIF,
8056 TIN,
8057 TTHEN,
8058 TUNTIL,
8059 TWHILE,
8060 TBEGIN,
8061 TEND
8062};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008063typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008064
Denys Vlasenko888527c2016-10-02 16:54:17 +02008065/* Nth bit indicates if token marks the end of a list */
8066enum {
8067 tokendlist = 0
8068 /* 0 */ | (1u << TEOF)
8069 /* 1 */ | (0u << TNL)
8070 /* 2 */ | (0u << TREDIR)
8071 /* 3 */ | (0u << TWORD)
8072 /* 4 */ | (0u << TSEMI)
8073 /* 5 */ | (0u << TBACKGND)
8074 /* 6 */ | (0u << TAND)
8075 /* 7 */ | (0u << TOR)
8076 /* 8 */ | (0u << TPIPE)
8077 /* 9 */ | (0u << TLP)
8078 /* 10 */ | (1u << TRP)
8079 /* 11 */ | (1u << TENDCASE)
8080 /* 12 */ | (1u << TENDBQUOTE)
8081 /* 13 */ | (0u << TNOT)
8082 /* 14 */ | (0u << TCASE)
8083 /* 15 */ | (1u << TDO)
8084 /* 16 */ | (1u << TDONE)
8085 /* 17 */ | (1u << TELIF)
8086 /* 18 */ | (1u << TELSE)
8087 /* 19 */ | (1u << TESAC)
8088 /* 20 */ | (1u << TFI)
8089 /* 21 */ | (0u << TFOR)
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008090#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008091 /* 22 */ | (0u << TFUNCTION)
Denys Vlasenko80729a42016-10-02 22:33:15 +02008092#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008093 /* 23 */ | (0u << TIF)
8094 /* 24 */ | (0u << TIN)
8095 /* 25 */ | (1u << TTHEN)
8096 /* 26 */ | (0u << TUNTIL)
8097 /* 27 */ | (0u << TWHILE)
8098 /* 28 */ | (0u << TBEGIN)
8099 /* 29 */ | (1u << TEND)
8100 , /* thus far 29 bits used */
8101};
8102
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008103static const char *const tokname_array[] = {
Denys Vlasenko888527c2016-10-02 16:54:17 +02008104 "end of file",
8105 "newline",
8106 "redirection",
8107 "word",
8108 ";",
8109 "&",
8110 "&&",
8111 "||",
8112 "|",
8113 "(",
8114 ")",
8115 ";;",
8116 "`",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008117#define KWDOFFSET 13
8118 /* the following are keywords */
Denys Vlasenko888527c2016-10-02 16:54:17 +02008119 "!",
8120 "case",
8121 "do",
8122 "done",
8123 "elif",
8124 "else",
8125 "esac",
8126 "fi",
8127 "for",
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008128#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008129 "function",
Ron Yorston95ebcf72015-11-03 09:42:23 +00008130#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008131 "if",
8132 "in",
8133 "then",
8134 "until",
8135 "while",
8136 "{",
8137 "}",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008138};
8139
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008140/* Wrapper around strcmp for qsort/bsearch/... */
8141static int
8142pstrcmp(const void *a, const void *b)
8143{
Denys Vlasenko888527c2016-10-02 16:54:17 +02008144 return strcmp((char*)a, *(char**)b);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008145}
8146
8147static const char *const *
8148findkwd(const char *s)
8149{
8150 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00008151 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8152 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008153}
8154
8155/*
8156 * Locate and print what a word is...
8157 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008158static int
Ron Yorston3f221112015-08-03 13:47:33 +01008159describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008160{
8161 struct cmdentry entry;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008162#if ENABLE_ASH_ALIAS
8163 const struct alias *ap;
8164#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008165
8166 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008167
8168 if (describe_command_verbose) {
8169 out1str(command);
8170 }
8171
8172 /* First look at the keywords */
8173 if (findkwd(command)) {
8174 out1str(describe_command_verbose ? " is a shell keyword" : command);
8175 goto out;
8176 }
8177
8178#if ENABLE_ASH_ALIAS
8179 /* Then look at the aliases */
8180 ap = lookupalias(command, 0);
8181 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008182 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008183 out1str("alias ");
8184 printalias(ap);
8185 return 0;
8186 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00008187 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008188 goto out;
8189 }
8190#endif
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008191 /* Brute force */
8192 find_command(command, &entry, DO_ABS, path);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008193
8194 switch (entry.cmdtype) {
8195 case CMDNORMAL: {
8196 int j = entry.u.index;
8197 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008198 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008199 p = command;
8200 } else {
8201 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008202 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008203 stunalloc(p);
8204 } while (--j >= 0);
8205 }
8206 if (describe_command_verbose) {
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008207 out1fmt(" is %s", p);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008208 } else {
8209 out1str(p);
8210 }
8211 break;
8212 }
8213
8214 case CMDFUNCTION:
8215 if (describe_command_verbose) {
8216 out1str(" is a shell function");
8217 } else {
8218 out1str(command);
8219 }
8220 break;
8221
8222 case CMDBUILTIN:
8223 if (describe_command_verbose) {
8224 out1fmt(" is a %sshell builtin",
8225 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8226 "special " : nullstr
8227 );
8228 } else {
8229 out1str(command);
8230 }
8231 break;
8232
8233 default:
8234 if (describe_command_verbose) {
8235 out1str(": not found\n");
8236 }
8237 return 127;
8238 }
8239 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008240 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008241 return 0;
8242}
8243
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008244static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008245typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008246{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008247 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008248 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008249 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008250
Denis Vlasenko46846e22007-05-20 13:08:31 +00008251 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008252 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008253 i++;
8254 verbose = 0;
8255 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008256 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008257 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008258 }
8259 return err;
8260}
8261
8262#if ENABLE_ASH_CMDCMD
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008263/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8264static char **
8265parse_command_args(char **argv, const char **path)
8266{
8267 char *cp, c;
8268
8269 for (;;) {
8270 cp = *++argv;
8271 if (!cp)
8272 return NULL;
8273 if (*cp++ != '-')
8274 break;
8275 c = *cp++;
8276 if (!c)
8277 break;
8278 if (c == '-' && !*cp) {
8279 if (!*++argv)
8280 return NULL;
8281 break;
8282 }
8283 do {
8284 switch (c) {
8285 case 'p':
8286 *path = bb_default_path;
8287 break;
8288 default:
8289 /* run 'typecmd' for other options */
8290 return NULL;
8291 }
8292 c = *cp++;
8293 } while (c);
8294 }
8295 return argv;
8296}
8297
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008298static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008299commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008300{
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008301 char *cmd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008302 int c;
8303 enum {
8304 VERIFY_BRIEF = 1,
8305 VERIFY_VERBOSE = 2,
8306 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008307 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008308
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008309 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8310 * never reaches this function.
8311 */
8312
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008313 while ((c = nextopt("pvV")) != '\0')
8314 if (c == 'V')
8315 verify |= VERIFY_VERBOSE;
8316 else if (c == 'v')
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008317 /*verify |= VERIFY_BRIEF*/;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008318#if DEBUG
8319 else if (c != 'p')
8320 abort();
8321#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008322 else
8323 path = bb_default_path;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008324
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008325 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008326 cmd = *argptr;
8327 if (/*verify && */ cmd)
8328 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008329
8330 return 0;
8331}
8332#endif
8333
8334
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008335/*static int funcblocksize; // size of structures in function */
8336/*static int funcstringsize; // size of strings in node */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008337static void *funcblock; /* block to allocate function from */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008338static char *funcstring_end; /* end of block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008339
Eric Andersencb57d552001-06-28 07:25:16 +00008340/* flags in argument to evaltree */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008341#define EV_EXIT 01 /* exit after evaluating tree */
8342#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Eric Andersencb57d552001-06-28 07:25:16 +00008343
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008344static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008345 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8346 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8347 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8348 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8349 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8350 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8351 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8352 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8353 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8354 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8355 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8356 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8357 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8358 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8359 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8360 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8361 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008362#if BASH_REDIR_OUTPUT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008363 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008364#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008365 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8366 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8367 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8368 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8369 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8370 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8371 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8372 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8373 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008374};
8375
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008376static int calcsize(int funcblocksize, union node *n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008377
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008378static int
8379sizenodelist(int funcblocksize, struct nodelist *lp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008380{
8381 while (lp) {
8382 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008383 funcblocksize = calcsize(funcblocksize, lp->n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008384 lp = lp->next;
8385 }
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008386 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008387}
8388
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008389static int
8390calcsize(int funcblocksize, union node *n)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008391{
8392 if (n == NULL)
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008393 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008394 funcblocksize += nodesize[n->type];
8395 switch (n->type) {
8396 case NCMD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008397 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8398 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8399 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008400 break;
8401 case NPIPE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008402 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008403 break;
8404 case NREDIR:
8405 case NBACKGND:
8406 case NSUBSHELL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008407 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8408 funcblocksize = calcsize(funcblocksize, n->nredir.n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008409 break;
8410 case NAND:
8411 case NOR:
8412 case NSEMI:
8413 case NWHILE:
8414 case NUNTIL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008415 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8416 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008417 break;
8418 case NIF:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008419 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8420 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8421 funcblocksize = calcsize(funcblocksize, n->nif.test);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008422 break;
8423 case NFOR:
Denys Vlasenko561639a2016-10-07 04:28:33 +02008424 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008425 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8426 funcblocksize = calcsize(funcblocksize, n->nfor.args);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008427 break;
8428 case NCASE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008429 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8430 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008431 break;
8432 case NCLIST:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008433 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8434 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8435 funcblocksize = calcsize(funcblocksize, n->nclist.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008436 break;
8437 case NDEFUN:
8438 case NARG:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008439 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
Denys Vlasenko561639a2016-10-07 04:28:33 +02008440 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008441 funcblocksize = calcsize(funcblocksize, n->narg.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008442 break;
8443 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008444#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008445 case NTO2:
8446#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008447 case NCLOBBER:
8448 case NFROM:
8449 case NFROMTO:
8450 case NAPPEND:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008451 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8452 funcblocksize = calcsize(funcblocksize, n->nfile.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008453 break;
8454 case NTOFD:
8455 case NFROMFD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008456 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8457 funcblocksize = calcsize(funcblocksize, n->ndup.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008458 break;
8459 case NHERE:
8460 case NXHERE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008461 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8462 funcblocksize = calcsize(funcblocksize, n->nhere.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008463 break;
8464 case NNOT:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008465 funcblocksize = calcsize(funcblocksize, n->nnot.com);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008466 break;
8467 };
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008468 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008469}
8470
8471static char *
8472nodeckstrdup(char *s)
8473{
Denys Vlasenko561639a2016-10-07 04:28:33 +02008474 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008475 return strcpy(funcstring_end, s);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008476}
8477
8478static union node *copynode(union node *);
8479
8480static struct nodelist *
8481copynodelist(struct nodelist *lp)
8482{
8483 struct nodelist *start;
8484 struct nodelist **lpp;
8485
8486 lpp = &start;
8487 while (lp) {
8488 *lpp = funcblock;
8489 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8490 (*lpp)->n = copynode(lp->n);
8491 lp = lp->next;
8492 lpp = &(*lpp)->next;
8493 }
8494 *lpp = NULL;
8495 return start;
8496}
8497
8498static union node *
8499copynode(union node *n)
8500{
8501 union node *new;
8502
8503 if (n == NULL)
8504 return NULL;
8505 new = funcblock;
8506 funcblock = (char *) funcblock + nodesize[n->type];
8507
8508 switch (n->type) {
8509 case NCMD:
8510 new->ncmd.redirect = copynode(n->ncmd.redirect);
8511 new->ncmd.args = copynode(n->ncmd.args);
8512 new->ncmd.assign = copynode(n->ncmd.assign);
8513 break;
8514 case NPIPE:
8515 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008516 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008517 break;
8518 case NREDIR:
8519 case NBACKGND:
8520 case NSUBSHELL:
8521 new->nredir.redirect = copynode(n->nredir.redirect);
8522 new->nredir.n = copynode(n->nredir.n);
8523 break;
8524 case NAND:
8525 case NOR:
8526 case NSEMI:
8527 case NWHILE:
8528 case NUNTIL:
8529 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8530 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8531 break;
8532 case NIF:
8533 new->nif.elsepart = copynode(n->nif.elsepart);
8534 new->nif.ifpart = copynode(n->nif.ifpart);
8535 new->nif.test = copynode(n->nif.test);
8536 break;
8537 case NFOR:
8538 new->nfor.var = nodeckstrdup(n->nfor.var);
8539 new->nfor.body = copynode(n->nfor.body);
8540 new->nfor.args = copynode(n->nfor.args);
8541 break;
8542 case NCASE:
8543 new->ncase.cases = copynode(n->ncase.cases);
8544 new->ncase.expr = copynode(n->ncase.expr);
8545 break;
8546 case NCLIST:
8547 new->nclist.body = copynode(n->nclist.body);
8548 new->nclist.pattern = copynode(n->nclist.pattern);
8549 new->nclist.next = copynode(n->nclist.next);
8550 break;
8551 case NDEFUN:
8552 case NARG:
8553 new->narg.backquote = copynodelist(n->narg.backquote);
8554 new->narg.text = nodeckstrdup(n->narg.text);
8555 new->narg.next = copynode(n->narg.next);
8556 break;
8557 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008558#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008559 case NTO2:
8560#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008561 case NCLOBBER:
8562 case NFROM:
8563 case NFROMTO:
8564 case NAPPEND:
8565 new->nfile.fname = copynode(n->nfile.fname);
8566 new->nfile.fd = n->nfile.fd;
8567 new->nfile.next = copynode(n->nfile.next);
8568 break;
8569 case NTOFD:
8570 case NFROMFD:
8571 new->ndup.vname = copynode(n->ndup.vname);
8572 new->ndup.dupfd = n->ndup.dupfd;
8573 new->ndup.fd = n->ndup.fd;
8574 new->ndup.next = copynode(n->ndup.next);
8575 break;
8576 case NHERE:
8577 case NXHERE:
8578 new->nhere.doc = copynode(n->nhere.doc);
8579 new->nhere.fd = n->nhere.fd;
8580 new->nhere.next = copynode(n->nhere.next);
8581 break;
8582 case NNOT:
8583 new->nnot.com = copynode(n->nnot.com);
8584 break;
8585 };
8586 new->type = n->type;
8587 return new;
8588}
8589
8590/*
8591 * Make a copy of a parse tree.
8592 */
8593static struct funcnode *
8594copyfunc(union node *n)
8595{
8596 struct funcnode *f;
8597 size_t blocksize;
8598
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008599 /*funcstringsize = 0;*/
8600 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8601 f = ckzalloc(blocksize /* + funcstringsize */);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008602 funcblock = (char *) f + offsetof(struct funcnode, n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008603 funcstring_end = (char *) f + blocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008604 copynode(n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008605 /* f->count = 0; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008606 return f;
8607}
8608
8609/*
8610 * Define a shell function.
8611 */
8612static void
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008613defun(union node *func)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008614{
8615 struct cmdentry entry;
8616
8617 INT_OFF;
8618 entry.cmdtype = CMDFUNCTION;
8619 entry.u.func = copyfunc(func);
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008620 addcmdentry(func->narg.text, &entry);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008621 INT_ON;
8622}
8623
Denis Vlasenko4b875702009-03-19 13:30:04 +00008624/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008625#define SKIPBREAK (1 << 0)
8626#define SKIPCONT (1 << 1)
8627#define SKIPFUNC (1 << 2)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008628static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008629static int skipcount; /* number of levels to skip */
8630static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008631static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008632
Denis Vlasenko4b875702009-03-19 13:30:04 +00008633/* Forward decl way out to parsing code - dotrap needs it */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008634static int evalstring(char *s, int flags);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008635
Denis Vlasenko4b875702009-03-19 13:30:04 +00008636/* Called to execute a trap.
8637 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008638 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008639 *
8640 * Perhaps we should avoid entering new trap handlers
8641 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008642 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008643static void
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008644dotrap(void)
8645{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008646 uint8_t *g;
8647 int sig;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008648 uint8_t last_status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008649
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008650 if (!pending_sig)
8651 return;
8652
8653 last_status = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008654 pending_sig = 0;
Denys Vlasenkode892052016-10-02 01:49:13 +02008655 barrier();
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008656
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008657 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008658 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008659 char *p;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008660
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008661 if (!*g)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008662 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008663
8664 if (evalskip) {
8665 pending_sig = sig;
8666 break;
8667 }
8668
8669 p = trap[sig];
Denis Vlasenko4b875702009-03-19 13:30:04 +00008670 /* non-trapped SIGINT is handled separately by raise_interrupt,
8671 * don't upset it by resetting gotsig[SIGINT-1] */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008672 if (sig == SIGINT && !p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008673 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008674
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008675 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008676 *g = 0;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008677 if (!p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008678 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008679 evalstring(p, 0);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008680 }
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008681 exitstatus = last_status;
8682 TRACE(("dotrap returns\n"));
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008683}
8684
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008685/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008686static int evalloop(union node *, int);
8687static int evalfor(union node *, int);
8688static int evalcase(union node *, int);
8689static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008690static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008691static int evalpipe(union node *, int);
8692static int evalcommand(union node *, int);
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008693static int evalbltin(const struct builtincmd *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008694static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008695
Eric Andersen62483552001-07-10 06:09:16 +00008696/*
Eric Andersenc470f442003-07-28 09:56:35 +00008697 * Evaluate a parse tree. The value is left in the global variable
8698 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008699 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008700static int
Eric Andersenc470f442003-07-28 09:56:35 +00008701evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008702{
Eric Andersenc470f442003-07-28 09:56:35 +00008703 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008704 int (*evalfn)(union node *, int);
8705 int status = 0;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008706
Eric Andersenc470f442003-07-28 09:56:35 +00008707 if (n == NULL) {
8708 TRACE(("evaltree(NULL) called\n"));
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02008709 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00008710 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008711 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008712
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008713 dotrap();
8714
Eric Andersenc470f442003-07-28 09:56:35 +00008715 switch (n->type) {
8716 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008717#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008718 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008719 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008720 break;
8721#endif
8722 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008723 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008724 goto setstatus;
8725 case NREDIR:
8726 expredir(n->nredir.redirect);
8727 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8728 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008729 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008730 }
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02008731 if (n->nredir.redirect)
8732 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
Eric Andersenc470f442003-07-28 09:56:35 +00008733 goto setstatus;
8734 case NCMD:
8735 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008736 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008737 if (eflag && !(flags & EV_TESTED))
8738 checkexit = ~0;
8739 goto calleval;
8740 case NFOR:
8741 evalfn = evalfor;
8742 goto calleval;
8743 case NWHILE:
8744 case NUNTIL:
8745 evalfn = evalloop;
8746 goto calleval;
8747 case NSUBSHELL:
8748 case NBACKGND:
8749 evalfn = evalsubshell;
Denys Vlasenkocf98b0c2016-10-25 18:19:39 +02008750 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00008751 case NPIPE:
8752 evalfn = evalpipe;
8753 goto checkexit;
8754 case NCASE:
8755 evalfn = evalcase;
8756 goto calleval;
8757 case NAND:
8758 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008759 case NSEMI: {
8760
Eric Andersenc470f442003-07-28 09:56:35 +00008761#if NAND + 1 != NOR
8762#error NAND + 1 != NOR
8763#endif
8764#if NOR + 1 != NSEMI
8765#error NOR + 1 != NSEMI
8766#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008767 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008768 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00008769 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008770 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008771 );
Denys Vlasenkobc1a0082016-10-02 15:31:33 +02008772 if ((!status) == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00008773 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008774 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008775 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008776 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008777 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008778 status = evalfn(n, flags);
8779 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008780 }
Eric Andersenc470f442003-07-28 09:56:35 +00008781 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008782 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008783 if (evalskip)
8784 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008785 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00008786 n = n->nif.ifpart;
8787 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008788 }
8789 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008790 n = n->nif.elsepart;
8791 goto evaln;
8792 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008793 status = 0;
8794 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00008795 case NDEFUN:
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008796 defun(n);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008797 /* Not necessary. To test it:
8798 * "false; f() { qwerty; }; echo $?" should print 0.
8799 */
8800 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008801 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00008802 exitstatus = status;
8803 break;
8804 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008805 out:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008806 /* Order of checks below is important:
8807 * signal handlers trigger before exit caused by "set -e".
8808 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008809 dotrap();
8810
8811 if (checkexit & status)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008812 raise_exception(EXEXIT);
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008813 if (flags & EV_EXIT)
8814 raise_exception(EXEXIT);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008815
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008816 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008817 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00008818}
8819
Eric Andersenc470f442003-07-28 09:56:35 +00008820#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8821static
8822#endif
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008823int evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
Eric Andersenc470f442003-07-28 09:56:35 +00008824
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02008825static int
8826skiploop(void)
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008827{
8828 int skip = evalskip;
8829
8830 switch (skip) {
8831 case 0:
8832 break;
8833 case SKIPBREAK:
8834 case SKIPCONT:
8835 if (--skipcount <= 0) {
8836 evalskip = 0;
8837 break;
8838 }
8839 skip = SKIPBREAK;
8840 break;
8841 }
8842 return skip;
8843}
8844
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008845static int
Eric Andersenc470f442003-07-28 09:56:35 +00008846evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008847{
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008848 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00008849 int status;
8850
8851 loopnest++;
8852 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008853 flags &= EV_TESTED;
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008854 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008855 int i;
8856
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008857 i = evaltree(n->nbinary.ch1, EV_TESTED);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008858 skip = skiploop();
8859 if (skip == SKIPFUNC)
8860 status = i;
8861 if (skip)
8862 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00008863 if (n->type != NWHILE)
8864 i = !i;
8865 if (i != 0)
8866 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008867 status = evaltree(n->nbinary.ch2, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008868 skip = skiploop();
8869 } while (!(skip & ~SKIPCONT));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008870 loopnest--;
8871
8872 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008873}
8874
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008875static int
Eric Andersenc470f442003-07-28 09:56:35 +00008876evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008877{
8878 struct arglist arglist;
8879 union node *argp;
8880 struct strlist *sp;
8881 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008882 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008883
8884 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008885 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008886 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008887 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02008888 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersencb57d552001-06-28 07:25:16 +00008889 }
8890 *arglist.lastp = NULL;
8891
Eric Andersencb57d552001-06-28 07:25:16 +00008892 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008893 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008894 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008895 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008896 status = evaltree(n->nfor.body, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008897 if (skiploop() & ~SKIPCONT)
Eric Andersencb57d552001-06-28 07:25:16 +00008898 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008899 }
8900 loopnest--;
Eric Andersencb57d552001-06-28 07:25:16 +00008901 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008902
8903 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008904}
8905
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008906static int
Eric Andersenc470f442003-07-28 09:56:35 +00008907evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008908{
8909 union node *cp;
8910 union node *patp;
8911 struct arglist arglist;
8912 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008913 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008914
8915 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008916 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008917 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00008918 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008919 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8920 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008921 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008922 /* Ensure body is non-empty as otherwise
8923 * EV_EXIT may prevent us from setting the
8924 * exit status.
8925 */
8926 if (evalskip == 0 && cp->nclist.body) {
8927 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008928 }
8929 goto out;
8930 }
8931 }
8932 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008933 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008934 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008935
8936 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008937}
8938
Eric Andersenc470f442003-07-28 09:56:35 +00008939/*
8940 * Kick off a subshell to evaluate a tree.
8941 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008942static int
Eric Andersenc470f442003-07-28 09:56:35 +00008943evalsubshell(union node *n, int flags)
8944{
8945 struct job *jp;
Denys Vlasenko098b7132017-01-11 19:59:03 +01008946 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
Eric Andersenc470f442003-07-28 09:56:35 +00008947 int status;
8948
8949 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02008950 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00008951 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008952 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01008953 if (backgnd == FORK_FG)
8954 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00008955 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008956 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02008957 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008958 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008959 flags |= EV_EXIT;
8960 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02008961 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00008962 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00008963 redirect(n->nredir.redirect, 0);
8964 evaltreenr(n->nredir.n, flags);
8965 /* never returns */
8966 }
Denys Vlasenko70392332016-10-27 02:31:55 +02008967 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00008968 status = 0;
Denys Vlasenko098b7132017-01-11 19:59:03 +01008969 if (backgnd == FORK_FG)
Eric Andersenc470f442003-07-28 09:56:35 +00008970 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00008971 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008972 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00008973}
8974
Eric Andersenc470f442003-07-28 09:56:35 +00008975/*
8976 * Compute the names of the files in a redirection list.
8977 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00008978static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008979static void
8980expredir(union node *n)
8981{
8982 union node *redir;
8983
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008984 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00008985 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008986
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008987 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008988 fn.lastp = &fn.list;
8989 switch (redir->type) {
8990 case NFROMTO:
8991 case NFROM:
8992 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008993#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008994 case NTO2:
8995#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008996 case NCLOBBER:
8997 case NAPPEND:
8998 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02008999 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009000#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009001 store_expfname:
9002#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009003#if 0
9004// By the design of stack allocator, the loop of this kind:
9005// while true; do while true; do break; done </dev/null; done
9006// will look like a memory leak: ash plans to free expfname's
9007// of "/dev/null" as soon as it finishes running the loop
9008// (in this case, never).
9009// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01009010 if (redir->nfile.expfname)
9011 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009012// It results in corrupted state of stacked allocations.
9013#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009014 redir->nfile.expfname = fn.list->text;
9015 break;
9016 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00009017 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00009018 if (redir->ndup.vname) {
9019 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009020 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009021 ash_msg_and_raise_error("redir error");
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009022#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009023//FIXME: we used expandarg with different args!
9024 if (!isdigit_str9(fn.list->text)) {
9025 /* >&file, not >&fd */
9026 if (redir->nfile.fd != 1) /* 123>&file - BAD */
9027 ash_msg_and_raise_error("redir error");
9028 redir->type = NTO2;
9029 goto store_expfname;
9030 }
9031#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009032 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009033 }
9034 break;
9035 }
9036 }
9037}
9038
Eric Andersencb57d552001-06-28 07:25:16 +00009039/*
Eric Andersencb57d552001-06-28 07:25:16 +00009040 * Evaluate a pipeline. All the processes in the pipeline are children
9041 * of the process creating the pipeline. (This differs from some versions
9042 * of the shell, which make the last process in a pipeline the parent
9043 * of all the rest.)
9044 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009045static int
Eric Andersenc470f442003-07-28 09:56:35 +00009046evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009047{
9048 struct job *jp;
9049 struct nodelist *lp;
9050 int pipelen;
9051 int prevfd;
9052 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009053 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009054
Eric Andersenc470f442003-07-28 09:56:35 +00009055 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00009056 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009057 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00009058 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009059 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009060 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009061 if (n->npipe.pipe_backgnd == 0)
9062 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009063 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00009064 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009065 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009066 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00009067 pip[1] = -1;
9068 if (lp->next) {
9069 if (pipe(pip) < 0) {
9070 close(prevfd);
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00009071 ash_msg_and_raise_error("pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00009072 }
9073 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009074 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02009075 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009076 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00009077 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009078 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00009079 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009080 if (prevfd > 0) {
9081 dup2(prevfd, 0);
9082 close(prevfd);
9083 }
9084 if (pip[1] > 1) {
9085 dup2(pip[1], 1);
9086 close(pip[1]);
9087 }
Eric Andersenc470f442003-07-28 09:56:35 +00009088 evaltreenr(lp->n, flags);
9089 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00009090 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009091 /* parent */
Eric Andersencb57d552001-06-28 07:25:16 +00009092 if (prevfd >= 0)
9093 close(prevfd);
9094 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00009095 /* Don't want to trigger debugging */
9096 if (pip[1] != -1)
9097 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009098 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009099 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009100 status = waitforjob(jp);
9101 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00009102 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009103 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009104
9105 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009106}
9107
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009108/*
9109 * Controls whether the shell is interactive or not.
9110 */
9111static void
9112setinteractive(int on)
9113{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009114 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009115
9116 if (++on == is_interactive)
9117 return;
9118 is_interactive = on;
9119 setsignal(SIGINT);
9120 setsignal(SIGQUIT);
9121 setsignal(SIGTERM);
9122#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9123 if (is_interactive > 1) {
9124 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009125 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009126
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009127 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009128 /* note: ash and hush share this string */
9129 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009130 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9131 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009132 bb_banner,
9133 "built-in shell (ash)"
9134 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009135 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009136 }
9137 }
9138#endif
9139}
9140
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009141static void
9142optschanged(void)
9143{
9144#if DEBUG
9145 opentrace();
9146#endif
9147 setinteractive(iflag);
9148 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009149#if ENABLE_FEATURE_EDITING_VI
9150 if (viflag)
9151 line_input_state->flags |= VI_MODE;
9152 else
9153 line_input_state->flags &= ~VI_MODE;
9154#else
9155 viflag = 0; /* forcibly keep the option off */
9156#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009157}
9158
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009159static struct localvar *localvars;
9160
9161/*
9162 * Called after a function returns.
9163 * Interrupts must be off.
9164 */
9165static void
9166poplocalvars(void)
9167{
9168 struct localvar *lvp;
9169 struct var *vp;
9170
9171 while ((lvp = localvars) != NULL) {
9172 localvars = lvp->next;
9173 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02009174 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009175 if (vp == NULL) { /* $- saved */
9176 memcpy(optlist, lvp->text, sizeof(optlist));
9177 free((char*)lvp->text);
9178 optschanged();
9179 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009180 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009181 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009182 if (vp->var_func)
9183 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009184 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009185 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009186 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009187 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009188 }
9189 free(lvp);
9190 }
9191}
9192
9193static int
9194evalfun(struct funcnode *func, int argc, char **argv, int flags)
9195{
9196 volatile struct shparam saveparam;
9197 struct localvar *volatile savelocalvars;
9198 struct jmploc *volatile savehandler;
9199 struct jmploc jmploc;
9200 int e;
9201
9202 saveparam = shellparam;
9203 savelocalvars = localvars;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009204 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009205 e = setjmp(jmploc.loc);
9206 if (e) {
9207 goto funcdone;
9208 }
9209 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009210 exception_handler = &jmploc;
9211 localvars = NULL;
Denis Vlasenko01631112007-12-16 17:20:38 +00009212 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009213 func->count++;
9214 funcnest++;
9215 INT_ON;
9216 shellparam.nparam = argc - 1;
9217 shellparam.p = argv + 1;
9218#if ENABLE_ASH_GETOPTS
9219 shellparam.optind = 1;
9220 shellparam.optoff = -1;
9221#endif
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009222 evaltree(func->n.narg.next, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00009223 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009224 INT_OFF;
9225 funcnest--;
9226 freefunc(func);
9227 poplocalvars();
9228 localvars = savelocalvars;
9229 freeparam(&shellparam);
9230 shellparam = saveparam;
9231 exception_handler = savehandler;
9232 INT_ON;
9233 evalskip &= ~SKIPFUNC;
9234 return e;
9235}
9236
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009237/*
9238 * Make a variable a local variable. When a variable is made local, it's
9239 * value and flags are saved in a localvar structure. The saved values
9240 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009241 * "-" as a special case: it makes changes to "set +-options" local
9242 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009243 */
9244static void
9245mklocal(char *name)
9246{
9247 struct localvar *lvp;
9248 struct var **vpp;
9249 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009250 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009251
9252 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009253 /* Cater for duplicate "local". Examples:
9254 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9255 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9256 */
9257 lvp = localvars;
9258 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009259 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009260 if (eq)
9261 setvareq(name, 0);
9262 /* else:
9263 * it's a duplicate "local VAR" declaration, do nothing
9264 */
Denys Vlasenko06b11492016-11-04 16:43:18 +01009265 goto ret;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009266 }
9267 lvp = lvp->next;
9268 }
9269
9270 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009271 if (LONE_DASH(name)) {
9272 char *p;
9273 p = ckmalloc(sizeof(optlist));
9274 lvp->text = memcpy(p, optlist, sizeof(optlist));
9275 vp = NULL;
9276 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009277 vpp = hashvar(name);
9278 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009279 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009280 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009281 if (eq)
9282 setvareq(name, VSTRFIXED);
9283 else
9284 setvar(name, NULL, VSTRFIXED);
9285 vp = *vpp; /* the new variable */
9286 lvp->flags = VUNSET;
9287 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009288 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009289 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009290 /* make sure neither "struct var" nor string gets freed
9291 * during (un)setting:
9292 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009293 vp->flags |= VSTRFIXED|VTEXTFIXED;
9294 if (eq)
9295 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009296 else
9297 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009298 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009299 }
9300 }
9301 lvp->vp = vp;
9302 lvp->next = localvars;
9303 localvars = lvp;
Denys Vlasenko06b11492016-11-04 16:43:18 +01009304 ret:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009305 INT_ON;
9306}
9307
9308/*
9309 * The "local" command.
9310 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009311static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009312localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009313{
9314 char *name;
9315
Ron Yorstonef2386b2015-10-29 16:19:14 +00009316 if (!funcnest)
9317 ash_msg_and_raise_error("not in a function");
9318
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009319 argv = argptr;
9320 while ((name = *argv++) != NULL) {
9321 mklocal(name);
9322 }
9323 return 0;
9324}
9325
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009326static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009327falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009328{
9329 return 1;
9330}
9331
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009332static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009333truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009334{
9335 return 0;
9336}
9337
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009338static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009339execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009340{
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009341 optionarg = NULL;
9342 while (nextopt("a:") != '\0')
9343 /* nextopt() sets optionarg to "-a ARGV0" */;
9344
9345 argv = argptr;
9346 if (argv[0]) {
9347 char *prog;
9348
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009349 iflag = 0; /* exit on error */
9350 mflag = 0;
9351 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009352 /* We should set up signals for "exec CMD"
9353 * the same way as for "CMD" without "exec".
9354 * But optschanged->setinteractive->setsignal
9355 * still thought we are a root shell. Therefore, for example,
9356 * SIGQUIT is still set to IGN. Fix it:
9357 */
9358 shlvl++;
9359 setsignal(SIGQUIT);
9360 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9361 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9362 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9363
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009364 prog = argv[0];
9365 if (optionarg)
9366 argv[0] = optionarg;
9367 shellexec(prog, argv, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009368 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009369 }
9370 return 0;
9371}
9372
9373/*
9374 * The return command.
9375 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009376static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009377returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009378{
9379 /*
9380 * If called outside a function, do what ksh does;
9381 * skip the rest of the file.
9382 */
Denys Vlasenko6a0710e2016-09-30 14:18:34 +02009383 evalskip = SKIPFUNC;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009384 return argv[1] ? number(argv[1]) : exitstatus;
9385}
9386
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009387/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009388static int breakcmd(int, char **) FAST_FUNC;
9389static int dotcmd(int, char **) FAST_FUNC;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009390static int evalcmd(int, char **, int) FAST_FUNC;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009391static int exitcmd(int, char **) FAST_FUNC;
9392static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009393#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009394static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009395#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009396#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009397static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009398#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009399#if MAX_HISTORY
9400static int historycmd(int, char **) FAST_FUNC;
9401#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009402#if ENABLE_FEATURE_SH_MATH
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009403static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009404#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009405static int readcmd(int, char **) FAST_FUNC;
9406static int setcmd(int, char **) FAST_FUNC;
9407static int shiftcmd(int, char **) FAST_FUNC;
9408static int timescmd(int, char **) FAST_FUNC;
9409static int trapcmd(int, char **) FAST_FUNC;
9410static int umaskcmd(int, char **) FAST_FUNC;
9411static int unsetcmd(int, char **) FAST_FUNC;
9412static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009413
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009414#define BUILTIN_NOSPEC "0"
9415#define BUILTIN_SPECIAL "1"
9416#define BUILTIN_REGULAR "2"
9417#define BUILTIN_SPEC_REG "3"
9418#define BUILTIN_ASSIGN "4"
9419#define BUILTIN_SPEC_ASSG "5"
9420#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009421#define BUILTIN_SPEC_REG_ASSG "7"
9422
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009423/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko265062d2017-01-10 15:13:30 +01009424#if ENABLE_ASH_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009425static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009426#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009427#if ENABLE_ASH_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009428static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009429#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009430#if ENABLE_ASH_TEST || BASH_TEST2
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009431static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009432#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009433
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009434/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009435static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009436 { BUILTIN_SPEC_REG "." , dotcmd },
9437 { BUILTIN_SPEC_REG ":" , truecmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009438#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009439 { BUILTIN_REGULAR "[" , testcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009440#endif
9441#if BASH_TEST2
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009442 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009443#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009444#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009445 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009446#endif
9447#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009448 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009449#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009450 { BUILTIN_SPEC_REG "break" , breakcmd },
9451 { BUILTIN_REGULAR "cd" , cdcmd },
9452 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009453#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009454 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009455#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009456 { BUILTIN_SPEC_REG "continue", breakcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009457#if ENABLE_ASH_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009458 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009459#endif
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009460 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009461 { BUILTIN_SPEC_REG "exec" , execcmd },
9462 { BUILTIN_SPEC_REG "exit" , exitcmd },
9463 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9464 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009465#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009466 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009467#endif
9468#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009469 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009470#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009471 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009472#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009473 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009474#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009475#if MAX_HISTORY
9476 { BUILTIN_NOSPEC "history" , historycmd },
9477#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009478#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009479 { BUILTIN_REGULAR "jobs" , jobscmd },
9480 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009481#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009482#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009483 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009484#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009485 { BUILTIN_ASSIGN "local" , localcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009486#if ENABLE_ASH_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009487 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009488#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009489 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9490 { BUILTIN_REGULAR "read" , readcmd },
9491 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9492 { BUILTIN_SPEC_REG "return" , returncmd },
9493 { BUILTIN_SPEC_REG "set" , setcmd },
9494 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009495#if BASH_SOURCE
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009496 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009497#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009498#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009499 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009500#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009501 { BUILTIN_SPEC_REG "times" , timescmd },
9502 { BUILTIN_SPEC_REG "trap" , trapcmd },
9503 { BUILTIN_REGULAR "true" , truecmd },
9504 { BUILTIN_NOSPEC "type" , typecmd },
9505 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9506 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009507#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009508 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009509#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009510 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9511 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009512};
9513
Denis Vlasenko80591b02008-03-25 07:49:43 +00009514/* Should match the above table! */
9515#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009516 /* . : */ 2 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009517 /* [ */ 1 * ENABLE_ASH_TEST + \
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009518 /* [[ */ 1 * BASH_TEST2 + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009519 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9520 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9521 /* break cd cddir */ 3)
9522#define EVALCMD (COMMANDCMD + \
9523 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9524 /* continue */ 1 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009525 /* echo */ 1 * ENABLE_ASH_ECHO + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009526 0)
9527#define EXECCMD (EVALCMD + \
9528 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009529
9530/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009531 * Search the table of builtin commands.
9532 */
Denys Vlasenko888527c2016-10-02 16:54:17 +02009533static int
9534pstrcmp1(const void *a, const void *b)
9535{
9536 return strcmp((char*)a, *(char**)b + 1);
9537}
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009538static struct builtincmd *
9539find_builtin(const char *name)
9540{
9541 struct builtincmd *bp;
9542
9543 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009544 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denys Vlasenko888527c2016-10-02 16:54:17 +02009545 pstrcmp1
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009546 );
9547 return bp;
9548}
9549
9550/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009551 * Execute a simple command.
9552 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009553static int
9554isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009555{
9556 const char *q = endofname(p);
9557 if (p == q)
9558 return 0;
9559 return *q == '=';
9560}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009561static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009562bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009563{
9564 /* Preserve exitstatus of a previous possible redirection
9565 * as POSIX mandates */
9566 return back_exitstatus;
9567}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009568static int
Eric Andersenc470f442003-07-28 09:56:35 +00009569evalcommand(union node *cmd, int flags)
9570{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009571 static const struct builtincmd null_bltin = {
9572 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009573 };
Eric Andersenc470f442003-07-28 09:56:35 +00009574 struct stackmark smark;
9575 union node *argp;
9576 struct arglist arglist;
9577 struct arglist varlist;
9578 char **argv;
9579 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009580 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009581 struct cmdentry cmdentry;
9582 struct job *jp;
9583 char *lastarg;
9584 const char *path;
9585 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009586 int status;
9587 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00009588 struct builtincmd *bcmd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009589 smallint cmd_is_exec;
9590 smallint pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009591
9592 /* First expand the arguments. */
9593 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9594 setstackmark(&smark);
9595 back_exitstatus = 0;
9596
9597 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009598 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009599 varlist.lastp = &varlist.list;
9600 *varlist.lastp = NULL;
9601 arglist.lastp = &arglist.list;
9602 *arglist.lastp = NULL;
9603
9604 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009605 if (cmd->ncmd.args) {
Paul Foxc3850c82005-07-20 18:23:39 +00009606 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9607 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9608 }
9609
Eric Andersenc470f442003-07-28 09:56:35 +00009610 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9611 struct strlist **spp;
9612
9613 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00009614 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00009615 expandarg(argp, &arglist, EXP_VARTILDE);
9616 else
9617 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9618
Eric Andersenc470f442003-07-28 09:56:35 +00009619 for (sp = *spp; sp; sp = sp->next)
9620 argc++;
9621 }
9622
Denys Vlasenko65a8b852016-10-26 22:29:11 +02009623 /* Reserve one extra spot at the front for shellexec. */
9624 nargv = stalloc(sizeof(char *) * (argc + 2));
9625 argv = ++nargv;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009626 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009627 TRACE(("evalcommand arg: %s\n", sp->text));
9628 *nargv++ = sp->text;
9629 }
9630 *nargv = NULL;
9631
9632 lastarg = NULL;
9633 if (iflag && funcnest == 0 && argc > 0)
9634 lastarg = nargv[-1];
9635
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009636 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009637 expredir(cmd->ncmd.redirect);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009638 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009639
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009640 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009641 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9642 struct strlist **spp;
9643 char *p;
9644
9645 spp = varlist.lastp;
9646 expandarg(argp, &varlist, EXP_VARTILDE);
9647
9648 /*
9649 * Modify the command lookup path, if a PATH= assignment
9650 * is present
9651 */
9652 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009653 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009654 path = p;
9655 }
9656
9657 /* Print the command if xflag is set. */
9658 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009659 int n;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009660 const char *p = " %s" + 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009661
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009662 fdprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009663 sp = varlist.list;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009664 for (n = 0; n < 2; n++) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009665 while (sp) {
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009666 fdprintf(preverrout_fd, p, sp->text);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009667 sp = sp->next;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009668 p = " %s";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009669 }
9670 sp = arglist.list;
9671 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009672 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009673 }
9674
9675 cmd_is_exec = 0;
9676 spclbltin = -1;
9677
9678 /* Now locate the command. */
9679 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009680 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02009681#if ENABLE_ASH_CMDCMD
9682 const char *oldpath = path + 5;
9683#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009684 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009685 for (;;) {
9686 find_command(argv[0], &cmdentry, cmd_flag, path);
9687 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009688 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009689 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009690 goto bail;
9691 }
9692
9693 /* implement bltin and command here */
9694 if (cmdentry.cmdtype != CMDBUILTIN)
9695 break;
9696 if (spclbltin < 0)
9697 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9698 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009699 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009700#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009701 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009702 path = oldpath;
9703 nargv = parse_command_args(argv, &path);
9704 if (!nargv)
9705 break;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02009706 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
9707 * nargv => "PROG". path is updated if -p.
9708 */
Eric Andersenc470f442003-07-28 09:56:35 +00009709 argc -= nargv - argv;
9710 argv = nargv;
9711 cmd_flag |= DO_NOFUNC;
9712 } else
9713#endif
9714 break;
9715 }
9716 }
9717
9718 if (status) {
Ron Yorstonea7d2f62017-01-03 11:18:23 +01009719 bail:
9720 exitstatus = status;
9721
Eric Andersenc470f442003-07-28 09:56:35 +00009722 /* We have a redirection error. */
9723 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009724 raise_exception(EXERROR);
Ron Yorstonea7d2f62017-01-03 11:18:23 +01009725
Eric Andersenc470f442003-07-28 09:56:35 +00009726 goto out;
9727 }
9728
9729 /* Execute the command. */
9730 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009731 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009732
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009733#if ENABLE_FEATURE_SH_NOFORK
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009734/* (1) BUG: if variables are set, we need to fork, or save/restore them
9735 * around run_nofork_applet() call.
9736 * (2) Should this check also be done in forkshell()?
9737 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9738 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009739 /* find_command() encodes applet_no as (-2 - applet_no) */
9740 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009741 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009742 listsetvar(varlist.list, VEXPORT|VSTACK);
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009743 /* run <applet>_main() */
Ron Yorston5ccb0e92016-10-20 12:24:02 +01009744 status = run_nofork_applet(applet_no, argv);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009745 break;
9746 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009747#endif
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009748 /* Can we avoid forking off? For example, very last command
9749 * in a script or a subshell does not need forking,
9750 * we can just exec it.
9751 */
Denys Vlasenko238bf182010-05-18 15:49:07 +02009752 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009753 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009754 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009755 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009756 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009757 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009758 /* parent */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009759 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009760 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009761 TRACE(("forked child exited with %d\n", status));
Eric Andersenc470f442003-07-28 09:56:35 +00009762 break;
9763 }
Denys Vlasenko238bf182010-05-18 15:49:07 +02009764 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009765 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +02009766 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +00009767 }
9768 listsetvar(varlist.list, VEXPORT|VSTACK);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02009769 shellexec(argv[0], argv, path, cmdentry.u.index);
Eric Andersenc470f442003-07-28 09:56:35 +00009770 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009771 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +00009772 case CMDBUILTIN:
9773 cmdenviron = varlist.list;
9774 if (cmdenviron) {
9775 struct strlist *list = cmdenviron;
9776 int i = VNOSET;
9777 if (spclbltin > 0 || argc == 0) {
9778 i = 0;
9779 if (cmd_is_exec && argc > 1)
9780 i = VEXPORT;
9781 }
9782 listsetvar(list, i);
9783 }
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009784 /* Tight loop with builtins only:
9785 * "while kill -0 $child; do true; done"
9786 * will never exit even if $child died, unless we do this
9787 * to reap the zombie and make kill detect that it's gone: */
9788 dowait(DOWAIT_NONBLOCK, NULL);
9789
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009790 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009791 if (exception_type == EXERROR && spclbltin <= 0) {
9792 FORCE_INT_ON;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02009793 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009794 }
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009795 raise:
9796 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009797 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009798 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009799
9800 case CMDFUNCTION:
9801 listsetvar(varlist.list, 0);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009802 /* See above for the rationale */
9803 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009804 if (evalfun(cmdentry.u.func, argc, argv, flags))
9805 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009806 readstatus:
9807 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009808 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009809 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +00009810
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009811 out:
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02009812 if (cmd->ncmd.redirect)
9813 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009814 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +00009815 /* dsl: I think this is intended to be used to support
9816 * '_' in 'vi' command mode during line editing...
9817 * However I implemented that within libedit itself.
9818 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009819 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009820 }
Eric Andersenc470f442003-07-28 09:56:35 +00009821 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009822
9823 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009824}
9825
9826static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009827evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009828{
Eric Andersenc470f442003-07-28 09:56:35 +00009829 char *volatile savecmdname;
9830 struct jmploc *volatile savehandler;
9831 struct jmploc jmploc;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009832 int status;
Eric Andersenc470f442003-07-28 09:56:35 +00009833 int i;
9834
9835 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009836 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009837 i = setjmp(jmploc.loc);
9838 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +00009839 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009840 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00009841 commandname = argv[0];
9842 argptr = argv + 1;
9843 optptr = NULL; /* initialize nextopt */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009844 if (cmd == EVALCMD)
9845 status = evalcmd(argc, argv, flags);
9846 else
9847 status = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009848 flush_stdout_stderr();
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009849 status |= ferror(stdout);
9850 exitstatus = status;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009851 cmddone:
Rob Landleyf296f0b2006-07-06 01:09:21 +00009852 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009853 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009854 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +00009855
9856 return i;
9857}
9858
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009859static int
9860goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009861{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02009862 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009863}
9864
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009865
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009866/*
9867 * Search for a command. This is called before we fork so that the
9868 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009869 * the child. The check for "goodname" is an overly conservative
9870 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009871 */
Eric Andersenc470f442003-07-28 09:56:35 +00009872static void
9873prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009874{
9875 struct cmdentry entry;
9876
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009877 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9878 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009879}
9880
Eric Andersencb57d552001-06-28 07:25:16 +00009881
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009882/* ============ Builtin commands
9883 *
9884 * Builtin commands whose functions are closely tied to evaluation
9885 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +00009886 */
9887
9888/*
Eric Andersencb57d552001-06-28 07:25:16 +00009889 * Handle break and continue commands. Break, continue, and return are
9890 * all handled by setting the evalskip flag. The evaluation routines
9891 * above all check this flag, and if it is set they start skipping
9892 * commands rather than executing them. The variable skipcount is
9893 * the number of loops to break/continue, or the number of function
9894 * levels to return. (The latter is always 1.) It should probably
9895 * be an error to break out of more loops than exist, but it isn't
9896 * in the standard shell so we don't make it one here.
9897 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009898static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009899breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009900{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009901 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009902
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00009903 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009904 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009905 if (n > loopnest)
9906 n = loopnest;
9907 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009908 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00009909 skipcount = n;
9910 }
9911 return 0;
9912}
9913
Eric Andersenc470f442003-07-28 09:56:35 +00009914
Denys Vlasenko70392332016-10-27 02:31:55 +02009915/*
Eric Andersen90898442003-08-06 11:20:52 +00009916 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00009917 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009918
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009919enum {
9920 INPUT_PUSH_FILE = 1,
9921 INPUT_NOFILE_OK = 2,
9922};
Eric Andersencb57d552001-06-28 07:25:16 +00009923
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009924static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009925/* values of checkkwd variable */
9926#define CHKALIAS 0x1
9927#define CHKKWD 0x2
9928#define CHKNL 0x4
9929
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009930/*
9931 * Push a string back onto the input at this current parsefile level.
9932 * We handle aliases this way.
9933 */
9934#if !ENABLE_ASH_ALIAS
9935#define pushstring(s, ap) pushstring(s)
9936#endif
9937static void
9938pushstring(char *s, struct alias *ap)
9939{
9940 struct strpush *sp;
9941 int len;
9942
9943 len = strlen(s);
9944 INT_OFF;
9945 if (g_parsefile->strpush) {
9946 sp = ckzalloc(sizeof(*sp));
9947 sp->prev = g_parsefile->strpush;
9948 } else {
9949 sp = &(g_parsefile->basestrpush);
9950 }
9951 g_parsefile->strpush = sp;
9952 sp->prev_string = g_parsefile->next_to_pgetc;
9953 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009954 sp->unget = g_parsefile->unget;
9955 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009956#if ENABLE_ASH_ALIAS
9957 sp->ap = ap;
9958 if (ap) {
9959 ap->flag |= ALIASINUSE;
9960 sp->string = s;
9961 }
9962#endif
9963 g_parsefile->next_to_pgetc = s;
9964 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009965 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009966 INT_ON;
9967}
9968
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009969static void
9970popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009971{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009972 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +00009973
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009974 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009975#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009976 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009977 if (g_parsefile->next_to_pgetc[-1] == ' '
9978 || g_parsefile->next_to_pgetc[-1] == '\t'
9979 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009980 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009981 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009982 if (sp->string != sp->ap->val) {
9983 free(sp->string);
9984 }
9985 sp->ap->flag &= ~ALIASINUSE;
9986 if (sp->ap->flag & ALIASDEAD) {
9987 unalias(sp->ap->name);
9988 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009989 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009990#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009991 g_parsefile->next_to_pgetc = sp->prev_string;
9992 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009993 g_parsefile->unget = sp->unget;
9994 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009995 g_parsefile->strpush = sp->prev;
9996 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009997 free(sp);
9998 INT_ON;
9999}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010000
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010001static int
10002preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010003{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010004 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +000010005 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010006
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010007 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +000010008#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +000010009 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010010 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +010010011 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010012 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010013 int timeout = -1;
10014# if ENABLE_ASH_IDLE_TIMEOUT
10015 if (iflag) {
10016 const char *tmout_var = lookupvar("TMOUT");
10017 if (tmout_var) {
10018 timeout = atoi(tmout_var) * 1000;
10019 if (timeout <= 0)
10020 timeout = -1;
10021 }
10022 }
10023# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010024# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010025 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010026# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +020010027 reinit_unicode_for_ash();
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010028 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010029 if (nr == 0) {
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010030 /* ^C pressed, "convert" to SIGINT */
10031 write(STDOUT_FILENO, "^C", 2);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010032 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010033 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010034 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010035 raise(SIGINT);
10036 return 1;
10037 }
Denys Vlasenko8660aeb2016-11-24 17:44:02 +010010038 exitstatus = 128 + SIGINT;
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010039 bb_putchar('\n');
Eric Andersenc470f442003-07-28 09:56:35 +000010040 goto retry;
10041 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010042 if (nr < 0) {
10043 if (errno == 0) {
10044 /* Ctrl+D pressed */
10045 nr = 0;
10046 }
10047# if ENABLE_ASH_IDLE_TIMEOUT
10048 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +020010049 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010050 exitshell();
10051 }
10052# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010053 }
Eric Andersencb57d552001-06-28 07:25:16 +000010054 }
10055#else
Ron Yorston61d6ae22015-04-19 10:50:25 +010010056 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +000010057#endif
10058
Denys Vlasenko80c5b682011-05-08 21:21:10 +020010059#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +000010060 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010061 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +000010062 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +000010063 if (flags >= 0 && (flags & O_NONBLOCK)) {
10064 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +000010065 if (fcntl(0, F_SETFL, flags) >= 0) {
10066 out2str("sh: turning off NDELAY mode\n");
10067 goto retry;
10068 }
10069 }
10070 }
10071 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +000010072#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010073 return nr;
10074}
10075
10076/*
10077 * Refill the input buffer and return the next input character:
10078 *
10079 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010080 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
10081 * or we are reading from a string so we can't refill the buffer,
10082 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +020010083 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +000010084 * 4) Process input up to the next newline, deleting nul characters.
10085 */
Denis Vlasenko727752d2008-11-28 03:41:47 +000010086//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
10087#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010088static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010089static int
Eric Andersenc470f442003-07-28 09:56:35 +000010090preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010091{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010092 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010093 int more;
Eric Andersencb57d552001-06-28 07:25:16 +000010094
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010095 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000010096#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010097 if (g_parsefile->left_in_line == -1
10098 && g_parsefile->strpush->ap
10099 && g_parsefile->next_to_pgetc[-1] != ' '
10100 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +000010101 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010102 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +000010103 return PEOA;
10104 }
Eric Andersen2870d962001-07-02 17:27:21 +000010105#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010106 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010107 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010108 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010109 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010110 * "pgetc" needs refilling.
10111 */
10112
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010113 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010114 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010115 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010116 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010117 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010118 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010119 /* even in failure keep left_in_line and next_to_pgetc
10120 * in lock step, for correct multi-layer pungetc.
10121 * left_in_line was decremented before preadbuffer(),
10122 * must inc next_to_pgetc: */
10123 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010124 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010125 }
Eric Andersencb57d552001-06-28 07:25:16 +000010126
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010127 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010128 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010129 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010130 again:
10131 more = preadfd();
10132 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010133 /* don't try reading again */
10134 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010135 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010136 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010137 return PEOF;
10138 }
10139 }
10140
Denis Vlasenko727752d2008-11-28 03:41:47 +000010141 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010142 * Set g_parsefile->left_in_line
10143 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010144 * NUL chars are deleted.
10145 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010146 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010147 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010148 char c;
Eric Andersencb57d552001-06-28 07:25:16 +000010149
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010150 more--;
Eric Andersenc470f442003-07-28 09:56:35 +000010151
Denis Vlasenko727752d2008-11-28 03:41:47 +000010152 c = *q;
10153 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010154 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010155 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010156 q++;
10157 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010158 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010159 break;
10160 }
Eric Andersencb57d552001-06-28 07:25:16 +000010161 }
10162
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010163 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010164 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10165 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010166 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010167 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010168 }
10169 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010170 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +000010171
Eric Andersencb57d552001-06-28 07:25:16 +000010172 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010173 char save = *q;
10174 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010175 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010176 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +000010177 }
10178
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010179 pgetc_debug("preadbuffer at %d:%p'%s'",
10180 g_parsefile->left_in_line,
10181 g_parsefile->next_to_pgetc,
10182 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +010010183 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010184}
10185
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010186static void
10187nlprompt(void)
10188{
10189 g_parsefile->linno++;
10190 setprompt_if(doprompt, 2);
10191}
10192static void
10193nlnoprompt(void)
10194{
10195 g_parsefile->linno++;
10196 needprompt = doprompt;
10197}
10198
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010199static int
10200pgetc(void)
10201{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010202 int c;
10203
10204 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010205 g_parsefile->left_in_line,
10206 g_parsefile->next_to_pgetc,
10207 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010208 if (g_parsefile->unget)
10209 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010210
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010211 if (--g_parsefile->left_in_line >= 0)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +010010212 c = (unsigned char)*g_parsefile->next_to_pgetc++;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010213 else
10214 c = preadbuffer();
10215
10216 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10217 g_parsefile->lastc[0] = c;
10218
10219 return c;
10220}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010221
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010222#if ENABLE_ASH_ALIAS
10223static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010224pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010225{
10226 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010227 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010228 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010229 g_parsefile->left_in_line,
10230 g_parsefile->next_to_pgetc,
10231 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010232 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010233 } while (c == PEOA);
10234 return c;
10235}
10236#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010237# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010238#endif
10239
10240/*
10241 * Read a line from the script.
10242 */
10243static char *
10244pfgets(char *line, int len)
10245{
10246 char *p = line;
10247 int nleft = len;
10248 int c;
10249
10250 while (--nleft > 0) {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010251 c = pgetc_without_PEOA();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010252 if (c == PEOF) {
10253 if (p == line)
10254 return NULL;
10255 break;
10256 }
10257 *p++ = c;
10258 if (c == '\n')
10259 break;
10260 }
10261 *p = '\0';
10262 return line;
10263}
10264
Eric Andersenc470f442003-07-28 09:56:35 +000010265/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010266 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010267 * PEOF may be pushed back.
10268 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010269static void
Eric Andersenc470f442003-07-28 09:56:35 +000010270pungetc(void)
10271{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010272 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010273}
10274
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010275/* This one eats backslash+newline */
10276static int
10277pgetc_eatbnl(void)
10278{
10279 int c;
10280
10281 while ((c = pgetc()) == '\\') {
10282 if (pgetc() != '\n') {
10283 pungetc();
10284 break;
10285 }
10286
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010287 nlprompt();
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010288 }
10289
10290 return c;
10291}
10292
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010293/*
10294 * To handle the "." command, a stack of input files is used. Pushfile
10295 * adds a new entry to the stack and popfile restores the previous level.
10296 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010297static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010298pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010299{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010300 struct parsefile *pf;
10301
Denis Vlasenko597906c2008-02-20 16:38:54 +000010302 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010303 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010304 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010305 /*pf->strpush = NULL; - ckzalloc did it */
10306 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010307 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010308 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010309}
10310
10311static void
10312popfile(void)
10313{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010314 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010315
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010010316 if (pf == &basepf)
10317 return;
10318
Denis Vlasenkob012b102007-02-19 22:43:01 +000010319 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010320 if (pf->pf_fd >= 0)
10321 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010322 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010323 while (pf->strpush)
10324 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010325 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010326 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010327 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010328}
10329
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010330/*
10331 * Return to top level.
10332 */
10333static void
10334popallfiles(void)
10335{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010336 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010337 popfile();
10338}
10339
10340/*
10341 * Close the file(s) that the shell is reading commands from. Called
10342 * after a fork is done.
10343 */
10344static void
10345closescript(void)
10346{
10347 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010348 if (g_parsefile->pf_fd > 0) {
10349 close(g_parsefile->pf_fd);
10350 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010351 }
10352}
10353
10354/*
10355 * Like setinputfile, but takes an open file descriptor. Call this with
10356 * interrupts off.
10357 */
10358static void
10359setinputfd(int fd, int push)
10360{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010361 if (push) {
10362 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010363 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010364 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010365 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010366 if (g_parsefile->buf == NULL)
10367 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010368 g_parsefile->left_in_buffer = 0;
10369 g_parsefile->left_in_line = 0;
10370 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010371}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010372
Eric Andersenc470f442003-07-28 09:56:35 +000010373/*
10374 * Set the input to take input from a file. If push is set, push the
10375 * old input onto the stack first.
10376 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010377static int
10378setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010379{
10380 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010381
Denis Vlasenkob012b102007-02-19 22:43:01 +000010382 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010383 fd = open(fname, O_RDONLY);
10384 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010385 if (flags & INPUT_NOFILE_OK)
10386 goto out;
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010387 exitstatus = 127;
Denis Vlasenko9604e1b2009-03-03 18:47:56 +000010388 ash_msg_and_raise_error("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010389 }
Denys Vlasenko64774602016-10-26 15:24:30 +020010390 if (fd < 10)
10391 fd = savefd(fd);
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020010392 else
10393 close_on_exec_on(fd);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010394 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010395 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010396 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010397 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010398}
10399
Eric Andersencb57d552001-06-28 07:25:16 +000010400/*
10401 * Like setinputfile, but takes input from a string.
10402 */
Eric Andersenc470f442003-07-28 09:56:35 +000010403static void
10404setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010405{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010406 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010407 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010408 g_parsefile->next_to_pgetc = string;
10409 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010410 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010411 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010412 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010413}
10414
10415
Denys Vlasenko70392332016-10-27 02:31:55 +020010416/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010417 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010418 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010419
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010420#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010421
Denys Vlasenko23841622015-10-09 15:52:03 +020010422/* Hash of mtimes of mailboxes */
10423static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010424/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010425static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010426
Eric Andersencb57d552001-06-28 07:25:16 +000010427/*
Eric Andersenc470f442003-07-28 09:56:35 +000010428 * Print appropriate message(s) if mail has arrived.
10429 * If mail_var_path_changed is set,
10430 * then the value of MAIL has mail_var_path_changed,
10431 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010432 */
Eric Andersenc470f442003-07-28 09:56:35 +000010433static void
10434chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010435{
Eric Andersencb57d552001-06-28 07:25:16 +000010436 const char *mpath;
10437 char *p;
10438 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010439 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010440 struct stackmark smark;
10441 struct stat statb;
10442
Eric Andersencb57d552001-06-28 07:25:16 +000010443 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010444 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010445 new_hash = 0;
10446 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010447 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010448 if (p == NULL)
10449 break;
10450 if (*p == '\0')
10451 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010452 for (q = p; *q; q++)
10453 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010454#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010455 if (q[-1] != '/')
10456 abort();
10457#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010458 q[-1] = '\0'; /* delete trailing '/' */
10459 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010460 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010461 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010462 /* Very simplistic "hash": just a sum of all mtimes */
10463 new_hash += (unsigned)statb.st_mtime;
10464 }
10465 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010466 if (mailtime_hash != 0)
10467 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010468 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010469 }
Eric Andersenc470f442003-07-28 09:56:35 +000010470 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010471 popstackmark(&smark);
10472}
Eric Andersencb57d552001-06-28 07:25:16 +000010473
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010474static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010475changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010476{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010477 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010478}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010479
Denis Vlasenko131ae172007-02-18 13:00:19 +000010480#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010481
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010482
10483/* ============ ??? */
10484
Eric Andersencb57d552001-06-28 07:25:16 +000010485/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010486 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010487 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010488static void
10489setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010490{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010491 char **newparam;
10492 char **ap;
10493 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010494
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010495 for (nparam = 0; argv[nparam]; nparam++)
10496 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010497 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10498 while (*argv) {
10499 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010500 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010501 *ap = NULL;
10502 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010503 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010504 shellparam.nparam = nparam;
10505 shellparam.p = newparam;
10506#if ENABLE_ASH_GETOPTS
10507 shellparam.optind = 1;
10508 shellparam.optoff = -1;
10509#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010510}
10511
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010512/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010513 * Process shell options. The global variable argptr contains a pointer
10514 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010515 *
10516 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10517 * For a non-interactive shell, an error condition encountered
10518 * by a special built-in ... shall cause the shell to write a diagnostic message
10519 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010520 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010521 * ...
10522 * Utility syntax error (option or operand error) Shall exit
10523 * ...
10524 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10525 * we see that bash does not do that (set "finishes" with error code 1 instead,
10526 * and shell continues), and people rely on this behavior!
10527 * Testcase:
10528 * set -o barfoo 2>/dev/null
10529 * echo $?
10530 *
10531 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010532 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010533static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010534plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010535{
10536 int i;
10537
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010538 if (name) {
10539 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010540 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010541 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010542 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010543 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010544 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010545 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010546 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010547 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010548 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010549 if (val) {
10550 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10551 } else {
10552 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10553 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010554 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010555 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010556}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010557static void
10558setoption(int flag, int val)
10559{
10560 int i;
10561
10562 for (i = 0; i < NOPTS; i++) {
10563 if (optletters(i) == flag) {
10564 optlist[i] = val;
10565 return;
10566 }
10567 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010568 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010569 /* NOTREACHED */
10570}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010571static int
Eric Andersenc470f442003-07-28 09:56:35 +000010572options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +000010573{
10574 char *p;
10575 int val;
10576 int c;
10577
10578 if (cmdline)
10579 minusc = NULL;
10580 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010581 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010582 if (c != '-' && c != '+')
10583 break;
10584 argptr++;
10585 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010586 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010587 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010588 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010589 if (!cmdline) {
10590 /* "-" means turn off -x and -v */
10591 if (p[0] == '\0')
10592 xflag = vflag = 0;
10593 /* "--" means reset params */
10594 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010595 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010596 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010597 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010598 }
Eric Andersencb57d552001-06-28 07:25:16 +000010599 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010600 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010601 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010602 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010603 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010604 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010605 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010606 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010607 /* it already printed err message */
10608 return 1; /* error */
10609 }
Eric Andersencb57d552001-06-28 07:25:16 +000010610 if (*argptr)
10611 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010612 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10613 isloginsh = 1;
10614 /* bash does not accept +-login, we also won't */
10615 } else if (cmdline && val && (c == '-')) { /* long options */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010616 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +000010617 isloginsh = 1;
10618 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010619 } else {
10620 setoption(c, val);
10621 }
10622 }
10623 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010624 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010625}
10626
Eric Andersencb57d552001-06-28 07:25:16 +000010627/*
Eric Andersencb57d552001-06-28 07:25:16 +000010628 * The shift builtin command.
10629 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010630static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010631shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010632{
10633 int n;
10634 char **ap1, **ap2;
10635
10636 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010637 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010638 n = number(argv[1]);
10639 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010640 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010641 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010642 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010643 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010644 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010645 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010646 }
10647 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010648 while ((*ap2++ = *ap1++) != NULL)
10649 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010650#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010651 shellparam.optind = 1;
10652 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010653#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010654 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010655 return 0;
10656}
10657
Eric Andersencb57d552001-06-28 07:25:16 +000010658/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010659 * POSIX requires that 'set' (but not export or readonly) output the
10660 * variables in lexicographic order - by the locale's collating order (sigh).
10661 * Maybe we could keep them in an ordered balanced binary tree
10662 * instead of hashed lists.
10663 * For now just roll 'em through qsort for printing...
10664 */
10665static int
10666showvars(const char *sep_prefix, int on, int off)
10667{
10668 const char *sep;
10669 char **ep, **epend;
10670
10671 ep = listvars(on, off, &epend);
10672 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10673
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010674 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010675
10676 for (; ep < epend; ep++) {
10677 const char *p;
10678 const char *q;
10679
10680 p = strchrnul(*ep, '=');
10681 q = nullstr;
10682 if (*p)
10683 q = single_quote(++p);
10684 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10685 }
10686 return 0;
10687}
10688
10689/*
Eric Andersencb57d552001-06-28 07:25:16 +000010690 * The set command builtin.
10691 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010692static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010693setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010694{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010695 int retval;
10696
Denis Vlasenko68404f12008-03-17 09:00:54 +000010697 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010698 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010699
Denis Vlasenkob012b102007-02-19 22:43:01 +000010700 INT_OFF;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010701 retval = options(/*cmdline:*/ 0);
10702 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010703 optschanged();
10704 if (*argptr != NULL) {
10705 setparam(argptr);
10706 }
Eric Andersencb57d552001-06-28 07:25:16 +000010707 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010708 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010709 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010710}
10711
Denis Vlasenko131ae172007-02-18 13:00:19 +000010712#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010713static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010714change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010715{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010716 uint32_t t;
10717
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010718 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010719 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010720 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010721 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010722 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010723 vrandom.flags &= ~VNOFUNC;
10724 } else {
10725 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010726 t = strtoul(value, NULL, 10);
10727 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010728 }
Eric Andersenef02f822004-03-11 13:34:24 +000010729}
Eric Andersen16767e22004-03-16 05:14:10 +000010730#endif
10731
Denis Vlasenko131ae172007-02-18 13:00:19 +000010732#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010733static int
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010734getopts(char *optstr, char *optvar, char **optfirst)
Eric Andersencb57d552001-06-28 07:25:16 +000010735{
10736 char *p, *q;
10737 char c = '?';
10738 int done = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010739 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000010740 char **optnext;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010741 int ind = shellparam.optind;
10742 int off = shellparam.optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010743
Denys Vlasenko9c541002015-10-07 15:44:36 +020010744 sbuf[1] = '\0';
10745
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010746 shellparam.optind = -1;
10747 optnext = optfirst + ind - 1;
Eric Andersena48b0a32003-10-22 10:56:47 +000010748
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010749 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
Eric Andersencb57d552001-06-28 07:25:16 +000010750 p = NULL;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010751 else
10752 p = optnext[-1] + off;
Eric Andersencb57d552001-06-28 07:25:16 +000010753 if (p == NULL || *p == '\0') {
10754 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010755 p = *optnext;
10756 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010757 atend:
Eric Andersencb57d552001-06-28 07:25:16 +000010758 p = NULL;
10759 done = 1;
10760 goto out;
10761 }
10762 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010763 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010764 goto atend;
10765 }
10766
10767 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010768 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010769 if (*q == '\0') {
10770 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010771 sbuf[0] = c;
10772 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010773 setvar0("OPTARG", sbuf);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010774 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010775 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010776 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010777 }
10778 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010779 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010780 }
10781 if (*++q == ':')
10782 q++;
10783 }
10784
10785 if (*++q == ':') {
10786 if (*p == '\0' && (p = *optnext) == NULL) {
10787 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010788 sbuf[0] = c;
10789 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010790 setvar0("OPTARG", sbuf);
Eric Andersencb57d552001-06-28 07:25:16 +000010791 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010792 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010793 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010794 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010795 c = '?';
10796 }
Eric Andersenc470f442003-07-28 09:56:35 +000010797 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010798 }
10799
10800 if (p == *optnext)
10801 optnext++;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010802 setvar0("OPTARG", p);
Eric Andersencb57d552001-06-28 07:25:16 +000010803 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010804 } else
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010805 setvar0("OPTARG", nullstr);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010806 out:
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010807 ind = optnext - optfirst + 1;
10808 setvar("OPTIND", itoa(ind), VNOFUNC);
Denys Vlasenko9c541002015-10-07 15:44:36 +020010809 sbuf[0] = c;
10810 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010811 setvar0(optvar, sbuf);
10812
10813 shellparam.optoff = p ? p - *(optnext - 1) : -1;
10814 shellparam.optind = ind;
10815
Eric Andersencb57d552001-06-28 07:25:16 +000010816 return done;
10817}
Eric Andersenc470f442003-07-28 09:56:35 +000010818
10819/*
10820 * The getopts builtin. Shellparam.optnext points to the next argument
10821 * to be processed. Shellparam.optptr points to the next character to
10822 * be processed in the current argument. If shellparam.optnext is NULL,
10823 * then it's the first time getopts has been called.
10824 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010825static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000010826getoptscmd(int argc, char **argv)
10827{
10828 char **optbase;
10829
10830 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010831 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010832 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000010833 optbase = shellparam.p;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010834 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
Eric Andersenc470f442003-07-28 09:56:35 +000010835 shellparam.optind = 1;
10836 shellparam.optoff = -1;
10837 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010838 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010839 optbase = &argv[3];
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010840 if ((unsigned)shellparam.optind > argc - 2) {
Eric Andersenc470f442003-07-28 09:56:35 +000010841 shellparam.optind = 1;
10842 shellparam.optoff = -1;
10843 }
10844 }
10845
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010846 return getopts(argv[1], argv[2], optbase);
Eric Andersenc470f442003-07-28 09:56:35 +000010847}
Denis Vlasenko131ae172007-02-18 13:00:19 +000010848#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000010849
Eric Andersencb57d552001-06-28 07:25:16 +000010850
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010851/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000010852
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010853struct heredoc {
10854 struct heredoc *next; /* next here document in list */
10855 union node *here; /* redirection node */
10856 char *eofmark; /* string indicating end of input */
10857 smallint striptabs; /* if set, strip leading tabs */
10858};
10859
10860static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010861static smallint quoteflag; /* set if (part of) last token was quoted */
10862static token_id_t lasttoken; /* last token read (integer id Txxx) */
10863static struct heredoc *heredoclist; /* list of here documents to read */
10864static char *wordtext; /* text of last word returned by readtoken */
10865static struct nodelist *backquotelist;
10866static union node *redirnode;
10867static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010868
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010869static const char *
10870tokname(char *buf, int tok)
10871{
10872 if (tok < TSEMI)
Denys Vlasenko888527c2016-10-02 16:54:17 +020010873 return tokname_array[tok];
10874 sprintf(buf, "\"%s\"", tokname_array[tok]);
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010875 return buf;
10876}
10877
10878/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010879 * Called when an unexpected token is read during the parse. The argument
10880 * is the token that is expected, or -1 if more than one type of token can
10881 * occur at this point.
10882 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010883static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010884static void
10885raise_error_unexpected_syntax(int token)
10886{
10887 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010888 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010889 int l;
10890
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010891 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010892 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010893 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010894 raise_error_syntax(msg);
10895 /* NOTREACHED */
10896}
Eric Andersencb57d552001-06-28 07:25:16 +000010897
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010898#define EOFMARKLEN 79
Eric Andersencb57d552001-06-28 07:25:16 +000010899
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010900/* parsing is heavily cross-recursive, need these forward decls */
10901static union node *andor(void);
10902static union node *pipeline(void);
10903static union node *parse_command(void);
10904static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000010905static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010906static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000010907
Eric Andersenc470f442003-07-28 09:56:35 +000010908static union node *
10909list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000010910{
10911 union node *n1, *n2, *n3;
10912 int tok;
10913
Eric Andersencb57d552001-06-28 07:25:16 +000010914 n1 = NULL;
10915 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010916 switch (peektoken()) {
10917 case TNL:
10918 if (!(nlflag & 1))
10919 break;
10920 parseheredoc();
10921 return n1;
10922
10923 case TEOF:
10924 if (!n1 && (nlflag & 1))
10925 n1 = NODE_EOF;
10926 parseheredoc();
10927 return n1;
10928 }
10929
10930 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko888527c2016-10-02 16:54:17 +020010931 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
Ron Yorstonc0e00762015-10-29 11:30:55 +000010932 return n1;
10933 nlflag |= 2;
10934
Eric Andersencb57d552001-06-28 07:25:16 +000010935 n2 = andor();
10936 tok = readtoken();
10937 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000010938 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010939 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010940 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010941 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010942 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000010943 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010944 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010945 n2 = n3;
10946 }
10947 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000010948 }
10949 }
10950 if (n1 == NULL) {
10951 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010952 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010953 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010954 n3->type = NSEMI;
10955 n3->nbinary.ch1 = n1;
10956 n3->nbinary.ch2 = n2;
10957 n1 = n3;
10958 }
10959 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010960 case TNL:
10961 case TEOF:
10962 tokpushback = 1;
10963 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000010964 case TBACKGND:
10965 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000010966 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010967 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000010968 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010969 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010970 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010971 return n1;
10972 }
10973 }
10974}
10975
Eric Andersenc470f442003-07-28 09:56:35 +000010976static union node *
10977andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010978{
Eric Andersencb57d552001-06-28 07:25:16 +000010979 union node *n1, *n2, *n3;
10980 int t;
10981
Eric Andersencb57d552001-06-28 07:25:16 +000010982 n1 = pipeline();
10983 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010984 t = readtoken();
10985 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000010986 t = NAND;
10987 } else if (t == TOR) {
10988 t = NOR;
10989 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010990 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010991 return n1;
10992 }
Eric Andersenc470f442003-07-28 09:56:35 +000010993 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010994 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010995 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010996 n3->type = t;
10997 n3->nbinary.ch1 = n1;
10998 n3->nbinary.ch2 = n2;
10999 n1 = n3;
11000 }
11001}
11002
Eric Andersenc470f442003-07-28 09:56:35 +000011003static union node *
11004pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011005{
Eric Andersencb57d552001-06-28 07:25:16 +000011006 union node *n1, *n2, *pipenode;
11007 struct nodelist *lp, *prev;
11008 int negate;
11009
11010 negate = 0;
11011 TRACE(("pipeline: entered\n"));
11012 if (readtoken() == TNOT) {
11013 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000011014 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011015 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011016 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011017 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011018 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011019 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000011020 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011021 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011022 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000011023 pipenode->npipe.cmdlist = lp;
11024 lp->n = n1;
11025 do {
11026 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011027 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000011028 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011029 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011030 prev->next = lp;
11031 } while (readtoken() == TPIPE);
11032 lp->next = NULL;
11033 n1 = pipenode;
11034 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011035 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011036 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011037 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000011038 n2->type = NNOT;
11039 n2->nnot.com = n1;
11040 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011041 }
11042 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000011043}
11044
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011045static union node *
11046makename(void)
11047{
11048 union node *n;
11049
Denis Vlasenko597906c2008-02-20 16:38:54 +000011050 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011051 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011052 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011053 n->narg.text = wordtext;
11054 n->narg.backquote = backquotelist;
11055 return n;
11056}
11057
11058static void
11059fixredir(union node *n, const char *text, int err)
11060{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011061 int fd;
11062
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011063 TRACE(("Fix redir %s %d\n", text, err));
11064 if (!err)
11065 n->ndup.vname = NULL;
11066
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011067 fd = bb_strtou(text, NULL, 10);
11068 if (!errno && fd >= 0)
11069 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011070 else if (LONE_DASH(text))
11071 n->ndup.dupfd = -1;
11072 else {
11073 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011074 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011075 n->ndup.vname = makename();
11076 }
11077}
11078
11079/*
11080 * Returns true if the text contains nothing to expand (no dollar signs
11081 * or backquotes).
11082 */
11083static int
Denis Vlasenko68819d12008-12-15 11:26:36 +000011084noexpand(const char *text)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011085{
Denys Vlasenkocd716832009-11-28 22:14:02 +010011086 unsigned char c;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011087
Denys Vlasenkocd716832009-11-28 22:14:02 +010011088 while ((c = *text++) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011089 if (c == CTLQUOTEMARK)
11090 continue;
11091 if (c == CTLESC)
Denys Vlasenkocd716832009-11-28 22:14:02 +010011092 text++;
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011093 else if (SIT(c, BASESYNTAX) == CCTL)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011094 return 0;
11095 }
11096 return 1;
11097}
11098
11099static void
11100parsefname(void)
11101{
11102 union node *n = redirnode;
11103
11104 if (readtoken() != TWORD)
11105 raise_error_unexpected_syntax(-1);
11106 if (n->type == NHERE) {
11107 struct heredoc *here = heredoc;
11108 struct heredoc *p;
11109 int i;
11110
11111 if (quoteflag == 0)
11112 n->type = NXHERE;
11113 TRACE(("Here document %d\n", n->type));
11114 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011115 raise_error_syntax("illegal eof marker for << redirection");
Denys Vlasenkob6c84342009-08-29 20:23:20 +020011116 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011117 here->eofmark = wordtext;
11118 here->next = NULL;
11119 if (heredoclist == NULL)
11120 heredoclist = here;
11121 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011122 for (p = heredoclist; p->next; p = p->next)
11123 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011124 p->next = here;
11125 }
11126 } else if (n->type == NTOFD || n->type == NFROMFD) {
11127 fixredir(n, wordtext, 0);
11128 } else {
11129 n->nfile.fname = makename();
11130 }
11131}
Eric Andersencb57d552001-06-28 07:25:16 +000011132
Eric Andersenc470f442003-07-28 09:56:35 +000011133static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011134simplecmd(void)
11135{
11136 union node *args, **app;
11137 union node *n = NULL;
11138 union node *vars, **vpp;
11139 union node **rpp, *redir;
11140 int savecheckkwd;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011141#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011142 smallint double_brackets_flag = 0;
11143#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011144 IF_BASH_FUNCTION(smallint function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011145
11146 args = NULL;
11147 app = &args;
11148 vars = NULL;
11149 vpp = &vars;
11150 redir = NULL;
11151 rpp = &redir;
11152
11153 savecheckkwd = CHKALIAS;
11154 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000011155 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011156 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011157 t = readtoken();
11158 switch (t) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011159#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011160 case TFUNCTION:
11161 if (peektoken() != TWORD)
11162 raise_error_unexpected_syntax(TWORD);
11163 function_flag = 1;
11164 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011165#endif
11166#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011167 case TAND: /* "&&" */
11168 case TOR: /* "||" */
11169 if (!double_brackets_flag) {
11170 tokpushback = 1;
11171 goto out;
11172 }
11173 wordtext = (char *) (t == TAND ? "-a" : "-o");
11174#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011175 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011176 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011177 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011178 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011179 n->narg.text = wordtext;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011180#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011181 if (strcmp("[[", wordtext) == 0)
11182 double_brackets_flag = 1;
11183 else if (strcmp("]]", wordtext) == 0)
11184 double_brackets_flag = 0;
11185#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011186 n->narg.backquote = backquotelist;
11187 if (savecheckkwd && isassignment(wordtext)) {
11188 *vpp = n;
11189 vpp = &n->narg.next;
11190 } else {
11191 *app = n;
11192 app = &n->narg.next;
11193 savecheckkwd = 0;
11194 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011195#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011196 if (function_flag) {
11197 checkkwd = CHKNL | CHKKWD;
11198 switch (peektoken()) {
11199 case TBEGIN:
11200 case TIF:
11201 case TCASE:
11202 case TUNTIL:
11203 case TWHILE:
11204 case TFOR:
11205 goto do_func;
11206 case TLP:
11207 function_flag = 0;
11208 break;
11209 case TWORD:
11210 if (strcmp("[[", wordtext) == 0)
11211 goto do_func;
11212 /* fall through */
11213 default:
11214 raise_error_unexpected_syntax(-1);
11215 }
11216 }
11217#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011218 break;
11219 case TREDIR:
11220 *rpp = n = redirnode;
11221 rpp = &n->nfile.next;
11222 parsefname(); /* read name of redirection file */
11223 break;
11224 case TLP:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011225 IF_BASH_FUNCTION(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011226 if (args && app == &args->narg.next
11227 && !vars && !redir
11228 ) {
11229 struct builtincmd *bcmd;
11230 const char *name;
11231
11232 /* We have a function */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011233 if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011234 raise_error_unexpected_syntax(TRP);
11235 name = n->narg.text;
11236 if (!goodname(name)
11237 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11238 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011239 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011240 }
11241 n->type = NDEFUN;
11242 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11243 n->narg.next = parse_command();
11244 return n;
11245 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011246 IF_BASH_FUNCTION(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011247 /* fall through */
11248 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011249 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011250 goto out;
11251 }
11252 }
11253 out:
11254 *app = NULL;
11255 *vpp = NULL;
11256 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011257 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011258 n->type = NCMD;
11259 n->ncmd.args = args;
11260 n->ncmd.assign = vars;
11261 n->ncmd.redirect = redir;
11262 return n;
11263}
11264
11265static union node *
11266parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011267{
Eric Andersencb57d552001-06-28 07:25:16 +000011268 union node *n1, *n2;
11269 union node *ap, **app;
11270 union node *cp, **cpp;
11271 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011272 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011273 int t;
11274
11275 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011276 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011277
Eric Andersencb57d552001-06-28 07:25:16 +000011278 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011279 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011280 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011281 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011282 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011283 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011284 n1->type = NIF;
11285 n1->nif.test = list(0);
11286 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011287 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011288 n1->nif.ifpart = list(0);
11289 n2 = n1;
11290 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011291 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011292 n2 = n2->nif.elsepart;
11293 n2->type = NIF;
11294 n2->nif.test = list(0);
11295 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011296 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011297 n2->nif.ifpart = list(0);
11298 }
11299 if (lasttoken == TELSE)
11300 n2->nif.elsepart = list(0);
11301 else {
11302 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011303 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011304 }
Eric Andersenc470f442003-07-28 09:56:35 +000011305 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011306 break;
11307 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011308 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011309 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011310 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011311 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011312 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011313 got = readtoken();
11314 if (got != TDO) {
Denys Vlasenko888527c2016-10-02 16:54:17 +020011315 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
Denis Vlasenko131ae172007-02-18 13:00:19 +000011316 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011317 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011318 }
11319 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011320 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011321 break;
11322 }
11323 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011324 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011325 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011326 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011327 n1->type = NFOR;
11328 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011329 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011330 if (readtoken() == TIN) {
11331 app = &ap;
11332 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011333 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011334 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011335 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011336 n2->narg.text = wordtext;
11337 n2->narg.backquote = backquotelist;
11338 *app = n2;
11339 app = &n2->narg.next;
11340 }
11341 *app = NULL;
11342 n1->nfor.args = ap;
11343 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011344 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011345 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011346 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011347 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011348 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011349 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011350 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011351 n1->nfor.args = n2;
11352 /*
11353 * Newline or semicolon here is optional (but note
11354 * that the original Bourne shell only allowed NL).
11355 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011356 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011357 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011358 }
Eric Andersenc470f442003-07-28 09:56:35 +000011359 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011360 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011361 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011362 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011363 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011364 break;
11365 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011366 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011367 n1->type = NCASE;
11368 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011369 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011370 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011371 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011372 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011373 n2->narg.text = wordtext;
11374 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011375 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11376 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011377 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011378 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011379 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011380 checkkwd = CHKNL | CHKKWD;
11381 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011382 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011383 if (lasttoken == TLP)
11384 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011385 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011386 cp->type = NCLIST;
11387 app = &cp->nclist.pattern;
11388 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011389 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011390 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011391 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011392 ap->narg.text = wordtext;
11393 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011394 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011395 break;
11396 app = &ap->narg.next;
11397 readtoken();
11398 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011399 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011400 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011401 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011402 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011403
Eric Andersenc470f442003-07-28 09:56:35 +000011404 cpp = &cp->nclist.next;
11405
11406 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011407 t = readtoken();
11408 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011409 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011410 raise_error_unexpected_syntax(TENDCASE);
11411 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011412 }
Eric Andersenc470f442003-07-28 09:56:35 +000011413 }
Eric Andersencb57d552001-06-28 07:25:16 +000011414 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011415 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011416 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011417 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011418 n1->type = NSUBSHELL;
11419 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011420 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011421 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011422 break;
11423 case TBEGIN:
11424 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011425 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011426 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011427 IF_BASH_FUNCTION(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011428 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011429 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011430 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011431 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011432 }
11433
Eric Andersenc470f442003-07-28 09:56:35 +000011434 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011435 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011436
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011437 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011438 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011439 checkkwd = CHKKWD | CHKALIAS;
11440 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011441 while (readtoken() == TREDIR) {
11442 *rpp = n2 = redirnode;
11443 rpp = &n2->nfile.next;
11444 parsefname();
11445 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011446 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011447 *rpp = NULL;
11448 if (redir) {
11449 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011450 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011451 n2->type = NREDIR;
11452 n2->nredir.n = n1;
11453 n1 = n2;
11454 }
11455 n1->nredir.redirect = redir;
11456 }
Eric Andersencb57d552001-06-28 07:25:16 +000011457 return n1;
11458}
11459
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011460#if BASH_DOLLAR_SQUOTE
Denys Vlasenko37dc08b2016-10-02 04:38:07 +020011461static int
11462decode_dollar_squote(void)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011463{
11464 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11465 int c, cnt;
11466 char *p;
11467 char buf[4];
11468
11469 c = pgetc();
11470 p = strchr(C_escapes, c);
11471 if (p) {
11472 buf[0] = c;
11473 p = buf;
11474 cnt = 3;
11475 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11476 do {
11477 c = pgetc();
11478 *++p = c;
11479 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11480 pungetc();
11481 } else if (c == 'x') { /* \xHH */
11482 do {
11483 c = pgetc();
11484 *++p = c;
11485 } while (isxdigit(c) && --cnt);
11486 pungetc();
11487 if (cnt == 3) { /* \x but next char is "bad" */
11488 c = 'x';
11489 goto unrecognized;
11490 }
11491 } else { /* simple seq like \\ or \t */
11492 p++;
11493 }
11494 *p = '\0';
11495 p = buf;
11496 c = bb_process_escape_sequence((void*)&p);
11497 } else { /* unrecognized "\z": print both chars unless ' or " */
11498 if (c != '\'' && c != '"') {
11499 unrecognized:
11500 c |= 0x100; /* "please encode \, then me" */
11501 }
11502 }
11503 return c;
11504}
11505#endif
11506
Eric Andersencb57d552001-06-28 07:25:16 +000011507/*
11508 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11509 * is not NULL, read a here document. In the latter case, eofmark is the
11510 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011511 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011512 * is the first character of the input token or document.
11513 *
11514 * Because C does not have internal subroutines, I have simulated them
11515 * using goto's to implement the subroutine linkage. The following macros
11516 * will run code that appears at the end of readtoken1.
11517 */
Eric Andersen2870d962001-07-02 17:27:21 +000011518#define CHECKEND() {goto checkend; checkend_return:;}
11519#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11520#define PARSESUB() {goto parsesub; parsesub_return:;}
11521#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11522#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11523#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011524static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011525readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011526{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011527 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011528 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011529 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020011530 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +000011531 char line[EOFMARKLEN + 1];
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011532 struct nodelist *bqlist;
11533 smallint quotef;
11534 smallint dblquote;
11535 smallint oldstyle;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011536 IF_FEATURE_SH_MATH(smallint prevsyntax;) /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011537 smallint pssyntax; /* we are expanding a prompt string */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011538 int varnest; /* levels of variables expansion */
Denys Vlasenko0b883582016-12-23 16:49:07 +010011539 IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */
11540 IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011541 int dqvarnest; /* levels of variables expansion within double quotes */
11542
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011543 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011544
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011545 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011546 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011547 quotef = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011548 IF_FEATURE_SH_MATH(prevsyntax = 0;)
Denis Vlasenko46a53062007-09-24 18:30:02 +000011549 pssyntax = (syntax == PSSYNTAX);
11550 if (pssyntax)
11551 syntax = DQSYNTAX;
Denis Vlasenko46a53062007-09-24 18:30:02 +000011552 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011553 varnest = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011554 IF_FEATURE_SH_MATH(arinest = 0;)
11555 IF_FEATURE_SH_MATH(parenlevel = 0;)
Eric Andersencb57d552001-06-28 07:25:16 +000011556 dqvarnest = 0;
11557
11558 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011559 loop:
11560 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011561 CHECKEND(); /* set c to PEOF if at end of here document */
11562 for (;;) { /* until end of line or end of word */
11563 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11564 switch (SIT(c, syntax)) {
11565 case CNL: /* '\n' */
11566 if (syntax == BASESYNTAX)
11567 goto endword; /* exit outer loop */
11568 USTPUTC(c, out);
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011569 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011570 c = pgetc();
11571 goto loop; /* continue outer loop */
11572 case CWORD:
11573 USTPUTC(c, out);
11574 break;
11575 case CCTL:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011576#if BASH_DOLLAR_SQUOTE
Denys Vlasenko958581a2010-09-12 15:04:27 +020011577 if (c == '\\' && bash_dollar_squote) {
11578 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020011579 if (c == '\0') {
11580 /* skip $'\000', $'\x00' (like bash) */
11581 break;
11582 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011583 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020011584 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011585 c = (unsigned char)c;
Denys Vlasenko13f20912016-09-25 20:54:25 +020011586 if (eofmark == NULL || dblquote)
11587 USTPUTC(CTLESC, out);
11588 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011589 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011590 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011591#endif
Denys Vlasenko13f20912016-09-25 20:54:25 +020011592 if (eofmark == NULL || dblquote)
11593 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011594 USTPUTC(c, out);
11595 break;
11596 case CBACK: /* backslash */
11597 c = pgetc_without_PEOA();
11598 if (c == PEOF) {
11599 USTPUTC(CTLESC, out);
11600 USTPUTC('\\', out);
11601 pungetc();
11602 } else if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011603 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011604 } else {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011605 if (c == '$' && pssyntax) {
Eric Andersenc470f442003-07-28 09:56:35 +000011606 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011607 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011608 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011609 /* Backslash is retained if we are in "str" and next char isn't special */
11610 if (dblquote
11611 && c != '\\'
11612 && c != '`'
11613 && c != '$'
11614 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011615 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011616 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011617 }
Ron Yorston549deab2015-05-18 09:57:51 +020011618 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011619 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011620 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011621 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011622 break;
11623 case CSQUOTE:
11624 syntax = SQSYNTAX;
11625 quotemark:
11626 if (eofmark == NULL) {
11627 USTPUTC(CTLQUOTEMARK, out);
11628 }
11629 break;
11630 case CDQUOTE:
11631 syntax = DQSYNTAX;
11632 dblquote = 1;
11633 goto quotemark;
11634 case CENDQUOTE:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011635 IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020011636 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011637 USTPUTC(c, out);
11638 } else {
11639 if (dqvarnest == 0) {
11640 syntax = BASESYNTAX;
11641 dblquote = 0;
11642 }
11643 quotef = 1;
11644 goto quotemark;
11645 }
11646 break;
11647 case CVAR: /* '$' */
11648 PARSESUB(); /* parse substitution */
11649 break;
11650 case CENDVAR: /* '}' */
11651 if (varnest > 0) {
11652 varnest--;
11653 if (dqvarnest > 0) {
11654 dqvarnest--;
11655 }
11656 c = CTLENDVAR;
11657 }
11658 USTPUTC(c, out);
11659 break;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011660#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko958581a2010-09-12 15:04:27 +020011661 case CLP: /* '(' in arithmetic */
11662 parenlevel++;
11663 USTPUTC(c, out);
11664 break;
11665 case CRP: /* ')' in arithmetic */
11666 if (parenlevel > 0) {
11667 parenlevel--;
11668 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011669 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020011670 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011671 if (--arinest == 0) {
11672 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011673 }
11674 } else {
11675 /*
11676 * unbalanced parens
11677 * (don't 2nd guess - no error)
11678 */
11679 pungetc();
11680 }
11681 }
11682 USTPUTC(c, out);
11683 break;
11684#endif
11685 case CBQUOTE: /* '`' */
11686 PARSEBACKQOLD();
11687 break;
11688 case CENDFILE:
11689 goto endword; /* exit outer loop */
11690 case CIGN:
11691 break;
11692 default:
11693 if (varnest == 0) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011694#if BASH_REDIR_OUTPUT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011695 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011696//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020011697 if (pgetc() == '>')
11698 c = 0x100 + '>'; /* flag &> */
11699 pungetc();
11700 }
11701#endif
11702 goto endword; /* exit outer loop */
11703 }
11704 IF_ASH_ALIAS(if (c != PEOA))
11705 USTPUTC(c, out);
11706 }
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020011707 c = pgetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011708 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011709 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011710
Denys Vlasenko0b883582016-12-23 16:49:07 +010011711#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000011712 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011713 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011714#endif
Ron Yorston0e056f72015-07-01 16:45:40 +010011715 if (syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011716 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011717 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011718 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011719 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011720 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011721 }
11722 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011723 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011724 out = stackblock();
11725 if (eofmark == NULL) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011726 if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011727 && quotef == 0
11728 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011729 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011730 PARSEREDIR(); /* passed as params: out, c */
11731 lasttoken = TREDIR;
11732 return lasttoken;
11733 }
11734 /* else: non-number X seen, interpret it
11735 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011736 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011737 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011738 }
11739 quoteflag = quotef;
11740 backquotelist = bqlist;
11741 grabstackblock(len);
11742 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011743 lasttoken = TWORD;
11744 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011745/* end of readtoken routine */
11746
Eric Andersencb57d552001-06-28 07:25:16 +000011747/*
11748 * Check to see whether we are at the end of the here document. When this
11749 * is called, c is set to the first character of the next input line. If
11750 * we are at the end of the here document, this routine sets the c to PEOF.
11751 */
Eric Andersenc470f442003-07-28 09:56:35 +000011752checkend: {
11753 if (eofmark) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000011754#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011755 if (c == PEOA)
11756 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011757#endif
11758 if (striptabs) {
11759 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011760 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011761 }
Eric Andersenc470f442003-07-28 09:56:35 +000011762 }
11763 if (c == *eofmark) {
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011764 if (pfgets(line, sizeof(line)) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000011765 char *p, *q;
Denys Vlasenko350e6862016-10-26 16:26:45 +020011766 int cc;
Eric Andersencb57d552001-06-28 07:25:16 +000011767
Eric Andersenc470f442003-07-28 09:56:35 +000011768 p = line;
Denys Vlasenko350e6862016-10-26 16:26:45 +020011769 for (q = eofmark + 1;; p++, q++) {
11770 cc = *p;
11771 if (cc == '\n')
11772 cc = 0;
11773 if (!*q || cc != *q)
11774 break;
11775 }
11776 if (cc == *q) {
Eric Andersenc470f442003-07-28 09:56:35 +000011777 c = PEOF;
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011778 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011779 } else {
11780 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011781 }
11782 }
11783 }
11784 }
Eric Andersenc470f442003-07-28 09:56:35 +000011785 goto checkend_return;
11786}
Eric Andersencb57d552001-06-28 07:25:16 +000011787
Eric Andersencb57d552001-06-28 07:25:16 +000011788/*
11789 * Parse a redirection operator. The variable "out" points to a string
11790 * specifying the fd to be redirected. The variable "c" contains the
11791 * first character of the redirection operator.
11792 */
Eric Andersenc470f442003-07-28 09:56:35 +000011793parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011794 /* out is already checked to be a valid number or "" */
11795 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000011796 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000011797
Denis Vlasenko597906c2008-02-20 16:38:54 +000011798 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000011799 if (c == '>') {
11800 np->nfile.fd = 1;
11801 c = pgetc();
11802 if (c == '>')
11803 np->type = NAPPEND;
11804 else if (c == '|')
11805 np->type = NCLOBBER;
11806 else if (c == '&')
11807 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011808 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000011809 else {
11810 np->type = NTO;
11811 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011812 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000011813 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011814#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000011815 else if (c == 0x100 + '>') { /* this flags &> redirection */
11816 np->nfile.fd = 1;
11817 pgetc(); /* this is '>', no need to check */
11818 np->type = NTO2;
11819 }
11820#endif
11821 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000011822 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011823 c = pgetc();
11824 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000011825 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011826 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011827 np = stzalloc(sizeof(struct nhere));
11828 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011829 }
11830 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011831 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000011832 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011833 c = pgetc();
11834 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000011835 heredoc->striptabs = 1;
11836 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011837 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011838 pungetc();
11839 }
11840 break;
11841
11842 case '&':
11843 np->type = NFROMFD;
11844 break;
11845
11846 case '>':
11847 np->type = NFROMTO;
11848 break;
11849
11850 default:
11851 np->type = NFROM;
11852 pungetc();
11853 break;
11854 }
Eric Andersencb57d552001-06-28 07:25:16 +000011855 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011856 if (fd >= 0)
11857 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011858 redirnode = np;
11859 goto parseredir_return;
11860}
Eric Andersencb57d552001-06-28 07:25:16 +000011861
Eric Andersencb57d552001-06-28 07:25:16 +000011862/*
11863 * Parse a substitution. At this point, we have read the dollar sign
11864 * and nothing else.
11865 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000011866
11867/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11868 * (assuming ascii char codes, as the original implementation did) */
11869#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011870 (((unsigned)(c) - 33 < 32) \
11871 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000011872parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010011873 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011874 int typeloc;
Eric Andersencb57d552001-06-28 07:25:16 +000011875
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011876 c = pgetc_eatbnl();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011877 if (c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011878 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000011879 ) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011880#if BASH_DOLLAR_SQUOTE
Ron Yorston84ba50c2016-04-03 22:43:14 +010011881 if (syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011882 bash_dollar_squote = 1;
11883 else
11884#endif
11885 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011886 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011887 } else if (c == '(') {
11888 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011889 if (pgetc_eatbnl() == '(') {
Denys Vlasenko0b883582016-12-23 16:49:07 +010011890#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000011891 PARSEARITH();
11892#else
Mike Frysinger98a6f562008-06-09 09:38:45 +000011893 raise_error_syntax("you disabled math support for $((arith)) syntax");
Eric Andersenc470f442003-07-28 09:56:35 +000011894#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011895 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011896 pungetc();
11897 PARSEBACKQNEW();
11898 }
11899 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011900 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000011901 USTPUTC(CTLVAR, out);
11902 typeloc = out - (char *)stackblock();
Denys Vlasenko3df14102016-10-26 16:41:13 +020011903 STADJUST(1, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011904 subtype = VSNORMAL;
11905 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011906 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011907 subtype = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011908 }
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011909 varname:
Denys Vlasenko3df14102016-10-26 16:41:13 +020011910 if (is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011911 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011912 do {
11913 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011914 c = pgetc_eatbnl();
Denys Vlasenko3df14102016-10-26 16:41:13 +020011915 } while (is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011916 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011917 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011918 do {
11919 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011920 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011921 } while (isdigit(c));
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011922 } else if (is_special(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011923 /* $[{[#]]<specialchar>[}] */
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011924 int cc = c;
11925
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011926 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011927 if (!subtype && cc == '#') {
11928 subtype = VSLENGTH;
11929 if (c == '_' || isalnum(c))
11930 goto varname;
11931 cc = c;
11932 c = pgetc_eatbnl();
11933 if (cc == '}' || c != '}') {
11934 pungetc();
11935 subtype = 0;
11936 c = cc;
11937 cc = '#';
11938 }
11939 }
11940 USTPUTC(cc, out);
Denis Vlasenko559691a2008-10-05 18:39:31 +000011941 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020011942 goto badsub;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011943 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011944 if (c != '}' && subtype == VSLENGTH) {
11945 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020011946 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011947 }
Eric Andersencb57d552001-06-28 07:25:16 +000011948
Eric Andersenc470f442003-07-28 09:56:35 +000011949 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011950 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011951 /* ${VAR...} but not $VAR or ${#VAR} */
11952 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000011953 switch (c) {
11954 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011955 c = pgetc_eatbnl();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011956#if BASH_SUBSTR
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011957 /* This check is only needed to not misinterpret
11958 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
11959 * constructs.
11960 */
11961 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011962 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011963 pungetc();
Denys Vlasenko88e15702016-10-26 01:55:56 +020011964 break; /* "goto badsub" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011965 }
11966#endif
Denys Vlasenko3df14102016-10-26 16:41:13 +020011967 subtype = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000011968 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011969 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011970 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000011971 if (p == NULL)
Denys Vlasenko88e15702016-10-26 01:55:56 +020011972 break;
Denys Vlasenko3df14102016-10-26 16:41:13 +020011973 subtype |= p - types + VSNORMAL;
Eric Andersenc470f442003-07-28 09:56:35 +000011974 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011975 }
Eric Andersenc470f442003-07-28 09:56:35 +000011976 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011977 case '#': {
11978 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011979 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011980 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011981 if (c != cc)
Denys Vlasenko88e15702016-10-26 01:55:56 +020011982 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011983 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011984 break;
11985 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011986#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011987 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011988 /* ${v/[/]pattern/repl} */
11989//TODO: encode pattern and repl separately.
11990// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011991 subtype = VSREPLACE;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011992 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011993 if (c != '/')
Denys Vlasenko88e15702016-10-26 01:55:56 +020011994 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011995 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011996 break;
11997#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011998 }
Eric Andersenc470f442003-07-28 09:56:35 +000011999 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020012000 badsub:
Eric Andersenc470f442003-07-28 09:56:35 +000012001 pungetc();
12002 }
Denys Vlasenko3df14102016-10-26 16:41:13 +020012003 ((unsigned char *)stackblock())[typeloc] = subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012004 if (subtype != VSNORMAL) {
12005 varnest++;
Denys Vlasenko3df14102016-10-26 16:41:13 +020012006 if (dblquote)
Eric Andersenc470f442003-07-28 09:56:35 +000012007 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000012008 }
Denys Vlasenko88e15702016-10-26 01:55:56 +020012009 STPUTC('=', out);
Eric Andersencb57d552001-06-28 07:25:16 +000012010 }
Eric Andersenc470f442003-07-28 09:56:35 +000012011 goto parsesub_return;
12012}
Eric Andersencb57d552001-06-28 07:25:16 +000012013
Eric Andersencb57d552001-06-28 07:25:16 +000012014/*
12015 * Called to parse command substitutions. Newstyle is set if the command
12016 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
12017 * list of commands (passed by reference), and savelen is the number of
12018 * characters on the top of the stack which must be preserved.
12019 */
Eric Andersenc470f442003-07-28 09:56:35 +000012020parsebackq: {
12021 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012022 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010012023 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000012024 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012025 smallint saveprompt = 0;
12026
Eric Andersenc470f442003-07-28 09:56:35 +000012027 str = NULL;
12028 savelen = out - (char *)stackblock();
12029 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012030 /*
12031 * FIXME: this can allocate very large block on stack and SEGV.
12032 * Example:
12033 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020012034 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012035 * a hundred command substitutions stack overflows.
12036 * With larger prepended string, SEGV happens sooner.
12037 */
Ron Yorston072fc602015-07-01 16:46:18 +010012038 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000012039 memcpy(str, stackblock(), savelen);
12040 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012041
Eric Andersenc470f442003-07-28 09:56:35 +000012042 if (oldstyle) {
12043 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010012044 * treatment to some slashes, and then push the string and
12045 * reread it as input, interpreting it normally.
12046 */
Eric Andersenc470f442003-07-28 09:56:35 +000012047 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000012048 size_t psavelen;
12049 char *pstr;
12050
Eric Andersenc470f442003-07-28 09:56:35 +000012051 STARTSTACKSTR(pout);
12052 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012053 int pc;
12054
12055 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012056 pc = pgetc();
12057 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000012058 case '`':
12059 goto done;
12060
12061 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012062 pc = pgetc();
12063 if (pc == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012064 nlprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012065 /*
12066 * If eating a newline, avoid putting
12067 * the newline into the new character
12068 * stream (via the STPUTC after the
12069 * switch).
12070 */
12071 continue;
12072 }
12073 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012074 && (!dblquote || pc != '"')
12075 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000012076 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012077 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010012078 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000012079 break;
12080 }
12081 /* fall through */
12082
12083 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012084 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012085 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012086 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000012087
12088 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012089 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012090 break;
12091
12092 default:
12093 break;
12094 }
12095 STPUTC(pc, pout);
12096 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012097 done:
Eric Andersenc470f442003-07-28 09:56:35 +000012098 STPUTC('\0', pout);
12099 psavelen = pout - (char *)stackblock();
12100 if (psavelen > 0) {
12101 pstr = grabstackstr(pout);
12102 setinputstring(pstr);
12103 }
12104 }
12105 nlpp = &bqlist;
12106 while (*nlpp)
12107 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012108 *nlpp = stzalloc(sizeof(**nlpp));
12109 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012110
12111 if (oldstyle) {
12112 saveprompt = doprompt;
12113 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012114 }
12115
Eric Andersenc470f442003-07-28 09:56:35 +000012116 n = list(2);
12117
12118 if (oldstyle)
12119 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012120 else if (readtoken() != TRP)
12121 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000012122
12123 (*nlpp)->n = n;
12124 if (oldstyle) {
12125 /*
12126 * Start reading from old file again, ignoring any pushed back
12127 * tokens left from the backquote parsing
12128 */
12129 popfile();
12130 tokpushback = 0;
12131 }
12132 while (stackblocksize() <= savelen)
12133 growstackblock();
12134 STARTSTACKSTR(out);
12135 if (str) {
12136 memcpy(out, str, savelen);
12137 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012138 }
Ron Yorston549deab2015-05-18 09:57:51 +020012139 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012140 if (oldstyle)
12141 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012142 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000012143}
12144
Denys Vlasenko0b883582016-12-23 16:49:07 +010012145#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000012146/*
12147 * Parse an arithmetic expansion (indicate start of one and set state)
12148 */
Eric Andersenc470f442003-07-28 09:56:35 +000012149parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000012150 if (++arinest == 1) {
12151 prevsyntax = syntax;
12152 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000012153 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020012154 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012155 goto parsearith_return;
12156}
12157#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012158} /* end of readtoken */
12159
Eric Andersencb57d552001-06-28 07:25:16 +000012160/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012161 * Read the next input token.
12162 * If the token is a word, we set backquotelist to the list of cmds in
12163 * backquotes. We set quoteflag to true if any part of the word was
12164 * quoted.
12165 * If the token is TREDIR, then we set redirnode to a structure containing
12166 * the redirection.
12167 * In all cases, the variable startlinno is set to the number of the line
12168 * on which the token starts.
12169 *
12170 * [Change comment: here documents and internal procedures]
12171 * [Readtoken shouldn't have any arguments. Perhaps we should make the
12172 * word parsing code into a separate routine. In this case, readtoken
12173 * doesn't need to have any internal procedures, but parseword does.
12174 * We could also make parseoperator in essence the main routine, and
12175 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000012176 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012177#define NEW_xxreadtoken
12178#ifdef NEW_xxreadtoken
12179/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012180static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000012181 '\n', '(', ')', /* singles */
12182 '&', '|', ';', /* doubles */
12183 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012184};
Eric Andersencb57d552001-06-28 07:25:16 +000012185
Denis Vlasenko834dee72008-10-07 09:18:30 +000012186#define xxreadtoken_singles 3
12187#define xxreadtoken_doubles 3
12188
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012189static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012190 TNL, TLP, TRP, /* only single occurrence allowed */
12191 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12192 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012193 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012194};
12195
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012196static int
12197xxreadtoken(void)
12198{
12199 int c;
12200
12201 if (tokpushback) {
12202 tokpushback = 0;
12203 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012204 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012205 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012206 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012207 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012208 c = pgetc();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000012209 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012210 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012211
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012212 if (c == '#') {
12213 while ((c = pgetc()) != '\n' && c != PEOF)
12214 continue;
12215 pungetc();
12216 } else if (c == '\\') {
12217 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012218 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012219 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012220 }
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012221 nlprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012222 } else {
12223 const char *p;
12224
12225 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12226 if (c != PEOF) {
12227 if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012228 nlnoprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012229 }
12230
12231 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000012232 if (p == NULL)
12233 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012234
Denis Vlasenko834dee72008-10-07 09:18:30 +000012235 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12236 int cc = pgetc();
12237 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012238 p += xxreadtoken_doubles + 1;
12239 } else {
12240 pungetc();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012241#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012242 if (c == '&' && cc == '>') /* &> */
12243 break; /* return readtoken1(...) */
12244#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012245 }
12246 }
12247 }
12248 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12249 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012250 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012251 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012252
12253 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012254}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012255#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012256#define RETURN(token) return lasttoken = token
12257static int
12258xxreadtoken(void)
12259{
12260 int c;
12261
12262 if (tokpushback) {
12263 tokpushback = 0;
12264 return lasttoken;
12265 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012266 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012267 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012268 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012269 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012270 switch (c) {
12271 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012272 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012273 continue;
12274 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012275 while ((c = pgetc()) != '\n' && c != PEOF)
12276 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012277 pungetc();
12278 continue;
12279 case '\\':
12280 if (pgetc() == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012281 nlprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012282 continue;
12283 }
12284 pungetc();
12285 goto breakloop;
12286 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012287 nlnoprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012288 RETURN(TNL);
12289 case PEOF:
12290 RETURN(TEOF);
12291 case '&':
12292 if (pgetc() == '&')
12293 RETURN(TAND);
12294 pungetc();
12295 RETURN(TBACKGND);
12296 case '|':
12297 if (pgetc() == '|')
12298 RETURN(TOR);
12299 pungetc();
12300 RETURN(TPIPE);
12301 case ';':
12302 if (pgetc() == ';')
12303 RETURN(TENDCASE);
12304 pungetc();
12305 RETURN(TSEMI);
12306 case '(':
12307 RETURN(TLP);
12308 case ')':
12309 RETURN(TRP);
12310 default:
12311 goto breakloop;
12312 }
12313 }
12314 breakloop:
12315 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12316#undef RETURN
12317}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012318#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012319
12320static int
12321readtoken(void)
12322{
12323 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012324 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012325#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012326 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012327#endif
12328
12329#if ENABLE_ASH_ALIAS
12330 top:
12331#endif
12332
12333 t = xxreadtoken();
12334
12335 /*
12336 * eat newlines
12337 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012338 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012339 while (t == TNL) {
12340 parseheredoc();
12341 t = xxreadtoken();
12342 }
12343 }
12344
12345 if (t != TWORD || quoteflag) {
12346 goto out;
12347 }
12348
12349 /*
12350 * check for keywords
12351 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012352 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012353 const char *const *pp;
12354
12355 pp = findkwd(wordtext);
12356 if (pp) {
12357 lasttoken = t = pp - tokname_array;
Denys Vlasenko888527c2016-10-02 16:54:17 +020012358 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012359 goto out;
12360 }
12361 }
12362
12363 if (checkkwd & CHKALIAS) {
12364#if ENABLE_ASH_ALIAS
12365 struct alias *ap;
12366 ap = lookupalias(wordtext, 1);
12367 if (ap != NULL) {
12368 if (*ap->val) {
12369 pushstring(ap->val, ap);
12370 }
12371 goto top;
12372 }
12373#endif
12374 }
12375 out:
12376 checkkwd = 0;
12377#if DEBUG
12378 if (!alreadyseen)
Denys Vlasenko888527c2016-10-02 16:54:17 +020012379 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012380 else
Denys Vlasenko888527c2016-10-02 16:54:17 +020012381 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012382#endif
12383 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012384}
12385
Ron Yorstonc0e00762015-10-29 11:30:55 +000012386static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012387peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012388{
12389 int t;
12390
12391 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012392 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012393 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012394}
Eric Andersencb57d552001-06-28 07:25:16 +000012395
12396/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012397 * Read and parse a command. Returns NODE_EOF on end of file.
12398 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012399 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012400static union node *
12401parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012402{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012403 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012404 checkkwd = 0;
12405 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012406 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012407 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012408 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012409 return list(1);
12410}
12411
12412/*
12413 * Input any here documents.
12414 */
12415static void
12416parseheredoc(void)
12417{
12418 struct heredoc *here;
12419 union node *n;
12420
12421 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012422 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012423
12424 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012425 setprompt_if(needprompt, 2);
12426 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012427 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012428 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012429 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012430 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012431 n->narg.text = wordtext;
12432 n->narg.backquote = backquotelist;
12433 here->here->nhere.doc = n;
12434 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012435 }
Eric Andersencb57d552001-06-28 07:25:16 +000012436}
12437
12438
12439/*
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012440 * called by editline -- any expansions to the prompt should be added here.
Eric Andersencb57d552001-06-28 07:25:16 +000012441 */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012442static const char *
12443expandstr(const char *ps)
12444{
12445 union node n;
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012446 int saveprompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012447
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000012448 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12449 * and token processing _can_ alter it (delete NULs etc). */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012450 setinputstring((char *)ps);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012451
12452 saveprompt = doprompt;
12453 doprompt = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000012454 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012455 doprompt = saveprompt;
12456
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012457 popfile();
12458
12459 n.narg.type = NARG;
12460 n.narg.next = NULL;
12461 n.narg.text = wordtext;
12462 n.narg.backquote = backquotelist;
12463
Ron Yorston549deab2015-05-18 09:57:51 +020012464 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012465 return stackblock();
12466}
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012467
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012468/*
12469 * Execute a command or commands contained in a string.
12470 */
12471static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012472evalstring(char *s, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000012473{
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012474 struct jmploc *volatile savehandler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012475 struct jmploc jmploc;
12476 int ex;
12477
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012478 union node *n;
12479 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012480 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012481
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012482 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012483 setinputstring(s);
12484 setstackmark(&smark);
12485
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012486 status = 0;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012487 /* On exception inside execution loop, we must popfile().
12488 * Try interactively:
12489 * readonly a=a
12490 * command eval "a=b" # throws "is read only" error
12491 * "command BLTIN" is not supposed to abort (even in non-interactive use).
12492 * But if we skip popfile(), we hit EOF in eval's string, and exit.
12493 */
12494 savehandler = exception_handler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012495 ex = setjmp(jmploc.loc);
12496 if (ex)
12497 goto out;
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012498 exception_handler = &jmploc;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012499
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012500 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012501 int i;
12502
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012503 i = evaltree(n, flags);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012504 if (n)
12505 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012506 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012507 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012508 break;
12509 }
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012510 out:
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012511 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012512 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012513 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012514
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012515 exception_handler = savehandler;
12516 if (ex)
12517 longjmp(exception_handler->loc, ex);
12518
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012519 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000012520}
12521
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012522/*
12523 * The eval command.
12524 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012525static int FAST_FUNC
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012526evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012527{
12528 char *p;
12529 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012530
Denis Vlasenko68404f12008-03-17 09:00:54 +000012531 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012532 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012533 argv += 2;
12534 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012535 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012536 for (;;) {
12537 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012538 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012539 if (p == NULL)
12540 break;
12541 STPUTC(' ', concat);
12542 }
12543 STPUTC('\0', concat);
12544 p = grabstackstr(concat);
12545 }
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012546 return evalstring(p, flags & EV_TESTED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012547 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012548 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012549}
12550
12551/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012552 * Read and execute commands.
12553 * "Top" is nonzero for the top level command loop;
12554 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012555 */
12556static int
12557cmdloop(int top)
12558{
12559 union node *n;
12560 struct stackmark smark;
12561 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012562 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012563 int numeof = 0;
12564
12565 TRACE(("cmdloop(%d) called\n", top));
12566 for (;;) {
12567 int skip;
12568
12569 setstackmark(&smark);
12570#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012571 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020012572 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012573#endif
12574 inter = 0;
12575 if (iflag && top) {
12576 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012577 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012578 }
12579 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012580#if DEBUG
12581 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012582 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012583#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012584 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012585 if (!top || numeof >= 50)
12586 break;
12587 if (!stoppedjobs()) {
12588 if (!Iflag)
12589 break;
12590 out2str("\nUse \"exit\" to leave shell.\n");
12591 }
12592 numeof++;
12593 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012594 int i;
12595
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012596 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12597 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012598 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012599 i = evaltree(n, 0);
12600 if (n)
12601 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012602 }
12603 popstackmark(&smark);
12604 skip = evalskip;
12605
12606 if (skip) {
Denys Vlasenko6a0710e2016-09-30 14:18:34 +020012607 evalskip &= ~SKIPFUNC;
Denys Vlasenko0840c912016-10-01 15:27:44 +020012608 break;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012609 }
12610 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012611 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012612}
12613
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012614/*
12615 * Take commands from a file. To be compatible we should do a path
12616 * search for the file, which is necessary to find sub-commands.
12617 */
12618static char *
12619find_dot_file(char *name)
12620{
12621 char *fullname;
12622 const char *path = pathval();
12623 struct stat statb;
12624
12625 /* don't try this for absolute or relative paths */
12626 if (strchr(name, '/'))
12627 return name;
12628
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012629 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012630 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12631 /*
12632 * Don't bother freeing here, since it will
12633 * be freed by the caller.
12634 */
12635 return fullname;
12636 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012637 if (fullname != name)
12638 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012639 }
12640
12641 /* not found in the PATH */
12642 ash_msg_and_raise_error("%s: not found", name);
12643 /* NOTREACHED */
12644}
12645
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012646static int FAST_FUNC
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012647dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012648{
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012649 /* "false; . empty_file; echo $?" should print 0, not 1: */
12650 int status = 0;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012651 char *fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012652 char **argv;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012653 char *args_need_save;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012654 struct strlist *sp;
12655 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012656
12657 for (sp = cmdenviron; sp; sp = sp->next)
Denis Vlasenko4222ae42007-02-25 02:37:49 +000012658 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012659
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012660 nextopt(nullstr); /* handle possible "--" */
12661 argv = argptr;
12662
12663 if (!argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012664 /* bash says: "bash: .: filename argument required" */
12665 return 2; /* bash compat */
12666 }
12667
Denys Vlasenko091f8312013-03-17 14:25:22 +010012668 /* This aborts if file isn't found, which is POSIXly correct.
12669 * bash returns exitcode 1 instead.
12670 */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012671 fullname = find_dot_file(argv[0]);
12672 argv++;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012673 args_need_save = argv[0];
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010012674 if (args_need_save) { /* ". FILE ARGS", and ARGS are not empty */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012675 int argc;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012676 saveparam = shellparam;
12677 shellparam.malloced = 0;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012678 argc = 1;
12679 while (argv[argc])
12680 argc++;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012681 shellparam.nparam = argc;
12682 shellparam.p = argv;
12683 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012684
Denys Vlasenko091f8312013-03-17 14:25:22 +010012685 /* This aborts if file can't be opened, which is POSIXly correct.
12686 * bash returns exitcode 1 instead.
12687 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012688 setinputfile(fullname, INPUT_PUSH_FILE);
12689 commandname = fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012690 status = cmdloop(0);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012691 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012692
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012693 if (args_need_save) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012694 freeparam(&shellparam);
12695 shellparam = saveparam;
12696 };
12697
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012698 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012699}
12700
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012701static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012702exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012703{
12704 if (stoppedjobs())
12705 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012706 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012707 exitstatus = number(argv[1]);
12708 raise_exception(EXEXIT);
12709 /* NOTREACHED */
12710}
12711
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012712/*
12713 * Read a file containing shell functions.
12714 */
12715static void
12716readcmdfile(char *name)
12717{
12718 setinputfile(name, INPUT_PUSH_FILE);
12719 cmdloop(0);
12720 popfile();
12721}
12722
12723
Denis Vlasenkocc571512007-02-23 21:10:35 +000012724/* ============ find_command inplementation */
12725
12726/*
12727 * Resolve a command name. If you change this routine, you may have to
12728 * change the shellexec routine as well.
12729 */
12730static void
12731find_command(char *name, struct cmdentry *entry, int act, const char *path)
12732{
12733 struct tblentry *cmdp;
12734 int idx;
12735 int prev;
12736 char *fullname;
12737 struct stat statb;
12738 int e;
12739 int updatetbl;
12740 struct builtincmd *bcmd;
12741
12742 /* If name contains a slash, don't use PATH or hash table */
12743 if (strchr(name, '/') != NULL) {
12744 entry->u.index = -1;
12745 if (act & DO_ABS) {
12746 while (stat(name, &statb) < 0) {
12747#ifdef SYSV
12748 if (errno == EINTR)
12749 continue;
12750#endif
12751 entry->cmdtype = CMDUNKNOWN;
12752 return;
12753 }
12754 }
12755 entry->cmdtype = CMDNORMAL;
12756 return;
12757 }
12758
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012759/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012760
12761 updatetbl = (path == pathval());
12762 if (!updatetbl) {
12763 act |= DO_ALTPATH;
12764 if (strstr(path, "%builtin") != NULL)
12765 act |= DO_ALTBLTIN;
12766 }
12767
12768 /* If name is in the table, check answer will be ok */
12769 cmdp = cmdlookup(name, 0);
12770 if (cmdp != NULL) {
12771 int bit;
12772
12773 switch (cmdp->cmdtype) {
12774 default:
12775#if DEBUG
12776 abort();
12777#endif
12778 case CMDNORMAL:
12779 bit = DO_ALTPATH;
12780 break;
12781 case CMDFUNCTION:
12782 bit = DO_NOFUNC;
12783 break;
12784 case CMDBUILTIN:
12785 bit = DO_ALTBLTIN;
12786 break;
12787 }
12788 if (act & bit) {
12789 updatetbl = 0;
12790 cmdp = NULL;
12791 } else if (cmdp->rehash == 0)
12792 /* if not invalidated by cd, we're done */
12793 goto success;
12794 }
12795
12796 /* If %builtin not in path, check for builtin next */
12797 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012798 if (bcmd) {
12799 if (IS_BUILTIN_REGULAR(bcmd))
12800 goto builtin_success;
12801 if (act & DO_ALTPATH) {
12802 if (!(act & DO_ALTBLTIN))
12803 goto builtin_success;
12804 } else if (builtinloc <= 0) {
12805 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000012806 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012807 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000012808
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012809#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000012810 {
12811 int applet_no = find_applet_by_name(name);
12812 if (applet_no >= 0) {
12813 entry->cmdtype = CMDNORMAL;
12814 entry->u.index = -2 - applet_no;
12815 return;
12816 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012817 }
12818#endif
12819
Denis Vlasenkocc571512007-02-23 21:10:35 +000012820 /* We have to search path. */
12821 prev = -1; /* where to start */
12822 if (cmdp && cmdp->rehash) { /* doing a rehash */
12823 if (cmdp->cmdtype == CMDBUILTIN)
12824 prev = builtinloc;
12825 else
12826 prev = cmdp->param.index;
12827 }
12828
12829 e = ENOENT;
12830 idx = -1;
12831 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012832 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000012833 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012834 /* NB: code below will still use fullname
12835 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012836 idx++;
12837 if (pathopt) {
12838 if (prefix(pathopt, "builtin")) {
12839 if (bcmd)
12840 goto builtin_success;
12841 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000012842 }
12843 if ((act & DO_NOFUNC)
12844 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020012845 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012846 continue;
12847 }
12848 }
12849 /* if rehash, don't redo absolute path names */
12850 if (fullname[0] == '/' && idx <= prev) {
12851 if (idx < prev)
12852 continue;
12853 TRACE(("searchexec \"%s\": no change\n", name));
12854 goto success;
12855 }
12856 while (stat(fullname, &statb) < 0) {
12857#ifdef SYSV
12858 if (errno == EINTR)
12859 continue;
12860#endif
12861 if (errno != ENOENT && errno != ENOTDIR)
12862 e = errno;
12863 goto loop;
12864 }
12865 e = EACCES; /* if we fail, this will be the error */
12866 if (!S_ISREG(statb.st_mode))
12867 continue;
12868 if (pathopt) { /* this is a %func directory */
12869 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012870 /* NB: stalloc will return space pointed by fullname
12871 * (because we don't have any intervening allocations
12872 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012873 readcmdfile(fullname);
12874 cmdp = cmdlookup(name, 0);
12875 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12876 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12877 stunalloc(fullname);
12878 goto success;
12879 }
12880 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12881 if (!updatetbl) {
12882 entry->cmdtype = CMDNORMAL;
12883 entry->u.index = idx;
12884 return;
12885 }
12886 INT_OFF;
12887 cmdp = cmdlookup(name, 1);
12888 cmdp->cmdtype = CMDNORMAL;
12889 cmdp->param.index = idx;
12890 INT_ON;
12891 goto success;
12892 }
12893
12894 /* We failed. If there was an entry for this command, delete it */
12895 if (cmdp && updatetbl)
12896 delete_cmd_entry();
12897 if (act & DO_ERR)
12898 ash_msg("%s: %s", name, errmsg(e, "not found"));
12899 entry->cmdtype = CMDUNKNOWN;
12900 return;
12901
12902 builtin_success:
12903 if (!updatetbl) {
12904 entry->cmdtype = CMDBUILTIN;
12905 entry->u.cmd = bcmd;
12906 return;
12907 }
12908 INT_OFF;
12909 cmdp = cmdlookup(name, 1);
12910 cmdp->cmdtype = CMDBUILTIN;
12911 cmdp->param.cmd = bcmd;
12912 INT_ON;
12913 success:
12914 cmdp->rehash = 0;
12915 entry->cmdtype = cmdp->cmdtype;
12916 entry->u = cmdp->param;
12917}
12918
12919
Eric Andersencb57d552001-06-28 07:25:16 +000012920/*
Eric Andersencb57d552001-06-28 07:25:16 +000012921 * The trap builtin.
12922 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012923static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012924trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012925{
12926 char *action;
12927 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012928 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012929
Eric Andersenc470f442003-07-28 09:56:35 +000012930 nextopt(nullstr);
12931 ap = argptr;
12932 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012933 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012934 char *tr = trap_ptr[signo];
12935 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012936 /* note: bash adds "SIG", but only if invoked
12937 * as "bash". If called as "sh", or if set -o posix,
12938 * then it prints short signal names.
12939 * We are printing short names: */
12940 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012941 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012942 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012943 /* trap_ptr != trap only if we are in special-cased `trap` code.
12944 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012945 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012946 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000012947 }
12948 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012949 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012950 if (trap_ptr != trap) {
12951 free(trap_ptr);
12952 trap_ptr = trap;
12953 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012954 */
Eric Andersencb57d552001-06-28 07:25:16 +000012955 return 0;
12956 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012957
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012958 action = NULL;
12959 if (ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000012960 action = *ap++;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012961 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012962 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012963 signo = get_signum(*ap);
Denys Vlasenkoe9aba3e2017-07-01 21:09:27 +020012964 if (signo < 0 || signo >= NSIG) {
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012965 /* Mimic bash message exactly */
12966 ash_msg("%s: invalid signal specification", *ap);
12967 exitcode = 1;
12968 goto next;
12969 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000012970 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000012971 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000012972 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000012973 action = NULL;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020012974 else {
12975 if (action[0]) /* not NULL and not "" and not "-" */
12976 may_have_traps = 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012977 action = ckstrdup(action);
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020012978 }
Eric Andersencb57d552001-06-28 07:25:16 +000012979 }
Denis Vlasenko60818682007-09-28 22:07:23 +000012980 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000012981 trap[signo] = action;
12982 if (signo != 0)
12983 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012984 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012985 next:
Eric Andersencb57d552001-06-28 07:25:16 +000012986 ap++;
12987 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012988 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012989}
12990
Eric Andersenc470f442003-07-28 09:56:35 +000012991
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012992/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000012993
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012994#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012995static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012996helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012997{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000012998 unsigned col;
12999 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000013000
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020013001 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000013002 "Built-in commands:\n"
13003 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000013004 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013005 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000013006 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013007 if (col > 60) {
13008 out1fmt("\n");
13009 col = 0;
13010 }
13011 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013012# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000013013 {
13014 const char *a = applet_names;
13015 while (*a) {
13016 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
13017 if (col > 60) {
13018 out1fmt("\n");
13019 col = 0;
13020 }
Ron Yorston2b919582016-04-08 11:57:20 +010013021 while (*a++ != '\0')
13022 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013023 }
13024 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013025# endif
Denys Vlasenkoebedb942016-10-02 18:45:09 +020013026 newline_and_flush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000013027 return EXIT_SUCCESS;
13028}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013029#endif
Eric Andersenc470f442003-07-28 09:56:35 +000013030
Flemming Madsend96ffda2013-04-07 18:47:24 +020013031#if MAX_HISTORY
13032static int FAST_FUNC
13033historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13034{
13035 show_history(line_input_state);
13036 return EXIT_SUCCESS;
13037}
13038#endif
13039
Eric Andersencb57d552001-06-28 07:25:16 +000013040/*
Eric Andersencb57d552001-06-28 07:25:16 +000013041 * The export and readonly commands.
13042 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013043static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013044exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000013045{
13046 struct var *vp;
13047 char *name;
13048 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000013049 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020013050 char opt;
13051 int flag;
13052 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000013053
Denys Vlasenkod5275882012-10-01 13:41:17 +020013054 /* "readonly" in bash accepts, but ignores -n.
13055 * We do the same: it saves a conditional in nextopt's param.
13056 */
13057 flag_off = 0;
13058 while ((opt = nextopt("np")) != '\0') {
13059 if (opt == 'n')
13060 flag_off = VEXPORT;
13061 }
13062 flag = VEXPORT;
13063 if (argv[0][0] == 'r') {
13064 flag = VREADONLY;
13065 flag_off = 0; /* readonly ignores -n */
13066 }
13067 flag_off = ~flag_off;
13068
Denys Vlasenko10ad6222017-04-17 16:13:32 +020013069 /*if (opt_p_not_specified) - bash doesn't check this. Try "export -p NAME" */
Denys Vlasenkod5275882012-10-01 13:41:17 +020013070 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013071 aptr = argptr;
13072 name = *aptr;
13073 if (name) {
13074 do {
13075 p = strchr(name, '=');
13076 if (p != NULL) {
13077 p++;
13078 } else {
13079 vp = *findvar(hashvar(name), name);
13080 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020013081 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013082 continue;
13083 }
Eric Andersencb57d552001-06-28 07:25:16 +000013084 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013085 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013086 } while ((name = *++aptr) != NULL);
13087 return 0;
13088 }
Eric Andersencb57d552001-06-28 07:25:16 +000013089 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013090
13091 /* No arguments. Show the list of exported or readonly vars.
13092 * -n is ignored.
13093 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013094 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000013095 return 0;
13096}
13097
Eric Andersencb57d552001-06-28 07:25:16 +000013098/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013099 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000013100 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013101static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013102unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000013103{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013104 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000013105
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013106 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013107 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013108 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000013109}
13110
Eric Andersencb57d552001-06-28 07:25:16 +000013111/*
Eric Andersencb57d552001-06-28 07:25:16 +000013112 * The unset builtin command. We unset the function before we unset the
13113 * variable to allow a function to be unset when there is a readonly variable
13114 * with the same name.
13115 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013116static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013117unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013118{
13119 char **ap;
13120 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013121 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013122 int ret = 0;
13123
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013124 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000013125 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000013126 }
Eric Andersencb57d552001-06-28 07:25:16 +000013127
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013128 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013129 if (flag != 'f') {
13130 i = unsetvar(*ap);
13131 ret |= i;
13132 if (!(i & 2))
13133 continue;
13134 }
13135 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000013136 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000013137 }
Eric Andersenc470f442003-07-28 09:56:35 +000013138 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000013139}
13140
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000013141static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013142 ' ', offsetof(struct tms, tms_utime),
13143 '\n', offsetof(struct tms, tms_stime),
13144 ' ', offsetof(struct tms, tms_cutime),
13145 '\n', offsetof(struct tms, tms_cstime),
13146 0
13147};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013148static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013149timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013150{
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020013151 unsigned long clk_tck, s, t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013152 const unsigned char *p;
13153 struct tms buf;
13154
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020013155 clk_tck = bb_clk_tck();
Eric Andersencb57d552001-06-28 07:25:16 +000013156 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013157
13158 p = timescmd_str;
13159 do {
13160 t = *(clock_t *)(((char *) &buf) + p[1]);
13161 s = t / clk_tck;
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020013162 t = t % clk_tck;
13163 out1fmt("%lum%lu.%03lus%c",
13164 s / 60, s % 60,
13165 (t * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013166 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013167 p += 2;
13168 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013169
Eric Andersencb57d552001-06-28 07:25:16 +000013170 return 0;
13171}
13172
Denys Vlasenko0b883582016-12-23 16:49:07 +010013173#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000013174/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013175 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013176 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000013177 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013178 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000013179 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013180static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013181letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013182{
Denis Vlasenko68404f12008-03-17 09:00:54 +000013183 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000013184
Denis Vlasenko68404f12008-03-17 09:00:54 +000013185 argv++;
13186 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000013187 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000013188 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013189 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013190 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013191
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000013192 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000013193}
Eric Andersenc470f442003-07-28 09:56:35 +000013194#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013195
Eric Andersenc470f442003-07-28 09:56:35 +000013196/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013197 * The read builtin. Options:
13198 * -r Do not interpret '\' specially
13199 * -s Turn off echo (tty only)
13200 * -n NCHARS Read NCHARS max
13201 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13202 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13203 * -u FD Read from given FD instead of fd 0
Eric Andersenc470f442003-07-28 09:56:35 +000013204 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013205 * TODO: bash also has:
13206 * -a ARRAY Read into array[0],[1],etc
13207 * -d DELIM End on DELIM char, not newline
13208 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000013209 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013210static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013211readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013212{
Denys Vlasenko73067272010-01-12 22:11:24 +010013213 char *opt_n = NULL;
13214 char *opt_p = NULL;
13215 char *opt_t = NULL;
13216 char *opt_u = NULL;
13217 int read_flags = 0;
13218 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000013219 int i;
13220
Denys Vlasenko73067272010-01-12 22:11:24 +010013221 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000013222 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000013223 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010013224 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013225 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013226 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010013227 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013228 break;
13229 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010013230 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000013231 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013232 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010013233 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013234 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013235 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010013236 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000013237 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013238 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010013239 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013240 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013241 default:
13242 break;
13243 }
Eric Andersenc470f442003-07-28 09:56:35 +000013244 }
Paul Fox02eb9342005-09-07 16:56:02 +000013245
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013246 /* "read -s" needs to save/restore termios, can't allow ^C
13247 * to jump out of it.
13248 */
Denys Vlasenkof5470412017-05-22 19:34:45 +020013249 again:
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013250 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013251 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010013252 argptr,
13253 bltinlookup("IFS"), /* can be NULL */
13254 read_flags,
13255 opt_n,
13256 opt_p,
13257 opt_t,
13258 opt_u
13259 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013260 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000013261
Denys Vlasenkof5470412017-05-22 19:34:45 +020013262 if ((uintptr_t)r == 1 && errno == EINTR) {
13263 /* to get SIGCHLD: sleep 1 & read x; echo $x */
13264 if (pending_sig == 0)
13265 goto again;
13266 }
13267
Denys Vlasenko73067272010-01-12 22:11:24 +010013268 if ((uintptr_t)r > 1)
13269 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000013270
Denys Vlasenko73067272010-01-12 22:11:24 +010013271 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000013272}
13273
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013274static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020013275umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013276{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013277 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000013278
Eric Andersenc470f442003-07-28 09:56:35 +000013279 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000013280 int symbolic_mode = 0;
13281
13282 while (nextopt("S") != '\0') {
13283 symbolic_mode = 1;
13284 }
13285
Denis Vlasenkob012b102007-02-19 22:43:01 +000013286 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013287 mask = umask(0);
13288 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013289 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013290
Denys Vlasenko6283f982015-10-07 16:56:20 +020013291 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013292 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013293 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013294 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013295 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013296
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013297 i = 2;
13298 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013299 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013300 *p++ = permuser[i];
13301 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013302 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013303 if (!(mask & 0400)) *p++ = 'r';
13304 if (!(mask & 0200)) *p++ = 'w';
13305 if (!(mask & 0100)) *p++ = 'x';
13306 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013307 if (--i < 0)
13308 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013309 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013310 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013311 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013312 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013313 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013314 }
13315 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013316 char *modestr = *argptr;
13317 /* numeric umasks are taken as-is */
13318 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
13319 if (!isdigit(modestr[0]))
13320 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013321 mask = bb_parse_mode(modestr, mask);
13322 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013323 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013324 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013325 if (!isdigit(modestr[0]))
13326 mask ^= 0777;
13327 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013328 }
13329 return 0;
13330}
13331
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013332static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013333ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013334{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013335 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013336}
13337
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013338/* ============ main() and helpers */
13339
13340/*
13341 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013342 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013343static void
13344exitshell(void)
13345{
13346 struct jmploc loc;
13347 char *p;
13348 int status;
13349
Denys Vlasenkobede2152011-09-04 16:12:33 +020013350#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13351 save_history(line_input_state);
13352#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013353 status = exitstatus;
13354 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13355 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013356 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013357 status = exitstatus;
13358 goto out;
13359 }
13360 exception_handler = &loc;
13361 p = trap[0];
13362 if (p) {
13363 trap[0] = NULL;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013364 evalskip = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013365 evalstring(p, 0);
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013366 /*free(p); - we'll exit soon */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013367 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013368 out:
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013369 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13370 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13371 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013372 setjobctl(0);
Denys Vlasenkocaee80c2016-10-25 20:49:53 +020013373 flush_stdout_stderr();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013374 _exit(status);
13375 /* NOTREACHED */
13376}
13377
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013378static void
13379init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013380{
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013381 /* we will never free this */
13382 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013383
Denys Vlasenko458c1f22016-10-27 23:51:19 +020013384 sigmode[SIGCHLD - 1] = S_DFL;
13385 setsignal(SIGCHLD);
13386
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013387 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13388 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13389 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013390 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013391
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013392 {
13393 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013394 const char *p;
13395 struct stat st1, st2;
13396
13397 initvar();
13398 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenkob6838b52016-09-30 11:33:47 +020013399 p = endofname(*envp);
13400 if (p != *envp && *p == '=') {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013401 setvareq(*envp, VEXPORT|VTEXTFIXED);
13402 }
13403 }
13404
Denys Vlasenkoe627ac92016-09-30 14:36:59 +020013405 setvareq((char*)defoptindvar, VTEXTFIXED);
13406
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013407 setvar0("PPID", utoa(getppid()));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013408#if BASH_SHLVL_VAR
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013409 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013410 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013411#endif
13412#if BASH_HOSTNAME_VAR
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013413 if (!lookupvar("HOSTNAME")) {
13414 struct utsname uts;
13415 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013416 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013417 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013418#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013419 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013420 if (p) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013421 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013422 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13423 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013424 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013425 }
13426 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013427 setpwd(p, 0);
13428 }
13429}
13430
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013431
13432//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013433//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013434//usage:#define ash_full_usage "\n\n"
13435//usage: "Unix shell interpreter"
13436
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013437/*
13438 * Process the shell command line arguments.
13439 */
13440static void
Denis Vlasenko68404f12008-03-17 09:00:54 +000013441procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013442{
13443 int i;
13444 const char *xminusc;
13445 char **xargv;
13446
13447 xargv = argv;
13448 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013449 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013450 xargv++;
13451 for (i = 0; i < NOPTS; i++)
13452 optlist[i] = 2;
13453 argptr = xargv;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013454 if (options(/*cmdline:*/ 1)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013455 /* it already printed err message */
13456 raise_exception(EXERROR);
13457 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013458 xargv = argptr;
13459 xminusc = minusc;
13460 if (*xargv == NULL) {
13461 if (xminusc)
13462 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13463 sflag = 1;
13464 }
13465 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13466 iflag = 1;
13467 if (mflag == 2)
13468 mflag = iflag;
13469 for (i = 0; i < NOPTS; i++)
13470 if (optlist[i] == 2)
13471 optlist[i] = 0;
13472#if DEBUG == 2
13473 debug = 1;
13474#endif
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013475 /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013476 if (xminusc) {
13477 minusc = *xargv++;
13478 if (*xargv)
13479 goto setarg0;
13480 } else if (!sflag) {
13481 setinputfile(*xargv, 0);
13482 setarg0:
13483 arg0 = *xargv++;
13484 commandname = arg0;
13485 }
13486
13487 shellparam.p = xargv;
13488#if ENABLE_ASH_GETOPTS
13489 shellparam.optind = 1;
13490 shellparam.optoff = -1;
13491#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013492 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013493 while (*xargv) {
13494 shellparam.nparam++;
13495 xargv++;
13496 }
13497 optschanged();
13498}
13499
13500/*
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013501 * Read /etc/profile, ~/.profile, $ENV.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013502 */
13503static void
13504read_profile(const char *name)
13505{
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013506 name = expandstr(name);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013507 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13508 return;
Denys Vlasenko0840c912016-10-01 15:27:44 +020013509 cmdloop(0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013510 popfile();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013511}
13512
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013513/*
13514 * This routine is called when an error or an interrupt occurs in an
13515 * interactive shell and control is returned to the main command loop.
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013516 * (In dash, this function is auto-generated by build machinery).
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013517 */
13518static void
13519reset(void)
13520{
13521 /* from eval.c: */
13522 evalskip = 0;
13523 loopnest = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013524
13525 /* from expand.c: */
13526 ifsfree();
13527
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013528 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013529 g_parsefile->left_in_buffer = 0;
13530 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013531 popallfiles();
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013532
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013533 /* from redir.c: */
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020013534 while (redirlist)
13535 popredir(/*drop:*/ 0, /*restore:*/ 0);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013536}
13537
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013538#if PROFILE
13539static short profile_buf[16384];
13540extern int etext();
13541#endif
13542
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013543/*
13544 * Main routine. We initialize things, parse the arguments, execute
13545 * profiles if we're a login shell, and then call cmdloop to execute
13546 * commands. The setjmp call sets up the location to jump to when an
13547 * exception occurs. When an exception occurs the variable "state"
13548 * is used to figure out how far we had gotten.
13549 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013550int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013551int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013552{
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013553 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013554 struct jmploc jmploc;
13555 struct stackmark smark;
13556
Denis Vlasenko01631112007-12-16 17:20:38 +000013557 /* Initialize global data */
13558 INIT_G_misc();
13559 INIT_G_memstack();
13560 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013561#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013562 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013563#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013564 INIT_G_cmdtable();
13565
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013566#if PROFILE
13567 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13568#endif
13569
13570#if ENABLE_FEATURE_EDITING
13571 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13572#endif
13573 state = 0;
13574 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013575 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013576 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013577
13578 reset();
13579
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013580 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013581 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013582 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013583 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013584 }
13585 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020013586 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013587 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013588
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013589 popstackmark(&smark);
13590 FORCE_INT_ON; /* enable interrupts */
13591 if (s == 1)
13592 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013593 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013594 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013595 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013596 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013597 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013598 }
13599 exception_handler = &jmploc;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013600 rootpid = getpid();
13601
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013602 init();
13603 setstackmark(&smark);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013604 procargs(argv);
Denys Vlasenko474ed062016-10-30 18:30:29 +010013605#if DEBUG
13606 TRACE(("Shell args: "));
13607 trace_puts_args(argv);
13608#endif
Denis Vlasenko68404f12008-03-17 09:00:54 +000013609
Denys Vlasenko6088e132010-12-25 23:58:42 +010013610 if (argv[0] && argv[0][0] == '-')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013611 isloginsh = 1;
13612 if (isloginsh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013613 const char *hp;
13614
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013615 state = 1;
13616 read_profile("/etc/profile");
13617 state1:
13618 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013619 hp = lookupvar("HOME");
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013620 if (hp)
13621 read_profile("$HOME/.profile");
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013622 }
13623 state2:
13624 state = 3;
13625 if (
13626#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013627 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013628#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013629 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013630 ) {
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013631 const char *shinit = lookupvar("ENV");
13632 if (shinit != NULL && *shinit != '\0')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013633 read_profile(shinit);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013634 }
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013635 popstackmark(&smark);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013636 state3:
13637 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013638 if (minusc) {
13639 /* evalstring pushes parsefile stack.
13640 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013641 * is one of stacked source fds.
13642 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013643 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013644 // ^^ not necessary since now we special-case fd 0
13645 // in is_hidden_fd() to not be considered "hidden fd"
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013646 evalstring(minusc, 0);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013647 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013648
13649 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020013650#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013651 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013652 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013653 if (!hp) {
13654 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013655 if (hp) {
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013656 INT_OFF;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013657 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013658 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013659 free((char*)hp);
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013660 INT_ON;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013661 hp = lookupvar("HISTFILE");
13662 }
13663 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013664 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013665 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013666# if ENABLE_FEATURE_SH_HISTFILESIZE
13667 hp = lookupvar("HISTFILESIZE");
13668 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13669# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013670 }
13671#endif
13672 state4: /* XXX ??? - why isn't this before the "if" statement */
13673 cmdloop(1);
13674 }
13675#if PROFILE
13676 monitor(0);
13677#endif
13678#ifdef GPROF
13679 {
13680 extern void _mcleanup(void);
13681 _mcleanup();
13682 }
13683#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013684 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013685 exitshell();
13686 /* NOTREACHED */
13687}
13688
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013689
Eric Andersendf82f612001-06-28 07:46:40 +000013690/*-
13691 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013692 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013693 *
13694 * This code is derived from software contributed to Berkeley by
13695 * Kenneth Almquist.
13696 *
13697 * Redistribution and use in source and binary forms, with or without
13698 * modification, are permitted provided that the following conditions
13699 * are met:
13700 * 1. Redistributions of source code must retain the above copyright
13701 * notice, this list of conditions and the following disclaimer.
13702 * 2. Redistributions in binary form must reproduce the above copyright
13703 * notice, this list of conditions and the following disclaimer in the
13704 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013705 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013706 * may be used to endorse or promote products derived from this software
13707 * without specific prior written permission.
13708 *
13709 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13710 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13711 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13712 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13713 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13714 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13715 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13716 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13717 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13718 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13719 * SUCH DAMAGE.
13720 */