blob: 70ee15ed8016607c48aaf6cc4587e28ac19d41b0 [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
2461#if ENABLE_ASH_EXPAND_PRMT
2462/* expandstr() needs parsing machinery, so it is far away ahead... */
2463static const char *expandstr(const char *ps);
2464#else
2465#define expandstr(s) s
2466#endif
2467
2468static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002469setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002470{
2471 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002472 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2473
2474 if (!do_set)
2475 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002476
2477 needprompt = 0;
2478
2479 switch (whichprompt) {
2480 case 1:
2481 prompt = ps1val();
2482 break;
2483 case 2:
2484 prompt = ps2val();
2485 break;
2486 default: /* 0 */
2487 prompt = nullstr;
2488 }
2489#if ENABLE_ASH_EXPAND_PRMT
Denys Vlasenko60ca8342016-09-30 11:21:21 +02002490 pushstackmark(&smark, stackblocksize());
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002491#endif
2492 putprompt(expandstr(prompt));
2493#if ENABLE_ASH_EXPAND_PRMT
2494 popstackmark(&smark);
2495#endif
2496}
2497
2498
2499/* ============ The cd and pwd commands */
2500
2501#define CD_PHYSICAL 1
2502#define CD_PRINT 2
2503
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002504static int
2505cdopt(void)
2506{
2507 int flags = 0;
2508 int i, j;
2509
2510 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002511 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002512 if (i != j) {
2513 flags ^= CD_PHYSICAL;
2514 j = i;
2515 }
2516 }
2517
2518 return flags;
2519}
2520
2521/*
2522 * Update curdir (the name of the current directory) in response to a
2523 * cd command.
2524 */
2525static const char *
2526updatepwd(const char *dir)
2527{
2528 char *new;
2529 char *p;
2530 char *cdcomppath;
2531 const char *lim;
2532
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02002533 cdcomppath = sstrdup(dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002534 STARTSTACKSTR(new);
2535 if (*dir != '/') {
2536 if (curdir == nullstr)
2537 return 0;
2538 new = stack_putstr(curdir, new);
2539 }
2540 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002541 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002542 if (*dir != '/') {
2543 if (new[-1] != '/')
2544 USTPUTC('/', new);
2545 if (new > lim && *lim == '/')
2546 lim++;
2547 } else {
2548 USTPUTC('/', new);
2549 cdcomppath++;
2550 if (dir[1] == '/' && dir[2] != '/') {
2551 USTPUTC('/', new);
2552 cdcomppath++;
2553 lim++;
2554 }
2555 }
2556 p = strtok(cdcomppath, "/");
2557 while (p) {
2558 switch (*p) {
2559 case '.':
2560 if (p[1] == '.' && p[2] == '\0') {
2561 while (new > lim) {
2562 STUNPUTC(new);
2563 if (new[-1] == '/')
2564 break;
2565 }
2566 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002567 }
2568 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002569 break;
2570 /* fall through */
2571 default:
2572 new = stack_putstr(p, new);
2573 USTPUTC('/', new);
2574 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002575 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002576 }
2577 if (new > lim)
2578 STUNPUTC(new);
2579 *new = 0;
2580 return stackblock();
2581}
2582
2583/*
2584 * Find out what the current directory is. If we already know the current
2585 * directory, this routine returns immediately.
2586 */
2587static char *
2588getpwd(void)
2589{
Denis Vlasenko01631112007-12-16 17:20:38 +00002590 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002591 return dir ? dir : nullstr;
2592}
2593
2594static void
2595setpwd(const char *val, int setold)
2596{
2597 char *oldcur, *dir;
2598
2599 oldcur = dir = curdir;
2600
2601 if (setold) {
2602 setvar("OLDPWD", oldcur, VEXPORT);
2603 }
2604 INT_OFF;
2605 if (physdir != nullstr) {
2606 if (physdir != oldcur)
2607 free(physdir);
2608 physdir = nullstr;
2609 }
2610 if (oldcur == val || !val) {
2611 char *s = getpwd();
2612 physdir = s;
2613 if (!val)
2614 dir = s;
2615 } else
2616 dir = ckstrdup(val);
2617 if (oldcur != dir && oldcur != nullstr) {
2618 free(oldcur);
2619 }
2620 curdir = dir;
2621 INT_ON;
2622 setvar("PWD", dir, VEXPORT);
2623}
2624
2625static void hashcd(void);
2626
2627/*
Denys Vlasenko70392332016-10-27 02:31:55 +02002628 * Actually do the chdir. We also call hashcd to let other routines
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002629 * know that the current directory has changed.
2630 */
2631static int
2632docd(const char *dest, int flags)
2633{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002634 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002635 int err;
2636
2637 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2638
2639 INT_OFF;
2640 if (!(flags & CD_PHYSICAL)) {
2641 dir = updatepwd(dest);
2642 if (dir)
2643 dest = dir;
2644 }
2645 err = chdir(dest);
2646 if (err)
2647 goto out;
2648 setpwd(dir, 1);
2649 hashcd();
2650 out:
2651 INT_ON;
2652 return err;
2653}
2654
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002655static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002656cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002657{
2658 const char *dest;
2659 const char *path;
2660 const char *p;
2661 char c;
2662 struct stat statb;
2663 int flags;
2664
2665 flags = cdopt();
2666 dest = *argptr;
2667 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002668 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002669 else if (LONE_DASH(dest)) {
2670 dest = bltinlookup("OLDPWD");
2671 flags |= CD_PRINT;
2672 }
2673 if (!dest)
2674 dest = nullstr;
2675 if (*dest == '/')
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002676 goto step6;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002677 if (*dest == '.') {
2678 c = dest[1];
2679 dotdot:
2680 switch (c) {
2681 case '\0':
2682 case '/':
2683 goto step6;
2684 case '.':
2685 c = dest[2];
2686 if (c != '.')
2687 goto dotdot;
2688 }
2689 }
2690 if (!*dest)
2691 dest = ".";
2692 path = bltinlookup("CDPATH");
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002693 while (path) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002694 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002695 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002696 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2697 if (c && c != ':')
2698 flags |= CD_PRINT;
2699 docd:
2700 if (!docd(p, flags))
2701 goto out;
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002702 goto err;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002703 }
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002704 }
2705
2706 step6:
2707 p = dest;
2708 goto docd;
2709
2710 err:
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002711 ash_msg_and_raise_error("can't cd to %s", dest);
2712 /* NOTREACHED */
2713 out:
2714 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002715 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002716 return 0;
2717}
2718
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002719static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002720pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002721{
2722 int flags;
2723 const char *dir = curdir;
2724
2725 flags = cdopt();
2726 if (flags) {
2727 if (physdir == nullstr)
2728 setpwd(dir, 0);
2729 dir = physdir;
2730 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002731 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002732 return 0;
2733}
2734
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002735
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002736/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002737
Denis Vlasenko834dee72008-10-07 09:18:30 +00002738
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002739#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002740
Eric Andersenc470f442003-07-28 09:56:35 +00002741/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002742#define CWORD 0 /* character is nothing special */
2743#define CNL 1 /* newline character */
2744#define CBACK 2 /* a backslash character */
2745#define CSQUOTE 3 /* single quote */
2746#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002747#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002748#define CBQUOTE 6 /* backwards single quote */
2749#define CVAR 7 /* a dollar sign */
2750#define CENDVAR 8 /* a '}' character */
2751#define CLP 9 /* a left paren in arithmetic */
2752#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002753#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002754#define CCTL 12 /* like CWORD, except it must be escaped */
2755#define CSPCL 13 /* these terminate a word */
2756#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002757
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002758#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002759#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002760# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002761#endif
2762
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002763#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002764
Denys Vlasenko0b883582016-12-23 16:49:07 +01002765#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002766# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002767#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002768# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002769#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002770static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002771#if ENABLE_ASH_ALIAS
2772 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2773#endif
2774 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2775 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2776 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2777 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2778 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2779 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2780 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2781 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2782 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2783 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2784 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002785#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002786 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2787 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2788 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2789#endif
2790#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002791};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002792/* Constants below must match table above */
2793enum {
2794#if ENABLE_ASH_ALIAS
2795 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2796#endif
2797 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2798 CNL_CNL_CNL_CNL , /* 2 */
2799 CWORD_CCTL_CCTL_CWORD , /* 3 */
2800 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2801 CVAR_CVAR_CWORD_CVAR , /* 5 */
2802 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2803 CSPCL_CWORD_CWORD_CLP , /* 7 */
2804 CSPCL_CWORD_CWORD_CRP , /* 8 */
2805 CBACK_CBACK_CCTL_CBACK , /* 9 */
2806 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2807 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2808 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2809 CWORD_CWORD_CWORD_CWORD , /* 13 */
2810 CCTL_CCTL_CCTL_CCTL , /* 14 */
2811};
Eric Andersen2870d962001-07-02 17:27:21 +00002812
Denys Vlasenkocd716832009-11-28 22:14:02 +01002813/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2814 * caller must ensure proper cast on it if c is *char_ptr!
2815 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002816/* Values for syntax param */
2817#define BASESYNTAX 0 /* not in quotes */
2818#define DQSYNTAX 1 /* in double quotes */
2819#define SQSYNTAX 2 /* in single quotes */
2820#define ARISYNTAX 3 /* in arithmetic */
2821#define PSSYNTAX 4 /* prompt. never passed to SIT() */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002822
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002823#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002824
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002825static int
2826SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002827{
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002828 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2829 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2830 /*
2831 * This causes '/' to be prepended with CTLESC in dquoted string,
2832 * making "./file"* treated incorrectly because we feed
2833 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2834 * The "homegrown" glob implementation is okay with that,
2835 * but glibc one isn't. With '/' always treated as CWORD,
2836 * both work fine.
2837 */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002838# if ENABLE_ASH_ALIAS
2839 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002840 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002841 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002842 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2843 11, 3 /* "}~" */
2844 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002845# else
2846 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002847 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002848 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002849 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2850 10, 2 /* "}~" */
2851 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002852# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002853 const char *s;
2854 int indx;
2855
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002856 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002857 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002858# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002859 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002860 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002861 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002862# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002863 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002864 /* Cast is purely for paranoia here,
2865 * just in case someone passed signed char to us */
2866 if ((unsigned char)c >= CTL_FIRST
2867 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002868 ) {
2869 return CCTL;
2870 }
2871 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002872 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002873 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002874 indx = syntax_index_table[s - spec_symbls];
2875 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002876 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002877}
2878
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002879#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002880
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002881static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002882 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002883 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2889 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2890 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2891 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2892 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2893 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2894 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2895 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2896 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2897 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2898 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2899 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2900 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2901 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2902 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2903 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2904 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2905 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2906 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2907 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2908 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2909 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2910 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2911 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2912 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2913 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2914 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2915 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2916 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2917 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2918 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2919 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2920 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2921 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2922 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2923 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2924 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2925 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2926 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2927 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2928 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2929 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002930/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
2931 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkocd716832009-11-28 22:14:02 +01002932 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2943 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2944 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2945 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2946 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2947 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2948 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2976 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2977 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2978 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2981 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2983 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2986 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2987 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2988 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2989 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2990 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2991 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2992 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2993 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2994 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2995 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2996 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2997 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2998 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2999 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
3000 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
3001 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
3002 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
3003 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
3004 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
3005 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
3006 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
3007 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
3008 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
3009 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3010 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
3011 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
3012 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
3013 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
3014 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
3015 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
3016 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
3017 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
3018 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
3019 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
3020 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3021 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3029 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3042 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3047 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3112 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3113 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3114 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3115 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3116 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3117 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3118 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3119 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3120 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3121 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3122 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3123 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3124 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3125 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3126 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3127 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3128 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3129 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3130 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3131 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3132 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3133 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3134 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3135 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3136 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3137 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3138 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3139 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003140 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003141# if ENABLE_ASH_ALIAS
3142 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3143# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003144};
3145
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003146#if 1
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003147# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003148#else /* debug version, caught one signed char bug */
3149# define SIT(c, syntax) \
3150 ({ \
3151 if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3152 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
Denys Vlasenko0b883582016-12-23 16:49:07 +01003153 if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003154 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3155 ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3156 })
3157#endif
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003158
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003159#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003160
Eric Andersen2870d962001-07-02 17:27:21 +00003161
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003162/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003163
Denis Vlasenko131ae172007-02-18 13:00:19 +00003164#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003165
3166#define ALIASINUSE 1
3167#define ALIASDEAD 2
3168
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003169struct alias {
3170 struct alias *next;
3171 char *name;
3172 char *val;
3173 int flag;
3174};
3175
Denis Vlasenko01631112007-12-16 17:20:38 +00003176
3177static struct alias **atab; // [ATABSIZE];
3178#define INIT_G_alias() do { \
3179 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3180} while (0)
3181
Eric Andersen2870d962001-07-02 17:27:21 +00003182
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003183static struct alias **
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02003184__lookupalias(const char *name)
3185{
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003186 unsigned int hashval;
3187 struct alias **app;
3188 const char *p;
3189 unsigned int ch;
3190
3191 p = name;
3192
3193 ch = (unsigned char)*p;
3194 hashval = ch << 4;
3195 while (ch) {
3196 hashval += ch;
3197 ch = (unsigned char)*++p;
3198 }
3199 app = &atab[hashval % ATABSIZE];
3200
3201 for (; *app; app = &(*app)->next) {
3202 if (strcmp(name, (*app)->name) == 0) {
3203 break;
3204 }
3205 }
3206
3207 return app;
3208}
3209
3210static struct alias *
3211lookupalias(const char *name, int check)
3212{
3213 struct alias *ap = *__lookupalias(name);
3214
3215 if (check && ap && (ap->flag & ALIASINUSE))
3216 return NULL;
3217 return ap;
3218}
3219
3220static struct alias *
3221freealias(struct alias *ap)
3222{
3223 struct alias *next;
3224
3225 if (ap->flag & ALIASINUSE) {
3226 ap->flag |= ALIASDEAD;
3227 return ap;
3228 }
3229
3230 next = ap->next;
3231 free(ap->name);
3232 free(ap->val);
3233 free(ap);
3234 return next;
3235}
Eric Andersencb57d552001-06-28 07:25:16 +00003236
Eric Andersenc470f442003-07-28 09:56:35 +00003237static void
3238setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003239{
3240 struct alias *ap, **app;
3241
3242 app = __lookupalias(name);
3243 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003244 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003245 if (ap) {
3246 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003247 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003248 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003249 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003250 ap->flag &= ~ALIASDEAD;
3251 } else {
3252 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003253 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003254 ap->name = ckstrdup(name);
3255 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003256 /*ap->flag = 0; - ckzalloc did it */
3257 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003258 *app = ap;
3259 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003260 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003261}
3262
Eric Andersenc470f442003-07-28 09:56:35 +00003263static int
3264unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003265{
Eric Andersencb57d552001-06-28 07:25:16 +00003266 struct alias **app;
3267
3268 app = __lookupalias(name);
3269
3270 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003271 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003272 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003273 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003274 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003275 }
3276
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003277 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003278}
3279
Eric Andersenc470f442003-07-28 09:56:35 +00003280static void
3281rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003282{
Eric Andersencb57d552001-06-28 07:25:16 +00003283 struct alias *ap, **app;
3284 int i;
3285
Denis Vlasenkob012b102007-02-19 22:43:01 +00003286 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003287 for (i = 0; i < ATABSIZE; i++) {
3288 app = &atab[i];
3289 for (ap = *app; ap; ap = *app) {
3290 *app = freealias(*app);
3291 if (ap == *app) {
3292 app = &ap->next;
3293 }
3294 }
3295 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003296 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003297}
3298
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003299static void
3300printalias(const struct alias *ap)
3301{
3302 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3303}
3304
Eric Andersencb57d552001-06-28 07:25:16 +00003305/*
3306 * TODO - sort output
3307 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003308static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003309aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003310{
3311 char *n, *v;
3312 int ret = 0;
3313 struct alias *ap;
3314
Denis Vlasenko68404f12008-03-17 09:00:54 +00003315 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003316 int i;
3317
Denis Vlasenko68404f12008-03-17 09:00:54 +00003318 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003319 for (ap = atab[i]; ap; ap = ap->next) {
3320 printalias(ap);
3321 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003322 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003323 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003324 }
3325 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003326 v = strchr(n+1, '=');
3327 if (v == NULL) { /* n+1: funny ksh stuff */
3328 ap = *__lookupalias(n);
3329 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003330 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003331 ret = 1;
3332 } else
3333 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003334 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003335 *v++ = '\0';
3336 setalias(n, v);
3337 }
3338 }
3339
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003340 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003341}
3342
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003343static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003344unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003345{
3346 int i;
3347
Denys Vlasenko6c149f42017-04-12 21:31:32 +02003348 while (nextopt("a") != '\0') {
3349 rmaliases();
3350 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003351 }
3352 for (i = 0; *argptr; argptr++) {
3353 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003354 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003355 i = 1;
3356 }
3357 }
3358
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003359 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003360}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003361
Denis Vlasenko131ae172007-02-18 13:00:19 +00003362#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003363
Eric Andersenc470f442003-07-28 09:56:35 +00003364
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003365/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003366#define FORK_FG 0
3367#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003368#define FORK_NOJOB 2
3369
3370/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003371#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3372#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3373#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003374#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003375
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003376/*
3377 * A job structure contains information about a job. A job is either a
3378 * single process or a set of processes contained in a pipeline. In the
3379 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3380 * array of pids.
3381 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003382struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003383 pid_t ps_pid; /* process id */
3384 int ps_status; /* last process status from wait() */
3385 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003386};
3387
3388struct job {
3389 struct procstat ps0; /* status of process */
3390 struct procstat *ps; /* status or processes when more than one */
3391#if JOBS
3392 int stopstatus; /* status of a stopped job */
3393#endif
Denys Vlasenko4c179372017-01-11 18:44:15 +01003394 unsigned nprocs; /* number of processes */
3395
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003396#define JOBRUNNING 0 /* at least one proc running */
3397#define JOBSTOPPED 1 /* all procs are stopped */
3398#define JOBDONE 2 /* all procs are completed */
Denys Vlasenko4c179372017-01-11 18:44:15 +01003399 unsigned
3400 state: 8,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003401#if JOBS
3402 sigint: 1, /* job was killed by SIGINT */
3403 jobctl: 1, /* job running under job control */
3404#endif
3405 waited: 1, /* true if this entry has been waited for */
3406 used: 1, /* true if this entry is in used */
3407 changed: 1; /* true if status has changed */
3408 struct job *prev_job; /* previous job */
3409};
3410
Denis Vlasenko68404f12008-03-17 09:00:54 +00003411static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003412static int forkshell(struct job *, union node *, int);
3413static int waitforjob(struct job *);
3414
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003415#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003416enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003417#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003418#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003419static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003420static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003421#endif
3422
3423/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003424 * Ignore a signal.
3425 */
3426static void
3427ignoresig(int signo)
3428{
3429 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3430 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3431 /* No, need to do it */
3432 signal(signo, SIG_IGN);
3433 }
3434 sigmode[signo - 1] = S_HARD_IGN;
3435}
3436
3437/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003438 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003439 */
3440static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003441signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003442{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003443 if (signo == SIGCHLD) {
3444 got_sigchld = 1;
3445 if (!trap[SIGCHLD])
3446 return;
3447 }
3448
Denis Vlasenko4b875702009-03-19 13:30:04 +00003449 gotsig[signo - 1] = 1;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003450 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003451
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003452 if (signo == SIGINT && !trap[SIGINT]) {
3453 if (!suppress_int) {
3454 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003455 raise_interrupt(); /* does not return */
3456 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003457 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003458 }
3459}
3460
3461/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003462 * Set the signal handler for the specified signal. The routine figures
3463 * out what it should be set to.
3464 */
3465static void
3466setsignal(int signo)
3467{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003468 char *t;
3469 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003470 struct sigaction act;
3471
3472 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003473 new_act = S_DFL;
3474 if (t != NULL) { /* trap for this sig is set */
3475 new_act = S_CATCH;
3476 if (t[0] == '\0') /* trap is "": ignore this sig */
3477 new_act = S_IGN;
3478 }
3479
3480 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003481 switch (signo) {
3482 case SIGINT:
3483 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003484 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003485 break;
3486 case SIGQUIT:
3487#if DEBUG
3488 if (debug)
3489 break;
3490#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003491 /* man bash:
3492 * "In all cases, bash ignores SIGQUIT. Non-builtin
3493 * commands run by bash have signal handlers
3494 * set to the values inherited by the shell
3495 * from its parent". */
3496 new_act = S_IGN;
3497 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003498 case SIGTERM:
3499 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003500 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003501 break;
3502#if JOBS
3503 case SIGTSTP:
3504 case SIGTTOU:
3505 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003506 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003507 break;
3508#endif
3509 }
3510 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003511//TODO: if !rootshell, we reset SIGQUIT to DFL,
3512//whereas we have to restore it to what shell got on entry
3513//from the parent. See comment above
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003514
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003515 if (signo == SIGCHLD)
3516 new_act = S_CATCH;
3517
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003518 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003519 cur_act = *t;
3520 if (cur_act == 0) {
3521 /* current setting is not yet known */
3522 if (sigaction(signo, NULL, &act)) {
3523 /* pretend it worked; maybe we should give a warning,
3524 * but other shells don't. We don't alter sigmode,
3525 * so we retry every time.
3526 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003527 return;
3528 }
3529 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003530 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003531 if (mflag
3532 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3533 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003534 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003535 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003536 }
3537 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003538 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003539 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003540
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003541 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003542 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003543 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003544 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003545 break;
3546 case S_IGN:
3547 act.sa_handler = SIG_IGN;
3548 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003549 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003550
3551 /* flags and mask matter only if !DFL and !IGN, but we do it
3552 * for all cases for more deterministic behavior:
3553 */
3554 act.sa_flags = 0;
3555 sigfillset(&act.sa_mask);
3556
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003557 sigaction_set(signo, &act);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003558
3559 *t = new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003560}
3561
3562/* mode flags for set_curjob */
3563#define CUR_DELETE 2
3564#define CUR_RUNNING 1
3565#define CUR_STOPPED 0
3566
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003567#if JOBS
3568/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003569static int initialpgrp; //references:2
3570static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003571#endif
3572/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003573static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003574/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003575static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003576/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003577static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003578/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003579static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003580
Denys Vlasenko098b7132017-01-11 19:59:03 +01003581#if 0
3582/* Bash has a feature: it restores termios after a successful wait for
3583 * a foreground job which had at least one stopped or sigkilled member.
3584 * The probable rationale is that SIGSTOP and SIGKILL can preclude task from
3585 * properly restoring tty state. Should we do this too?
3586 * A reproducer: ^Z an interactive python:
3587 *
3588 * # python
3589 * Python 2.7.12 (...)
3590 * >>> ^Z
3591 * { python leaves tty in -icanon -echo state. We do survive that... }
3592 * [1]+ Stopped python
3593 * { ...however, next program (python #2) does not survive it well: }
3594 * # python
3595 * Python 2.7.12 (...)
3596 * >>> Traceback (most recent call last):
3597 * { above, I typed "qwerty<CR>", but -echo state is still in effect }
3598 * File "<stdin>", line 1, in <module>
3599 * NameError: name 'qwerty' is not defined
3600 *
3601 * The implementation below is modeled on bash code and seems to work.
3602 * However, I'm not sure we should do this. For one: what if I'd fg
3603 * the stopped python instead? It'll be confused by "restored" tty state.
3604 */
3605static struct termios shell_tty_info;
3606static void
3607get_tty_state(void)
3608{
3609 if (rootshell && ttyfd >= 0)
3610 tcgetattr(ttyfd, &shell_tty_info);
3611}
3612static void
3613set_tty_state(void)
3614{
3615 /* if (rootshell) - caller ensures this */
3616 if (ttyfd >= 0)
3617 tcsetattr(ttyfd, TCSADRAIN, &shell_tty_info);
3618}
3619static int
3620job_signal_status(struct job *jp)
3621{
3622 int status;
3623 unsigned i;
3624 struct procstat *ps = jp->ps;
3625 for (i = 0; i < jp->nprocs; i++) {
3626 status = ps[i].ps_status;
3627 if (WIFSIGNALED(status) || WIFSTOPPED(status))
3628 return status;
3629 }
3630 return 0;
3631}
3632static void
3633restore_tty_if_stopped_or_signaled(struct job *jp)
3634{
3635//TODO: check what happens if we come from waitforjob() in expbackq()
3636 if (rootshell) {
3637 int s = job_signal_status(jp);
3638 if (s) /* WIFSIGNALED(s) || WIFSTOPPED(s) */
3639 set_tty_state();
3640 }
3641}
3642#else
3643# define get_tty_state() ((void)0)
3644# define restore_tty_if_stopped_or_signaled(jp) ((void)0)
3645#endif
3646
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003647static void
3648set_curjob(struct job *jp, unsigned mode)
3649{
3650 struct job *jp1;
3651 struct job **jpp, **curp;
3652
3653 /* first remove from list */
3654 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003655 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003656 jp1 = *jpp;
3657 if (jp1 == jp)
3658 break;
3659 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003660 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003661 *jpp = jp1->prev_job;
3662
3663 /* Then re-insert in correct position */
3664 jpp = curp;
3665 switch (mode) {
3666 default:
3667#if DEBUG
3668 abort();
3669#endif
3670 case CUR_DELETE:
3671 /* job being deleted */
3672 break;
3673 case CUR_RUNNING:
3674 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003675 * put after all stopped jobs.
3676 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003677 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003678 jp1 = *jpp;
3679#if JOBS
3680 if (!jp1 || jp1->state != JOBSTOPPED)
3681#endif
3682 break;
3683 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003684 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003685 /* FALLTHROUGH */
3686#if JOBS
3687 case CUR_STOPPED:
3688#endif
3689 /* newly stopped job - becomes curjob */
3690 jp->prev_job = *jpp;
3691 *jpp = jp;
3692 break;
3693 }
3694}
3695
3696#if JOBS || DEBUG
3697static int
3698jobno(const struct job *jp)
3699{
3700 return jp - jobtab + 1;
3701}
3702#endif
3703
3704/*
3705 * Convert a job name to a job structure.
3706 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003707#if !JOBS
3708#define getjob(name, getctl) getjob(name)
3709#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003710static struct job *
3711getjob(const char *name, int getctl)
3712{
3713 struct job *jp;
3714 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003715 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003716 unsigned num;
3717 int c;
3718 const char *p;
3719 char *(*match)(const char *, const char *);
3720
3721 jp = curjob;
3722 p = name;
3723 if (!p)
3724 goto currentjob;
3725
3726 if (*p != '%')
3727 goto err;
3728
3729 c = *++p;
3730 if (!c)
3731 goto currentjob;
3732
3733 if (!p[1]) {
3734 if (c == '+' || c == '%') {
3735 currentjob:
3736 err_msg = "No current job";
3737 goto check;
3738 }
3739 if (c == '-') {
3740 if (jp)
3741 jp = jp->prev_job;
3742 err_msg = "No previous job";
3743 check:
3744 if (!jp)
3745 goto err;
3746 goto gotit;
3747 }
3748 }
3749
3750 if (is_number(p)) {
3751 num = atoi(p);
Denys Vlasenko46a45ce2016-09-29 01:10:08 +02003752 if (num > 0 && num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003753 jp = jobtab + num - 1;
3754 if (jp->used)
3755 goto gotit;
3756 goto err;
3757 }
3758 }
3759
3760 match = prefix;
3761 if (*p == '?') {
3762 match = strstr;
3763 p++;
3764 }
3765
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003766 found = NULL;
3767 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003768 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003769 if (found)
3770 goto err;
3771 found = jp;
3772 err_msg = "%s: ambiguous";
3773 }
3774 jp = jp->prev_job;
3775 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003776 if (!found)
3777 goto err;
3778 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003779
3780 gotit:
3781#if JOBS
3782 err_msg = "job %s not created under job control";
3783 if (getctl && jp->jobctl == 0)
3784 goto err;
3785#endif
3786 return jp;
3787 err:
3788 ash_msg_and_raise_error(err_msg, name);
3789}
3790
3791/*
3792 * Mark a job structure as unused.
3793 */
3794static void
3795freejob(struct job *jp)
3796{
3797 struct procstat *ps;
3798 int i;
3799
3800 INT_OFF;
3801 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003802 if (ps->ps_cmd != nullstr)
3803 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003804 }
3805 if (jp->ps != &jp->ps0)
3806 free(jp->ps);
3807 jp->used = 0;
3808 set_curjob(jp, CUR_DELETE);
3809 INT_ON;
3810}
3811
3812#if JOBS
3813static void
3814xtcsetpgrp(int fd, pid_t pgrp)
3815{
3816 if (tcsetpgrp(fd, pgrp))
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003817 ash_msg_and_raise_error("can't set tty process group (%m)");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003818}
3819
3820/*
3821 * Turn job control on and off.
3822 *
3823 * Note: This code assumes that the third arg to ioctl is a character
3824 * pointer, which is true on Berkeley systems but not System V. Since
3825 * System V doesn't have job control yet, this isn't a problem now.
3826 *
3827 * Called with interrupts off.
3828 */
3829static void
3830setjobctl(int on)
3831{
3832 int fd;
3833 int pgrp;
3834
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003835 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003836 return;
3837 if (on) {
3838 int ofd;
3839 ofd = fd = open(_PATH_TTY, O_RDWR);
3840 if (fd < 0) {
3841 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3842 * That sometimes helps to acquire controlling tty.
3843 * Obviously, a workaround for bugs when someone
3844 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003845 fd = 2;
3846 while (!isatty(fd))
3847 if (--fd < 0)
3848 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003849 }
Denys Vlasenko64774602016-10-26 15:24:30 +02003850 /* fd is a tty at this point */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003851 fd = fcntl(fd, F_DUPFD, 10);
Denys Vlasenko10ad6222017-04-17 16:13:32 +02003852 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, don't */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003853 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003854 if (fd < 0)
Denys Vlasenko64774602016-10-26 15:24:30 +02003855 goto out; /* F_DUPFD failed */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003856 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003857 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003858 pgrp = tcgetpgrp(fd);
3859 if (pgrp < 0) {
3860 out:
3861 ash_msg("can't access tty; job control turned off");
3862 mflag = on = 0;
3863 goto close;
3864 }
3865 if (pgrp == getpgrp())
3866 break;
3867 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003868 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003869 initialpgrp = pgrp;
3870
3871 setsignal(SIGTSTP);
3872 setsignal(SIGTTOU);
3873 setsignal(SIGTTIN);
3874 pgrp = rootpid;
3875 setpgid(0, pgrp);
3876 xtcsetpgrp(fd, pgrp);
3877 } else {
3878 /* turning job control off */
3879 fd = ttyfd;
3880 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003881 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003882 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003883 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003884 setpgid(0, pgrp);
3885 setsignal(SIGTSTP);
3886 setsignal(SIGTTOU);
3887 setsignal(SIGTTIN);
3888 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003889 if (fd >= 0)
3890 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003891 fd = -1;
3892 }
3893 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003894 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003895}
3896
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003897static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003898killcmd(int argc, char **argv)
3899{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003900 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003901 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003902 do {
3903 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003904 /*
3905 * "kill %N" - job kill
3906 * Converting to pgrp / pid kill
3907 */
3908 struct job *jp;
3909 char *dst;
3910 int j, n;
3911
3912 jp = getjob(argv[i], 0);
3913 /*
3914 * In jobs started under job control, we signal
3915 * entire process group by kill -PGRP_ID.
3916 * This happens, f.e., in interactive shell.
3917 *
3918 * Otherwise, we signal each child via
3919 * kill PID1 PID2 PID3.
3920 * Testcases:
3921 * sh -c 'sleep 1|sleep 1 & kill %1'
3922 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3923 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3924 */
3925 n = jp->nprocs; /* can't be 0 (I hope) */
3926 if (jp->jobctl)
3927 n = 1;
3928 dst = alloca(n * sizeof(int)*4);
3929 argv[i] = dst;
3930 for (j = 0; j < n; j++) {
3931 struct procstat *ps = &jp->ps[j];
3932 /* Skip non-running and not-stopped members
3933 * (i.e. dead members) of the job
3934 */
3935 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3936 continue;
3937 /*
3938 * kill_main has matching code to expect
3939 * leading space. Needed to not confuse
3940 * negative pids with "kill -SIGNAL_NO" syntax
3941 */
3942 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3943 }
3944 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003945 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003946 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003947 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003948 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003949}
3950
3951static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01003952showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003953{
Denys Vlasenko285ad152009-12-04 23:02:27 +01003954 struct procstat *ps;
3955 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003956
Denys Vlasenko285ad152009-12-04 23:02:27 +01003957 psend = jp->ps + jp->nprocs;
3958 for (ps = jp->ps + 1; ps < psend; ps++)
3959 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003960 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003961 flush_stdout_stderr();
3962}
3963
3964
3965static int
3966restartjob(struct job *jp, int mode)
3967{
3968 struct procstat *ps;
3969 int i;
3970 int status;
3971 pid_t pgid;
3972
3973 INT_OFF;
3974 if (jp->state == JOBDONE)
3975 goto out;
3976 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003977 pgid = jp->ps[0].ps_pid;
Denys Vlasenko098b7132017-01-11 19:59:03 +01003978 if (mode == FORK_FG) {
3979 get_tty_state();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003980 xtcsetpgrp(ttyfd, pgid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01003981 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003982 killpg(pgid, SIGCONT);
3983 ps = jp->ps;
3984 i = jp->nprocs;
3985 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003986 if (WIFSTOPPED(ps->ps_status)) {
3987 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003988 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003989 ps++;
3990 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003991 out:
3992 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3993 INT_ON;
3994 return status;
3995}
3996
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003997static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003998fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003999{
4000 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004001 int mode;
4002 int retval;
4003
4004 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
4005 nextopt(nullstr);
4006 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004007 do {
4008 jp = getjob(*argv, 1);
4009 if (mode == FORK_BG) {
4010 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004011 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004012 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004013 out1str(jp->ps[0].ps_cmd);
4014 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004015 retval = restartjob(jp, mode);
4016 } while (*argv && *++argv);
4017 return retval;
4018}
4019#endif
4020
4021static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02004022sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004023{
4024 int col;
4025 int st;
4026
4027 col = 0;
4028 if (!WIFEXITED(status)) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004029 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004030 st = WSTOPSIG(status);
4031 else
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004032 st = WTERMSIG(status);
4033 if (sigonly) {
4034 if (st == SIGINT || st == SIGPIPE)
4035 goto out;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004036 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004037 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004038 }
4039 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01004040//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004041 col = fmtstr(s, 32, strsignal(st));
4042 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004043 strcpy(s + col, " (core dumped)");
4044 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004045 }
4046 } else if (!sigonly) {
4047 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004048 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004049 }
4050 out:
4051 return col;
4052}
4053
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004054static int
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004055wait_block_or_sig(int *status)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004056{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004057 int pid;
4058
4059 do {
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004060 sigset_t mask;
4061
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004062 /* Poll all children for changes in their state */
4063 got_sigchld = 0;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004064 /* if job control is active, accept stopped processes too */
4065 pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004066 if (pid != 0)
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004067 break; /* Error (e.g. EINTR, ECHILD) or pid */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004068
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004069 /* Children exist, but none are ready. Sleep until interesting signal */
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004070#if 1
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004071 sigfillset(&mask);
4072 sigprocmask(SIG_SETMASK, &mask, &mask);
4073 while (!got_sigchld && !pending_sig)
4074 sigsuspend(&mask);
4075 sigprocmask(SIG_SETMASK, &mask, NULL);
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004076#else /* unsafe: a signal can set pending_sig after check, but before pause() */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004077 while (!got_sigchld && !pending_sig)
4078 pause();
4079#endif
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004080
4081 /* If it was SIGCHLD, poll children again */
4082 } while (got_sigchld);
4083
4084 return pid;
4085}
4086
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004087#define DOWAIT_NONBLOCK 0
4088#define DOWAIT_BLOCK 1
4089#define DOWAIT_BLOCK_OR_SIG 2
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004090
4091static int
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004092dowait(int block, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004093{
4094 int pid;
4095 int status;
4096 struct job *jp;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004097 struct job *thisjob = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004098
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004099 TRACE(("dowait(0x%x) called\n", block));
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00004100
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004101 /* It's wrong to call waitpid() outside of INT_OFF region:
4102 * signal can arrive just after syscall return and handler can
4103 * longjmp away, losing stop/exit notification processing.
4104 * Thus, for "jobs" builtin, and for waiting for a fg job,
4105 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4106 *
4107 * However, for "wait" builtin it is wrong to simply call waitpid()
4108 * in INT_OFF region: "wait" needs to wait for any running job
4109 * to change state, but should exit on any trap too.
4110 * In INT_OFF region, a signal just before syscall entry can set
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004111 * pending_sig variables, but we can't check them, and we would
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004112 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004113 *
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004114 * Because of this, we run inside INT_OFF, but use a special routine
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004115 * which combines waitpid() and sigsuspend().
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004116 * This is the reason why we need to have a handler for SIGCHLD:
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004117 * SIG_DFL handler does not wake sigsuspend().
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004118 */
4119 INT_OFF;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004120 if (block == DOWAIT_BLOCK_OR_SIG) {
4121 pid = wait_block_or_sig(&status);
4122 } else {
4123 int wait_flags = 0;
4124 if (block == DOWAIT_NONBLOCK)
4125 wait_flags = WNOHANG;
4126 /* if job control is active, accept stopped processes too */
4127 if (doing_jobctl)
4128 wait_flags |= WUNTRACED;
4129 /* NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004130 pid = waitpid(-1, &status, wait_flags);
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004131 }
Denis Vlasenkob21f3792009-03-19 23:09:58 +00004132 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4133 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004134 if (pid <= 0)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004135 goto out;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004136
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004137 thisjob = NULL;
4138 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004139 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004140 struct procstat *ps;
4141 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004142 if (jp->state == JOBDONE)
4143 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004144 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004145 ps = jp->ps;
4146 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004147 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004148 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004149 TRACE(("Job %d: changing status of proc %d "
4150 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01004151 jobno(jp), pid, ps->ps_status, status));
4152 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004153 thisjob = jp;
4154 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004155 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004156 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004157#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004158 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004159 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004160 if (WIFSTOPPED(ps->ps_status)) {
4161 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004162 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004163 }
4164#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004165 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004166 if (!thisjob)
4167 continue;
4168
4169 /* Found the job where one of its processes changed its state.
4170 * Is there at least one live and running process in this job? */
4171 if (jobstate != JOBRUNNING) {
4172 /* No. All live processes in the job are stopped
4173 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4174 */
4175 thisjob->changed = 1;
4176 if (thisjob->state != jobstate) {
4177 TRACE(("Job %d: changing state from %d to %d\n",
4178 jobno(thisjob), thisjob->state, jobstate));
4179 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004180#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004181 if (jobstate == JOBSTOPPED)
4182 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004183#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004184 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004185 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004186 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004187 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004188 /* The process wasn't found in job list */
4189 if (JOBS && !WIFSTOPPED(status))
4190 jobless--;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004191 out:
4192 INT_ON;
4193
4194 if (thisjob && thisjob == job) {
4195 char s[48 + 1];
4196 int len;
4197
Denys Vlasenko9c541002015-10-07 15:44:36 +02004198 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004199 if (len) {
4200 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004201 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004202 out2str(s);
4203 }
4204 }
4205 return pid;
4206}
4207
4208#if JOBS
4209static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004210showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004211{
4212 struct procstat *ps;
4213 struct procstat *psend;
4214 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004215 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004216 char s[16 + 16 + 48];
4217 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004218
4219 ps = jp->ps;
4220
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004221 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004222 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004223 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004224 return;
4225 }
4226
4227 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004228 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004229
4230 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004231 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004232 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004233 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004234
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004235 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004236 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004237
4238 psend = ps + jp->nprocs;
4239
4240 if (jp->state == JOBRUNNING) {
4241 strcpy(s + col, "Running");
4242 col += sizeof("Running") - 1;
4243 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004244 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004245 if (jp->state == JOBSTOPPED)
4246 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004247 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004248 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004249 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004250
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004251 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4252 * or prints several "PID | <cmdN>" lines,
4253 * depending on SHOW_PIDS bit.
4254 * We do not print status of individual processes
4255 * between PID and <cmdN>. bash does it, but not very well:
4256 * first line shows overall job status, not process status,
4257 * making it impossible to know 1st process status.
4258 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004259 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004260 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004261 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004262 s[0] = '\0';
4263 col = 33;
4264 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004265 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004266 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004267 fprintf(out, "%s%*c%s%s",
4268 s,
4269 33 - col >= 0 ? 33 - col : 0, ' ',
4270 ps == jp->ps ? "" : "| ",
4271 ps->ps_cmd
4272 );
4273 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004274 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004275
4276 jp->changed = 0;
4277
4278 if (jp->state == JOBDONE) {
4279 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4280 freejob(jp);
4281 }
4282}
4283
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004284/*
4285 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4286 * statuses have changed since the last call to showjobs.
4287 */
4288static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004289showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004290{
4291 struct job *jp;
4292
Denys Vlasenko883cea42009-07-11 15:31:59 +02004293 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004294
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004295 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004296 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004297 continue;
4298
4299 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004300 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004301 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004302 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004303 }
4304}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004305
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004306static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004307jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004308{
4309 int mode, m;
4310
4311 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004312 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004313 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004314 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004315 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004316 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004317 }
4318
4319 argv = argptr;
4320 if (*argv) {
4321 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004322 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004323 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004324 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004325 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004326 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004327
4328 return 0;
4329}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004330#endif /* JOBS */
4331
Michael Abbott359da5e2009-12-04 23:03:29 +01004332/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004333static int
4334getstatus(struct job *job)
4335{
4336 int status;
4337 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004338 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004339
Michael Abbott359da5e2009-12-04 23:03:29 +01004340 /* Fetch last member's status */
4341 ps = job->ps + job->nprocs - 1;
4342 status = ps->ps_status;
4343 if (pipefail) {
4344 /* "set -o pipefail" mode: use last _nonzero_ status */
4345 while (status == 0 && --ps >= job->ps)
4346 status = ps->ps_status;
4347 }
4348
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004349 retval = WEXITSTATUS(status);
4350 if (!WIFEXITED(status)) {
4351#if JOBS
4352 retval = WSTOPSIG(status);
4353 if (!WIFSTOPPED(status))
4354#endif
4355 {
4356 /* XXX: limits number of signals */
4357 retval = WTERMSIG(status);
4358#if JOBS
4359 if (retval == SIGINT)
4360 job->sigint = 1;
4361#endif
4362 }
4363 retval += 128;
4364 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004365 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004366 jobno(job), job->nprocs, status, retval));
4367 return retval;
4368}
4369
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004370static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004371waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004372{
4373 struct job *job;
4374 int retval;
4375 struct job *jp;
4376
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004377 nextopt(nullstr);
4378 retval = 0;
4379
4380 argv = argptr;
4381 if (!*argv) {
4382 /* wait for all jobs */
4383 for (;;) {
4384 jp = curjob;
4385 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004386 if (!jp) /* no running procs */
4387 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004388 if (jp->state == JOBRUNNING)
4389 break;
4390 jp->waited = 1;
4391 jp = jp->prev_job;
4392 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004393 /* man bash:
4394 * "When bash is waiting for an asynchronous command via
4395 * the wait builtin, the reception of a signal for which a trap
4396 * has been set will cause the wait builtin to return immediately
4397 * with an exit status greater than 128, immediately after which
4398 * the trap is executed."
Denys Vlasenko69188112016-10-27 20:18:18 +02004399 */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004400 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004401 /* if child sends us a signal *and immediately exits*,
4402 * dowait() returns pid > 0. Check this case,
4403 * not "if (dowait() < 0)"!
4404 */
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004405 if (pending_sig)
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004406 goto sigout;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004407 }
4408 }
4409
4410 retval = 127;
4411 do {
4412 if (**argv != '%') {
4413 pid_t pid = number(*argv);
4414 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004415 while (1) {
4416 if (!job)
4417 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004418 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004419 break;
4420 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004421 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004422 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004423 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004424 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004425 /* loop until process terminated or stopped */
Denys Vlasenko69188112016-10-27 20:18:18 +02004426 while (job->state == JOBRUNNING) {
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004427 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004428 if (pending_sig)
4429 goto sigout;
Denys Vlasenko69188112016-10-27 20:18:18 +02004430 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004431 job->waited = 1;
4432 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004433 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004434 } while (*++argv);
4435
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004436 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004437 return retval;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004438 sigout:
4439 retval = 128 + pending_sig;
4440 return retval;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004441}
4442
4443static struct job *
4444growjobtab(void)
4445{
4446 size_t len;
4447 ptrdiff_t offset;
4448 struct job *jp, *jq;
4449
4450 len = njobs * sizeof(*jp);
4451 jq = jobtab;
4452 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4453
4454 offset = (char *)jp - (char *)jq;
4455 if (offset) {
4456 /* Relocate pointers */
4457 size_t l = len;
4458
4459 jq = (struct job *)((char *)jq + l);
4460 while (l) {
4461 l -= sizeof(*jp);
4462 jq--;
4463#define joff(p) ((struct job *)((char *)(p) + l))
4464#define jmove(p) (p) = (void *)((char *)(p) + offset)
4465 if (joff(jp)->ps == &jq->ps0)
4466 jmove(joff(jp)->ps);
4467 if (joff(jp)->prev_job)
4468 jmove(joff(jp)->prev_job);
4469 }
4470 if (curjob)
4471 jmove(curjob);
4472#undef joff
4473#undef jmove
4474 }
4475
4476 njobs += 4;
4477 jobtab = jp;
4478 jp = (struct job *)((char *)jp + len);
4479 jq = jp + 3;
4480 do {
4481 jq->used = 0;
4482 } while (--jq >= jp);
4483 return jp;
4484}
4485
4486/*
4487 * Return a new job structure.
4488 * Called with interrupts off.
4489 */
4490static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004491makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004492{
4493 int i;
4494 struct job *jp;
4495
4496 for (i = njobs, jp = jobtab; ; jp++) {
4497 if (--i < 0) {
4498 jp = growjobtab();
4499 break;
4500 }
4501 if (jp->used == 0)
4502 break;
4503 if (jp->state != JOBDONE || !jp->waited)
4504 continue;
4505#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004506 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004507 continue;
4508#endif
4509 freejob(jp);
4510 break;
4511 }
4512 memset(jp, 0, sizeof(*jp));
4513#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004514 /* jp->jobctl is a bitfield.
Denys Vlasenko098b7132017-01-11 19:59:03 +01004515 * "jp->jobctl |= doing_jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004516 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004517 jp->jobctl = 1;
4518#endif
4519 jp->prev_job = curjob;
4520 curjob = jp;
4521 jp->used = 1;
4522 jp->ps = &jp->ps0;
4523 if (nprocs > 1) {
4524 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4525 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004526 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004527 jobno(jp)));
4528 return jp;
4529}
4530
4531#if JOBS
4532/*
4533 * Return a string identifying a command (to be printed by the
4534 * jobs command).
4535 */
4536static char *cmdnextc;
4537
4538static void
4539cmdputs(const char *s)
4540{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004541 static const char vstype[VSTYPE + 1][3] = {
4542 "", "}", "-", "+", "?", "=",
4543 "%", "%%", "#", "##"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004544 IF_BASH_SUBSTR(, ":")
4545 IF_BASH_PATTERN_SUBST(, "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004546 };
4547
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004548 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004549 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004550 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004551 unsigned char c;
4552 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004553 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004554
Denys Vlasenko46a14772009-12-10 21:27:13 +01004555 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004556 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4557 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004558 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004559 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004560 switch (c) {
4561 case CTLESC:
4562 c = *p++;
4563 break;
4564 case CTLVAR:
4565 subtype = *p++;
4566 if ((subtype & VSTYPE) == VSLENGTH)
4567 str = "${#";
4568 else
4569 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004570 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004571 case CTLENDVAR:
4572 str = "\"}" + !(quoted & 1);
4573 quoted >>= 1;
4574 subtype = 0;
4575 goto dostr;
4576 case CTLBACKQ:
4577 str = "$(...)";
4578 goto dostr;
Denys Vlasenko0b883582016-12-23 16:49:07 +01004579#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004580 case CTLARI:
4581 str = "$((";
4582 goto dostr;
4583 case CTLENDARI:
4584 str = "))";
4585 goto dostr;
4586#endif
4587 case CTLQUOTEMARK:
4588 quoted ^= 1;
4589 c = '"';
4590 break;
4591 case '=':
4592 if (subtype == 0)
4593 break;
4594 if ((subtype & VSTYPE) != VSNORMAL)
4595 quoted <<= 1;
4596 str = vstype[subtype & VSTYPE];
4597 if (subtype & VSNUL)
4598 c = ':';
4599 else
4600 goto checkstr;
4601 break;
4602 case '\'':
4603 case '\\':
4604 case '"':
4605 case '$':
4606 /* These can only happen inside quotes */
4607 cc[0] = c;
4608 str = cc;
4609 c = '\\';
4610 break;
4611 default:
4612 break;
4613 }
4614 USTPUTC(c, nextc);
4615 checkstr:
4616 if (!str)
4617 continue;
4618 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004619 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004620 USTPUTC(c, nextc);
4621 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004622 } /* while *p++ not NUL */
4623
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004624 if (quoted & 1) {
4625 USTPUTC('"', nextc);
4626 }
4627 *nextc = 0;
4628 cmdnextc = nextc;
4629}
4630
4631/* cmdtxt() and cmdlist() call each other */
4632static void cmdtxt(union node *n);
4633
4634static void
4635cmdlist(union node *np, int sep)
4636{
4637 for (; np; np = np->narg.next) {
4638 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004639 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004640 cmdtxt(np);
4641 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004642 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004643 }
4644}
4645
4646static void
4647cmdtxt(union node *n)
4648{
4649 union node *np;
4650 struct nodelist *lp;
4651 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004652
4653 if (!n)
4654 return;
4655 switch (n->type) {
4656 default:
4657#if DEBUG
4658 abort();
4659#endif
4660 case NPIPE:
4661 lp = n->npipe.cmdlist;
4662 for (;;) {
4663 cmdtxt(lp->n);
4664 lp = lp->next;
4665 if (!lp)
4666 break;
4667 cmdputs(" | ");
4668 }
4669 break;
4670 case NSEMI:
4671 p = "; ";
4672 goto binop;
4673 case NAND:
4674 p = " && ";
4675 goto binop;
4676 case NOR:
4677 p = " || ";
4678 binop:
4679 cmdtxt(n->nbinary.ch1);
4680 cmdputs(p);
4681 n = n->nbinary.ch2;
4682 goto donode;
4683 case NREDIR:
4684 case NBACKGND:
4685 n = n->nredir.n;
4686 goto donode;
4687 case NNOT:
4688 cmdputs("!");
4689 n = n->nnot.com;
4690 donode:
4691 cmdtxt(n);
4692 break;
4693 case NIF:
4694 cmdputs("if ");
4695 cmdtxt(n->nif.test);
4696 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004697 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004698 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004699 cmdputs("; else ");
4700 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004701 } else {
4702 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004703 }
4704 p = "; fi";
4705 goto dotail;
4706 case NSUBSHELL:
4707 cmdputs("(");
4708 n = n->nredir.n;
4709 p = ")";
4710 goto dotail;
4711 case NWHILE:
4712 p = "while ";
4713 goto until;
4714 case NUNTIL:
4715 p = "until ";
4716 until:
4717 cmdputs(p);
4718 cmdtxt(n->nbinary.ch1);
4719 n = n->nbinary.ch2;
4720 p = "; done";
4721 dodo:
4722 cmdputs("; do ");
4723 dotail:
4724 cmdtxt(n);
4725 goto dotail2;
4726 case NFOR:
4727 cmdputs("for ");
4728 cmdputs(n->nfor.var);
4729 cmdputs(" in ");
4730 cmdlist(n->nfor.args, 1);
4731 n = n->nfor.body;
4732 p = "; done";
4733 goto dodo;
4734 case NDEFUN:
4735 cmdputs(n->narg.text);
4736 p = "() { ... }";
4737 goto dotail2;
4738 case NCMD:
4739 cmdlist(n->ncmd.args, 1);
4740 cmdlist(n->ncmd.redirect, 0);
4741 break;
4742 case NARG:
4743 p = n->narg.text;
4744 dotail2:
4745 cmdputs(p);
4746 break;
4747 case NHERE:
4748 case NXHERE:
4749 p = "<<...";
4750 goto dotail2;
4751 case NCASE:
4752 cmdputs("case ");
4753 cmdputs(n->ncase.expr->narg.text);
4754 cmdputs(" in ");
4755 for (np = n->ncase.cases; np; np = np->nclist.next) {
4756 cmdtxt(np->nclist.pattern);
4757 cmdputs(") ");
4758 cmdtxt(np->nclist.body);
4759 cmdputs(";; ");
4760 }
4761 p = "esac";
4762 goto dotail2;
4763 case NTO:
4764 p = ">";
4765 goto redir;
4766 case NCLOBBER:
4767 p = ">|";
4768 goto redir;
4769 case NAPPEND:
4770 p = ">>";
4771 goto redir;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004772#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00004773 case NTO2:
4774#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004775 case NTOFD:
4776 p = ">&";
4777 goto redir;
4778 case NFROM:
4779 p = "<";
4780 goto redir;
4781 case NFROMFD:
4782 p = "<&";
4783 goto redir;
4784 case NFROMTO:
4785 p = "<>";
4786 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004787 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004788 cmdputs(p);
4789 if (n->type == NTOFD || n->type == NFROMFD) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004790 cmdputs(utoa(n->ndup.dupfd));
4791 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004792 }
4793 n = n->nfile.fname;
4794 goto donode;
4795 }
4796}
4797
4798static char *
4799commandtext(union node *n)
4800{
4801 char *name;
4802
4803 STARTSTACKSTR(cmdnextc);
4804 cmdtxt(n);
4805 name = stackblock();
Denys Vlasenko6a94cee2016-10-25 17:40:25 +02004806 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004807 return ckstrdup(name);
4808}
4809#endif /* JOBS */
4810
4811/*
4812 * Fork off a subshell. If we are doing job control, give the subshell its
4813 * own process group. Jp is a job structure that the job is to be added to.
4814 * N is the command that will be evaluated by the child. Both jp and n may
4815 * be NULL. The mode parameter can be one of the following:
4816 * FORK_FG - Fork off a foreground process.
4817 * FORK_BG - Fork off a background process.
4818 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4819 * process group even if job control is on.
4820 *
4821 * When job control is turned off, background processes have their standard
4822 * input redirected to /dev/null (except for the second and later processes
4823 * in a pipeline).
4824 *
4825 * Called with interrupts off.
4826 */
4827/*
4828 * Clear traps on a fork.
4829 */
4830static void
4831clear_traps(void)
4832{
4833 char **tp;
4834
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004835 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004836 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004837 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004838 if (trap_ptr == trap)
4839 free(*tp);
4840 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004841 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004842 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004843 setsignal(tp - trap);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004844 }
4845 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004846 may_have_traps = 0;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004847 INT_ON;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004848}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004849
4850/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004851static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004852
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004853/* Called after fork(), in child */
Denys Vlasenko70392332016-10-27 02:31:55 +02004854/* jp and n are NULL when called by openhere() for heredoc support */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004855static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004856forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004857{
4858 int oldlvl;
4859
4860 TRACE(("Child shell %d\n", getpid()));
4861 oldlvl = shlvl;
4862 shlvl++;
4863
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004864 /* man bash: "Non-builtin commands run by bash have signal handlers
4865 * set to the values inherited by the shell from its parent".
4866 * Do we do it correctly? */
4867
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004868 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004869
4870 if (mode == FORK_NOJOB /* is it `xxx` ? */
4871 && n && n->type == NCMD /* is it single cmd? */
4872 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004873 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004874 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4875 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4876 ) {
4877 TRACE(("Trap hack\n"));
4878 /* Awful hack for `trap` or $(trap).
4879 *
4880 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4881 * contains an example where "trap" is executed in a subshell:
4882 *
4883 * save_traps=$(trap)
4884 * ...
4885 * eval "$save_traps"
4886 *
4887 * Standard does not say that "trap" in subshell shall print
4888 * parent shell's traps. It only says that its output
4889 * must have suitable form, but then, in the above example
4890 * (which is not supposed to be normative), it implies that.
4891 *
4892 * bash (and probably other shell) does implement it
4893 * (traps are reset to defaults, but "trap" still shows them),
4894 * but as a result, "trap" logic is hopelessly messed up:
4895 *
4896 * # trap
4897 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4898 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4899 * # true | trap <--- trap is in subshell - no output (ditto)
4900 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4901 * trap -- 'echo Ho' SIGWINCH
4902 * # echo `(trap)` <--- in subshell in subshell - output
4903 * trap -- 'echo Ho' SIGWINCH
4904 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4905 * trap -- 'echo Ho' SIGWINCH
4906 *
4907 * The rules when to forget and when to not forget traps
4908 * get really complex and nonsensical.
4909 *
4910 * Our solution: ONLY bare $(trap) or `trap` is special.
4911 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004912 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02004913 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004914 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004915 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004916 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004917#if JOBS
4918 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004919 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004920 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004921 pid_t pgrp;
4922
4923 if (jp->nprocs == 0)
4924 pgrp = getpid();
4925 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004926 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004927 /* this can fail because we are doing it in the parent also */
4928 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004929 if (mode == FORK_FG)
4930 xtcsetpgrp(ttyfd, pgrp);
4931 setsignal(SIGTSTP);
4932 setsignal(SIGTTOU);
4933 } else
4934#endif
4935 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004936 /* man bash: "When job control is not in effect,
4937 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004938 ignoresig(SIGINT);
4939 ignoresig(SIGQUIT);
4940 if (jp->nprocs == 0) {
4941 close(0);
4942 if (open(bb_dev_null, O_RDONLY) != 0)
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00004943 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004944 }
4945 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004946 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004947 if (iflag) { /* why if iflag only? */
4948 setsignal(SIGINT);
4949 setsignal(SIGTERM);
4950 }
4951 /* man bash:
4952 * "In all cases, bash ignores SIGQUIT. Non-builtin
4953 * commands run by bash have signal handlers
4954 * set to the values inherited by the shell
4955 * from its parent".
4956 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004957 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004958 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004959#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02004960 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01004961 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004962 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004963 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02004964 /* "jobs": we do not want to clear job list for it,
4965 * instead we remove only _its_ own_ job from job list.
4966 * This makes "jobs .... | cat" more useful.
4967 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004968 freejob(curjob);
4969 return;
4970 }
4971#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004972 for (jp = curjob; jp; jp = jp->prev_job)
4973 freejob(jp);
4974 jobless = 0;
4975}
4976
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004977/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00004978#if !JOBS
4979#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4980#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004981static void
4982forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4983{
4984 TRACE(("In parent shell: child = %d\n", pid));
4985 if (!jp) {
Denys Vlasenko70392332016-10-27 02:31:55 +02004986 /* jp is NULL when called by openhere() for heredoc support */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004987 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4988 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004989 jobless++;
4990 return;
4991 }
4992#if JOBS
4993 if (mode != FORK_NOJOB && jp->jobctl) {
4994 int pgrp;
4995
4996 if (jp->nprocs == 0)
4997 pgrp = pid;
4998 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004999 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005000 /* This can fail because we are doing it in the child also */
5001 setpgid(pid, pgrp);
5002 }
5003#endif
5004 if (mode == FORK_BG) {
5005 backgndpid = pid; /* set $! */
5006 set_curjob(jp, CUR_RUNNING);
5007 }
5008 if (jp) {
5009 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01005010 ps->ps_pid = pid;
5011 ps->ps_status = -1;
5012 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005013#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005014 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01005015 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005016#endif
5017 }
5018}
5019
Denys Vlasenko70392332016-10-27 02:31:55 +02005020/* jp and n are NULL when called by openhere() for heredoc support */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005021static int
5022forkshell(struct job *jp, union node *n, int mode)
5023{
5024 int pid;
5025
5026 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5027 pid = fork();
5028 if (pid < 0) {
5029 TRACE(("Fork failed, errno=%d", errno));
5030 if (jp)
5031 freejob(jp);
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +00005032 ash_msg_and_raise_error("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005033 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02005034 if (pid == 0) {
5035 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005036 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005037 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005038 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005039 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005040 return pid;
5041}
5042
5043/*
5044 * Wait for job to finish.
5045 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005046 * Under job control we have the problem that while a child process
5047 * is running interrupts generated by the user are sent to the child
5048 * but not to the shell. This means that an infinite loop started by
5049 * an interactive user may be hard to kill. With job control turned off,
5050 * an interactive user may place an interactive program inside a loop.
5051 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005052 * these interrupts to also abort the loop. The approach we take here
5053 * is to have the shell ignore interrupt signals while waiting for a
5054 * foreground process to terminate, and then send itself an interrupt
5055 * signal if the child process was terminated by an interrupt signal.
5056 * Unfortunately, some programs want to do a bit of cleanup and then
5057 * exit on interrupt; unless these processes terminate themselves by
5058 * sending a signal to themselves (instead of calling exit) they will
5059 * confuse this approach.
5060 *
5061 * Called with interrupts off.
5062 */
5063static int
5064waitforjob(struct job *jp)
5065{
5066 int st;
5067
5068 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005069
5070 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005071 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005072 /* In non-interactive shells, we _can_ get
5073 * a keyboard signal here and be EINTRed,
5074 * but we just loop back, waiting for command to complete.
5075 *
5076 * man bash:
5077 * "If bash is waiting for a command to complete and receives
5078 * a signal for which a trap has been set, the trap
5079 * will not be executed until the command completes."
5080 *
5081 * Reality is that even if trap is not set, bash
5082 * will not act on the signal until command completes.
5083 * Try this. sleep5intoff.c:
5084 * #include <signal.h>
5085 * #include <unistd.h>
5086 * int main() {
5087 * sigset_t set;
5088 * sigemptyset(&set);
5089 * sigaddset(&set, SIGINT);
5090 * sigaddset(&set, SIGQUIT);
5091 * sigprocmask(SIG_BLOCK, &set, NULL);
5092 * sleep(5);
5093 * return 0;
5094 * }
5095 * $ bash -c './sleep5intoff; echo hi'
5096 * ^C^C^C^C <--- pressing ^C once a second
5097 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005098 * $ bash -c './sleep5intoff; echo hi'
5099 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5100 * $ _
5101 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005102 dowait(DOWAIT_BLOCK, jp);
5103 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005104 INT_ON;
5105
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005106 st = getstatus(jp);
5107#if JOBS
5108 if (jp->jobctl) {
5109 xtcsetpgrp(ttyfd, rootpid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01005110 restore_tty_if_stopped_or_signaled(jp);
5111
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005112 /*
5113 * This is truly gross.
5114 * If we're doing job control, then we did a TIOCSPGRP which
5115 * caused us (the shell) to no longer be in the controlling
5116 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
5117 * intuit from the subprocess exit status whether a SIGINT
5118 * occurred, and if so interrupt ourselves. Yuck. - mycroft
5119 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00005120 if (jp->sigint) /* TODO: do the same with all signals */
5121 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005122 }
5123 if (jp->state == JOBDONE)
5124#endif
5125 freejob(jp);
5126 return st;
5127}
5128
5129/*
5130 * return 1 if there are stopped jobs, otherwise 0
5131 */
5132static int
5133stoppedjobs(void)
5134{
5135 struct job *jp;
5136 int retval;
5137
5138 retval = 0;
5139 if (job_warning)
5140 goto out;
5141 jp = curjob;
5142 if (jp && jp->state == JOBSTOPPED) {
5143 out2str("You have stopped jobs.\n");
5144 job_warning = 2;
5145 retval++;
5146 }
5147 out:
5148 return retval;
5149}
5150
5151
Denys Vlasenko70392332016-10-27 02:31:55 +02005152/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005153 * Code for dealing with input/output redirection.
5154 */
5155
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005156#undef EMPTY
5157#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005158#define EMPTY -2 /* marks an unused slot in redirtab */
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005159#define CLOSED -3 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005160
5161/*
5162 * Open a file in noclobber mode.
5163 * The code was copied from bash.
5164 */
5165static int
5166noclobberopen(const char *fname)
5167{
5168 int r, fd;
5169 struct stat finfo, finfo2;
5170
5171 /*
5172 * If the file exists and is a regular file, return an error
5173 * immediately.
5174 */
5175 r = stat(fname, &finfo);
5176 if (r == 0 && S_ISREG(finfo.st_mode)) {
5177 errno = EEXIST;
5178 return -1;
5179 }
5180
5181 /*
5182 * If the file was not present (r != 0), make sure we open it
5183 * exclusively so that if it is created before we open it, our open
5184 * will fail. Make sure that we do not truncate an existing file.
5185 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5186 * file was not a regular file, we leave O_EXCL off.
5187 */
5188 if (r != 0)
5189 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5190 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5191
5192 /* If the open failed, return the file descriptor right away. */
5193 if (fd < 0)
5194 return fd;
5195
5196 /*
5197 * OK, the open succeeded, but the file may have been changed from a
5198 * non-regular file to a regular file between the stat and the open.
5199 * We are assuming that the O_EXCL open handles the case where FILENAME
5200 * did not exist and is symlinked to an existing file between the stat
5201 * and open.
5202 */
5203
5204 /*
5205 * If we can open it and fstat the file descriptor, and neither check
5206 * revealed that it was a regular file, and the file has not been
5207 * replaced, return the file descriptor.
5208 */
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005209 if (fstat(fd, &finfo2) == 0
5210 && !S_ISREG(finfo2.st_mode)
5211 && finfo.st_dev == finfo2.st_dev
5212 && finfo.st_ino == finfo2.st_ino
5213 ) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005214 return fd;
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005215 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005216
5217 /* The file has been replaced. badness. */
5218 close(fd);
5219 errno = EEXIST;
5220 return -1;
5221}
5222
5223/*
5224 * Handle here documents. Normally we fork off a process to write the
5225 * data to a pipe. If the document is short, we can stuff the data in
5226 * the pipe without forking.
5227 */
5228/* openhere needs this forward reference */
5229static void expandhere(union node *arg, int fd);
5230static int
5231openhere(union node *redir)
5232{
5233 int pip[2];
5234 size_t len = 0;
5235
5236 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005237 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005238 if (redir->type == NHERE) {
5239 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005240 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005241 full_write(pip[1], redir->nhere.doc->narg.text, len);
5242 goto out;
5243 }
5244 }
5245 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005246 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005247 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005248 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5249 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5250 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5251 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005252 signal(SIGPIPE, SIG_DFL);
5253 if (redir->type == NHERE)
5254 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005255 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005256 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005257 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005258 }
5259 out:
5260 close(pip[1]);
5261 return pip[0];
5262}
5263
5264static int
5265openredirect(union node *redir)
5266{
5267 char *fname;
5268 int f;
5269
5270 switch (redir->nfile.type) {
Denys Vlasenko557482c2016-09-25 21:24:04 +02005271/* Can't happen, our single caller does this itself */
5272// case NTOFD:
5273// case NFROMFD:
5274// return -1;
5275 case NHERE:
5276 case NXHERE:
5277 return openhere(redir);
5278 }
5279
5280 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5281 * allocated space. Do it only when we know it is safe.
5282 */
5283 fname = redir->nfile.expfname;
5284
5285 switch (redir->nfile.type) {
5286 default:
5287#if DEBUG
5288 abort();
5289#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005290 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005291 f = open(fname, O_RDONLY);
5292 if (f < 0)
5293 goto eopen;
5294 break;
5295 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005296 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005297 if (f < 0)
5298 goto ecreate;
5299 break;
5300 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005301#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005302 case NTO2:
5303#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005304 /* Take care of noclobber mode. */
5305 if (Cflag) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005306 f = noclobberopen(fname);
5307 if (f < 0)
5308 goto ecreate;
5309 break;
5310 }
5311 /* FALLTHROUGH */
5312 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005313 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5314 if (f < 0)
5315 goto ecreate;
5316 break;
5317 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005318 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5319 if (f < 0)
5320 goto ecreate;
5321 break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005322 }
5323
5324 return f;
5325 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005326 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005327 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005328 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005329}
5330
5331/*
Denys Vlasenko64774602016-10-26 15:24:30 +02005332 * Copy a file descriptor to be >= 10. Throws exception on error.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005333 */
5334static int
Denys Vlasenko64774602016-10-26 15:24:30 +02005335savefd(int from)
5336{
5337 int newfd;
5338 int err;
5339
5340 newfd = fcntl(from, F_DUPFD, 10);
5341 err = newfd < 0 ? errno : 0;
5342 if (err != EBADF) {
5343 if (err)
5344 ash_msg_and_raise_error("%d: %m", from);
5345 close(from);
5346 fcntl(newfd, F_SETFD, FD_CLOEXEC);
5347 }
5348
5349 return newfd;
5350}
5351static int
5352dup2_or_raise(int from, int to)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005353{
5354 int newfd;
5355
Denys Vlasenko64774602016-10-26 15:24:30 +02005356 newfd = (from != to) ? dup2(from, to) : to;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005357 if (newfd < 0) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005358 /* Happens when source fd is not open: try "echo >&99" */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005359 ash_msg_and_raise_error("%d: %m", from);
5360 }
5361 return newfd;
5362}
5363
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005364/* Struct def and variable are moved down to the first usage site */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005365struct two_fd_t {
5366 int orig, copy;
5367};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005368struct redirtab {
5369 struct redirtab *next;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005370 int pair_count;
Denys Vlasenko606291b2009-09-23 23:15:43 +02005371 struct two_fd_t two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005372};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005373#define redirlist (G_var.redirlist)
Denys Vlasenko64774602016-10-26 15:24:30 +02005374enum {
5375 COPYFD_RESTORE = (int)~(INT_MAX),
5376};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005377
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005378static int
5379need_to_remember(struct redirtab *rp, int fd)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005380{
5381 int i;
5382
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005383 if (!rp) /* remembering was not requested */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005384 return 0;
5385
5386 for (i = 0; i < rp->pair_count; i++) {
5387 if (rp->two_fd[i].orig == fd) {
5388 /* already remembered */
5389 return 0;
5390 }
5391 }
5392 return 1;
5393}
5394
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005395/* "hidden" fd is a fd used to read scripts, or a copy of such */
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005396static int
5397is_hidden_fd(struct redirtab *rp, int fd)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005398{
5399 int i;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005400 struct parsefile *pf;
5401
5402 if (fd == -1)
5403 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005404 /* Check open scripts' fds */
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005405 pf = g_parsefile;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005406 while (pf) {
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005407 /* We skip pf_fd == 0 case because of the following case:
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005408 * $ ash # running ash interactively
5409 * $ . ./script.sh
5410 * and in script.sh: "exec 9>&0".
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005411 * Even though top-level pf_fd _is_ 0,
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005412 * it's still ok to use it: "read" builtin uses it,
5413 * why should we cripple "exec" builtin?
5414 */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005415 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005416 return 1;
5417 }
5418 pf = pf->prev;
5419 }
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005420
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005421 if (!rp)
5422 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005423 /* Check saved fds of redirects */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005424 fd |= COPYFD_RESTORE;
5425 for (i = 0; i < rp->pair_count; i++) {
5426 if (rp->two_fd[i].copy == fd) {
5427 return 1;
5428 }
5429 }
5430 return 0;
5431}
5432
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005433/*
5434 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5435 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005436 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005437 */
5438/* flags passed to redirect */
5439#define REDIR_PUSH 01 /* save previous values of file descriptors */
5440#define REDIR_SAVEFD2 03 /* set preverrout */
5441static void
5442redirect(union node *redir, int flags)
5443{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005444 struct redirtab *sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005445 int sv_pos;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005446 int i;
5447 int fd;
5448 int newfd;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005449 int copied_fd2 = -1;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005450
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005451 if (!redir) {
5452 return;
5453 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005454
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005455 sv = NULL;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005456 sv_pos = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005457 INT_OFF;
5458 if (flags & REDIR_PUSH) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005459 union node *tmp = redir;
5460 do {
5461 sv_pos++;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005462#if BASH_REDIR_OUTPUT
Chris Metcalfc3c1fb62010-01-08 13:18:06 +01005463 if (tmp->nfile.type == NTO2)
Denis Vlasenko559691a2008-10-05 18:39:31 +00005464 sv_pos++;
5465#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005466 tmp = tmp->nfile.next;
5467 } while (tmp);
5468 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005469 sv->next = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005470 sv->pair_count = sv_pos;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005471 redirlist = sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005472 while (sv_pos > 0) {
5473 sv_pos--;
5474 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5475 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005476 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005477
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005478 do {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005479 int right_fd = -1;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005480 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005481 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005482 right_fd = redir->ndup.dupfd;
5483 //bb_error_msg("doing %d > %d", fd, right_fd);
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005484 /* redirect from/to same file descriptor? */
5485 if (right_fd == fd)
5486 continue;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005487 /* "echo >&10" and 10 is a fd opened to a sh script? */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005488 if (is_hidden_fd(sv, right_fd)) {
5489 errno = EBADF; /* as if it is closed */
5490 ash_msg_and_raise_error("%d: %m", right_fd);
5491 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005492 newfd = -1;
5493 } else {
5494 newfd = openredirect(redir); /* always >= 0 */
5495 if (fd == newfd) {
5496 /* Descriptor wasn't open before redirect.
5497 * Mark it for close in the future */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005498 if (need_to_remember(sv, fd)) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005499 goto remember_to_close;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005500 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005501 continue;
5502 }
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005503 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005504#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005505 redirect_more:
5506#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005507 if (need_to_remember(sv, fd)) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005508 /* Copy old descriptor */
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005509 /* Careful to not accidentally "save"
5510 * to the same fd as right side fd in N>&M */
5511 int minfd = right_fd < 10 ? 10 : right_fd + 1;
Denys Vlasenko86584e12017-01-07 10:15:01 +01005512#if defined(F_DUPFD_CLOEXEC)
5513 i = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
5514#else
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005515 i = fcntl(fd, F_DUPFD, minfd);
Denys Vlasenko86584e12017-01-07 10:15:01 +01005516#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005517 if (i == -1) {
5518 i = errno;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005519 if (i != EBADF) {
5520 /* Strange error (e.g. "too many files" EMFILE?) */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005521 if (newfd >= 0)
5522 close(newfd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005523 errno = i;
5524 ash_msg_and_raise_error("%d: %m", fd);
5525 /* NOTREACHED */
5526 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005527 /* EBADF: it is not open - good, remember to close it */
5528 remember_to_close:
5529 i = CLOSED;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005530 } else { /* fd is open, save its copy */
Denys Vlasenko86584e12017-01-07 10:15:01 +01005531#if !defined(F_DUPFD_CLOEXEC)
5532 fcntl(i, F_SETFD, FD_CLOEXEC);
5533#endif
Denis Vlasenko22f74142008-07-24 22:34:43 +00005534 /* "exec fd>&-" should not close fds
5535 * which point to script file(s).
5536 * Force them to be restored afterwards */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005537 if (is_hidden_fd(sv, fd))
5538 i |= COPYFD_RESTORE;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005539 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005540 if (fd == 2)
5541 copied_fd2 = i;
5542 sv->two_fd[sv_pos].orig = fd;
5543 sv->two_fd[sv_pos].copy = i;
5544 sv_pos++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005545 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005546 if (newfd < 0) {
5547 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005548 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005549 /* Don't want to trigger debugging */
5550 if (fd != -1)
5551 close(fd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005552 } else {
Denys Vlasenko64774602016-10-26 15:24:30 +02005553 dup2_or_raise(redir->ndup.dupfd, fd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005554 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005555 } else if (fd != newfd) { /* move newfd to fd */
Denys Vlasenko64774602016-10-26 15:24:30 +02005556 dup2_or_raise(newfd, fd);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005557#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005558 if (!(redir->nfile.type == NTO2 && fd == 2))
5559#endif
5560 close(newfd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005561 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005562#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005563 if (redir->nfile.type == NTO2 && fd == 1) {
5564 /* We already redirected it to fd 1, now copy it to 2 */
5565 newfd = 1;
5566 fd = 2;
5567 goto redirect_more;
5568 }
5569#endif
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005570 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005571
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005572 INT_ON;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005573 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5574 preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005575}
5576
5577/*
5578 * Undo the effects of the last redirection.
5579 */
5580static void
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005581popredir(int drop, int restore)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005582{
5583 struct redirtab *rp;
5584 int i;
5585
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02005586 if (redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005587 return;
5588 INT_OFF;
5589 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005590 for (i = 0; i < rp->pair_count; i++) {
5591 int fd = rp->two_fd[i].orig;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005592 int copy = rp->two_fd[i].copy;
5593 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005594 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005595 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005596 continue;
5597 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005598 if (copy != EMPTY) {
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005599 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
Denis Vlasenko22f74142008-07-24 22:34:43 +00005600 copy &= ~COPYFD_RESTORE;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005601 /*close(fd);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02005602 dup2_or_raise(copy, fd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005603 }
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005604 close(copy & ~COPYFD_RESTORE);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005605 }
5606 }
5607 redirlist = rp->next;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005608 free(rp);
5609 INT_ON;
5610}
5611
5612/*
5613 * Undo all redirections. Called on error or interrupt.
5614 */
5615
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005616static int
5617redirectsafe(union node *redir, int flags)
5618{
5619 int err;
5620 volatile int saveint;
5621 struct jmploc *volatile savehandler = exception_handler;
5622 struct jmploc jmploc;
5623
5624 SAVE_INT(saveint);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005625 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5626 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005627 if (!err) {
5628 exception_handler = &jmploc;
5629 redirect(redir, flags);
5630 }
5631 exception_handler = savehandler;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00005632 if (err && exception_type != EXERROR)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005633 longjmp(exception_handler->loc, 1);
5634 RESTORE_INT(saveint);
5635 return err;
5636}
5637
5638
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005639/* ============ Routines to expand arguments to commands
5640 *
5641 * We have to deal with backquotes, shell variables, and file metacharacters.
5642 */
5643
Denys Vlasenko0b883582016-12-23 16:49:07 +01005644#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005645static arith_t
5646ash_arith(const char *s)
5647{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005648 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005649 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005650
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005651 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005652 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005653 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005654
5655 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005656 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005657 if (math_state.errmsg)
5658 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005659 INT_ON;
5660
5661 return result;
5662}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005663#endif
5664
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005665/*
5666 * expandarg flags
5667 */
5668#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5669#define EXP_TILDE 0x2 /* do normal tilde expansion */
5670#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5671#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
Denys Vlasenkodb74c6c2016-10-24 21:12:33 +02005672/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5673 * POSIX says for this case:
5674 * Pathname expansion shall not be performed on the word by a
5675 * non-interactive shell; an interactive shell may perform it, but shall
5676 * do so only when the expansion would result in one word.
5677 * Currently, our code complies to the above rule by never globbing
5678 * redirection filenames.
5679 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5680 * (this means that on a typical Linux distro, bash almost always
5681 * performs globbing, and thus diverges from what we do).
5682 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005683#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Ron Yorston549deab2015-05-18 09:57:51 +02005684#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005685#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5686#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005687#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005688/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005689 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005690 */
5691#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5692#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005693#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5694#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Ron Yorston417622c2015-05-18 09:59:14 +02005695#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005696
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005697/* Add CTLESC when necessary. */
Ron Yorston549deab2015-05-18 09:57:51 +02005698#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005699/* Do not skip NUL characters. */
5700#define QUOTES_KEEPNUL EXP_TILDE
5701
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005702/*
5703 * Structure specifying which parts of the string should be searched
5704 * for IFS characters.
5705 */
5706struct ifsregion {
5707 struct ifsregion *next; /* next region in list */
5708 int begoff; /* offset of start of region */
5709 int endoff; /* offset of end of region */
5710 int nulonly; /* search for nul bytes only */
5711};
5712
5713struct arglist {
5714 struct strlist *list;
5715 struct strlist **lastp;
5716};
5717
5718/* output of current string */
5719static char *expdest;
5720/* list of back quote expressions */
5721static struct nodelist *argbackq;
5722/* first struct in list of ifs regions */
5723static struct ifsregion ifsfirst;
5724/* last struct in list */
5725static struct ifsregion *ifslastp;
5726/* holds expanded arg list */
5727static struct arglist exparg;
5728
5729/*
5730 * Our own itoa().
5731 */
Denys Vlasenko0b883582016-12-23 16:49:07 +01005732#if !ENABLE_FEATURE_SH_MATH
Denys Vlasenko26777aa2010-11-22 23:49:10 +01005733/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5734typedef long arith_t;
5735# define ARITH_FMT "%ld"
5736#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005737static int
5738cvtnum(arith_t num)
5739{
5740 int len;
5741
Denys Vlasenko9c541002015-10-07 15:44:36 +02005742 expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest);
5743 len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005744 STADJUST(len, expdest);
5745 return len;
5746}
5747
Denys Vlasenko455e4222016-10-27 14:45:13 +02005748/*
5749 * Break the argument string into pieces based upon IFS and add the
5750 * strings to the argument list. The regions of the string to be
5751 * searched for IFS characters have been stored by recordregion.
5752 */
5753static void
5754ifsbreakup(char *string, struct arglist *arglist)
5755{
5756 struct ifsregion *ifsp;
5757 struct strlist *sp;
5758 char *start;
5759 char *p;
5760 char *q;
5761 const char *ifs, *realifs;
5762 int ifsspc;
5763 int nulonly;
5764
5765 start = string;
5766 if (ifslastp != NULL) {
5767 ifsspc = 0;
5768 nulonly = 0;
5769 realifs = ifsset() ? ifsval() : defifs;
5770 ifsp = &ifsfirst;
5771 do {
5772 p = string + ifsp->begoff;
5773 nulonly = ifsp->nulonly;
5774 ifs = nulonly ? nullstr : realifs;
5775 ifsspc = 0;
5776 while (p < string + ifsp->endoff) {
5777 q = p;
5778 if ((unsigned char)*p == CTLESC)
5779 p++;
5780 if (!strchr(ifs, *p)) {
5781 p++;
5782 continue;
5783 }
5784 if (!nulonly)
5785 ifsspc = (strchr(defifs, *p) != NULL);
5786 /* Ignore IFS whitespace at start */
5787 if (q == start && ifsspc) {
5788 p++;
5789 start = p;
5790 continue;
5791 }
5792 *q = '\0';
5793 sp = stzalloc(sizeof(*sp));
5794 sp->text = start;
5795 *arglist->lastp = sp;
5796 arglist->lastp = &sp->next;
5797 p++;
5798 if (!nulonly) {
5799 for (;;) {
5800 if (p >= string + ifsp->endoff) {
5801 break;
5802 }
5803 q = p;
5804 if ((unsigned char)*p == CTLESC)
5805 p++;
5806 if (strchr(ifs, *p) == NULL) {
5807 p = q;
5808 break;
5809 }
5810 if (strchr(defifs, *p) == NULL) {
5811 if (ifsspc) {
5812 p++;
5813 ifsspc = 0;
5814 } else {
5815 p = q;
5816 break;
5817 }
5818 } else
5819 p++;
5820 }
5821 }
5822 start = p;
5823 } /* while */
5824 ifsp = ifsp->next;
5825 } while (ifsp != NULL);
5826 if (nulonly)
5827 goto add;
5828 }
5829
5830 if (!*start)
5831 return;
5832
5833 add:
5834 sp = stzalloc(sizeof(*sp));
5835 sp->text = start;
5836 *arglist->lastp = sp;
5837 arglist->lastp = &sp->next;
5838}
5839
5840static void
5841ifsfree(void)
5842{
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005843 struct ifsregion *p = ifsfirst.next;
5844
5845 if (!p)
5846 goto out;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005847
5848 INT_OFF;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005849 do {
5850 struct ifsregion *ifsp;
5851 ifsp = p->next;
5852 free(p);
5853 p = ifsp;
5854 } while (p);
Denys Vlasenko455e4222016-10-27 14:45:13 +02005855 ifsfirst.next = NULL;
5856 INT_ON;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005857 out:
5858 ifslastp = NULL;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005859}
5860
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005861static size_t
5862esclen(const char *start, const char *p)
5863{
5864 size_t esc = 0;
5865
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005866 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005867 esc++;
5868 }
5869 return esc;
5870}
5871
5872/*
5873 * Remove any CTLESC characters from a string.
5874 */
5875static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005876rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005877{
Ron Yorston417622c2015-05-18 09:59:14 +02005878 static const char qchars[] ALIGN1 = {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005879 IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005880
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005881 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005882 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005883 unsigned protect_against_glob;
5884 unsigned globbing;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005885 IF_BASH_PATTERN_SUBST(unsigned slash = flag & RMESCAPE_SLASH;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005886
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005887 p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005888 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005889 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005890
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005891 q = p;
5892 r = str;
5893 if (flag & RMESCAPE_ALLOC) {
5894 size_t len = p - str;
5895 size_t fulllen = len + strlen(p) + 1;
5896
5897 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005898 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005899 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005900 /* p and str may be invalidated by makestrspace */
5901 str = (char *)stackblock() + strloc;
5902 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005903 } else if (flag & RMESCAPE_HEAP) {
5904 r = ckmalloc(fulllen);
5905 } else {
5906 r = stalloc(fulllen);
5907 }
5908 q = r;
5909 if (len > 0) {
Denis Vlasenko29eb3592008-05-18 14:06:08 +00005910 q = (char *)memcpy(q, str, len) + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005911 }
5912 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005913
Ron Yorston549deab2015-05-18 09:57:51 +02005914 inquotes = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005915 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005916 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005917 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005918 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005919// Note: both inquotes and protect_against_glob only affect whether
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005920 inquotes = ~inquotes;
5921 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005922 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005923 continue;
5924 }
Ron Yorston549deab2015-05-18 09:57:51 +02005925 if ((unsigned char)*p == CTLESC) {
5926 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02005927#if DEBUG
5928 if (*p == '\0')
5929 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
5930#endif
Ron Yorston549deab2015-05-18 09:57:51 +02005931 if (protect_against_glob) {
5932 *q++ = '\\';
5933 }
5934 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005935 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005936 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005937 goto copy;
5938 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005939#if BASH_PATTERN_SUBST
Ron Yorston417622c2015-05-18 09:59:14 +02005940 else if (*p == '/' && slash) {
5941 /* stop handling globbing and mark location of slash */
5942 globbing = slash = 0;
5943 *p = CTLESC;
5944 }
5945#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005946 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005947 copy:
5948 *q++ = *p++;
5949 }
5950 *q = '\0';
5951 if (flag & RMESCAPE_GROW) {
5952 expdest = r;
5953 STADJUST(q - r + 1, expdest);
5954 }
5955 return r;
5956}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005957#define pmatch(a, b) !fnmatch((a), (b), 0)
5958
5959/*
5960 * Prepare a pattern for a expmeta (internal glob(3)) call.
5961 *
5962 * Returns an stalloced string.
5963 */
5964static char *
Ron Yorston549deab2015-05-18 09:57:51 +02005965preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005966{
Ron Yorston549deab2015-05-18 09:57:51 +02005967 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005968}
5969
5970/*
5971 * Put a string on the stack.
5972 */
5973static void
5974memtodest(const char *p, size_t len, int syntax, int quotes)
5975{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005976 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005977
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005978 if (!len)
5979 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005980
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005981 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
5982
5983 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005984 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005985 if (c) {
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01005986 if (quotes & QUOTES_ESC) {
5987 int n = SIT(c, syntax);
5988 if (n == CCTL
5989 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
5990 && n == CBACK
5991 )
5992 ) {
5993 USTPUTC(CTLESC, q);
5994 }
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02005995 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005996 } else if (!(quotes & QUOTES_KEEPNUL))
5997 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005998 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005999 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006000
6001 expdest = q;
6002}
6003
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006004static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006005strtodest(const char *p, int syntax, int quotes)
6006{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006007 size_t len = strlen(p);
6008 memtodest(p, len, syntax, quotes);
6009 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006010}
6011
6012/*
6013 * Record the fact that we have to scan this region of the
6014 * string for IFS characters.
6015 */
6016static void
6017recordregion(int start, int end, int nulonly)
6018{
6019 struct ifsregion *ifsp;
6020
6021 if (ifslastp == NULL) {
6022 ifsp = &ifsfirst;
6023 } else {
6024 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00006025 ifsp = ckzalloc(sizeof(*ifsp));
6026 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006027 ifslastp->next = ifsp;
6028 INT_ON;
6029 }
6030 ifslastp = ifsp;
6031 ifslastp->begoff = start;
6032 ifslastp->endoff = end;
6033 ifslastp->nulonly = nulonly;
6034}
6035
6036static void
6037removerecordregions(int endoff)
6038{
6039 if (ifslastp == NULL)
6040 return;
6041
6042 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006043 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006044 struct ifsregion *ifsp;
6045 INT_OFF;
6046 ifsp = ifsfirst.next->next;
6047 free(ifsfirst.next);
6048 ifsfirst.next = ifsp;
6049 INT_ON;
6050 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006051 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006052 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006053 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006054 ifslastp = &ifsfirst;
6055 ifsfirst.endoff = endoff;
6056 }
6057 return;
6058 }
6059
6060 ifslastp = &ifsfirst;
6061 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006062 ifslastp = ifslastp->next;
6063 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006064 struct ifsregion *ifsp;
6065 INT_OFF;
6066 ifsp = ifslastp->next->next;
6067 free(ifslastp->next);
6068 ifslastp->next = ifsp;
6069 INT_ON;
6070 }
6071 if (ifslastp->endoff > endoff)
6072 ifslastp->endoff = endoff;
6073}
6074
6075static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006076exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006077{
Denys Vlasenkocd716832009-11-28 22:14:02 +01006078 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006079 char *name;
6080 struct passwd *pw;
6081 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006082 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006083
6084 name = p + 1;
6085
6086 while ((c = *++p) != '\0') {
6087 switch (c) {
6088 case CTLESC:
6089 return startp;
6090 case CTLQUOTEMARK:
6091 return startp;
6092 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006093 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006094 goto done;
6095 break;
6096 case '/':
6097 case CTLENDVAR:
6098 goto done;
6099 }
6100 }
6101 done:
6102 *p = '\0';
6103 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02006104 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006105 } else {
6106 pw = getpwnam(name);
6107 if (pw == NULL)
6108 goto lose;
6109 home = pw->pw_dir;
6110 }
6111 if (!home || !*home)
6112 goto lose;
6113 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006114 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006115 return p;
6116 lose:
6117 *p = c;
6118 return startp;
6119}
6120
6121/*
6122 * Execute a command inside back quotes. If it's a builtin command, we
6123 * want to save its output in a block obtained from malloc. Otherwise
6124 * we fork off a subprocess and get the output of the command via a pipe.
6125 * Should be called with interrupts off.
6126 */
6127struct backcmd { /* result of evalbackcmd */
6128 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006129 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00006130 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006131 struct job *jp; /* job structure for command */
6132};
6133
6134/* These forward decls are needed to use "eval" code for backticks handling: */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006135#define EV_EXIT 01 /* exit after evaluating tree */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02006136static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006137
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02006138static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006139evalbackcmd(union node *n, struct backcmd *result)
6140{
Denys Vlasenko579ad102016-10-25 21:10:20 +02006141 int pip[2];
6142 struct job *jp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006143
6144 result->fd = -1;
6145 result->buf = NULL;
6146 result->nleft = 0;
6147 result->jp = NULL;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006148 if (n == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006149 goto out;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006150 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006151
Denys Vlasenko579ad102016-10-25 21:10:20 +02006152 if (pipe(pip) < 0)
6153 ash_msg_and_raise_error("pipe call failed");
6154 jp = makejob(/*n,*/ 1);
6155 if (forkshell(jp, n, FORK_NOJOB) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02006156 /* child */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006157 FORCE_INT_ON;
6158 close(pip[0]);
6159 if (pip[1] != 1) {
6160 /*close(1);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02006161 dup2_or_raise(pip[1], 1);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006162 close(pip[1]);
6163 }
Denys Vlasenko960ca382016-10-25 18:12:15 +02006164/* TODO: eflag clearing makes the following not abort:
6165 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6166 * which is what bash does (unless it is in POSIX mode).
6167 * dash deleted "eflag = 0" line in the commit
6168 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6169 * [EVAL] Don't clear eflag in evalbackcmd
6170 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6171 */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006172 eflag = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006173 ifsfree();
Denys Vlasenko579ad102016-10-25 21:10:20 +02006174 evaltree(n, EV_EXIT); /* actually evaltreenr... */
6175 /* NOTREACHED */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006176 }
Denys Vlasenko70392332016-10-27 02:31:55 +02006177 /* parent */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006178 close(pip[1]);
6179 result->fd = pip[0];
6180 result->jp = jp;
6181
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006182 out:
6183 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6184 result->fd, result->buf, result->nleft, result->jp));
6185}
6186
6187/*
6188 * Expand stuff in backwards quotes.
6189 */
6190static void
Ron Yorston549deab2015-05-18 09:57:51 +02006191expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006192{
6193 struct backcmd in;
6194 int i;
6195 char buf[128];
6196 char *p;
6197 char *dest;
6198 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02006199 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006200 struct stackmark smark;
6201
6202 INT_OFF;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02006203 startloc = expdest - (char *)stackblock();
6204 pushstackmark(&smark, startloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006205 evalbackcmd(cmd, &in);
6206 popstackmark(&smark);
6207
6208 p = in.buf;
6209 i = in.nleft;
6210 if (i == 0)
6211 goto read;
6212 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02006213 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006214 read:
6215 if (in.fd < 0)
6216 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01006217 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006218 TRACE(("expbackq: read returns %d\n", i));
6219 if (i <= 0)
6220 break;
6221 p = buf;
6222 }
6223
Denis Vlasenko60818682007-09-28 22:07:23 +00006224 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006225 if (in.fd >= 0) {
6226 close(in.fd);
6227 back_exitstatus = waitforjob(in.jp);
6228 }
6229 INT_ON;
6230
6231 /* Eat all trailing newlines */
6232 dest = expdest;
6233 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6234 STUNPUTC(dest);
6235 expdest = dest;
6236
Ron Yorston549deab2015-05-18 09:57:51 +02006237 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006238 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006239 TRACE(("evalbackq: size:%d:'%.*s'\n",
6240 (int)((dest - (char *)stackblock()) - startloc),
6241 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006242 stackblock() + startloc));
6243}
6244
Denys Vlasenko0b883582016-12-23 16:49:07 +01006245#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006246/*
6247 * Expand arithmetic expression. Backup to start of expression,
6248 * evaluate, place result in (backed up) result, adjust string position.
6249 */
6250static void
Ron Yorston549deab2015-05-18 09:57:51 +02006251expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006252{
6253 char *p, *start;
6254 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006255 int len;
6256
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006257 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006258
6259 /*
6260 * This routine is slightly over-complicated for
6261 * efficiency. Next we scan backwards looking for the
6262 * start of arithmetic.
6263 */
6264 start = stackblock();
6265 p = expdest - 1;
6266 *p = '\0';
6267 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006268 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006269 int esc;
6270
Denys Vlasenkocd716832009-11-28 22:14:02 +01006271 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006272 p--;
6273#if DEBUG
6274 if (p < start) {
6275 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6276 }
6277#endif
6278 }
6279
6280 esc = esclen(start, p);
6281 if (!(esc % 2)) {
6282 break;
6283 }
6284
6285 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006286 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006287
6288 begoff = p - start;
6289
6290 removerecordregions(begoff);
6291
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006292 expdest = p;
6293
Ron Yorston549deab2015-05-18 09:57:51 +02006294 if (flag & QUOTES_ESC)
6295 rmescapes(p + 1, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006296
Ron Yorston549deab2015-05-18 09:57:51 +02006297 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006298
Ron Yorston549deab2015-05-18 09:57:51 +02006299 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006300 recordregion(begoff, begoff + len, 0);
6301}
6302#endif
6303
6304/* argstr needs it */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006305static char *evalvar(char *p, int flags, struct strlist *var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006306
6307/*
6308 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6309 * characters to allow for further processing. Otherwise treat
6310 * $@ like $* since no splitting will be performed.
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006311 *
6312 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
Denys Vlasenko10ad6222017-04-17 16:13:32 +02006313 * over shell variables. Needed for "A=a B=$A; echo $B" case - we use it
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006314 * for correct expansion of "B=$A" word.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006315 */
6316static void
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006317argstr(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006318{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006319 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006320 '=',
6321 ':',
6322 CTLQUOTEMARK,
6323 CTLENDVAR,
6324 CTLESC,
6325 CTLVAR,
6326 CTLBACKQ,
Denys Vlasenko0b883582016-12-23 16:49:07 +01006327#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006328 CTLENDARI,
6329#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006330 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006331 };
6332 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006333 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006334 int inquotes;
6335 size_t length;
6336 int startloc;
6337
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006338 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006339 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006340 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006341 reject++;
6342 }
6343 inquotes = 0;
6344 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006345 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006346 char *q;
6347
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006348 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006349 tilde:
6350 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006351 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006352 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006353 }
6354 start:
6355 startloc = expdest - (char *)stackblock();
6356 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006357 unsigned char c;
6358
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006359 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006360 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006361 if (c) {
6362 if (!(c & 0x80)
Denys Vlasenko0b883582016-12-23 16:49:07 +01006363 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006364 ) {
6365 /* c == '=' || c == ':' || c == CTLENDARI */
6366 length++;
6367 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006368 }
6369 if (length > 0) {
6370 int newloc;
6371 expdest = stack_nputstr(p, length, expdest);
6372 newloc = expdest - (char *)stackblock();
6373 if (breakall && !inquotes && newloc > startloc) {
6374 recordregion(startloc, newloc, 0);
6375 }
6376 startloc = newloc;
6377 }
6378 p += length + 1;
6379 length = 0;
6380
6381 switch (c) {
6382 case '\0':
6383 goto breakloop;
6384 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006385 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006386 p--;
6387 continue;
6388 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006389 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006390 reject++;
6391 /* fall through */
6392 case ':':
6393 /*
6394 * sort of a hack - expand tildes in variable
6395 * assignments (after the first '=' and after ':'s).
6396 */
6397 if (*--p == '~') {
6398 goto tilde;
6399 }
6400 continue;
6401 }
6402
6403 switch (c) {
6404 case CTLENDVAR: /* ??? */
6405 goto breakloop;
6406 case CTLQUOTEMARK:
Ron Yorston549deab2015-05-18 09:57:51 +02006407 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006408 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006409 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6410 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006411 goto start;
6412 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006413 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006414 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006415 p--;
6416 length++;
6417 startloc++;
6418 }
6419 break;
6420 case CTLESC:
6421 startloc++;
6422 length++;
Ron Yorston549deab2015-05-18 09:57:51 +02006423
6424 /*
6425 * Quoted parameter expansion pattern: remove quote
6426 * unless inside inner quotes or we have a literal
6427 * backslash.
6428 */
6429 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6430 EXP_QPAT && *p != '\\')
6431 break;
6432
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006433 goto addquote;
6434 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006435 TRACE(("argstr: evalvar('%s')\n", p));
Ron Yorston549deab2015-05-18 09:57:51 +02006436 p = evalvar(p, flags | inquotes, var_str_list);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006437 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006438 goto start;
6439 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006440 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006441 argbackq = argbackq->next;
6442 goto start;
Denys Vlasenko0b883582016-12-23 16:49:07 +01006443#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006444 case CTLENDARI:
6445 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006446 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006447 goto start;
6448#endif
6449 }
6450 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006451 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006452}
6453
6454static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006455scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6456 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006457{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006458 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006459 char c;
6460
6461 loc = startp;
6462 loc2 = rmesc;
6463 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006464 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006465 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006466
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006467 c = *loc2;
6468 if (zero) {
6469 *loc2 = '\0';
6470 s = rmesc;
6471 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006472 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006473
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006474 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006475 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006476 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006477 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006478 loc++;
6479 loc++;
6480 loc2++;
6481 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006482 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006483}
6484
6485static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006486scanright(char *startp, char *rmesc, char *rmescend,
6487 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006488{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006489#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6490 int try2optimize = match_at_start;
6491#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006492 int esc = 0;
6493 char *loc;
6494 char *loc2;
6495
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006496 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6497 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6498 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6499 * Logic:
6500 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6501 * and on each iteration they go back two/one char until they reach the beginning.
6502 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6503 */
6504 /* TODO: document in what other circumstances we are called. */
6505
6506 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006507 int match;
6508 char c = *loc2;
6509 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006510 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006511 *loc2 = '\0';
6512 s = rmesc;
6513 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006514 match = pmatch(pattern, s);
6515 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006516 *loc2 = c;
6517 if (match)
6518 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006519#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6520 if (try2optimize) {
6521 /* Maybe we can optimize this:
6522 * if pattern ends with unescaped *, we can avoid checking
Denys Vlasenko10ad6222017-04-17 16:13:32 +02006523 * shorter strings: if "foo*" doesn't match "raw_value_of_v",
6524 * it won't match truncated "raw_value_of_" strings too.
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006525 */
6526 unsigned plen = strlen(pattern);
6527 /* Does it end with "*"? */
6528 if (plen != 0 && pattern[--plen] == '*') {
6529 /* "xxxx*" is not escaped */
6530 /* "xxx\*" is escaped */
6531 /* "xx\\*" is not escaped */
6532 /* "x\\\*" is escaped */
6533 int slashes = 0;
6534 while (plen != 0 && pattern[--plen] == '\\')
6535 slashes++;
6536 if (!(slashes & 1))
6537 break; /* ends with unescaped "*" */
6538 }
6539 try2optimize = 0;
6540 }
6541#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006542 loc--;
6543 if (quotes) {
6544 if (--esc < 0) {
6545 esc = esclen(startp, loc);
6546 }
6547 if (esc % 2) {
6548 esc--;
6549 loc--;
6550 }
6551 }
6552 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006553 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006554}
6555
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006556static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006557static void
6558varunset(const char *end, const char *var, const char *umsg, int varflags)
6559{
6560 const char *msg;
6561 const char *tail;
6562
6563 tail = nullstr;
6564 msg = "parameter not set";
6565 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006566 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006567 if (varflags & VSNUL)
6568 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006569 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006570 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006571 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006572 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006573 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006574}
6575
6576static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006577subevalvar(char *p, char *varname, int strloc, int subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006578 int startloc, int varflags, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006579{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006580 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006581 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006582 char *startp;
6583 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006584 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006585 char *str;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006586 IF_BASH_SUBSTR(int pos, len, orig_len;)
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006587 int amount, resetloc;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006588 IF_BASH_PATTERN_SUBST(int workloc;)
6589 IF_BASH_PATTERN_SUBST(char *repl = NULL;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006590 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006591 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006592
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006593 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6594 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006595
Ron Yorstoneb6b48b2015-05-18 09:51:35 +02006596 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
Ron Yorston549deab2015-05-18 09:57:51 +02006597 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6598 var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006599 STPUTC('\0', expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006600 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006601 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006602
6603 switch (subtype) {
6604 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006605 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006606 amount = startp - expdest;
6607 STADJUST(amount, expdest);
6608 return startp;
6609
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006610 case VSQUESTION:
6611 varunset(p, varname, startp, varflags);
6612 /* NOTREACHED */
6613
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006614#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006615 case VSSUBSTR:
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +02006616//TODO: support more general format ${v:EXPR:EXPR},
6617// where EXPR follows $(()) rules
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006618 loc = str = stackblock() + strloc;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006619 /* Read POS in ${var:POS:LEN} */
6620 pos = atoi(loc); /* number(loc) errors out on "1:4" */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006621 len = str - startp - 1;
6622
6623 /* *loc != '\0', guaranteed by parser */
6624 if (quotes) {
6625 char *ptr;
6626
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006627 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006628 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006629 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006630 len--;
6631 ptr++;
6632 }
6633 }
6634 }
6635 orig_len = len;
6636
6637 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006638 /* ${var::LEN} */
6639 len = number(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006640 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006641 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006642 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006643 while (*loc && *loc != ':') {
6644 /* TODO?
6645 * bash complains on: var=qwe; echo ${var:1a:123}
6646 if (!isdigit(*loc))
6647 ash_msg_and_raise_error(msg_illnum, str);
6648 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006649 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006650 }
6651 if (*loc++ == ':') {
6652 len = number(loc);
6653 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006654 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006655 if (pos < 0) {
6656 /* ${VAR:$((-n)):l} starts n chars from the end */
6657 pos = orig_len + pos;
6658 }
6659 if ((unsigned)pos >= orig_len) {
6660 /* apart from obvious ${VAR:999999:l},
6661 * covers ${VAR:$((-9999999)):l} - result is ""
6662 * (bash-compat)
6663 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006664 pos = 0;
6665 len = 0;
6666 }
6667 if (len > (orig_len - pos))
6668 len = orig_len - pos;
6669
6670 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006671 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006672 str++;
6673 }
6674 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006675 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006676 *loc++ = *str++;
6677 *loc++ = *str++;
6678 }
6679 *loc = '\0';
6680 amount = loc - expdest;
6681 STADJUST(amount, expdest);
6682 return loc;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006683#endif /* BASH_SUBSTR */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006684 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006685
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006686 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006687
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006688#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006689 /* We'll comeback here if we grow the stack while handling
6690 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6691 * stack will need rebasing, and we'll need to remove our work
6692 * areas each time
6693 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006694 restart:
6695#endif
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006696
6697 amount = expdest - ((char *)stackblock() + resetloc);
6698 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006699 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006700
6701 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006702 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006703 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006704 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006705 if (rmesc != startp) {
6706 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006707 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006708 }
6709 }
6710 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006711 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02006712 /*
6713 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6714 * The result is a_\_z_c (not a\_\_z_c)!
6715 *
6716 * The search pattern and replace string treat backslashes differently!
6717 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6718 * and string. It's only used on the first call.
6719 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006720 preglob(str, IF_BASH_PATTERN_SUBST(
Ron Yorston417622c2015-05-18 09:59:14 +02006721 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006722 RMESCAPE_SLASH : ) 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006723
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006724#if BASH_PATTERN_SUBST
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006725 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006726 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006727 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006728
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006729 if (!repl) {
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006730 repl = strchr(str, CTLESC);
6731 if (repl)
Ron Yorston417622c2015-05-18 09:59:14 +02006732 *repl++ = '\0';
6733 else
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006734 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006735 }
Ron Yorston417622c2015-05-18 09:59:14 +02006736 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006737
6738 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006739 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006740 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006741
6742 len = 0;
6743 idx = startp;
6744 end = str - 1;
6745 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006746 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006747 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006748 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006749 if (!loc) {
6750 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006751 char *restart_detect = stackblock();
6752 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006753 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006754 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006755 idx++;
6756 len++;
6757 STPUTC(*idx, expdest);
6758 }
6759 if (stackblock() != restart_detect)
6760 goto restart;
6761 idx++;
6762 len++;
6763 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006764 /* continue; - prone to quadratic behavior, smarter code: */
6765 if (idx >= end)
6766 break;
6767 if (str[0] == '*') {
6768 /* Pattern is "*foo". If "*foo" does not match "long_string",
6769 * it would never match "ong_string" etc, no point in trying.
6770 */
6771 goto skip_matching;
6772 }
6773 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006774 }
6775
6776 if (subtype == VSREPLACEALL) {
6777 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006778 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006779 idx++;
6780 idx++;
6781 rmesc++;
6782 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006783 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006784 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006785 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006786
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006787 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006788 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006789 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006790 if (quotes && *loc == '\\') {
6791 STPUTC(CTLESC, expdest);
6792 len++;
6793 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006794 STPUTC(*loc, expdest);
6795 if (stackblock() != restart_detect)
6796 goto restart;
6797 len++;
6798 }
6799
6800 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006801 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006802 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006803 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006804 STPUTC(*idx, expdest);
6805 if (stackblock() != restart_detect)
6806 goto restart;
6807 len++;
6808 idx++;
6809 }
6810 break;
6811 }
6812 }
6813
6814 /* We've put the replaced text into a buffer at workloc, now
6815 * move it to the right place and adjust the stack.
6816 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006817 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006818 startp = (char *)stackblock() + startloc;
6819 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006820 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006821 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006822 STADJUST(-amount, expdest);
6823 return startp;
6824 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006825#endif /* BASH_PATTERN_SUBST */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006826
6827 subtype -= VSTRIMRIGHT;
6828#if DEBUG
6829 if (subtype < 0 || subtype > 7)
6830 abort();
6831#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006832 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006833 zero = subtype >> 1;
6834 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6835 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6836
6837 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6838 if (loc) {
6839 if (zero) {
6840 memmove(startp, loc, str - loc);
6841 loc = startp + (str - loc) - 1;
6842 }
6843 *loc = '\0';
6844 amount = loc - expdest;
6845 STADJUST(amount, expdest);
6846 }
6847 return loc;
6848}
6849
6850/*
6851 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006852 * name parameter (examples):
6853 * ash -c 'echo $1' name:'1='
6854 * ash -c 'echo $qwe' name:'qwe='
6855 * ash -c 'echo $$' name:'$='
6856 * ash -c 'echo ${$}' name:'$='
6857 * ash -c 'echo ${$##q}' name:'$=q'
6858 * ash -c 'echo ${#$}' name:'$='
6859 * note: examples with bad shell syntax:
6860 * ash -c 'echo ${#$1}' name:'$=1'
6861 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006862 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02006863static NOINLINE ssize_t
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006864varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int *quotedp)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006865{
Mike Frysinger98c52642009-04-02 10:02:37 +00006866 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006867 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006868 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006869 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006870 int sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006871 int quoted = *quotedp;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006872 int subtype = varflags & VSTYPE;
6873 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6874 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006875 int syntax;
6876
6877 sep = (flags & EXP_FULL) << CHAR_BIT;
6878 syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006879
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006880 switch (*name) {
6881 case '$':
6882 num = rootpid;
6883 goto numvar;
6884 case '?':
6885 num = exitstatus;
6886 goto numvar;
6887 case '#':
6888 num = shellparam.nparam;
6889 goto numvar;
6890 case '!':
6891 num = backgndpid;
6892 if (num == 0)
6893 return -1;
6894 numvar:
6895 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006896 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006897 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00006898 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006899 for (i = NOPTS - 1; i >= 0; i--) {
6900 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00006901 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006902 len++;
6903 }
6904 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006905 check_1char_name:
6906#if 0
6907 /* handles cases similar to ${#$1} */
6908 if (name[2] != '\0')
6909 raise_error_syntax("bad substitution");
6910#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006911 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006912 case '@':
6913 if (quoted && sep)
6914 goto param;
6915 /* fall through */
6916 case '*': {
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006917 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006918 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006919
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006920 if (quoted)
6921 sep = 0;
6922 sep |= ifsset() ? ifsval()[0] : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006923 param:
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006924 sepc = sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006925 *quotedp = !sepc;
6926 ap = shellparam.p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006927 if (!ap)
6928 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006929 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006930 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006931
6932 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006933 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006934 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006935 }
6936 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006937 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006938 } /* case '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006939 case '0':
6940 case '1':
6941 case '2':
6942 case '3':
6943 case '4':
6944 case '5':
6945 case '6':
6946 case '7':
6947 case '8':
6948 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02006949 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006950 if (num < 0 || num > shellparam.nparam)
6951 return -1;
6952 p = num ? shellparam.p[num - 1] : arg0;
6953 goto value;
6954 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006955 /* NB: name has form "VAR=..." */
6956
6957 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6958 * which should be considered before we check variables. */
6959 if (var_str_list) {
6960 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6961 p = NULL;
6962 do {
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00006963 char *str, *eq;
6964 str = var_str_list->text;
6965 eq = strchr(str, '=');
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006966 if (!eq) /* stop at first non-assignment */
6967 break;
6968 eq++;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00006969 if (name_len == (unsigned)(eq - str)
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006970 && strncmp(str, name, name_len) == 0
6971 ) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006972 p = eq;
6973 /* goto value; - WRONG! */
6974 /* think "A=1 A=2 B=$A" */
6975 }
6976 var_str_list = var_str_list->next;
6977 } while (var_str_list);
6978 if (p)
6979 goto value;
6980 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006981 p = lookupvar(name);
6982 value:
6983 if (!p)
6984 return -1;
6985
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006986 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006987#if ENABLE_UNICODE_SUPPORT
6988 if (subtype == VSLENGTH && len > 0) {
6989 reinit_unicode_for_ash();
6990 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00006991 STADJUST(-len, expdest);
6992 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006993 len = unicode_strlen(p);
6994 }
6995 }
6996#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006997 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006998 }
6999
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007000 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007001 STADJUST(-len, expdest);
7002 return len;
7003}
7004
7005/*
7006 * Expand a variable, and return a pointer to the next character in the
7007 * input string.
7008 */
7009static char *
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007010evalvar(char *p, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007011{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007012 char varflags;
7013 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02007014 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007015 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007016 char *var;
7017 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007018 int startloc;
7019 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007020
Denys Vlasenkob0d63382009-09-16 16:18:32 +02007021 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007022 subtype = varflags & VSTYPE;
Denys Vlasenko88e15702016-10-26 01:55:56 +02007023
7024 if (!subtype)
7025 raise_error_syntax("bad substitution");
7026
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007027 quoted = flag & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007028 var = p;
7029 easy = (!quoted || (*var == '@' && shellparam.nparam));
7030 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02007031 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007032
7033 again:
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007034 varlen = varvalue(var, varflags, flag, var_str_list, &quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007035 if (varflags & VSNUL)
7036 varlen--;
7037
7038 if (subtype == VSPLUS) {
7039 varlen = -1 - varlen;
7040 goto vsplus;
7041 }
7042
7043 if (subtype == VSMINUS) {
7044 vsplus:
7045 if (varlen < 0) {
7046 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02007047 p,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007048 flag | EXP_TILDE | EXP_WORD,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007049 var_str_list
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007050 );
7051 goto end;
7052 }
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007053 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007054 }
7055
7056 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007057 if (varlen >= 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007058 goto record;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007059
7060 subevalvar(p, var, 0, subtype, startloc, varflags,
7061 flag & ~QUOTES_ESC, var_str_list);
7062 varflags &= ~VSNUL;
7063 /*
7064 * Remove any recorded regions beyond
7065 * start of variable
7066 */
7067 removerecordregions(startloc);
7068 goto again;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007069 }
7070
7071 if (varlen < 0 && uflag)
7072 varunset(p, var, 0, 0);
7073
7074 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007075 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007076 goto record;
7077 }
7078
7079 if (subtype == VSNORMAL) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007080 record:
7081 if (!easy)
7082 goto end;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007083 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007084 goto end;
7085 }
7086
7087#if DEBUG
7088 switch (subtype) {
7089 case VSTRIMLEFT:
7090 case VSTRIMLEFTMAX:
7091 case VSTRIMRIGHT:
7092 case VSTRIMRIGHTMAX:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007093#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007094 case VSSUBSTR:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007095#endif
7096#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007097 case VSREPLACE:
7098 case VSREPLACEALL:
7099#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007100 break;
7101 default:
7102 abort();
7103 }
7104#endif
7105
7106 if (varlen >= 0) {
7107 /*
7108 * Terminate the string and start recording the pattern
7109 * right after it
7110 */
7111 STPUTC('\0', expdest);
7112 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007113 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007114 startloc, varflags, flag, var_str_list)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007115 int amount = expdest - (
7116 (char *)stackblock() + patloc - 1
7117 );
7118 STADJUST(-amount, expdest);
7119 }
7120 /* Remove any recorded regions beyond start of variable */
7121 removerecordregions(startloc);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007122 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007123 }
7124
7125 end:
7126 if (subtype != VSNORMAL) { /* skip to end of alternative */
7127 int nesting = 1;
7128 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007129 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007130 if (c == CTLESC)
7131 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02007132 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007133 if (varlen >= 0)
7134 argbackq = argbackq->next;
7135 } else if (c == CTLVAR) {
7136 if ((*p++ & VSTYPE) != VSNORMAL)
7137 nesting++;
7138 } else if (c == CTLENDVAR) {
7139 if (--nesting == 0)
7140 break;
7141 }
7142 }
7143 }
7144 return p;
7145}
7146
7147/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007148 * Add a file name to the list.
7149 */
7150static void
7151addfname(const char *name)
7152{
7153 struct strlist *sp;
7154
Denis Vlasenko597906c2008-02-20 16:38:54 +00007155 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02007156 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007157 *exparg.lastp = sp;
7158 exparg.lastp = &sp->next;
7159}
7160
Felix Fietkaub5b21122017-01-31 21:58:55 +01007161/* Avoid glob() (and thus, stat() et al) for words like "echo" */
7162static int
7163hasmeta(const char *p)
7164{
7165 static const char chars[] ALIGN1 = {
7166 '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
7167 };
7168
7169 for (;;) {
7170 p = strpbrk(p, chars);
7171 if (!p)
7172 break;
7173 switch ((unsigned char) *p) {
7174 case CTLQUOTEMARK:
7175 for (;;) {
7176 p++;
7177 if (*p == CTLQUOTEMARK)
7178 break;
7179 if (*p == CTLESC)
7180 p++;
7181 if (*p == '\0') /* huh? */
7182 return 0;
7183 }
7184 break;
7185 case '\\':
7186 case CTLESC:
7187 p++;
7188 if (*p == '\0')
7189 return 0;
7190 break;
7191 case '[':
7192 if (!strchr(p + 1, ']')) {
7193 /* It's not a properly closed [] pattern,
7194 * but other metas may follow. Continue checking.
7195 * my[file* _is_ globbed by bash
7196 * and matches filenames like "my[file1".
7197 */
7198 break;
7199 }
7200 /* fallthrough */
7201 default:
7202 /* case '*': */
7203 /* case '?': */
7204 return 1;
7205 }
7206 p++;
7207 }
7208
7209 return 0;
7210}
7211
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007212/* If we want to use glob() from libc... */
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007213#if !ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007214
7215/* Add the result of glob() to the list */
7216static void
7217addglob(const glob_t *pglob)
7218{
7219 char **p = pglob->gl_pathv;
7220
7221 do {
7222 addfname(*p);
7223 } while (*++p);
7224}
7225static void
7226expandmeta(struct strlist *str /*, int flag*/)
7227{
7228 /* TODO - EXP_REDIR */
7229
7230 while (str) {
7231 char *p;
7232 glob_t pglob;
7233 int i;
7234
7235 if (fflag)
7236 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007237
Felix Fietkaub5b21122017-01-31 21:58:55 +01007238 if (!hasmeta(str->text))
7239 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007240
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007241 INT_OFF;
7242 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007243// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7244// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7245//
7246// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7247// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7248// Which means you need to unescape the string, right? Not so fast:
7249// if there _is_ a file named "file\?" (with backslash), it is returned
7250// as "file\?" too (whichever pattern you used to find it, say, "file*").
Denys Vlasenko10ad6222017-04-17 16:13:32 +02007251// You DON'T KNOW by looking at the result whether you need to unescape it.
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007252//
7253// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7254// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7255// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7256// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7257// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7258// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7259 i = glob(p, 0, NULL, &pglob);
7260 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007261 if (p != str->text)
7262 free(p);
7263 switch (i) {
7264 case 0:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007265#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007266 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7267 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7268 goto nometa2;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007269#endif
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007270 addglob(&pglob);
7271 globfree(&pglob);
7272 INT_ON;
7273 break;
7274 case GLOB_NOMATCH:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007275 //nometa2:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007276 globfree(&pglob);
7277 INT_ON;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007278 nometa:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007279 *exparg.lastp = str;
7280 rmescapes(str->text, 0);
7281 exparg.lastp = &str->next;
7282 break;
7283 default: /* GLOB_NOSPACE */
7284 globfree(&pglob);
7285 INT_ON;
7286 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7287 }
7288 str = str->next;
7289 }
7290}
7291
7292#else
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007293/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007294
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007295/*
7296 * Do metacharacter (i.e. *, ?, [...]) expansion.
7297 */
7298static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007299expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007300{
7301 char *p;
7302 const char *cp;
7303 char *start;
7304 char *endname;
7305 int metaflag;
7306 struct stat statb;
7307 DIR *dirp;
7308 struct dirent *dp;
7309 int atend;
7310 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007311 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007312
7313 metaflag = 0;
7314 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007315 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007316 if (*p == '*' || *p == '?')
7317 metaflag = 1;
7318 else if (*p == '[') {
7319 char *q = p + 1;
7320 if (*q == '!')
7321 q++;
7322 for (;;) {
7323 if (*q == '\\')
7324 q++;
7325 if (*q == '/' || *q == '\0')
7326 break;
7327 if (*++q == ']') {
7328 metaflag = 1;
7329 break;
7330 }
7331 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007332 } else {
7333 if (*p == '\\')
7334 esc++;
7335 if (p[esc] == '/') {
7336 if (metaflag)
7337 break;
7338 start = p + esc + 1;
7339 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007340 }
7341 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007342 if (metaflag == 0) { /* we've reached the end of the file name */
7343 if (enddir != expdir)
7344 metaflag++;
7345 p = name;
7346 do {
7347 if (*p == '\\')
7348 p++;
7349 *enddir++ = *p;
7350 } while (*p++);
7351 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7352 addfname(expdir);
7353 return;
7354 }
7355 endname = p;
7356 if (name < start) {
7357 p = name;
7358 do {
7359 if (*p == '\\')
7360 p++;
7361 *enddir++ = *p++;
7362 } while (p < start);
7363 }
7364 if (enddir == expdir) {
7365 cp = ".";
7366 } else if (enddir == expdir + 1 && *expdir == '/') {
7367 cp = "/";
7368 } else {
7369 cp = expdir;
7370 enddir[-1] = '\0';
7371 }
7372 dirp = opendir(cp);
7373 if (dirp == NULL)
7374 return;
7375 if (enddir != expdir)
7376 enddir[-1] = '/';
7377 if (*endname == 0) {
7378 atend = 1;
7379 } else {
7380 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007381 *endname = '\0';
7382 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007383 }
7384 matchdot = 0;
7385 p = start;
7386 if (*p == '\\')
7387 p++;
7388 if (*p == '.')
7389 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007390 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007391 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007392 continue;
7393 if (pmatch(start, dp->d_name)) {
7394 if (atend) {
7395 strcpy(enddir, dp->d_name);
7396 addfname(expdir);
7397 } else {
7398 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7399 continue;
7400 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007401 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007402 }
7403 }
7404 }
7405 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007406 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007407 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007408}
7409
7410static struct strlist *
7411msort(struct strlist *list, int len)
7412{
7413 struct strlist *p, *q = NULL;
7414 struct strlist **lpp;
7415 int half;
7416 int n;
7417
7418 if (len <= 1)
7419 return list;
7420 half = len >> 1;
7421 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007422 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007423 q = p;
7424 p = p->next;
7425 }
7426 q->next = NULL; /* terminate first half of list */
7427 q = msort(list, half); /* sort first half of list */
7428 p = msort(p, len - half); /* sort second half */
7429 lpp = &list;
7430 for (;;) {
7431#if ENABLE_LOCALE_SUPPORT
7432 if (strcoll(p->text, q->text) < 0)
7433#else
7434 if (strcmp(p->text, q->text) < 0)
7435#endif
7436 {
7437 *lpp = p;
7438 lpp = &p->next;
7439 p = *lpp;
7440 if (p == NULL) {
7441 *lpp = q;
7442 break;
7443 }
7444 } else {
7445 *lpp = q;
7446 lpp = &q->next;
7447 q = *lpp;
7448 if (q == NULL) {
7449 *lpp = p;
7450 break;
7451 }
7452 }
7453 }
7454 return list;
7455}
7456
7457/*
7458 * Sort the results of file name expansion. It calculates the number of
7459 * strings to sort and then calls msort (short for merge sort) to do the
7460 * work.
7461 */
7462static struct strlist *
7463expsort(struct strlist *str)
7464{
7465 int len;
7466 struct strlist *sp;
7467
7468 len = 0;
7469 for (sp = str; sp; sp = sp->next)
7470 len++;
7471 return msort(str, len);
7472}
7473
7474static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007475expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007476{
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007477 /* TODO - EXP_REDIR */
7478
7479 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007480 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007481 struct strlist **savelastp;
7482 struct strlist *sp;
7483 char *p;
7484
7485 if (fflag)
7486 goto nometa;
Felix Fietkaub5b21122017-01-31 21:58:55 +01007487 if (!hasmeta(str->text))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007488 goto nometa;
7489 savelastp = exparg.lastp;
7490
7491 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007492 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007493 {
7494 int i = strlen(str->text);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007495//BUGGY estimation of how long expanded name can be
7496 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007497 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007498 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007499 free(expdir);
7500 if (p != str->text)
7501 free(p);
7502 INT_ON;
7503 if (exparg.lastp == savelastp) {
7504 /*
7505 * no matches
7506 */
7507 nometa:
7508 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007509 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007510 exparg.lastp = &str->next;
7511 } else {
7512 *exparg.lastp = NULL;
7513 *savelastp = sp = expsort(*savelastp);
7514 while (sp->next != NULL)
7515 sp = sp->next;
7516 exparg.lastp = &sp->next;
7517 }
7518 str = str->next;
7519 }
7520}
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007521#endif /* ENABLE_ASH_INTERNAL_GLOB */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007522
7523/*
7524 * Perform variable substitution and command substitution on an argument,
7525 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7526 * perform splitting and file name expansion. When arglist is NULL, perform
7527 * here document expansion.
7528 */
7529static void
7530expandarg(union node *arg, struct arglist *arglist, int flag)
7531{
7532 struct strlist *sp;
7533 char *p;
7534
7535 argbackq = arg->narg.backquote;
7536 STARTSTACKSTR(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007537 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007538 argstr(arg->narg.text, flag,
7539 /* var_str_list: */ arglist ? arglist->list : NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007540 p = _STPUTC('\0', expdest);
7541 expdest = p - 1;
7542 if (arglist == NULL) {
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007543 /* here document expanded */
7544 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007545 }
7546 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007547 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007548 exparg.lastp = &exparg.list;
7549 /*
7550 * TODO - EXP_REDIR
7551 */
7552 if (flag & EXP_FULL) {
7553 ifsbreakup(p, &exparg);
7554 *exparg.lastp = NULL;
7555 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007556 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007557 } else {
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007558 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007559 rmescapes(p, 0);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007560 TRACE(("expandarg: rmescapes:'%s'\n", p));
7561 }
Denis Vlasenko597906c2008-02-20 16:38:54 +00007562 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007563 sp->text = p;
7564 *exparg.lastp = sp;
7565 exparg.lastp = &sp->next;
7566 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007567 *exparg.lastp = NULL;
7568 if (exparg.list) {
7569 *arglist->lastp = exparg.list;
7570 arglist->lastp = exparg.lastp;
7571 }
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007572
7573 out:
7574 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007575}
7576
7577/*
7578 * Expand shell variables and backquotes inside a here document.
7579 */
7580static void
7581expandhere(union node *arg, int fd)
7582{
Ron Yorston549deab2015-05-18 09:57:51 +02007583 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007584 full_write(fd, stackblock(), expdest - (char *)stackblock());
7585}
7586
7587/*
7588 * Returns true if the pattern matches the string.
7589 */
7590static int
7591patmatch(char *pattern, const char *string)
7592{
Ron Yorston549deab2015-05-18 09:57:51 +02007593 return pmatch(preglob(pattern, 0), string);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007594}
7595
7596/*
7597 * See if a pattern matches in a case statement.
7598 */
7599static int
7600casematch(union node *pattern, char *val)
7601{
7602 struct stackmark smark;
7603 int result;
7604
7605 setstackmark(&smark);
7606 argbackq = pattern->narg.backquote;
7607 STARTSTACKSTR(expdest);
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007608 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7609 /* var_str_list: */ NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007610 STACKSTRNUL(expdest);
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007611 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007612 result = patmatch(stackblock(), val);
7613 popstackmark(&smark);
7614 return result;
7615}
7616
7617
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007618/* ============ find_command */
7619
7620struct builtincmd {
7621 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007622 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007623 /* unsigned flags; */
7624};
7625#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007626/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007627 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007628#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007629#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007630
7631struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007632 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007633 union param {
7634 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007635 /* index >= 0 for commands without path (slashes) */
7636 /* (TODO: what exactly does the value mean? PATH position?) */
7637 /* index == -1 for commands with slashes */
7638 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007639 const struct builtincmd *cmd;
7640 struct funcnode *func;
7641 } u;
7642};
7643/* values of cmdtype */
7644#define CMDUNKNOWN -1 /* no entry in table for command */
7645#define CMDNORMAL 0 /* command is an executable program */
7646#define CMDFUNCTION 1 /* command is a shell function */
7647#define CMDBUILTIN 2 /* command is a shell builtin */
7648
7649/* action to find_command() */
7650#define DO_ERR 0x01 /* prints errors */
7651#define DO_ABS 0x02 /* checks absolute paths */
7652#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7653#define DO_ALTPATH 0x08 /* using alternate path */
7654#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7655
7656static void find_command(char *, struct cmdentry *, int, const char *);
7657
7658
7659/* ============ Hashing commands */
7660
7661/*
7662 * When commands are first encountered, they are entered in a hash table.
7663 * This ensures that a full path search will not have to be done for them
7664 * on each invocation.
7665 *
7666 * We should investigate converting to a linear search, even though that
7667 * would make the command name "hash" a misnomer.
7668 */
7669
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007670struct tblentry {
7671 struct tblentry *next; /* next entry in hash chain */
7672 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007673 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007674 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007675 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007676};
7677
Denis Vlasenko01631112007-12-16 17:20:38 +00007678static struct tblentry **cmdtable;
7679#define INIT_G_cmdtable() do { \
7680 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7681} while (0)
7682
7683static int builtinloc = -1; /* index in path of %builtin, or -1 */
7684
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007685
7686static void
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007687tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007688{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007689#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007690 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007691 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007692 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007693 while (*envp)
7694 putenv(*envp++);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007695 run_applet_no_and_exit(applet_no, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007696 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007697 /* re-exec ourselves with the new arguments */
7698 execve(bb_busybox_exec_path, argv, envp);
7699 /* If they called chroot or otherwise made the binary no longer
7700 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007701 }
7702#endif
7703
7704 repeat:
7705#ifdef SYSV
7706 do {
7707 execve(cmd, argv, envp);
7708 } while (errno == EINTR);
7709#else
7710 execve(cmd, argv, envp);
7711#endif
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007712 if (cmd != (char*) bb_busybox_exec_path && errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007713 /* Run "cmd" as a shell script:
7714 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7715 * "If the execve() function fails with ENOEXEC, the shell
7716 * shall execute a command equivalent to having a shell invoked
7717 * with the command name as its first operand,
7718 * with any remaining arguments passed to the new shell"
7719 *
7720 * That is, do not use $SHELL, user's shell, or /bin/sh;
7721 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007722 *
7723 * Note that bash reads ~80 chars of the file, and if it sees
7724 * a zero byte before it sees newline, it doesn't try to
7725 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007726 * message and exit code 126. For one, this prevents attempts
7727 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007728 */
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007729 argv[0] = cmd;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007730 cmd = (char*) bb_busybox_exec_path;
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007731 /* NB: this is only possible because all callers of shellexec()
7732 * ensure that the argv[-1] slot exists!
7733 */
7734 argv--;
7735 argv[0] = (char*) "ash";
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007736 goto repeat;
7737 }
7738}
7739
7740/*
7741 * Exec a program. Never returns. If you change this routine, you may
7742 * have to change the find_command routine as well.
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007743 * argv[-1] must exist and be writable! See tryexec() for why.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007744 */
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007745static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN;
7746static void shellexec(char *prog, char **argv, const char *path, int idx)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007747{
7748 char *cmdname;
7749 int e;
7750 char **envp;
7751 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007752 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007753
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007754 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007755 if (strchr(prog, '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007756#if ENABLE_FEATURE_SH_STANDALONE
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007757 || (applet_no = find_applet_by_name(prog)) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007758#endif
7759 ) {
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007760 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007761 if (applet_no >= 0) {
7762 /* We tried execing ourself, but it didn't work.
7763 * Maybe /proc/self/exe doesn't exist?
7764 * Try $PATH search.
7765 */
7766 goto try_PATH;
7767 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007768 e = errno;
7769 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007770 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007771 e = ENOENT;
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007772 while ((cmdname = path_advance(&path, prog)) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007773 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007774 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007775 if (errno != ENOENT && errno != ENOTDIR)
7776 e = errno;
7777 }
7778 stunalloc(cmdname);
7779 }
7780 }
7781
7782 /* Map to POSIX errors */
7783 switch (e) {
7784 case EACCES:
7785 exerrno = 126;
7786 break;
7787 case ENOENT:
7788 exerrno = 127;
7789 break;
7790 default:
7791 exerrno = 2;
7792 break;
7793 }
7794 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007795 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007796 prog, e, suppress_int));
7797 ash_msg_and_raise(EXEXIT, "%s: %s", prog, errmsg(e, "not found"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007798 /* NOTREACHED */
7799}
7800
7801static void
7802printentry(struct tblentry *cmdp)
7803{
7804 int idx;
7805 const char *path;
7806 char *name;
7807
7808 idx = cmdp->param.index;
7809 path = pathval();
7810 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007811 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007812 stunalloc(name);
7813 } while (--idx >= 0);
7814 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7815}
7816
7817/*
7818 * Clear out command entries. The argument specifies the first entry in
7819 * PATH which has changed.
7820 */
7821static void
7822clearcmdentry(int firstchange)
7823{
7824 struct tblentry **tblp;
7825 struct tblentry **pp;
7826 struct tblentry *cmdp;
7827
7828 INT_OFF;
7829 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7830 pp = tblp;
7831 while ((cmdp = *pp) != NULL) {
7832 if ((cmdp->cmdtype == CMDNORMAL &&
7833 cmdp->param.index >= firstchange)
7834 || (cmdp->cmdtype == CMDBUILTIN &&
7835 builtinloc >= firstchange)
7836 ) {
7837 *pp = cmdp->next;
7838 free(cmdp);
7839 } else {
7840 pp = &cmdp->next;
7841 }
7842 }
7843 }
7844 INT_ON;
7845}
7846
7847/*
7848 * Locate a command in the command hash table. If "add" is nonzero,
7849 * add the command to the table if it is not already present. The
7850 * variable "lastcmdentry" is set to point to the address of the link
7851 * pointing to the entry, so that delete_cmd_entry can delete the
7852 * entry.
7853 *
7854 * Interrupts must be off if called with add != 0.
7855 */
7856static struct tblentry **lastcmdentry;
7857
7858static struct tblentry *
7859cmdlookup(const char *name, int add)
7860{
7861 unsigned int hashval;
7862 const char *p;
7863 struct tblentry *cmdp;
7864 struct tblentry **pp;
7865
7866 p = name;
7867 hashval = (unsigned char)*p << 4;
7868 while (*p)
7869 hashval += (unsigned char)*p++;
7870 hashval &= 0x7FFF;
7871 pp = &cmdtable[hashval % CMDTABLESIZE];
7872 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7873 if (strcmp(cmdp->cmdname, name) == 0)
7874 break;
7875 pp = &cmdp->next;
7876 }
7877 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007878 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7879 + strlen(name)
7880 /* + 1 - already done because
7881 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007882 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007883 cmdp->cmdtype = CMDUNKNOWN;
7884 strcpy(cmdp->cmdname, name);
7885 }
7886 lastcmdentry = pp;
7887 return cmdp;
7888}
7889
7890/*
7891 * Delete the command entry returned on the last lookup.
7892 */
7893static void
7894delete_cmd_entry(void)
7895{
7896 struct tblentry *cmdp;
7897
7898 INT_OFF;
7899 cmdp = *lastcmdentry;
7900 *lastcmdentry = cmdp->next;
7901 if (cmdp->cmdtype == CMDFUNCTION)
7902 freefunc(cmdp->param.func);
7903 free(cmdp);
7904 INT_ON;
7905}
7906
7907/*
7908 * Add a new command entry, replacing any existing command entry for
7909 * the same name - except special builtins.
7910 */
7911static void
7912addcmdentry(char *name, struct cmdentry *entry)
7913{
7914 struct tblentry *cmdp;
7915
7916 cmdp = cmdlookup(name, 1);
7917 if (cmdp->cmdtype == CMDFUNCTION) {
7918 freefunc(cmdp->param.func);
7919 }
7920 cmdp->cmdtype = entry->cmdtype;
7921 cmdp->param = entry->u;
7922 cmdp->rehash = 0;
7923}
7924
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007925static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007926hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007927{
7928 struct tblentry **pp;
7929 struct tblentry *cmdp;
7930 int c;
7931 struct cmdentry entry;
7932 char *name;
7933
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007934 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007935 clearcmdentry(0);
7936 return 0;
7937 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007938
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007939 if (*argptr == NULL) {
7940 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7941 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7942 if (cmdp->cmdtype == CMDNORMAL)
7943 printentry(cmdp);
7944 }
7945 }
7946 return 0;
7947 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007948
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007949 c = 0;
7950 while ((name = *argptr) != NULL) {
7951 cmdp = cmdlookup(name, 0);
7952 if (cmdp != NULL
7953 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007954 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7955 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007956 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007957 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007958 find_command(name, &entry, DO_ERR, pathval());
7959 if (entry.cmdtype == CMDUNKNOWN)
7960 c = 1;
7961 argptr++;
7962 }
7963 return c;
7964}
7965
7966/*
7967 * Called when a cd is done. Marks all commands so the next time they
7968 * are executed they will be rehashed.
7969 */
7970static void
7971hashcd(void)
7972{
7973 struct tblentry **pp;
7974 struct tblentry *cmdp;
7975
7976 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7977 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007978 if (cmdp->cmdtype == CMDNORMAL
7979 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02007980 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007981 && builtinloc > 0)
7982 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007983 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007984 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007985 }
7986 }
7987}
7988
7989/*
7990 * Fix command hash table when PATH changed.
7991 * Called before PATH is changed. The argument is the new value of PATH;
7992 * pathval() still returns the old value at this point.
7993 * Called with interrupts off.
7994 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007995static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007996changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007997{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007998 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007999 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008000 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008001 int idx_bltin;
8002
8003 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008004 firstchange = 9999; /* assume no change */
8005 idx = 0;
8006 idx_bltin = -1;
8007 for (;;) {
8008 if (*old != *new) {
8009 firstchange = idx;
8010 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008011 || (*old == ':' && *new == '\0')
8012 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008013 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008014 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008015 old = new; /* ignore subsequent differences */
8016 }
8017 if (*new == '\0')
8018 break;
8019 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
8020 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008021 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008022 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008023 new++;
8024 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008025 }
8026 if (builtinloc < 0 && idx_bltin >= 0)
8027 builtinloc = idx_bltin; /* zap builtins */
8028 if (builtinloc >= 0 && idx_bltin < 0)
8029 firstchange = 0;
8030 clearcmdentry(firstchange);
8031 builtinloc = idx_bltin;
8032}
Ron Yorston95ebcf72015-11-03 09:42:23 +00008033enum {
8034 TEOF,
8035 TNL,
8036 TREDIR,
8037 TWORD,
8038 TSEMI,
8039 TBACKGND,
8040 TAND,
8041 TOR,
8042 TPIPE,
8043 TLP,
8044 TRP,
8045 TENDCASE,
8046 TENDBQUOTE,
8047 TNOT,
8048 TCASE,
8049 TDO,
8050 TDONE,
8051 TELIF,
8052 TELSE,
8053 TESAC,
8054 TFI,
8055 TFOR,
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008056#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +00008057 TFUNCTION,
8058#endif
8059 TIF,
8060 TIN,
8061 TTHEN,
8062 TUNTIL,
8063 TWHILE,
8064 TBEGIN,
8065 TEND
8066};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008067typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008068
Denys Vlasenko888527c2016-10-02 16:54:17 +02008069/* Nth bit indicates if token marks the end of a list */
8070enum {
8071 tokendlist = 0
8072 /* 0 */ | (1u << TEOF)
8073 /* 1 */ | (0u << TNL)
8074 /* 2 */ | (0u << TREDIR)
8075 /* 3 */ | (0u << TWORD)
8076 /* 4 */ | (0u << TSEMI)
8077 /* 5 */ | (0u << TBACKGND)
8078 /* 6 */ | (0u << TAND)
8079 /* 7 */ | (0u << TOR)
8080 /* 8 */ | (0u << TPIPE)
8081 /* 9 */ | (0u << TLP)
8082 /* 10 */ | (1u << TRP)
8083 /* 11 */ | (1u << TENDCASE)
8084 /* 12 */ | (1u << TENDBQUOTE)
8085 /* 13 */ | (0u << TNOT)
8086 /* 14 */ | (0u << TCASE)
8087 /* 15 */ | (1u << TDO)
8088 /* 16 */ | (1u << TDONE)
8089 /* 17 */ | (1u << TELIF)
8090 /* 18 */ | (1u << TELSE)
8091 /* 19 */ | (1u << TESAC)
8092 /* 20 */ | (1u << TFI)
8093 /* 21 */ | (0u << TFOR)
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008094#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008095 /* 22 */ | (0u << TFUNCTION)
Denys Vlasenko80729a42016-10-02 22:33:15 +02008096#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008097 /* 23 */ | (0u << TIF)
8098 /* 24 */ | (0u << TIN)
8099 /* 25 */ | (1u << TTHEN)
8100 /* 26 */ | (0u << TUNTIL)
8101 /* 27 */ | (0u << TWHILE)
8102 /* 28 */ | (0u << TBEGIN)
8103 /* 29 */ | (1u << TEND)
8104 , /* thus far 29 bits used */
8105};
8106
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008107static const char *const tokname_array[] = {
Denys Vlasenko888527c2016-10-02 16:54:17 +02008108 "end of file",
8109 "newline",
8110 "redirection",
8111 "word",
8112 ";",
8113 "&",
8114 "&&",
8115 "||",
8116 "|",
8117 "(",
8118 ")",
8119 ";;",
8120 "`",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008121#define KWDOFFSET 13
8122 /* the following are keywords */
Denys Vlasenko888527c2016-10-02 16:54:17 +02008123 "!",
8124 "case",
8125 "do",
8126 "done",
8127 "elif",
8128 "else",
8129 "esac",
8130 "fi",
8131 "for",
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008132#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008133 "function",
Ron Yorston95ebcf72015-11-03 09:42:23 +00008134#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008135 "if",
8136 "in",
8137 "then",
8138 "until",
8139 "while",
8140 "{",
8141 "}",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008142};
8143
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008144/* Wrapper around strcmp for qsort/bsearch/... */
8145static int
8146pstrcmp(const void *a, const void *b)
8147{
Denys Vlasenko888527c2016-10-02 16:54:17 +02008148 return strcmp((char*)a, *(char**)b);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008149}
8150
8151static const char *const *
8152findkwd(const char *s)
8153{
8154 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00008155 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8156 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008157}
8158
8159/*
8160 * Locate and print what a word is...
8161 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008162static int
Ron Yorston3f221112015-08-03 13:47:33 +01008163describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008164{
8165 struct cmdentry entry;
8166 struct tblentry *cmdp;
8167#if ENABLE_ASH_ALIAS
8168 const struct alias *ap;
8169#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008170
8171 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008172
8173 if (describe_command_verbose) {
8174 out1str(command);
8175 }
8176
8177 /* First look at the keywords */
8178 if (findkwd(command)) {
8179 out1str(describe_command_verbose ? " is a shell keyword" : command);
8180 goto out;
8181 }
8182
8183#if ENABLE_ASH_ALIAS
8184 /* Then look at the aliases */
8185 ap = lookupalias(command, 0);
8186 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008187 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008188 out1str("alias ");
8189 printalias(ap);
8190 return 0;
8191 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00008192 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008193 goto out;
8194 }
8195#endif
8196 /* Then check if it is a tracked alias */
8197 cmdp = cmdlookup(command, 0);
8198 if (cmdp != NULL) {
8199 entry.cmdtype = cmdp->cmdtype;
8200 entry.u = cmdp->param;
8201 } else {
8202 /* Finally use brute force */
8203 find_command(command, &entry, DO_ABS, path);
8204 }
8205
8206 switch (entry.cmdtype) {
8207 case CMDNORMAL: {
8208 int j = entry.u.index;
8209 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008210 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008211 p = command;
8212 } else {
8213 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008214 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008215 stunalloc(p);
8216 } while (--j >= 0);
8217 }
8218 if (describe_command_verbose) {
8219 out1fmt(" is%s %s",
8220 (cmdp ? " a tracked alias for" : nullstr), p
8221 );
8222 } else {
8223 out1str(p);
8224 }
8225 break;
8226 }
8227
8228 case CMDFUNCTION:
8229 if (describe_command_verbose) {
8230 out1str(" is a shell function");
8231 } else {
8232 out1str(command);
8233 }
8234 break;
8235
8236 case CMDBUILTIN:
8237 if (describe_command_verbose) {
8238 out1fmt(" is a %sshell builtin",
8239 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8240 "special " : nullstr
8241 );
8242 } else {
8243 out1str(command);
8244 }
8245 break;
8246
8247 default:
8248 if (describe_command_verbose) {
8249 out1str(": not found\n");
8250 }
8251 return 127;
8252 }
8253 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008254 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008255 return 0;
8256}
8257
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008258static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008259typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008260{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008261 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008262 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008263 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008264
Denis Vlasenko46846e22007-05-20 13:08:31 +00008265 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008266 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008267 i++;
8268 verbose = 0;
8269 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008270 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008271 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008272 }
8273 return err;
8274}
8275
8276#if ENABLE_ASH_CMDCMD
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008277/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8278static char **
8279parse_command_args(char **argv, const char **path)
8280{
8281 char *cp, c;
8282
8283 for (;;) {
8284 cp = *++argv;
8285 if (!cp)
8286 return NULL;
8287 if (*cp++ != '-')
8288 break;
8289 c = *cp++;
8290 if (!c)
8291 break;
8292 if (c == '-' && !*cp) {
8293 if (!*++argv)
8294 return NULL;
8295 break;
8296 }
8297 do {
8298 switch (c) {
8299 case 'p':
8300 *path = bb_default_path;
8301 break;
8302 default:
8303 /* run 'typecmd' for other options */
8304 return NULL;
8305 }
8306 c = *cp++;
8307 } while (c);
8308 }
8309 return argv;
8310}
8311
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008312static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008313commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008314{
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008315 char *cmd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008316 int c;
8317 enum {
8318 VERIFY_BRIEF = 1,
8319 VERIFY_VERBOSE = 2,
8320 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008321 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008322
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008323 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8324 * never reaches this function.
8325 */
8326
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008327 while ((c = nextopt("pvV")) != '\0')
8328 if (c == 'V')
8329 verify |= VERIFY_VERBOSE;
8330 else if (c == 'v')
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008331 /*verify |= VERIFY_BRIEF*/;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008332#if DEBUG
8333 else if (c != 'p')
8334 abort();
8335#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008336 else
8337 path = bb_default_path;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008338
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008339 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008340 cmd = *argptr;
8341 if (/*verify && */ cmd)
8342 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008343
8344 return 0;
8345}
8346#endif
8347
8348
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008349/*static int funcblocksize; // size of structures in function */
8350/*static int funcstringsize; // size of strings in node */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008351static void *funcblock; /* block to allocate function from */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008352static char *funcstring_end; /* end of block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008353
Eric Andersencb57d552001-06-28 07:25:16 +00008354/* flags in argument to evaltree */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008355#define EV_EXIT 01 /* exit after evaluating tree */
8356#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Eric Andersencb57d552001-06-28 07:25:16 +00008357
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008358static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008359 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8360 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8361 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8362 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8363 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8364 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8365 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8366 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8367 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8368 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8369 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8370 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8371 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8372 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8373 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8374 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8375 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008376#if BASH_REDIR_OUTPUT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008377 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008378#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008379 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8380 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8381 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8382 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8383 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8384 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8385 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8386 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8387 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008388};
8389
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008390static int calcsize(int funcblocksize, union node *n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008391
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008392static int
8393sizenodelist(int funcblocksize, struct nodelist *lp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008394{
8395 while (lp) {
8396 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008397 funcblocksize = calcsize(funcblocksize, lp->n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008398 lp = lp->next;
8399 }
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008400 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008401}
8402
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008403static int
8404calcsize(int funcblocksize, union node *n)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008405{
8406 if (n == NULL)
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008407 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008408 funcblocksize += nodesize[n->type];
8409 switch (n->type) {
8410 case NCMD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008411 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8412 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8413 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008414 break;
8415 case NPIPE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008416 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008417 break;
8418 case NREDIR:
8419 case NBACKGND:
8420 case NSUBSHELL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008421 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8422 funcblocksize = calcsize(funcblocksize, n->nredir.n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008423 break;
8424 case NAND:
8425 case NOR:
8426 case NSEMI:
8427 case NWHILE:
8428 case NUNTIL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008429 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8430 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008431 break;
8432 case NIF:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008433 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8434 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8435 funcblocksize = calcsize(funcblocksize, n->nif.test);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008436 break;
8437 case NFOR:
Denys Vlasenko561639a2016-10-07 04:28:33 +02008438 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008439 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8440 funcblocksize = calcsize(funcblocksize, n->nfor.args);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008441 break;
8442 case NCASE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008443 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8444 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008445 break;
8446 case NCLIST:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008447 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8448 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8449 funcblocksize = calcsize(funcblocksize, n->nclist.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008450 break;
8451 case NDEFUN:
8452 case NARG:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008453 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
Denys Vlasenko561639a2016-10-07 04:28:33 +02008454 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008455 funcblocksize = calcsize(funcblocksize, n->narg.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008456 break;
8457 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008458#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008459 case NTO2:
8460#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008461 case NCLOBBER:
8462 case NFROM:
8463 case NFROMTO:
8464 case NAPPEND:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008465 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8466 funcblocksize = calcsize(funcblocksize, n->nfile.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008467 break;
8468 case NTOFD:
8469 case NFROMFD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008470 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8471 funcblocksize = calcsize(funcblocksize, n->ndup.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008472 break;
8473 case NHERE:
8474 case NXHERE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008475 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8476 funcblocksize = calcsize(funcblocksize, n->nhere.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008477 break;
8478 case NNOT:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008479 funcblocksize = calcsize(funcblocksize, n->nnot.com);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008480 break;
8481 };
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008482 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008483}
8484
8485static char *
8486nodeckstrdup(char *s)
8487{
Denys Vlasenko561639a2016-10-07 04:28:33 +02008488 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008489 return strcpy(funcstring_end, s);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008490}
8491
8492static union node *copynode(union node *);
8493
8494static struct nodelist *
8495copynodelist(struct nodelist *lp)
8496{
8497 struct nodelist *start;
8498 struct nodelist **lpp;
8499
8500 lpp = &start;
8501 while (lp) {
8502 *lpp = funcblock;
8503 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8504 (*lpp)->n = copynode(lp->n);
8505 lp = lp->next;
8506 lpp = &(*lpp)->next;
8507 }
8508 *lpp = NULL;
8509 return start;
8510}
8511
8512static union node *
8513copynode(union node *n)
8514{
8515 union node *new;
8516
8517 if (n == NULL)
8518 return NULL;
8519 new = funcblock;
8520 funcblock = (char *) funcblock + nodesize[n->type];
8521
8522 switch (n->type) {
8523 case NCMD:
8524 new->ncmd.redirect = copynode(n->ncmd.redirect);
8525 new->ncmd.args = copynode(n->ncmd.args);
8526 new->ncmd.assign = copynode(n->ncmd.assign);
8527 break;
8528 case NPIPE:
8529 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008530 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008531 break;
8532 case NREDIR:
8533 case NBACKGND:
8534 case NSUBSHELL:
8535 new->nredir.redirect = copynode(n->nredir.redirect);
8536 new->nredir.n = copynode(n->nredir.n);
8537 break;
8538 case NAND:
8539 case NOR:
8540 case NSEMI:
8541 case NWHILE:
8542 case NUNTIL:
8543 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8544 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8545 break;
8546 case NIF:
8547 new->nif.elsepart = copynode(n->nif.elsepart);
8548 new->nif.ifpart = copynode(n->nif.ifpart);
8549 new->nif.test = copynode(n->nif.test);
8550 break;
8551 case NFOR:
8552 new->nfor.var = nodeckstrdup(n->nfor.var);
8553 new->nfor.body = copynode(n->nfor.body);
8554 new->nfor.args = copynode(n->nfor.args);
8555 break;
8556 case NCASE:
8557 new->ncase.cases = copynode(n->ncase.cases);
8558 new->ncase.expr = copynode(n->ncase.expr);
8559 break;
8560 case NCLIST:
8561 new->nclist.body = copynode(n->nclist.body);
8562 new->nclist.pattern = copynode(n->nclist.pattern);
8563 new->nclist.next = copynode(n->nclist.next);
8564 break;
8565 case NDEFUN:
8566 case NARG:
8567 new->narg.backquote = copynodelist(n->narg.backquote);
8568 new->narg.text = nodeckstrdup(n->narg.text);
8569 new->narg.next = copynode(n->narg.next);
8570 break;
8571 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008572#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008573 case NTO2:
8574#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008575 case NCLOBBER:
8576 case NFROM:
8577 case NFROMTO:
8578 case NAPPEND:
8579 new->nfile.fname = copynode(n->nfile.fname);
8580 new->nfile.fd = n->nfile.fd;
8581 new->nfile.next = copynode(n->nfile.next);
8582 break;
8583 case NTOFD:
8584 case NFROMFD:
8585 new->ndup.vname = copynode(n->ndup.vname);
8586 new->ndup.dupfd = n->ndup.dupfd;
8587 new->ndup.fd = n->ndup.fd;
8588 new->ndup.next = copynode(n->ndup.next);
8589 break;
8590 case NHERE:
8591 case NXHERE:
8592 new->nhere.doc = copynode(n->nhere.doc);
8593 new->nhere.fd = n->nhere.fd;
8594 new->nhere.next = copynode(n->nhere.next);
8595 break;
8596 case NNOT:
8597 new->nnot.com = copynode(n->nnot.com);
8598 break;
8599 };
8600 new->type = n->type;
8601 return new;
8602}
8603
8604/*
8605 * Make a copy of a parse tree.
8606 */
8607static struct funcnode *
8608copyfunc(union node *n)
8609{
8610 struct funcnode *f;
8611 size_t blocksize;
8612
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008613 /*funcstringsize = 0;*/
8614 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8615 f = ckzalloc(blocksize /* + funcstringsize */);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008616 funcblock = (char *) f + offsetof(struct funcnode, n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008617 funcstring_end = (char *) f + blocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008618 copynode(n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008619 /* f->count = 0; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008620 return f;
8621}
8622
8623/*
8624 * Define a shell function.
8625 */
8626static void
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008627defun(union node *func)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008628{
8629 struct cmdentry entry;
8630
8631 INT_OFF;
8632 entry.cmdtype = CMDFUNCTION;
8633 entry.u.func = copyfunc(func);
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008634 addcmdentry(func->narg.text, &entry);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008635 INT_ON;
8636}
8637
Denis Vlasenko4b875702009-03-19 13:30:04 +00008638/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008639#define SKIPBREAK (1 << 0)
8640#define SKIPCONT (1 << 1)
8641#define SKIPFUNC (1 << 2)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008642static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008643static int skipcount; /* number of levels to skip */
8644static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008645static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008646
Denis Vlasenko4b875702009-03-19 13:30:04 +00008647/* Forward decl way out to parsing code - dotrap needs it */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008648static int evalstring(char *s, int flags);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008649
Denis Vlasenko4b875702009-03-19 13:30:04 +00008650/* Called to execute a trap.
8651 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008652 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008653 *
8654 * Perhaps we should avoid entering new trap handlers
8655 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008656 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008657static void
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008658dotrap(void)
8659{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008660 uint8_t *g;
8661 int sig;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008662 uint8_t last_status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008663
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008664 if (!pending_sig)
8665 return;
8666
8667 last_status = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008668 pending_sig = 0;
Denys Vlasenkode892052016-10-02 01:49:13 +02008669 barrier();
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008670
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008671 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008672 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008673 char *p;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008674
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008675 if (!*g)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008676 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008677
8678 if (evalskip) {
8679 pending_sig = sig;
8680 break;
8681 }
8682
8683 p = trap[sig];
Denis Vlasenko4b875702009-03-19 13:30:04 +00008684 /* non-trapped SIGINT is handled separately by raise_interrupt,
8685 * don't upset it by resetting gotsig[SIGINT-1] */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008686 if (sig == SIGINT && !p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008687 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008688
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008689 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008690 *g = 0;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008691 if (!p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008692 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008693 evalstring(p, 0);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008694 }
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008695 exitstatus = last_status;
8696 TRACE(("dotrap returns\n"));
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008697}
8698
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008699/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008700static int evalloop(union node *, int);
8701static int evalfor(union node *, int);
8702static int evalcase(union node *, int);
8703static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008704static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008705static int evalpipe(union node *, int);
8706static int evalcommand(union node *, int);
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008707static int evalbltin(const struct builtincmd *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008708static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008709
Eric Andersen62483552001-07-10 06:09:16 +00008710/*
Eric Andersenc470f442003-07-28 09:56:35 +00008711 * Evaluate a parse tree. The value is left in the global variable
8712 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008713 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008714static int
Eric Andersenc470f442003-07-28 09:56:35 +00008715evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008716{
Eric Andersenc470f442003-07-28 09:56:35 +00008717 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008718 int (*evalfn)(union node *, int);
8719 int status = 0;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008720
Eric Andersenc470f442003-07-28 09:56:35 +00008721 if (n == NULL) {
8722 TRACE(("evaltree(NULL) called\n"));
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02008723 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00008724 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008725 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008726
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008727 dotrap();
8728
Eric Andersenc470f442003-07-28 09:56:35 +00008729 switch (n->type) {
8730 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008731#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008732 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008733 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008734 break;
8735#endif
8736 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008737 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008738 goto setstatus;
8739 case NREDIR:
8740 expredir(n->nredir.redirect);
8741 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8742 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008743 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008744 }
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02008745 if (n->nredir.redirect)
8746 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
Eric Andersenc470f442003-07-28 09:56:35 +00008747 goto setstatus;
8748 case NCMD:
8749 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008750 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008751 if (eflag && !(flags & EV_TESTED))
8752 checkexit = ~0;
8753 goto calleval;
8754 case NFOR:
8755 evalfn = evalfor;
8756 goto calleval;
8757 case NWHILE:
8758 case NUNTIL:
8759 evalfn = evalloop;
8760 goto calleval;
8761 case NSUBSHELL:
8762 case NBACKGND:
8763 evalfn = evalsubshell;
Denys Vlasenkocf98b0c2016-10-25 18:19:39 +02008764 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00008765 case NPIPE:
8766 evalfn = evalpipe;
8767 goto checkexit;
8768 case NCASE:
8769 evalfn = evalcase;
8770 goto calleval;
8771 case NAND:
8772 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008773 case NSEMI: {
8774
Eric Andersenc470f442003-07-28 09:56:35 +00008775#if NAND + 1 != NOR
8776#error NAND + 1 != NOR
8777#endif
8778#if NOR + 1 != NSEMI
8779#error NOR + 1 != NSEMI
8780#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008781 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008782 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00008783 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008784 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008785 );
Denys Vlasenkobc1a0082016-10-02 15:31:33 +02008786 if ((!status) == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00008787 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008788 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008789 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008790 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008791 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008792 status = evalfn(n, flags);
8793 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008794 }
Eric Andersenc470f442003-07-28 09:56:35 +00008795 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008796 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008797 if (evalskip)
8798 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008799 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00008800 n = n->nif.ifpart;
8801 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008802 }
8803 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008804 n = n->nif.elsepart;
8805 goto evaln;
8806 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008807 status = 0;
8808 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00008809 case NDEFUN:
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008810 defun(n);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008811 /* Not necessary. To test it:
8812 * "false; f() { qwerty; }; echo $?" should print 0.
8813 */
8814 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008815 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00008816 exitstatus = status;
8817 break;
8818 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008819 out:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008820 /* Order of checks below is important:
8821 * signal handlers trigger before exit caused by "set -e".
8822 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008823 dotrap();
8824
8825 if (checkexit & status)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008826 raise_exception(EXEXIT);
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008827 if (flags & EV_EXIT)
8828 raise_exception(EXEXIT);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008829
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008830 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008831 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00008832}
8833
Eric Andersenc470f442003-07-28 09:56:35 +00008834#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8835static
8836#endif
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008837int evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
Eric Andersenc470f442003-07-28 09:56:35 +00008838
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02008839static int
8840skiploop(void)
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008841{
8842 int skip = evalskip;
8843
8844 switch (skip) {
8845 case 0:
8846 break;
8847 case SKIPBREAK:
8848 case SKIPCONT:
8849 if (--skipcount <= 0) {
8850 evalskip = 0;
8851 break;
8852 }
8853 skip = SKIPBREAK;
8854 break;
8855 }
8856 return skip;
8857}
8858
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008859static int
Eric Andersenc470f442003-07-28 09:56:35 +00008860evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008861{
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008862 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00008863 int status;
8864
8865 loopnest++;
8866 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008867 flags &= EV_TESTED;
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008868 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008869 int i;
8870
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008871 i = evaltree(n->nbinary.ch1, EV_TESTED);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008872 skip = skiploop();
8873 if (skip == SKIPFUNC)
8874 status = i;
8875 if (skip)
8876 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00008877 if (n->type != NWHILE)
8878 i = !i;
8879 if (i != 0)
8880 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008881 status = evaltree(n->nbinary.ch2, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008882 skip = skiploop();
8883 } while (!(skip & ~SKIPCONT));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008884 loopnest--;
8885
8886 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008887}
8888
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008889static int
Eric Andersenc470f442003-07-28 09:56:35 +00008890evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008891{
8892 struct arglist arglist;
8893 union node *argp;
8894 struct strlist *sp;
8895 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008896 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008897
8898 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008899 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008900 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008901 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02008902 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersencb57d552001-06-28 07:25:16 +00008903 }
8904 *arglist.lastp = NULL;
8905
Eric Andersencb57d552001-06-28 07:25:16 +00008906 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008907 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008908 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008909 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008910 status = evaltree(n->nfor.body, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008911 if (skiploop() & ~SKIPCONT)
Eric Andersencb57d552001-06-28 07:25:16 +00008912 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008913 }
8914 loopnest--;
Eric Andersencb57d552001-06-28 07:25:16 +00008915 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008916
8917 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008918}
8919
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008920static int
Eric Andersenc470f442003-07-28 09:56:35 +00008921evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008922{
8923 union node *cp;
8924 union node *patp;
8925 struct arglist arglist;
8926 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008927 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008928
8929 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008930 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008931 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00008932 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008933 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8934 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008935 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008936 /* Ensure body is non-empty as otherwise
8937 * EV_EXIT may prevent us from setting the
8938 * exit status.
8939 */
8940 if (evalskip == 0 && cp->nclist.body) {
8941 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008942 }
8943 goto out;
8944 }
8945 }
8946 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008947 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008948 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008949
8950 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008951}
8952
Eric Andersenc470f442003-07-28 09:56:35 +00008953/*
8954 * Kick off a subshell to evaluate a tree.
8955 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008956static int
Eric Andersenc470f442003-07-28 09:56:35 +00008957evalsubshell(union node *n, int flags)
8958{
8959 struct job *jp;
Denys Vlasenko098b7132017-01-11 19:59:03 +01008960 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
Eric Andersenc470f442003-07-28 09:56:35 +00008961 int status;
8962
8963 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02008964 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00008965 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008966 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01008967 if (backgnd == FORK_FG)
8968 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00008969 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008970 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02008971 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008972 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008973 flags |= EV_EXIT;
8974 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02008975 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00008976 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00008977 redirect(n->nredir.redirect, 0);
8978 evaltreenr(n->nredir.n, flags);
8979 /* never returns */
8980 }
Denys Vlasenko70392332016-10-27 02:31:55 +02008981 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00008982 status = 0;
Denys Vlasenko098b7132017-01-11 19:59:03 +01008983 if (backgnd == FORK_FG)
Eric Andersenc470f442003-07-28 09:56:35 +00008984 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00008985 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008986 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00008987}
8988
Eric Andersenc470f442003-07-28 09:56:35 +00008989/*
8990 * Compute the names of the files in a redirection list.
8991 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00008992static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008993static void
8994expredir(union node *n)
8995{
8996 union node *redir;
8997
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008998 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00008999 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009000
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009001 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009002 fn.lastp = &fn.list;
9003 switch (redir->type) {
9004 case NFROMTO:
9005 case NFROM:
9006 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009007#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009008 case NTO2:
9009#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009010 case NCLOBBER:
9011 case NAPPEND:
9012 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02009013 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009014#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009015 store_expfname:
9016#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009017#if 0
9018// By the design of stack allocator, the loop of this kind:
9019// while true; do while true; do break; done </dev/null; done
9020// will look like a memory leak: ash plans to free expfname's
9021// of "/dev/null" as soon as it finishes running the loop
9022// (in this case, never).
9023// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01009024 if (redir->nfile.expfname)
9025 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009026// It results in corrupted state of stacked allocations.
9027#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009028 redir->nfile.expfname = fn.list->text;
9029 break;
9030 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00009031 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00009032 if (redir->ndup.vname) {
9033 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009034 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009035 ash_msg_and_raise_error("redir error");
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009036#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009037//FIXME: we used expandarg with different args!
9038 if (!isdigit_str9(fn.list->text)) {
9039 /* >&file, not >&fd */
9040 if (redir->nfile.fd != 1) /* 123>&file - BAD */
9041 ash_msg_and_raise_error("redir error");
9042 redir->type = NTO2;
9043 goto store_expfname;
9044 }
9045#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009046 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009047 }
9048 break;
9049 }
9050 }
9051}
9052
Eric Andersencb57d552001-06-28 07:25:16 +00009053/*
Eric Andersencb57d552001-06-28 07:25:16 +00009054 * Evaluate a pipeline. All the processes in the pipeline are children
9055 * of the process creating the pipeline. (This differs from some versions
9056 * of the shell, which make the last process in a pipeline the parent
9057 * of all the rest.)
9058 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009059static int
Eric Andersenc470f442003-07-28 09:56:35 +00009060evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009061{
9062 struct job *jp;
9063 struct nodelist *lp;
9064 int pipelen;
9065 int prevfd;
9066 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009067 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009068
Eric Andersenc470f442003-07-28 09:56:35 +00009069 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00009070 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009071 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00009072 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009073 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009074 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009075 if (n->npipe.pipe_backgnd == 0)
9076 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009077 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00009078 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009079 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009080 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00009081 pip[1] = -1;
9082 if (lp->next) {
9083 if (pipe(pip) < 0) {
9084 close(prevfd);
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00009085 ash_msg_and_raise_error("pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00009086 }
9087 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009088 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02009089 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009090 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00009091 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009092 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00009093 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009094 if (prevfd > 0) {
9095 dup2(prevfd, 0);
9096 close(prevfd);
9097 }
9098 if (pip[1] > 1) {
9099 dup2(pip[1], 1);
9100 close(pip[1]);
9101 }
Eric Andersenc470f442003-07-28 09:56:35 +00009102 evaltreenr(lp->n, flags);
9103 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00009104 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009105 /* parent */
Eric Andersencb57d552001-06-28 07:25:16 +00009106 if (prevfd >= 0)
9107 close(prevfd);
9108 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00009109 /* Don't want to trigger debugging */
9110 if (pip[1] != -1)
9111 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009112 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009113 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009114 status = waitforjob(jp);
9115 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00009116 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009117 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009118
9119 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009120}
9121
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009122/*
9123 * Controls whether the shell is interactive or not.
9124 */
9125static void
9126setinteractive(int on)
9127{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009128 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009129
9130 if (++on == is_interactive)
9131 return;
9132 is_interactive = on;
9133 setsignal(SIGINT);
9134 setsignal(SIGQUIT);
9135 setsignal(SIGTERM);
9136#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9137 if (is_interactive > 1) {
9138 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009139 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009140
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009141 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009142 /* note: ash and hush share this string */
9143 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009144 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9145 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009146 bb_banner,
9147 "built-in shell (ash)"
9148 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009149 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009150 }
9151 }
9152#endif
9153}
9154
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009155static void
9156optschanged(void)
9157{
9158#if DEBUG
9159 opentrace();
9160#endif
9161 setinteractive(iflag);
9162 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009163#if ENABLE_FEATURE_EDITING_VI
9164 if (viflag)
9165 line_input_state->flags |= VI_MODE;
9166 else
9167 line_input_state->flags &= ~VI_MODE;
9168#else
9169 viflag = 0; /* forcibly keep the option off */
9170#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009171}
9172
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009173static struct localvar *localvars;
9174
9175/*
9176 * Called after a function returns.
9177 * Interrupts must be off.
9178 */
9179static void
9180poplocalvars(void)
9181{
9182 struct localvar *lvp;
9183 struct var *vp;
9184
9185 while ((lvp = localvars) != NULL) {
9186 localvars = lvp->next;
9187 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02009188 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009189 if (vp == NULL) { /* $- saved */
9190 memcpy(optlist, lvp->text, sizeof(optlist));
9191 free((char*)lvp->text);
9192 optschanged();
9193 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009194 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009195 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009196 if (vp->var_func)
9197 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009198 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009199 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009200 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009201 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009202 }
9203 free(lvp);
9204 }
9205}
9206
9207static int
9208evalfun(struct funcnode *func, int argc, char **argv, int flags)
9209{
9210 volatile struct shparam saveparam;
9211 struct localvar *volatile savelocalvars;
9212 struct jmploc *volatile savehandler;
9213 struct jmploc jmploc;
9214 int e;
9215
9216 saveparam = shellparam;
9217 savelocalvars = localvars;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009218 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009219 e = setjmp(jmploc.loc);
9220 if (e) {
9221 goto funcdone;
9222 }
9223 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009224 exception_handler = &jmploc;
9225 localvars = NULL;
Denis Vlasenko01631112007-12-16 17:20:38 +00009226 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009227 func->count++;
9228 funcnest++;
9229 INT_ON;
9230 shellparam.nparam = argc - 1;
9231 shellparam.p = argv + 1;
9232#if ENABLE_ASH_GETOPTS
9233 shellparam.optind = 1;
9234 shellparam.optoff = -1;
9235#endif
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009236 evaltree(func->n.narg.next, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00009237 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009238 INT_OFF;
9239 funcnest--;
9240 freefunc(func);
9241 poplocalvars();
9242 localvars = savelocalvars;
9243 freeparam(&shellparam);
9244 shellparam = saveparam;
9245 exception_handler = savehandler;
9246 INT_ON;
9247 evalskip &= ~SKIPFUNC;
9248 return e;
9249}
9250
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009251/*
9252 * Make a variable a local variable. When a variable is made local, it's
9253 * value and flags are saved in a localvar structure. The saved values
9254 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009255 * "-" as a special case: it makes changes to "set +-options" local
9256 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009257 */
9258static void
9259mklocal(char *name)
9260{
9261 struct localvar *lvp;
9262 struct var **vpp;
9263 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009264 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009265
9266 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009267 /* Cater for duplicate "local". Examples:
9268 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9269 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9270 */
9271 lvp = localvars;
9272 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009273 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009274 if (eq)
9275 setvareq(name, 0);
9276 /* else:
9277 * it's a duplicate "local VAR" declaration, do nothing
9278 */
Denys Vlasenko06b11492016-11-04 16:43:18 +01009279 goto ret;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009280 }
9281 lvp = lvp->next;
9282 }
9283
9284 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009285 if (LONE_DASH(name)) {
9286 char *p;
9287 p = ckmalloc(sizeof(optlist));
9288 lvp->text = memcpy(p, optlist, sizeof(optlist));
9289 vp = NULL;
9290 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009291 vpp = hashvar(name);
9292 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009293 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009294 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009295 if (eq)
9296 setvareq(name, VSTRFIXED);
9297 else
9298 setvar(name, NULL, VSTRFIXED);
9299 vp = *vpp; /* the new variable */
9300 lvp->flags = VUNSET;
9301 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009302 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009303 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009304 /* make sure neither "struct var" nor string gets freed
9305 * during (un)setting:
9306 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009307 vp->flags |= VSTRFIXED|VTEXTFIXED;
9308 if (eq)
9309 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009310 else
9311 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009312 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009313 }
9314 }
9315 lvp->vp = vp;
9316 lvp->next = localvars;
9317 localvars = lvp;
Denys Vlasenko06b11492016-11-04 16:43:18 +01009318 ret:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009319 INT_ON;
9320}
9321
9322/*
9323 * The "local" command.
9324 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009325static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009326localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009327{
9328 char *name;
9329
Ron Yorstonef2386b2015-10-29 16:19:14 +00009330 if (!funcnest)
9331 ash_msg_and_raise_error("not in a function");
9332
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009333 argv = argptr;
9334 while ((name = *argv++) != NULL) {
9335 mklocal(name);
9336 }
9337 return 0;
9338}
9339
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009340static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009341falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009342{
9343 return 1;
9344}
9345
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009346static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009347truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009348{
9349 return 0;
9350}
9351
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009352static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009353execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009354{
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009355 optionarg = NULL;
9356 while (nextopt("a:") != '\0')
9357 /* nextopt() sets optionarg to "-a ARGV0" */;
9358
9359 argv = argptr;
9360 if (argv[0]) {
9361 char *prog;
9362
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009363 iflag = 0; /* exit on error */
9364 mflag = 0;
9365 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009366 /* We should set up signals for "exec CMD"
9367 * the same way as for "CMD" without "exec".
9368 * But optschanged->setinteractive->setsignal
9369 * still thought we are a root shell. Therefore, for example,
9370 * SIGQUIT is still set to IGN. Fix it:
9371 */
9372 shlvl++;
9373 setsignal(SIGQUIT);
9374 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9375 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9376 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9377
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009378 prog = argv[0];
9379 if (optionarg)
9380 argv[0] = optionarg;
9381 shellexec(prog, argv, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009382 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009383 }
9384 return 0;
9385}
9386
9387/*
9388 * The return command.
9389 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009390static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009391returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009392{
9393 /*
9394 * If called outside a function, do what ksh does;
9395 * skip the rest of the file.
9396 */
Denys Vlasenko6a0710e2016-09-30 14:18:34 +02009397 evalskip = SKIPFUNC;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009398 return argv[1] ? number(argv[1]) : exitstatus;
9399}
9400
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009401/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009402static int breakcmd(int, char **) FAST_FUNC;
9403static int dotcmd(int, char **) FAST_FUNC;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009404static int evalcmd(int, char **, int) FAST_FUNC;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009405static int exitcmd(int, char **) FAST_FUNC;
9406static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009407#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009408static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009409#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009410#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009411static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009412#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009413#if MAX_HISTORY
9414static int historycmd(int, char **) FAST_FUNC;
9415#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009416#if ENABLE_FEATURE_SH_MATH
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009417static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009418#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009419static int readcmd(int, char **) FAST_FUNC;
9420static int setcmd(int, char **) FAST_FUNC;
9421static int shiftcmd(int, char **) FAST_FUNC;
9422static int timescmd(int, char **) FAST_FUNC;
9423static int trapcmd(int, char **) FAST_FUNC;
9424static int umaskcmd(int, char **) FAST_FUNC;
9425static int unsetcmd(int, char **) FAST_FUNC;
9426static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009427
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009428#define BUILTIN_NOSPEC "0"
9429#define BUILTIN_SPECIAL "1"
9430#define BUILTIN_REGULAR "2"
9431#define BUILTIN_SPEC_REG "3"
9432#define BUILTIN_ASSIGN "4"
9433#define BUILTIN_SPEC_ASSG "5"
9434#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009435#define BUILTIN_SPEC_REG_ASSG "7"
9436
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009437/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko265062d2017-01-10 15:13:30 +01009438#if ENABLE_ASH_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009439static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009440#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009441#if ENABLE_ASH_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009442static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009443#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009444#if ENABLE_ASH_TEST || BASH_TEST2
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009445static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009446#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009447
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009448/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009449static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009450 { BUILTIN_SPEC_REG "." , dotcmd },
9451 { BUILTIN_SPEC_REG ":" , truecmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009452#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009453 { BUILTIN_REGULAR "[" , testcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009454#endif
9455#if BASH_TEST2
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009456 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009457#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009458#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009459 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009460#endif
9461#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009462 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009463#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009464 { BUILTIN_SPEC_REG "break" , breakcmd },
9465 { BUILTIN_REGULAR "cd" , cdcmd },
9466 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009467#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009468 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009469#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009470 { BUILTIN_SPEC_REG "continue", breakcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009471#if ENABLE_ASH_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009472 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009473#endif
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009474 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009475 { BUILTIN_SPEC_REG "exec" , execcmd },
9476 { BUILTIN_SPEC_REG "exit" , exitcmd },
9477 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9478 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009479#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009480 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009481#endif
9482#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009483 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009484#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009485 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009486#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009487 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009488#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009489#if MAX_HISTORY
9490 { BUILTIN_NOSPEC "history" , historycmd },
9491#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009492#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009493 { BUILTIN_REGULAR "jobs" , jobscmd },
9494 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009495#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009496#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009497 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009498#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009499 { BUILTIN_ASSIGN "local" , localcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009500#if ENABLE_ASH_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009501 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009502#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009503 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9504 { BUILTIN_REGULAR "read" , readcmd },
9505 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9506 { BUILTIN_SPEC_REG "return" , returncmd },
9507 { BUILTIN_SPEC_REG "set" , setcmd },
9508 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009509#if BASH_SOURCE
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009510 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009511#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009512#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009513 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009514#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009515 { BUILTIN_SPEC_REG "times" , timescmd },
9516 { BUILTIN_SPEC_REG "trap" , trapcmd },
9517 { BUILTIN_REGULAR "true" , truecmd },
9518 { BUILTIN_NOSPEC "type" , typecmd },
9519 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9520 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009521#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009522 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009523#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009524 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9525 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009526};
9527
Denis Vlasenko80591b02008-03-25 07:49:43 +00009528/* Should match the above table! */
9529#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009530 /* . : */ 2 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009531 /* [ */ 1 * ENABLE_ASH_TEST + \
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009532 /* [[ */ 1 * BASH_TEST2 + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009533 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9534 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9535 /* break cd cddir */ 3)
9536#define EVALCMD (COMMANDCMD + \
9537 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9538 /* continue */ 1 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009539 /* echo */ 1 * ENABLE_ASH_ECHO + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009540 0)
9541#define EXECCMD (EVALCMD + \
9542 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009543
9544/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009545 * Search the table of builtin commands.
9546 */
Denys Vlasenko888527c2016-10-02 16:54:17 +02009547static int
9548pstrcmp1(const void *a, const void *b)
9549{
9550 return strcmp((char*)a, *(char**)b + 1);
9551}
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009552static struct builtincmd *
9553find_builtin(const char *name)
9554{
9555 struct builtincmd *bp;
9556
9557 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009558 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denys Vlasenko888527c2016-10-02 16:54:17 +02009559 pstrcmp1
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009560 );
9561 return bp;
9562}
9563
9564/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009565 * Execute a simple command.
9566 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009567static int
9568isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009569{
9570 const char *q = endofname(p);
9571 if (p == q)
9572 return 0;
9573 return *q == '=';
9574}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009575static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009576bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009577{
9578 /* Preserve exitstatus of a previous possible redirection
9579 * as POSIX mandates */
9580 return back_exitstatus;
9581}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009582static int
Eric Andersenc470f442003-07-28 09:56:35 +00009583evalcommand(union node *cmd, int flags)
9584{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009585 static const struct builtincmd null_bltin = {
9586 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009587 };
Eric Andersenc470f442003-07-28 09:56:35 +00009588 struct stackmark smark;
9589 union node *argp;
9590 struct arglist arglist;
9591 struct arglist varlist;
9592 char **argv;
9593 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009594 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009595 struct cmdentry cmdentry;
9596 struct job *jp;
9597 char *lastarg;
9598 const char *path;
9599 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009600 int status;
9601 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00009602 struct builtincmd *bcmd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009603 smallint cmd_is_exec;
9604 smallint pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009605
9606 /* First expand the arguments. */
9607 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9608 setstackmark(&smark);
9609 back_exitstatus = 0;
9610
9611 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009612 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009613 varlist.lastp = &varlist.list;
9614 *varlist.lastp = NULL;
9615 arglist.lastp = &arglist.list;
9616 *arglist.lastp = NULL;
9617
9618 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009619 if (cmd->ncmd.args) {
Paul Foxc3850c82005-07-20 18:23:39 +00009620 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9621 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9622 }
9623
Eric Andersenc470f442003-07-28 09:56:35 +00009624 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9625 struct strlist **spp;
9626
9627 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00009628 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00009629 expandarg(argp, &arglist, EXP_VARTILDE);
9630 else
9631 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9632
Eric Andersenc470f442003-07-28 09:56:35 +00009633 for (sp = *spp; sp; sp = sp->next)
9634 argc++;
9635 }
9636
Denys Vlasenko65a8b852016-10-26 22:29:11 +02009637 /* Reserve one extra spot at the front for shellexec. */
9638 nargv = stalloc(sizeof(char *) * (argc + 2));
9639 argv = ++nargv;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009640 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009641 TRACE(("evalcommand arg: %s\n", sp->text));
9642 *nargv++ = sp->text;
9643 }
9644 *nargv = NULL;
9645
9646 lastarg = NULL;
9647 if (iflag && funcnest == 0 && argc > 0)
9648 lastarg = nargv[-1];
9649
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009650 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009651 expredir(cmd->ncmd.redirect);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009652 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009653
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009654 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009655 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9656 struct strlist **spp;
9657 char *p;
9658
9659 spp = varlist.lastp;
9660 expandarg(argp, &varlist, EXP_VARTILDE);
9661
9662 /*
9663 * Modify the command lookup path, if a PATH= assignment
9664 * is present
9665 */
9666 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009667 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009668 path = p;
9669 }
9670
9671 /* Print the command if xflag is set. */
9672 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009673 int n;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009674 const char *p = " %s" + 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009675
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009676 fdprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009677 sp = varlist.list;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009678 for (n = 0; n < 2; n++) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009679 while (sp) {
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009680 fdprintf(preverrout_fd, p, sp->text);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009681 sp = sp->next;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009682 p = " %s";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009683 }
9684 sp = arglist.list;
9685 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009686 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009687 }
9688
9689 cmd_is_exec = 0;
9690 spclbltin = -1;
9691
9692 /* Now locate the command. */
9693 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009694 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02009695#if ENABLE_ASH_CMDCMD
9696 const char *oldpath = path + 5;
9697#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009698 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009699 for (;;) {
9700 find_command(argv[0], &cmdentry, cmd_flag, path);
9701 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009702 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009703 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009704 goto bail;
9705 }
9706
9707 /* implement bltin and command here */
9708 if (cmdentry.cmdtype != CMDBUILTIN)
9709 break;
9710 if (spclbltin < 0)
9711 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9712 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009713 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009714#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009715 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009716 path = oldpath;
9717 nargv = parse_command_args(argv, &path);
9718 if (!nargv)
9719 break;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02009720 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
9721 * nargv => "PROG". path is updated if -p.
9722 */
Eric Andersenc470f442003-07-28 09:56:35 +00009723 argc -= nargv - argv;
9724 argv = nargv;
9725 cmd_flag |= DO_NOFUNC;
9726 } else
9727#endif
9728 break;
9729 }
9730 }
9731
9732 if (status) {
Ron Yorstonea7d2f62017-01-03 11:18:23 +01009733 bail:
9734 exitstatus = status;
9735
Eric Andersenc470f442003-07-28 09:56:35 +00009736 /* We have a redirection error. */
9737 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009738 raise_exception(EXERROR);
Ron Yorstonea7d2f62017-01-03 11:18:23 +01009739
Eric Andersenc470f442003-07-28 09:56:35 +00009740 goto out;
9741 }
9742
9743 /* Execute the command. */
9744 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009745 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009746
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009747#if ENABLE_FEATURE_SH_NOFORK
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009748/* (1) BUG: if variables are set, we need to fork, or save/restore them
9749 * around run_nofork_applet() call.
9750 * (2) Should this check also be done in forkshell()?
9751 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9752 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009753 /* find_command() encodes applet_no as (-2 - applet_no) */
9754 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009755 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009756 listsetvar(varlist.list, VEXPORT|VSTACK);
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009757 /* run <applet>_main() */
Ron Yorston5ccb0e92016-10-20 12:24:02 +01009758 status = run_nofork_applet(applet_no, argv);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009759 break;
9760 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009761#endif
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009762 /* Can we avoid forking off? For example, very last command
9763 * in a script or a subshell does not need forking,
9764 * we can just exec it.
9765 */
Denys Vlasenko238bf182010-05-18 15:49:07 +02009766 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009767 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009768 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009769 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009770 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009771 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009772 /* parent */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009773 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009774 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009775 TRACE(("forked child exited with %d\n", status));
Eric Andersenc470f442003-07-28 09:56:35 +00009776 break;
9777 }
Denys Vlasenko238bf182010-05-18 15:49:07 +02009778 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009779 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +02009780 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +00009781 }
9782 listsetvar(varlist.list, VEXPORT|VSTACK);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02009783 shellexec(argv[0], argv, path, cmdentry.u.index);
Eric Andersenc470f442003-07-28 09:56:35 +00009784 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009785 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +00009786 case CMDBUILTIN:
9787 cmdenviron = varlist.list;
9788 if (cmdenviron) {
9789 struct strlist *list = cmdenviron;
9790 int i = VNOSET;
9791 if (spclbltin > 0 || argc == 0) {
9792 i = 0;
9793 if (cmd_is_exec && argc > 1)
9794 i = VEXPORT;
9795 }
9796 listsetvar(list, i);
9797 }
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009798 /* Tight loop with builtins only:
9799 * "while kill -0 $child; do true; done"
9800 * will never exit even if $child died, unless we do this
9801 * to reap the zombie and make kill detect that it's gone: */
9802 dowait(DOWAIT_NONBLOCK, NULL);
9803
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009804 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009805 if (exception_type == EXERROR && spclbltin <= 0) {
9806 FORCE_INT_ON;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02009807 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009808 }
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009809 raise:
9810 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009811 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009812 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009813
9814 case CMDFUNCTION:
9815 listsetvar(varlist.list, 0);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009816 /* See above for the rationale */
9817 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009818 if (evalfun(cmdentry.u.func, argc, argv, flags))
9819 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009820 readstatus:
9821 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009822 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009823 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +00009824
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009825 out:
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02009826 if (cmd->ncmd.redirect)
9827 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009828 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +00009829 /* dsl: I think this is intended to be used to support
9830 * '_' in 'vi' command mode during line editing...
9831 * However I implemented that within libedit itself.
9832 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009833 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009834 }
Eric Andersenc470f442003-07-28 09:56:35 +00009835 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009836
9837 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009838}
9839
9840static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009841evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009842{
Eric Andersenc470f442003-07-28 09:56:35 +00009843 char *volatile savecmdname;
9844 struct jmploc *volatile savehandler;
9845 struct jmploc jmploc;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009846 int status;
Eric Andersenc470f442003-07-28 09:56:35 +00009847 int i;
9848
9849 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009850 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009851 i = setjmp(jmploc.loc);
9852 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +00009853 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009854 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00009855 commandname = argv[0];
9856 argptr = argv + 1;
9857 optptr = NULL; /* initialize nextopt */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009858 if (cmd == EVALCMD)
9859 status = evalcmd(argc, argv, flags);
9860 else
9861 status = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009862 flush_stdout_stderr();
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009863 status |= ferror(stdout);
9864 exitstatus = status;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009865 cmddone:
Rob Landleyf296f0b2006-07-06 01:09:21 +00009866 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009867 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009868 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +00009869
9870 return i;
9871}
9872
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009873static int
9874goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009875{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02009876 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009877}
9878
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009879
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009880/*
9881 * Search for a command. This is called before we fork so that the
9882 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009883 * the child. The check for "goodname" is an overly conservative
9884 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009885 */
Eric Andersenc470f442003-07-28 09:56:35 +00009886static void
9887prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009888{
9889 struct cmdentry entry;
9890
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009891 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9892 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009893}
9894
Eric Andersencb57d552001-06-28 07:25:16 +00009895
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009896/* ============ Builtin commands
9897 *
9898 * Builtin commands whose functions are closely tied to evaluation
9899 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +00009900 */
9901
9902/*
Eric Andersencb57d552001-06-28 07:25:16 +00009903 * Handle break and continue commands. Break, continue, and return are
9904 * all handled by setting the evalskip flag. The evaluation routines
9905 * above all check this flag, and if it is set they start skipping
9906 * commands rather than executing them. The variable skipcount is
9907 * the number of loops to break/continue, or the number of function
9908 * levels to return. (The latter is always 1.) It should probably
9909 * be an error to break out of more loops than exist, but it isn't
9910 * in the standard shell so we don't make it one here.
9911 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009912static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009913breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009914{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009915 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009916
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00009917 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009918 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009919 if (n > loopnest)
9920 n = loopnest;
9921 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009922 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00009923 skipcount = n;
9924 }
9925 return 0;
9926}
9927
Eric Andersenc470f442003-07-28 09:56:35 +00009928
Denys Vlasenko70392332016-10-27 02:31:55 +02009929/*
Eric Andersen90898442003-08-06 11:20:52 +00009930 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00009931 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009932
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009933enum {
9934 INPUT_PUSH_FILE = 1,
9935 INPUT_NOFILE_OK = 2,
9936};
Eric Andersencb57d552001-06-28 07:25:16 +00009937
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009938static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009939/* values of checkkwd variable */
9940#define CHKALIAS 0x1
9941#define CHKKWD 0x2
9942#define CHKNL 0x4
9943
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009944/*
9945 * Push a string back onto the input at this current parsefile level.
9946 * We handle aliases this way.
9947 */
9948#if !ENABLE_ASH_ALIAS
9949#define pushstring(s, ap) pushstring(s)
9950#endif
9951static void
9952pushstring(char *s, struct alias *ap)
9953{
9954 struct strpush *sp;
9955 int len;
9956
9957 len = strlen(s);
9958 INT_OFF;
9959 if (g_parsefile->strpush) {
9960 sp = ckzalloc(sizeof(*sp));
9961 sp->prev = g_parsefile->strpush;
9962 } else {
9963 sp = &(g_parsefile->basestrpush);
9964 }
9965 g_parsefile->strpush = sp;
9966 sp->prev_string = g_parsefile->next_to_pgetc;
9967 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009968 sp->unget = g_parsefile->unget;
9969 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009970#if ENABLE_ASH_ALIAS
9971 sp->ap = ap;
9972 if (ap) {
9973 ap->flag |= ALIASINUSE;
9974 sp->string = s;
9975 }
9976#endif
9977 g_parsefile->next_to_pgetc = s;
9978 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009979 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009980 INT_ON;
9981}
9982
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009983static void
9984popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009985{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009986 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +00009987
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009988 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009989#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009990 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009991 if (g_parsefile->next_to_pgetc[-1] == ' '
9992 || g_parsefile->next_to_pgetc[-1] == '\t'
9993 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009994 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009995 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009996 if (sp->string != sp->ap->val) {
9997 free(sp->string);
9998 }
9999 sp->ap->flag &= ~ALIASINUSE;
10000 if (sp->ap->flag & ALIASDEAD) {
10001 unalias(sp->ap->name);
10002 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010003 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010004#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010005 g_parsefile->next_to_pgetc = sp->prev_string;
10006 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010007 g_parsefile->unget = sp->unget;
10008 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010009 g_parsefile->strpush = sp->prev;
10010 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010011 free(sp);
10012 INT_ON;
10013}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010014
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010015static int
10016preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010017{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010018 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +000010019 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010020
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010021 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +000010022#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +000010023 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010024 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +010010025 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010026 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010027 int timeout = -1;
10028# if ENABLE_ASH_IDLE_TIMEOUT
10029 if (iflag) {
10030 const char *tmout_var = lookupvar("TMOUT");
10031 if (tmout_var) {
10032 timeout = atoi(tmout_var) * 1000;
10033 if (timeout <= 0)
10034 timeout = -1;
10035 }
10036 }
10037# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010038# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010039 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010040# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +020010041 reinit_unicode_for_ash();
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010042 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010043 if (nr == 0) {
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010044 /* ^C pressed, "convert" to SIGINT */
10045 write(STDOUT_FILENO, "^C", 2);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010046 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010047 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010048 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010049 raise(SIGINT);
10050 return 1;
10051 }
Denys Vlasenko8660aeb2016-11-24 17:44:02 +010010052 exitstatus = 128 + SIGINT;
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010053 bb_putchar('\n');
Eric Andersenc470f442003-07-28 09:56:35 +000010054 goto retry;
10055 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010056 if (nr < 0) {
10057 if (errno == 0) {
10058 /* Ctrl+D pressed */
10059 nr = 0;
10060 }
10061# if ENABLE_ASH_IDLE_TIMEOUT
10062 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +020010063 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010064 exitshell();
10065 }
10066# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010067 }
Eric Andersencb57d552001-06-28 07:25:16 +000010068 }
10069#else
Ron Yorston61d6ae22015-04-19 10:50:25 +010010070 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +000010071#endif
10072
Denys Vlasenko80c5b682011-05-08 21:21:10 +020010073#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +000010074 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010075 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +000010076 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +000010077 if (flags >= 0 && (flags & O_NONBLOCK)) {
10078 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +000010079 if (fcntl(0, F_SETFL, flags) >= 0) {
10080 out2str("sh: turning off NDELAY mode\n");
10081 goto retry;
10082 }
10083 }
10084 }
10085 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +000010086#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010087 return nr;
10088}
10089
10090/*
10091 * Refill the input buffer and return the next input character:
10092 *
10093 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010094 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
10095 * or we are reading from a string so we can't refill the buffer,
10096 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +020010097 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +000010098 * 4) Process input up to the next newline, deleting nul characters.
10099 */
Denis Vlasenko727752d2008-11-28 03:41:47 +000010100//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
10101#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010102static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010103static int
Eric Andersenc470f442003-07-28 09:56:35 +000010104preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010105{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010106 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010107 int more;
Eric Andersencb57d552001-06-28 07:25:16 +000010108
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010109 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000010110#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010111 if (g_parsefile->left_in_line == -1
10112 && g_parsefile->strpush->ap
10113 && g_parsefile->next_to_pgetc[-1] != ' '
10114 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +000010115 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010116 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +000010117 return PEOA;
10118 }
Eric Andersen2870d962001-07-02 17:27:21 +000010119#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010120 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010121 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010122 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010123 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010124 * "pgetc" needs refilling.
10125 */
10126
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010127 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010128 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010129 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010130 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010131 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010132 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010133 /* even in failure keep left_in_line and next_to_pgetc
10134 * in lock step, for correct multi-layer pungetc.
10135 * left_in_line was decremented before preadbuffer(),
10136 * must inc next_to_pgetc: */
10137 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010138 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010139 }
Eric Andersencb57d552001-06-28 07:25:16 +000010140
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010141 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010142 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010143 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010144 again:
10145 more = preadfd();
10146 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010147 /* don't try reading again */
10148 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010149 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010150 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010151 return PEOF;
10152 }
10153 }
10154
Denis Vlasenko727752d2008-11-28 03:41:47 +000010155 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010156 * Set g_parsefile->left_in_line
10157 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010158 * NUL chars are deleted.
10159 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010160 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010161 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010162 char c;
Eric Andersencb57d552001-06-28 07:25:16 +000010163
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010164 more--;
Eric Andersenc470f442003-07-28 09:56:35 +000010165
Denis Vlasenko727752d2008-11-28 03:41:47 +000010166 c = *q;
10167 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010168 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010169 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010170 q++;
10171 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010172 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010173 break;
10174 }
Eric Andersencb57d552001-06-28 07:25:16 +000010175 }
10176
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010177 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010178 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10179 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010180 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010181 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010182 }
10183 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010184 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +000010185
Eric Andersencb57d552001-06-28 07:25:16 +000010186 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010187 char save = *q;
10188 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010189 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010190 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +000010191 }
10192
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010193 pgetc_debug("preadbuffer at %d:%p'%s'",
10194 g_parsefile->left_in_line,
10195 g_parsefile->next_to_pgetc,
10196 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +010010197 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010198}
10199
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010200static void
10201nlprompt(void)
10202{
10203 g_parsefile->linno++;
10204 setprompt_if(doprompt, 2);
10205}
10206static void
10207nlnoprompt(void)
10208{
10209 g_parsefile->linno++;
10210 needprompt = doprompt;
10211}
10212
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010213static int
10214pgetc(void)
10215{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010216 int c;
10217
10218 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010219 g_parsefile->left_in_line,
10220 g_parsefile->next_to_pgetc,
10221 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010222 if (g_parsefile->unget)
10223 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010224
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010225 if (--g_parsefile->left_in_line >= 0)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +010010226 c = (unsigned char)*g_parsefile->next_to_pgetc++;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010227 else
10228 c = preadbuffer();
10229
10230 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10231 g_parsefile->lastc[0] = c;
10232
10233 return c;
10234}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010235
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010236#if ENABLE_ASH_ALIAS
10237static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010238pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010239{
10240 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010241 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010242 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010243 g_parsefile->left_in_line,
10244 g_parsefile->next_to_pgetc,
10245 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010246 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010247 } while (c == PEOA);
10248 return c;
10249}
10250#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010251# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010252#endif
10253
10254/*
10255 * Read a line from the script.
10256 */
10257static char *
10258pfgets(char *line, int len)
10259{
10260 char *p = line;
10261 int nleft = len;
10262 int c;
10263
10264 while (--nleft > 0) {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010265 c = pgetc_without_PEOA();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010266 if (c == PEOF) {
10267 if (p == line)
10268 return NULL;
10269 break;
10270 }
10271 *p++ = c;
10272 if (c == '\n')
10273 break;
10274 }
10275 *p = '\0';
10276 return line;
10277}
10278
Eric Andersenc470f442003-07-28 09:56:35 +000010279/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010280 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010281 * PEOF may be pushed back.
10282 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010283static void
Eric Andersenc470f442003-07-28 09:56:35 +000010284pungetc(void)
10285{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010286 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010287}
10288
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010289/* This one eats backslash+newline */
10290static int
10291pgetc_eatbnl(void)
10292{
10293 int c;
10294
10295 while ((c = pgetc()) == '\\') {
10296 if (pgetc() != '\n') {
10297 pungetc();
10298 break;
10299 }
10300
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010301 nlprompt();
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010302 }
10303
10304 return c;
10305}
10306
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010307/*
10308 * To handle the "." command, a stack of input files is used. Pushfile
10309 * adds a new entry to the stack and popfile restores the previous level.
10310 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010311static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010312pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010313{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010314 struct parsefile *pf;
10315
Denis Vlasenko597906c2008-02-20 16:38:54 +000010316 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010317 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010318 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010319 /*pf->strpush = NULL; - ckzalloc did it */
10320 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010321 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010322 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010323}
10324
10325static void
10326popfile(void)
10327{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010328 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010329
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010010330 if (pf == &basepf)
10331 return;
10332
Denis Vlasenkob012b102007-02-19 22:43:01 +000010333 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010334 if (pf->pf_fd >= 0)
10335 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010336 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010337 while (pf->strpush)
10338 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010339 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010340 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010341 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010342}
10343
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010344/*
10345 * Return to top level.
10346 */
10347static void
10348popallfiles(void)
10349{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010350 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010351 popfile();
10352}
10353
10354/*
10355 * Close the file(s) that the shell is reading commands from. Called
10356 * after a fork is done.
10357 */
10358static void
10359closescript(void)
10360{
10361 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010362 if (g_parsefile->pf_fd > 0) {
10363 close(g_parsefile->pf_fd);
10364 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010365 }
10366}
10367
10368/*
10369 * Like setinputfile, but takes an open file descriptor. Call this with
10370 * interrupts off.
10371 */
10372static void
10373setinputfd(int fd, int push)
10374{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010375 if (push) {
10376 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010377 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010378 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010379 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010380 if (g_parsefile->buf == NULL)
10381 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010382 g_parsefile->left_in_buffer = 0;
10383 g_parsefile->left_in_line = 0;
10384 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010385}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010386
Eric Andersenc470f442003-07-28 09:56:35 +000010387/*
10388 * Set the input to take input from a file. If push is set, push the
10389 * old input onto the stack first.
10390 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010391static int
10392setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010393{
10394 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010395
Denis Vlasenkob012b102007-02-19 22:43:01 +000010396 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010397 fd = open(fname, O_RDONLY);
10398 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010399 if (flags & INPUT_NOFILE_OK)
10400 goto out;
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010401 exitstatus = 127;
Denis Vlasenko9604e1b2009-03-03 18:47:56 +000010402 ash_msg_and_raise_error("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010403 }
Denys Vlasenko64774602016-10-26 15:24:30 +020010404 if (fd < 10)
10405 fd = savefd(fd);
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020010406 else
10407 close_on_exec_on(fd);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010408 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010409 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010410 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010411 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010412}
10413
Eric Andersencb57d552001-06-28 07:25:16 +000010414/*
10415 * Like setinputfile, but takes input from a string.
10416 */
Eric Andersenc470f442003-07-28 09:56:35 +000010417static void
10418setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010419{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010420 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010421 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010422 g_parsefile->next_to_pgetc = string;
10423 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010424 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010425 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010426 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010427}
10428
10429
Denys Vlasenko70392332016-10-27 02:31:55 +020010430/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010431 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010432 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010433
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010434#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010435
Denys Vlasenko23841622015-10-09 15:52:03 +020010436/* Hash of mtimes of mailboxes */
10437static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010438/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010439static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010440
Eric Andersencb57d552001-06-28 07:25:16 +000010441/*
Eric Andersenc470f442003-07-28 09:56:35 +000010442 * Print appropriate message(s) if mail has arrived.
10443 * If mail_var_path_changed is set,
10444 * then the value of MAIL has mail_var_path_changed,
10445 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010446 */
Eric Andersenc470f442003-07-28 09:56:35 +000010447static void
10448chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010449{
Eric Andersencb57d552001-06-28 07:25:16 +000010450 const char *mpath;
10451 char *p;
10452 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010453 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010454 struct stackmark smark;
10455 struct stat statb;
10456
Eric Andersencb57d552001-06-28 07:25:16 +000010457 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010458 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010459 new_hash = 0;
10460 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010461 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010462 if (p == NULL)
10463 break;
10464 if (*p == '\0')
10465 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010466 for (q = p; *q; q++)
10467 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010468#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010469 if (q[-1] != '/')
10470 abort();
10471#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010472 q[-1] = '\0'; /* delete trailing '/' */
10473 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010474 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010475 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010476 /* Very simplistic "hash": just a sum of all mtimes */
10477 new_hash += (unsigned)statb.st_mtime;
10478 }
10479 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010480 if (mailtime_hash != 0)
10481 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010482 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010483 }
Eric Andersenc470f442003-07-28 09:56:35 +000010484 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010485 popstackmark(&smark);
10486}
Eric Andersencb57d552001-06-28 07:25:16 +000010487
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010488static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010489changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010490{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010491 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010492}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010493
Denis Vlasenko131ae172007-02-18 13:00:19 +000010494#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010495
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010496
10497/* ============ ??? */
10498
Eric Andersencb57d552001-06-28 07:25:16 +000010499/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010500 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010501 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010502static void
10503setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010504{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010505 char **newparam;
10506 char **ap;
10507 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010508
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010509 for (nparam = 0; argv[nparam]; nparam++)
10510 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010511 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10512 while (*argv) {
10513 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010514 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010515 *ap = NULL;
10516 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010517 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010518 shellparam.nparam = nparam;
10519 shellparam.p = newparam;
10520#if ENABLE_ASH_GETOPTS
10521 shellparam.optind = 1;
10522 shellparam.optoff = -1;
10523#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010524}
10525
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010526/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010527 * Process shell options. The global variable argptr contains a pointer
10528 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010529 *
10530 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10531 * For a non-interactive shell, an error condition encountered
10532 * by a special built-in ... shall cause the shell to write a diagnostic message
10533 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010534 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010535 * ...
10536 * Utility syntax error (option or operand error) Shall exit
10537 * ...
10538 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10539 * we see that bash does not do that (set "finishes" with error code 1 instead,
10540 * and shell continues), and people rely on this behavior!
10541 * Testcase:
10542 * set -o barfoo 2>/dev/null
10543 * echo $?
10544 *
10545 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010546 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010547static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010548plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010549{
10550 int i;
10551
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010552 if (name) {
10553 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010554 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010555 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010556 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010557 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010558 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010559 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010560 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010561 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010562 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010563 if (val) {
10564 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10565 } else {
10566 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10567 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010568 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010569 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010570}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010571static void
10572setoption(int flag, int val)
10573{
10574 int i;
10575
10576 for (i = 0; i < NOPTS; i++) {
10577 if (optletters(i) == flag) {
10578 optlist[i] = val;
10579 return;
10580 }
10581 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010582 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010583 /* NOTREACHED */
10584}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010585static int
Eric Andersenc470f442003-07-28 09:56:35 +000010586options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +000010587{
10588 char *p;
10589 int val;
10590 int c;
10591
10592 if (cmdline)
10593 minusc = NULL;
10594 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010595 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010596 if (c != '-' && c != '+')
10597 break;
10598 argptr++;
10599 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010600 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010601 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010602 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010603 if (!cmdline) {
10604 /* "-" means turn off -x and -v */
10605 if (p[0] == '\0')
10606 xflag = vflag = 0;
10607 /* "--" means reset params */
10608 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010609 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010610 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010611 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010612 }
Eric Andersencb57d552001-06-28 07:25:16 +000010613 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010614 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010615 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010616 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010617 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010618 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010619 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010620 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010621 /* it already printed err message */
10622 return 1; /* error */
10623 }
Eric Andersencb57d552001-06-28 07:25:16 +000010624 if (*argptr)
10625 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010626 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10627 isloginsh = 1;
10628 /* bash does not accept +-login, we also won't */
10629 } else if (cmdline && val && (c == '-')) { /* long options */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010630 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +000010631 isloginsh = 1;
10632 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010633 } else {
10634 setoption(c, val);
10635 }
10636 }
10637 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010638 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010639}
10640
Eric Andersencb57d552001-06-28 07:25:16 +000010641/*
Eric Andersencb57d552001-06-28 07:25:16 +000010642 * The shift builtin command.
10643 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010644static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010645shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010646{
10647 int n;
10648 char **ap1, **ap2;
10649
10650 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010651 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010652 n = number(argv[1]);
10653 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010654 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010655 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010656 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010657 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010658 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010659 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010660 }
10661 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010662 while ((*ap2++ = *ap1++) != NULL)
10663 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010664#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010665 shellparam.optind = 1;
10666 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010667#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010668 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010669 return 0;
10670}
10671
Eric Andersencb57d552001-06-28 07:25:16 +000010672/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010673 * POSIX requires that 'set' (but not export or readonly) output the
10674 * variables in lexicographic order - by the locale's collating order (sigh).
10675 * Maybe we could keep them in an ordered balanced binary tree
10676 * instead of hashed lists.
10677 * For now just roll 'em through qsort for printing...
10678 */
10679static int
10680showvars(const char *sep_prefix, int on, int off)
10681{
10682 const char *sep;
10683 char **ep, **epend;
10684
10685 ep = listvars(on, off, &epend);
10686 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10687
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010688 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010689
10690 for (; ep < epend; ep++) {
10691 const char *p;
10692 const char *q;
10693
10694 p = strchrnul(*ep, '=');
10695 q = nullstr;
10696 if (*p)
10697 q = single_quote(++p);
10698 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10699 }
10700 return 0;
10701}
10702
10703/*
Eric Andersencb57d552001-06-28 07:25:16 +000010704 * The set command builtin.
10705 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010706static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010707setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010708{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010709 int retval;
10710
Denis Vlasenko68404f12008-03-17 09:00:54 +000010711 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010712 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010713
Denis Vlasenkob012b102007-02-19 22:43:01 +000010714 INT_OFF;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010715 retval = options(/*cmdline:*/ 0);
10716 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010717 optschanged();
10718 if (*argptr != NULL) {
10719 setparam(argptr);
10720 }
Eric Andersencb57d552001-06-28 07:25:16 +000010721 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010722 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010723 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010724}
10725
Denis Vlasenko131ae172007-02-18 13:00:19 +000010726#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010727static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010728change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010729{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010730 uint32_t t;
10731
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010732 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010733 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010734 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010735 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010736 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010737 vrandom.flags &= ~VNOFUNC;
10738 } else {
10739 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010740 t = strtoul(value, NULL, 10);
10741 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010742 }
Eric Andersenef02f822004-03-11 13:34:24 +000010743}
Eric Andersen16767e22004-03-16 05:14:10 +000010744#endif
10745
Denis Vlasenko131ae172007-02-18 13:00:19 +000010746#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010747static int
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010748getopts(char *optstr, char *optvar, char **optfirst)
Eric Andersencb57d552001-06-28 07:25:16 +000010749{
10750 char *p, *q;
10751 char c = '?';
10752 int done = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010753 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000010754 char **optnext;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010755 int ind = shellparam.optind;
10756 int off = shellparam.optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010757
Denys Vlasenko9c541002015-10-07 15:44:36 +020010758 sbuf[1] = '\0';
10759
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010760 shellparam.optind = -1;
10761 optnext = optfirst + ind - 1;
Eric Andersena48b0a32003-10-22 10:56:47 +000010762
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010763 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
Eric Andersencb57d552001-06-28 07:25:16 +000010764 p = NULL;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010765 else
10766 p = optnext[-1] + off;
Eric Andersencb57d552001-06-28 07:25:16 +000010767 if (p == NULL || *p == '\0') {
10768 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010769 p = *optnext;
10770 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010771 atend:
Eric Andersencb57d552001-06-28 07:25:16 +000010772 p = NULL;
10773 done = 1;
10774 goto out;
10775 }
10776 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010777 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010778 goto atend;
10779 }
10780
10781 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010782 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010783 if (*q == '\0') {
10784 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010785 sbuf[0] = c;
10786 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010787 setvar0("OPTARG", sbuf);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010788 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010789 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010790 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010791 }
10792 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010793 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010794 }
10795 if (*++q == ':')
10796 q++;
10797 }
10798
10799 if (*++q == ':') {
10800 if (*p == '\0' && (p = *optnext) == NULL) {
10801 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010802 sbuf[0] = c;
10803 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010804 setvar0("OPTARG", sbuf);
Eric Andersencb57d552001-06-28 07:25:16 +000010805 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010806 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010807 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010808 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010809 c = '?';
10810 }
Eric Andersenc470f442003-07-28 09:56:35 +000010811 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010812 }
10813
10814 if (p == *optnext)
10815 optnext++;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010816 setvar0("OPTARG", p);
Eric Andersencb57d552001-06-28 07:25:16 +000010817 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010818 } else
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010819 setvar0("OPTARG", nullstr);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010820 out:
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010821 ind = optnext - optfirst + 1;
10822 setvar("OPTIND", itoa(ind), VNOFUNC);
Denys Vlasenko9c541002015-10-07 15:44:36 +020010823 sbuf[0] = c;
10824 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010825 setvar0(optvar, sbuf);
10826
10827 shellparam.optoff = p ? p - *(optnext - 1) : -1;
10828 shellparam.optind = ind;
10829
Eric Andersencb57d552001-06-28 07:25:16 +000010830 return done;
10831}
Eric Andersenc470f442003-07-28 09:56:35 +000010832
10833/*
10834 * The getopts builtin. Shellparam.optnext points to the next argument
10835 * to be processed. Shellparam.optptr points to the next character to
10836 * be processed in the current argument. If shellparam.optnext is NULL,
10837 * then it's the first time getopts has been called.
10838 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010839static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000010840getoptscmd(int argc, char **argv)
10841{
10842 char **optbase;
10843
10844 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010845 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010846 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000010847 optbase = shellparam.p;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010848 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
Eric Andersenc470f442003-07-28 09:56:35 +000010849 shellparam.optind = 1;
10850 shellparam.optoff = -1;
10851 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010852 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010853 optbase = &argv[3];
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010854 if ((unsigned)shellparam.optind > argc - 2) {
Eric Andersenc470f442003-07-28 09:56:35 +000010855 shellparam.optind = 1;
10856 shellparam.optoff = -1;
10857 }
10858 }
10859
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010860 return getopts(argv[1], argv[2], optbase);
Eric Andersenc470f442003-07-28 09:56:35 +000010861}
Denis Vlasenko131ae172007-02-18 13:00:19 +000010862#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000010863
Eric Andersencb57d552001-06-28 07:25:16 +000010864
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010865/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000010866
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010867struct heredoc {
10868 struct heredoc *next; /* next here document in list */
10869 union node *here; /* redirection node */
10870 char *eofmark; /* string indicating end of input */
10871 smallint striptabs; /* if set, strip leading tabs */
10872};
10873
10874static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010875static smallint quoteflag; /* set if (part of) last token was quoted */
10876static token_id_t lasttoken; /* last token read (integer id Txxx) */
10877static struct heredoc *heredoclist; /* list of here documents to read */
10878static char *wordtext; /* text of last word returned by readtoken */
10879static struct nodelist *backquotelist;
10880static union node *redirnode;
10881static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010882
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010883static const char *
10884tokname(char *buf, int tok)
10885{
10886 if (tok < TSEMI)
Denys Vlasenko888527c2016-10-02 16:54:17 +020010887 return tokname_array[tok];
10888 sprintf(buf, "\"%s\"", tokname_array[tok]);
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010889 return buf;
10890}
10891
10892/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010893 * Called when an unexpected token is read during the parse. The argument
10894 * is the token that is expected, or -1 if more than one type of token can
10895 * occur at this point.
10896 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010897static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010898static void
10899raise_error_unexpected_syntax(int token)
10900{
10901 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010902 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010903 int l;
10904
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010905 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010906 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010907 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010908 raise_error_syntax(msg);
10909 /* NOTREACHED */
10910}
Eric Andersencb57d552001-06-28 07:25:16 +000010911
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010912#define EOFMARKLEN 79
Eric Andersencb57d552001-06-28 07:25:16 +000010913
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010914/* parsing is heavily cross-recursive, need these forward decls */
10915static union node *andor(void);
10916static union node *pipeline(void);
10917static union node *parse_command(void);
10918static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000010919static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010920static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000010921
Eric Andersenc470f442003-07-28 09:56:35 +000010922static union node *
10923list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000010924{
10925 union node *n1, *n2, *n3;
10926 int tok;
10927
Eric Andersencb57d552001-06-28 07:25:16 +000010928 n1 = NULL;
10929 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010930 switch (peektoken()) {
10931 case TNL:
10932 if (!(nlflag & 1))
10933 break;
10934 parseheredoc();
10935 return n1;
10936
10937 case TEOF:
10938 if (!n1 && (nlflag & 1))
10939 n1 = NODE_EOF;
10940 parseheredoc();
10941 return n1;
10942 }
10943
10944 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko888527c2016-10-02 16:54:17 +020010945 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
Ron Yorstonc0e00762015-10-29 11:30:55 +000010946 return n1;
10947 nlflag |= 2;
10948
Eric Andersencb57d552001-06-28 07:25:16 +000010949 n2 = andor();
10950 tok = readtoken();
10951 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000010952 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010953 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010954 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010955 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010956 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000010957 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010958 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010959 n2 = n3;
10960 }
10961 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000010962 }
10963 }
10964 if (n1 == NULL) {
10965 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010966 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010967 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010968 n3->type = NSEMI;
10969 n3->nbinary.ch1 = n1;
10970 n3->nbinary.ch2 = n2;
10971 n1 = n3;
10972 }
10973 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010974 case TNL:
10975 case TEOF:
10976 tokpushback = 1;
10977 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000010978 case TBACKGND:
10979 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000010980 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010981 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000010982 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010983 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010984 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010985 return n1;
10986 }
10987 }
10988}
10989
Eric Andersenc470f442003-07-28 09:56:35 +000010990static union node *
10991andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010992{
Eric Andersencb57d552001-06-28 07:25:16 +000010993 union node *n1, *n2, *n3;
10994 int t;
10995
Eric Andersencb57d552001-06-28 07:25:16 +000010996 n1 = pipeline();
10997 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010998 t = readtoken();
10999 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000011000 t = NAND;
11001 } else if (t == TOR) {
11002 t = NOR;
11003 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011004 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011005 return n1;
11006 }
Eric Andersenc470f442003-07-28 09:56:35 +000011007 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011008 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011009 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011010 n3->type = t;
11011 n3->nbinary.ch1 = n1;
11012 n3->nbinary.ch2 = n2;
11013 n1 = n3;
11014 }
11015}
11016
Eric Andersenc470f442003-07-28 09:56:35 +000011017static union node *
11018pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011019{
Eric Andersencb57d552001-06-28 07:25:16 +000011020 union node *n1, *n2, *pipenode;
11021 struct nodelist *lp, *prev;
11022 int negate;
11023
11024 negate = 0;
11025 TRACE(("pipeline: entered\n"));
11026 if (readtoken() == TNOT) {
11027 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000011028 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011029 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011030 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011031 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011032 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011033 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000011034 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011035 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011036 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000011037 pipenode->npipe.cmdlist = lp;
11038 lp->n = n1;
11039 do {
11040 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011041 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000011042 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011043 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011044 prev->next = lp;
11045 } while (readtoken() == TPIPE);
11046 lp->next = NULL;
11047 n1 = pipenode;
11048 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011049 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011050 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011051 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000011052 n2->type = NNOT;
11053 n2->nnot.com = n1;
11054 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011055 }
11056 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000011057}
11058
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011059static union node *
11060makename(void)
11061{
11062 union node *n;
11063
Denis Vlasenko597906c2008-02-20 16:38:54 +000011064 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011065 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011066 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011067 n->narg.text = wordtext;
11068 n->narg.backquote = backquotelist;
11069 return n;
11070}
11071
11072static void
11073fixredir(union node *n, const char *text, int err)
11074{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011075 int fd;
11076
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011077 TRACE(("Fix redir %s %d\n", text, err));
11078 if (!err)
11079 n->ndup.vname = NULL;
11080
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011081 fd = bb_strtou(text, NULL, 10);
11082 if (!errno && fd >= 0)
11083 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011084 else if (LONE_DASH(text))
11085 n->ndup.dupfd = -1;
11086 else {
11087 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011088 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011089 n->ndup.vname = makename();
11090 }
11091}
11092
11093/*
11094 * Returns true if the text contains nothing to expand (no dollar signs
11095 * or backquotes).
11096 */
11097static int
Denis Vlasenko68819d12008-12-15 11:26:36 +000011098noexpand(const char *text)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011099{
Denys Vlasenkocd716832009-11-28 22:14:02 +010011100 unsigned char c;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011101
Denys Vlasenkocd716832009-11-28 22:14:02 +010011102 while ((c = *text++) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011103 if (c == CTLQUOTEMARK)
11104 continue;
11105 if (c == CTLESC)
Denys Vlasenkocd716832009-11-28 22:14:02 +010011106 text++;
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011107 else if (SIT(c, BASESYNTAX) == CCTL)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011108 return 0;
11109 }
11110 return 1;
11111}
11112
11113static void
11114parsefname(void)
11115{
11116 union node *n = redirnode;
11117
11118 if (readtoken() != TWORD)
11119 raise_error_unexpected_syntax(-1);
11120 if (n->type == NHERE) {
11121 struct heredoc *here = heredoc;
11122 struct heredoc *p;
11123 int i;
11124
11125 if (quoteflag == 0)
11126 n->type = NXHERE;
11127 TRACE(("Here document %d\n", n->type));
11128 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011129 raise_error_syntax("illegal eof marker for << redirection");
Denys Vlasenkob6c84342009-08-29 20:23:20 +020011130 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011131 here->eofmark = wordtext;
11132 here->next = NULL;
11133 if (heredoclist == NULL)
11134 heredoclist = here;
11135 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011136 for (p = heredoclist; p->next; p = p->next)
11137 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011138 p->next = here;
11139 }
11140 } else if (n->type == NTOFD || n->type == NFROMFD) {
11141 fixredir(n, wordtext, 0);
11142 } else {
11143 n->nfile.fname = makename();
11144 }
11145}
Eric Andersencb57d552001-06-28 07:25:16 +000011146
Eric Andersenc470f442003-07-28 09:56:35 +000011147static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011148simplecmd(void)
11149{
11150 union node *args, **app;
11151 union node *n = NULL;
11152 union node *vars, **vpp;
11153 union node **rpp, *redir;
11154 int savecheckkwd;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011155#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011156 smallint double_brackets_flag = 0;
11157#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011158 IF_BASH_FUNCTION(smallint function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011159
11160 args = NULL;
11161 app = &args;
11162 vars = NULL;
11163 vpp = &vars;
11164 redir = NULL;
11165 rpp = &redir;
11166
11167 savecheckkwd = CHKALIAS;
11168 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000011169 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011170 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011171 t = readtoken();
11172 switch (t) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011173#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011174 case TFUNCTION:
11175 if (peektoken() != TWORD)
11176 raise_error_unexpected_syntax(TWORD);
11177 function_flag = 1;
11178 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011179#endif
11180#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011181 case TAND: /* "&&" */
11182 case TOR: /* "||" */
11183 if (!double_brackets_flag) {
11184 tokpushback = 1;
11185 goto out;
11186 }
11187 wordtext = (char *) (t == TAND ? "-a" : "-o");
11188#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011189 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011190 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011191 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011192 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011193 n->narg.text = wordtext;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011194#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011195 if (strcmp("[[", wordtext) == 0)
11196 double_brackets_flag = 1;
11197 else if (strcmp("]]", wordtext) == 0)
11198 double_brackets_flag = 0;
11199#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011200 n->narg.backquote = backquotelist;
11201 if (savecheckkwd && isassignment(wordtext)) {
11202 *vpp = n;
11203 vpp = &n->narg.next;
11204 } else {
11205 *app = n;
11206 app = &n->narg.next;
11207 savecheckkwd = 0;
11208 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011209#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011210 if (function_flag) {
11211 checkkwd = CHKNL | CHKKWD;
11212 switch (peektoken()) {
11213 case TBEGIN:
11214 case TIF:
11215 case TCASE:
11216 case TUNTIL:
11217 case TWHILE:
11218 case TFOR:
11219 goto do_func;
11220 case TLP:
11221 function_flag = 0;
11222 break;
11223 case TWORD:
11224 if (strcmp("[[", wordtext) == 0)
11225 goto do_func;
11226 /* fall through */
11227 default:
11228 raise_error_unexpected_syntax(-1);
11229 }
11230 }
11231#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011232 break;
11233 case TREDIR:
11234 *rpp = n = redirnode;
11235 rpp = &n->nfile.next;
11236 parsefname(); /* read name of redirection file */
11237 break;
11238 case TLP:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011239 IF_BASH_FUNCTION(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011240 if (args && app == &args->narg.next
11241 && !vars && !redir
11242 ) {
11243 struct builtincmd *bcmd;
11244 const char *name;
11245
11246 /* We have a function */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011247 if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011248 raise_error_unexpected_syntax(TRP);
11249 name = n->narg.text;
11250 if (!goodname(name)
11251 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11252 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011253 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011254 }
11255 n->type = NDEFUN;
11256 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11257 n->narg.next = parse_command();
11258 return n;
11259 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011260 IF_BASH_FUNCTION(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011261 /* fall through */
11262 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011263 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011264 goto out;
11265 }
11266 }
11267 out:
11268 *app = NULL;
11269 *vpp = NULL;
11270 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011271 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011272 n->type = NCMD;
11273 n->ncmd.args = args;
11274 n->ncmd.assign = vars;
11275 n->ncmd.redirect = redir;
11276 return n;
11277}
11278
11279static union node *
11280parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011281{
Eric Andersencb57d552001-06-28 07:25:16 +000011282 union node *n1, *n2;
11283 union node *ap, **app;
11284 union node *cp, **cpp;
11285 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011286 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011287 int t;
11288
11289 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011290 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011291
Eric Andersencb57d552001-06-28 07:25:16 +000011292 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011293 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011294 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011295 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011296 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011297 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011298 n1->type = NIF;
11299 n1->nif.test = list(0);
11300 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011301 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011302 n1->nif.ifpart = list(0);
11303 n2 = n1;
11304 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011305 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011306 n2 = n2->nif.elsepart;
11307 n2->type = NIF;
11308 n2->nif.test = list(0);
11309 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011310 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011311 n2->nif.ifpart = list(0);
11312 }
11313 if (lasttoken == TELSE)
11314 n2->nif.elsepart = list(0);
11315 else {
11316 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011317 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011318 }
Eric Andersenc470f442003-07-28 09:56:35 +000011319 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011320 break;
11321 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011322 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011323 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011324 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011325 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011326 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011327 got = readtoken();
11328 if (got != TDO) {
Denys Vlasenko888527c2016-10-02 16:54:17 +020011329 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
Denis Vlasenko131ae172007-02-18 13:00:19 +000011330 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011331 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011332 }
11333 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011334 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011335 break;
11336 }
11337 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011338 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011339 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011340 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011341 n1->type = NFOR;
11342 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011343 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011344 if (readtoken() == TIN) {
11345 app = &ap;
11346 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011347 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011348 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011349 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011350 n2->narg.text = wordtext;
11351 n2->narg.backquote = backquotelist;
11352 *app = n2;
11353 app = &n2->narg.next;
11354 }
11355 *app = NULL;
11356 n1->nfor.args = ap;
11357 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011358 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011359 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011360 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011361 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011362 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011363 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011364 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011365 n1->nfor.args = n2;
11366 /*
11367 * Newline or semicolon here is optional (but note
11368 * that the original Bourne shell only allowed NL).
11369 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011370 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011371 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011372 }
Eric Andersenc470f442003-07-28 09:56:35 +000011373 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011374 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011375 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011376 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011377 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011378 break;
11379 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011380 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011381 n1->type = NCASE;
11382 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011383 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011384 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011385 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011386 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011387 n2->narg.text = wordtext;
11388 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011389 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11390 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011391 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011392 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011393 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011394 checkkwd = CHKNL | CHKKWD;
11395 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011396 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011397 if (lasttoken == TLP)
11398 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011399 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011400 cp->type = NCLIST;
11401 app = &cp->nclist.pattern;
11402 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011403 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011404 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011405 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011406 ap->narg.text = wordtext;
11407 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011408 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011409 break;
11410 app = &ap->narg.next;
11411 readtoken();
11412 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011413 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011414 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011415 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011416 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011417
Eric Andersenc470f442003-07-28 09:56:35 +000011418 cpp = &cp->nclist.next;
11419
11420 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011421 t = readtoken();
11422 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011423 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011424 raise_error_unexpected_syntax(TENDCASE);
11425 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011426 }
Eric Andersenc470f442003-07-28 09:56:35 +000011427 }
Eric Andersencb57d552001-06-28 07:25:16 +000011428 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011429 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011430 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011431 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011432 n1->type = NSUBSHELL;
11433 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011434 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011435 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011436 break;
11437 case TBEGIN:
11438 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011439 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011440 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011441 IF_BASH_FUNCTION(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011442 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011443 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011444 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011445 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011446 }
11447
Eric Andersenc470f442003-07-28 09:56:35 +000011448 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011449 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011450
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011451 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011452 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011453 checkkwd = CHKKWD | CHKALIAS;
11454 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011455 while (readtoken() == TREDIR) {
11456 *rpp = n2 = redirnode;
11457 rpp = &n2->nfile.next;
11458 parsefname();
11459 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011460 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011461 *rpp = NULL;
11462 if (redir) {
11463 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011464 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011465 n2->type = NREDIR;
11466 n2->nredir.n = n1;
11467 n1 = n2;
11468 }
11469 n1->nredir.redirect = redir;
11470 }
Eric Andersencb57d552001-06-28 07:25:16 +000011471 return n1;
11472}
11473
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011474#if BASH_DOLLAR_SQUOTE
Denys Vlasenko37dc08b2016-10-02 04:38:07 +020011475static int
11476decode_dollar_squote(void)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011477{
11478 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11479 int c, cnt;
11480 char *p;
11481 char buf[4];
11482
11483 c = pgetc();
11484 p = strchr(C_escapes, c);
11485 if (p) {
11486 buf[0] = c;
11487 p = buf;
11488 cnt = 3;
11489 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11490 do {
11491 c = pgetc();
11492 *++p = c;
11493 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11494 pungetc();
11495 } else if (c == 'x') { /* \xHH */
11496 do {
11497 c = pgetc();
11498 *++p = c;
11499 } while (isxdigit(c) && --cnt);
11500 pungetc();
11501 if (cnt == 3) { /* \x but next char is "bad" */
11502 c = 'x';
11503 goto unrecognized;
11504 }
11505 } else { /* simple seq like \\ or \t */
11506 p++;
11507 }
11508 *p = '\0';
11509 p = buf;
11510 c = bb_process_escape_sequence((void*)&p);
11511 } else { /* unrecognized "\z": print both chars unless ' or " */
11512 if (c != '\'' && c != '"') {
11513 unrecognized:
11514 c |= 0x100; /* "please encode \, then me" */
11515 }
11516 }
11517 return c;
11518}
11519#endif
11520
Eric Andersencb57d552001-06-28 07:25:16 +000011521/*
11522 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11523 * is not NULL, read a here document. In the latter case, eofmark is the
11524 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011525 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011526 * is the first character of the input token or document.
11527 *
11528 * Because C does not have internal subroutines, I have simulated them
11529 * using goto's to implement the subroutine linkage. The following macros
11530 * will run code that appears at the end of readtoken1.
11531 */
Eric Andersen2870d962001-07-02 17:27:21 +000011532#define CHECKEND() {goto checkend; checkend_return:;}
11533#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11534#define PARSESUB() {goto parsesub; parsesub_return:;}
11535#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11536#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11537#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011538static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011539readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011540{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011541 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011542 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011543 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020011544 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +000011545 char line[EOFMARKLEN + 1];
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011546 struct nodelist *bqlist;
11547 smallint quotef;
11548 smallint dblquote;
11549 smallint oldstyle;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011550 IF_FEATURE_SH_MATH(smallint prevsyntax;) /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011551#if ENABLE_ASH_EXPAND_PRMT
11552 smallint pssyntax; /* we are expanding a prompt string */
11553#endif
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011554 int varnest; /* levels of variables expansion */
Denys Vlasenko0b883582016-12-23 16:49:07 +010011555 IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */
11556 IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011557 int dqvarnest; /* levels of variables expansion within double quotes */
11558
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011559 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011560
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011561 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011562 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011563 quotef = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011564 IF_FEATURE_SH_MATH(prevsyntax = 0;)
Denis Vlasenko46a53062007-09-24 18:30:02 +000011565#if ENABLE_ASH_EXPAND_PRMT
11566 pssyntax = (syntax == PSSYNTAX);
11567 if (pssyntax)
11568 syntax = DQSYNTAX;
11569#endif
11570 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011571 varnest = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011572 IF_FEATURE_SH_MATH(arinest = 0;)
11573 IF_FEATURE_SH_MATH(parenlevel = 0;)
Eric Andersencb57d552001-06-28 07:25:16 +000011574 dqvarnest = 0;
11575
11576 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011577 loop:
11578 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011579 CHECKEND(); /* set c to PEOF if at end of here document */
11580 for (;;) { /* until end of line or end of word */
11581 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11582 switch (SIT(c, syntax)) {
11583 case CNL: /* '\n' */
11584 if (syntax == BASESYNTAX)
11585 goto endword; /* exit outer loop */
11586 USTPUTC(c, out);
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011587 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011588 c = pgetc();
11589 goto loop; /* continue outer loop */
11590 case CWORD:
11591 USTPUTC(c, out);
11592 break;
11593 case CCTL:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011594#if BASH_DOLLAR_SQUOTE
Denys Vlasenko958581a2010-09-12 15:04:27 +020011595 if (c == '\\' && bash_dollar_squote) {
11596 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020011597 if (c == '\0') {
11598 /* skip $'\000', $'\x00' (like bash) */
11599 break;
11600 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011601 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020011602 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011603 c = (unsigned char)c;
Denys Vlasenko13f20912016-09-25 20:54:25 +020011604 if (eofmark == NULL || dblquote)
11605 USTPUTC(CTLESC, out);
11606 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011607 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011608 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011609#endif
Denys Vlasenko13f20912016-09-25 20:54:25 +020011610 if (eofmark == NULL || dblquote)
11611 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011612 USTPUTC(c, out);
11613 break;
11614 case CBACK: /* backslash */
11615 c = pgetc_without_PEOA();
11616 if (c == PEOF) {
11617 USTPUTC(CTLESC, out);
11618 USTPUTC('\\', out);
11619 pungetc();
11620 } else if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011621 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011622 } else {
11623#if ENABLE_ASH_EXPAND_PRMT
11624 if (c == '$' && pssyntax) {
Eric Andersenc470f442003-07-28 09:56:35 +000011625 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011626 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011627 }
Denis Vlasenko46a53062007-09-24 18:30:02 +000011628#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011629 /* Backslash is retained if we are in "str" and next char isn't special */
11630 if (dblquote
11631 && c != '\\'
11632 && c != '`'
11633 && c != '$'
11634 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011635 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011636 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011637 }
Ron Yorston549deab2015-05-18 09:57:51 +020011638 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011639 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011640 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011641 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011642 break;
11643 case CSQUOTE:
11644 syntax = SQSYNTAX;
11645 quotemark:
11646 if (eofmark == NULL) {
11647 USTPUTC(CTLQUOTEMARK, out);
11648 }
11649 break;
11650 case CDQUOTE:
11651 syntax = DQSYNTAX;
11652 dblquote = 1;
11653 goto quotemark;
11654 case CENDQUOTE:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011655 IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020011656 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011657 USTPUTC(c, out);
11658 } else {
11659 if (dqvarnest == 0) {
11660 syntax = BASESYNTAX;
11661 dblquote = 0;
11662 }
11663 quotef = 1;
11664 goto quotemark;
11665 }
11666 break;
11667 case CVAR: /* '$' */
11668 PARSESUB(); /* parse substitution */
11669 break;
11670 case CENDVAR: /* '}' */
11671 if (varnest > 0) {
11672 varnest--;
11673 if (dqvarnest > 0) {
11674 dqvarnest--;
11675 }
11676 c = CTLENDVAR;
11677 }
11678 USTPUTC(c, out);
11679 break;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011680#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko958581a2010-09-12 15:04:27 +020011681 case CLP: /* '(' in arithmetic */
11682 parenlevel++;
11683 USTPUTC(c, out);
11684 break;
11685 case CRP: /* ')' in arithmetic */
11686 if (parenlevel > 0) {
11687 parenlevel--;
11688 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011689 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020011690 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011691 if (--arinest == 0) {
11692 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011693 }
11694 } else {
11695 /*
11696 * unbalanced parens
11697 * (don't 2nd guess - no error)
11698 */
11699 pungetc();
11700 }
11701 }
11702 USTPUTC(c, out);
11703 break;
11704#endif
11705 case CBQUOTE: /* '`' */
11706 PARSEBACKQOLD();
11707 break;
11708 case CENDFILE:
11709 goto endword; /* exit outer loop */
11710 case CIGN:
11711 break;
11712 default:
11713 if (varnest == 0) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011714#if BASH_REDIR_OUTPUT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011715 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011716//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020011717 if (pgetc() == '>')
11718 c = 0x100 + '>'; /* flag &> */
11719 pungetc();
11720 }
11721#endif
11722 goto endword; /* exit outer loop */
11723 }
11724 IF_ASH_ALIAS(if (c != PEOA))
11725 USTPUTC(c, out);
11726 }
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020011727 c = pgetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011728 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011729 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011730
Denys Vlasenko0b883582016-12-23 16:49:07 +010011731#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000011732 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011733 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011734#endif
Ron Yorston0e056f72015-07-01 16:45:40 +010011735 if (syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011736 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011737 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011738 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011739 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011740 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011741 }
11742 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011743 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011744 out = stackblock();
11745 if (eofmark == NULL) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011746 if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011747 && quotef == 0
11748 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011749 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011750 PARSEREDIR(); /* passed as params: out, c */
11751 lasttoken = TREDIR;
11752 return lasttoken;
11753 }
11754 /* else: non-number X seen, interpret it
11755 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011756 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011757 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011758 }
11759 quoteflag = quotef;
11760 backquotelist = bqlist;
11761 grabstackblock(len);
11762 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011763 lasttoken = TWORD;
11764 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011765/* end of readtoken routine */
11766
Eric Andersencb57d552001-06-28 07:25:16 +000011767/*
11768 * Check to see whether we are at the end of the here document. When this
11769 * is called, c is set to the first character of the next input line. If
11770 * we are at the end of the here document, this routine sets the c to PEOF.
11771 */
Eric Andersenc470f442003-07-28 09:56:35 +000011772checkend: {
11773 if (eofmark) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000011774#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011775 if (c == PEOA)
11776 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011777#endif
11778 if (striptabs) {
11779 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011780 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011781 }
Eric Andersenc470f442003-07-28 09:56:35 +000011782 }
11783 if (c == *eofmark) {
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011784 if (pfgets(line, sizeof(line)) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000011785 char *p, *q;
Denys Vlasenko350e6862016-10-26 16:26:45 +020011786 int cc;
Eric Andersencb57d552001-06-28 07:25:16 +000011787
Eric Andersenc470f442003-07-28 09:56:35 +000011788 p = line;
Denys Vlasenko350e6862016-10-26 16:26:45 +020011789 for (q = eofmark + 1;; p++, q++) {
11790 cc = *p;
11791 if (cc == '\n')
11792 cc = 0;
11793 if (!*q || cc != *q)
11794 break;
11795 }
11796 if (cc == *q) {
Eric Andersenc470f442003-07-28 09:56:35 +000011797 c = PEOF;
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011798 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011799 } else {
11800 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011801 }
11802 }
11803 }
11804 }
Eric Andersenc470f442003-07-28 09:56:35 +000011805 goto checkend_return;
11806}
Eric Andersencb57d552001-06-28 07:25:16 +000011807
Eric Andersencb57d552001-06-28 07:25:16 +000011808/*
11809 * Parse a redirection operator. The variable "out" points to a string
11810 * specifying the fd to be redirected. The variable "c" contains the
11811 * first character of the redirection operator.
11812 */
Eric Andersenc470f442003-07-28 09:56:35 +000011813parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011814 /* out is already checked to be a valid number or "" */
11815 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000011816 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000011817
Denis Vlasenko597906c2008-02-20 16:38:54 +000011818 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000011819 if (c == '>') {
11820 np->nfile.fd = 1;
11821 c = pgetc();
11822 if (c == '>')
11823 np->type = NAPPEND;
11824 else if (c == '|')
11825 np->type = NCLOBBER;
11826 else if (c == '&')
11827 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011828 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000011829 else {
11830 np->type = NTO;
11831 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011832 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000011833 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011834#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000011835 else if (c == 0x100 + '>') { /* this flags &> redirection */
11836 np->nfile.fd = 1;
11837 pgetc(); /* this is '>', no need to check */
11838 np->type = NTO2;
11839 }
11840#endif
11841 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000011842 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011843 c = pgetc();
11844 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000011845 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011846 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011847 np = stzalloc(sizeof(struct nhere));
11848 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011849 }
11850 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011851 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000011852 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011853 c = pgetc();
11854 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000011855 heredoc->striptabs = 1;
11856 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011857 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011858 pungetc();
11859 }
11860 break;
11861
11862 case '&':
11863 np->type = NFROMFD;
11864 break;
11865
11866 case '>':
11867 np->type = NFROMTO;
11868 break;
11869
11870 default:
11871 np->type = NFROM;
11872 pungetc();
11873 break;
11874 }
Eric Andersencb57d552001-06-28 07:25:16 +000011875 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011876 if (fd >= 0)
11877 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011878 redirnode = np;
11879 goto parseredir_return;
11880}
Eric Andersencb57d552001-06-28 07:25:16 +000011881
Eric Andersencb57d552001-06-28 07:25:16 +000011882/*
11883 * Parse a substitution. At this point, we have read the dollar sign
11884 * and nothing else.
11885 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000011886
11887/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11888 * (assuming ascii char codes, as the original implementation did) */
11889#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011890 (((unsigned)(c) - 33 < 32) \
11891 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000011892parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010011893 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011894 int typeloc;
Eric Andersencb57d552001-06-28 07:25:16 +000011895
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011896 c = pgetc_eatbnl();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011897 if (c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011898 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000011899 ) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011900#if BASH_DOLLAR_SQUOTE
Ron Yorston84ba50c2016-04-03 22:43:14 +010011901 if (syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011902 bash_dollar_squote = 1;
11903 else
11904#endif
11905 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011906 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011907 } else if (c == '(') {
11908 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011909 if (pgetc_eatbnl() == '(') {
Denys Vlasenko0b883582016-12-23 16:49:07 +010011910#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000011911 PARSEARITH();
11912#else
Mike Frysinger98a6f562008-06-09 09:38:45 +000011913 raise_error_syntax("you disabled math support for $((arith)) syntax");
Eric Andersenc470f442003-07-28 09:56:35 +000011914#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011915 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011916 pungetc();
11917 PARSEBACKQNEW();
11918 }
11919 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011920 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000011921 USTPUTC(CTLVAR, out);
11922 typeloc = out - (char *)stackblock();
Denys Vlasenko3df14102016-10-26 16:41:13 +020011923 STADJUST(1, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011924 subtype = VSNORMAL;
11925 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011926 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011927 subtype = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011928 }
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011929 varname:
Denys Vlasenko3df14102016-10-26 16:41:13 +020011930 if (is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011931 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011932 do {
11933 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011934 c = pgetc_eatbnl();
Denys Vlasenko3df14102016-10-26 16:41:13 +020011935 } while (is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011936 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011937 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011938 do {
11939 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011940 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011941 } while (isdigit(c));
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011942 } else if (is_special(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011943 /* $[{[#]]<specialchar>[}] */
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011944 int cc = c;
11945
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011946 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011947 if (!subtype && cc == '#') {
11948 subtype = VSLENGTH;
11949 if (c == '_' || isalnum(c))
11950 goto varname;
11951 cc = c;
11952 c = pgetc_eatbnl();
11953 if (cc == '}' || c != '}') {
11954 pungetc();
11955 subtype = 0;
11956 c = cc;
11957 cc = '#';
11958 }
11959 }
11960 USTPUTC(cc, out);
Denis Vlasenko559691a2008-10-05 18:39:31 +000011961 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020011962 goto badsub;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011963 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011964 if (c != '}' && subtype == VSLENGTH) {
11965 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020011966 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011967 }
Eric Andersencb57d552001-06-28 07:25:16 +000011968
Eric Andersenc470f442003-07-28 09:56:35 +000011969 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011970 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011971 /* ${VAR...} but not $VAR or ${#VAR} */
11972 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000011973 switch (c) {
11974 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011975 c = pgetc_eatbnl();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011976#if BASH_SUBSTR
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011977 /* This check is only needed to not misinterpret
11978 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
11979 * constructs.
11980 */
11981 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011982 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011983 pungetc();
Denys Vlasenko88e15702016-10-26 01:55:56 +020011984 break; /* "goto badsub" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011985 }
11986#endif
Denys Vlasenko3df14102016-10-26 16:41:13 +020011987 subtype = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000011988 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011989 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011990 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000011991 if (p == NULL)
Denys Vlasenko88e15702016-10-26 01:55:56 +020011992 break;
Denys Vlasenko3df14102016-10-26 16:41:13 +020011993 subtype |= p - types + VSNORMAL;
Eric Andersenc470f442003-07-28 09:56:35 +000011994 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011995 }
Eric Andersenc470f442003-07-28 09:56:35 +000011996 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011997 case '#': {
11998 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011999 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012000 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012001 if (c != cc)
Denys Vlasenko88e15702016-10-26 01:55:56 +020012002 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012003 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012004 break;
12005 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012006#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012007 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020012008 /* ${v/[/]pattern/repl} */
12009//TODO: encode pattern and repl separately.
12010// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012011 subtype = VSREPLACE;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012012 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012013 if (c != '/')
Denys Vlasenko88e15702016-10-26 01:55:56 +020012014 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012015 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012016 break;
12017#endif
Eric Andersencb57d552001-06-28 07:25:16 +000012018 }
Eric Andersenc470f442003-07-28 09:56:35 +000012019 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020012020 badsub:
Eric Andersenc470f442003-07-28 09:56:35 +000012021 pungetc();
12022 }
Denys Vlasenko3df14102016-10-26 16:41:13 +020012023 ((unsigned char *)stackblock())[typeloc] = subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012024 if (subtype != VSNORMAL) {
12025 varnest++;
Denys Vlasenko3df14102016-10-26 16:41:13 +020012026 if (dblquote)
Eric Andersenc470f442003-07-28 09:56:35 +000012027 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000012028 }
Denys Vlasenko88e15702016-10-26 01:55:56 +020012029 STPUTC('=', out);
Eric Andersencb57d552001-06-28 07:25:16 +000012030 }
Eric Andersenc470f442003-07-28 09:56:35 +000012031 goto parsesub_return;
12032}
Eric Andersencb57d552001-06-28 07:25:16 +000012033
Eric Andersencb57d552001-06-28 07:25:16 +000012034/*
12035 * Called to parse command substitutions. Newstyle is set if the command
12036 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
12037 * list of commands (passed by reference), and savelen is the number of
12038 * characters on the top of the stack which must be preserved.
12039 */
Eric Andersenc470f442003-07-28 09:56:35 +000012040parsebackq: {
12041 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012042 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010012043 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000012044 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012045 smallint saveprompt = 0;
12046
Eric Andersenc470f442003-07-28 09:56:35 +000012047 str = NULL;
12048 savelen = out - (char *)stackblock();
12049 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012050 /*
12051 * FIXME: this can allocate very large block on stack and SEGV.
12052 * Example:
12053 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020012054 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012055 * a hundred command substitutions stack overflows.
12056 * With larger prepended string, SEGV happens sooner.
12057 */
Ron Yorston072fc602015-07-01 16:46:18 +010012058 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000012059 memcpy(str, stackblock(), savelen);
12060 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012061
Eric Andersenc470f442003-07-28 09:56:35 +000012062 if (oldstyle) {
12063 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010012064 * treatment to some slashes, and then push the string and
12065 * reread it as input, interpreting it normally.
12066 */
Eric Andersenc470f442003-07-28 09:56:35 +000012067 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000012068 size_t psavelen;
12069 char *pstr;
12070
Eric Andersenc470f442003-07-28 09:56:35 +000012071 STARTSTACKSTR(pout);
12072 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012073 int pc;
12074
12075 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012076 pc = pgetc();
12077 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000012078 case '`':
12079 goto done;
12080
12081 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012082 pc = pgetc();
12083 if (pc == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012084 nlprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012085 /*
12086 * If eating a newline, avoid putting
12087 * the newline into the new character
12088 * stream (via the STPUTC after the
12089 * switch).
12090 */
12091 continue;
12092 }
12093 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012094 && (!dblquote || pc != '"')
12095 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000012096 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012097 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010012098 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000012099 break;
12100 }
12101 /* fall through */
12102
12103 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012104 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012105 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012106 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000012107
12108 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012109 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012110 break;
12111
12112 default:
12113 break;
12114 }
12115 STPUTC(pc, pout);
12116 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012117 done:
Eric Andersenc470f442003-07-28 09:56:35 +000012118 STPUTC('\0', pout);
12119 psavelen = pout - (char *)stackblock();
12120 if (psavelen > 0) {
12121 pstr = grabstackstr(pout);
12122 setinputstring(pstr);
12123 }
12124 }
12125 nlpp = &bqlist;
12126 while (*nlpp)
12127 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012128 *nlpp = stzalloc(sizeof(**nlpp));
12129 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012130
12131 if (oldstyle) {
12132 saveprompt = doprompt;
12133 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012134 }
12135
Eric Andersenc470f442003-07-28 09:56:35 +000012136 n = list(2);
12137
12138 if (oldstyle)
12139 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012140 else if (readtoken() != TRP)
12141 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000012142
12143 (*nlpp)->n = n;
12144 if (oldstyle) {
12145 /*
12146 * Start reading from old file again, ignoring any pushed back
12147 * tokens left from the backquote parsing
12148 */
12149 popfile();
12150 tokpushback = 0;
12151 }
12152 while (stackblocksize() <= savelen)
12153 growstackblock();
12154 STARTSTACKSTR(out);
12155 if (str) {
12156 memcpy(out, str, savelen);
12157 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012158 }
Ron Yorston549deab2015-05-18 09:57:51 +020012159 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012160 if (oldstyle)
12161 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012162 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000012163}
12164
Denys Vlasenko0b883582016-12-23 16:49:07 +010012165#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000012166/*
12167 * Parse an arithmetic expansion (indicate start of one and set state)
12168 */
Eric Andersenc470f442003-07-28 09:56:35 +000012169parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000012170 if (++arinest == 1) {
12171 prevsyntax = syntax;
12172 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000012173 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020012174 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012175 goto parsearith_return;
12176}
12177#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012178} /* end of readtoken */
12179
Eric Andersencb57d552001-06-28 07:25:16 +000012180/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012181 * Read the next input token.
12182 * If the token is a word, we set backquotelist to the list of cmds in
12183 * backquotes. We set quoteflag to true if any part of the word was
12184 * quoted.
12185 * If the token is TREDIR, then we set redirnode to a structure containing
12186 * the redirection.
12187 * In all cases, the variable startlinno is set to the number of the line
12188 * on which the token starts.
12189 *
12190 * [Change comment: here documents and internal procedures]
12191 * [Readtoken shouldn't have any arguments. Perhaps we should make the
12192 * word parsing code into a separate routine. In this case, readtoken
12193 * doesn't need to have any internal procedures, but parseword does.
12194 * We could also make parseoperator in essence the main routine, and
12195 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000012196 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012197#define NEW_xxreadtoken
12198#ifdef NEW_xxreadtoken
12199/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012200static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000012201 '\n', '(', ')', /* singles */
12202 '&', '|', ';', /* doubles */
12203 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012204};
Eric Andersencb57d552001-06-28 07:25:16 +000012205
Denis Vlasenko834dee72008-10-07 09:18:30 +000012206#define xxreadtoken_singles 3
12207#define xxreadtoken_doubles 3
12208
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012209static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012210 TNL, TLP, TRP, /* only single occurrence allowed */
12211 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12212 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012213 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012214};
12215
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012216static int
12217xxreadtoken(void)
12218{
12219 int c;
12220
12221 if (tokpushback) {
12222 tokpushback = 0;
12223 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012224 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012225 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012226 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012227 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012228 c = pgetc();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000012229 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012230 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012231
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012232 if (c == '#') {
12233 while ((c = pgetc()) != '\n' && c != PEOF)
12234 continue;
12235 pungetc();
12236 } else if (c == '\\') {
12237 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012238 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012239 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012240 }
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012241 nlprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012242 } else {
12243 const char *p;
12244
12245 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12246 if (c != PEOF) {
12247 if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012248 nlnoprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012249 }
12250
12251 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000012252 if (p == NULL)
12253 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012254
Denis Vlasenko834dee72008-10-07 09:18:30 +000012255 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12256 int cc = pgetc();
12257 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012258 p += xxreadtoken_doubles + 1;
12259 } else {
12260 pungetc();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012261#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012262 if (c == '&' && cc == '>') /* &> */
12263 break; /* return readtoken1(...) */
12264#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012265 }
12266 }
12267 }
12268 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12269 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012270 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012271 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012272
12273 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012274}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012275#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012276#define RETURN(token) return lasttoken = token
12277static int
12278xxreadtoken(void)
12279{
12280 int c;
12281
12282 if (tokpushback) {
12283 tokpushback = 0;
12284 return lasttoken;
12285 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012286 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012287 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012288 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012289 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012290 switch (c) {
12291 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012292 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012293 continue;
12294 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012295 while ((c = pgetc()) != '\n' && c != PEOF)
12296 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012297 pungetc();
12298 continue;
12299 case '\\':
12300 if (pgetc() == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012301 nlprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012302 continue;
12303 }
12304 pungetc();
12305 goto breakloop;
12306 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012307 nlnoprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012308 RETURN(TNL);
12309 case PEOF:
12310 RETURN(TEOF);
12311 case '&':
12312 if (pgetc() == '&')
12313 RETURN(TAND);
12314 pungetc();
12315 RETURN(TBACKGND);
12316 case '|':
12317 if (pgetc() == '|')
12318 RETURN(TOR);
12319 pungetc();
12320 RETURN(TPIPE);
12321 case ';':
12322 if (pgetc() == ';')
12323 RETURN(TENDCASE);
12324 pungetc();
12325 RETURN(TSEMI);
12326 case '(':
12327 RETURN(TLP);
12328 case ')':
12329 RETURN(TRP);
12330 default:
12331 goto breakloop;
12332 }
12333 }
12334 breakloop:
12335 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12336#undef RETURN
12337}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012338#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012339
12340static int
12341readtoken(void)
12342{
12343 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012344 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012345#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012346 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012347#endif
12348
12349#if ENABLE_ASH_ALIAS
12350 top:
12351#endif
12352
12353 t = xxreadtoken();
12354
12355 /*
12356 * eat newlines
12357 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012358 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012359 while (t == TNL) {
12360 parseheredoc();
12361 t = xxreadtoken();
12362 }
12363 }
12364
12365 if (t != TWORD || quoteflag) {
12366 goto out;
12367 }
12368
12369 /*
12370 * check for keywords
12371 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012372 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012373 const char *const *pp;
12374
12375 pp = findkwd(wordtext);
12376 if (pp) {
12377 lasttoken = t = pp - tokname_array;
Denys Vlasenko888527c2016-10-02 16:54:17 +020012378 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012379 goto out;
12380 }
12381 }
12382
12383 if (checkkwd & CHKALIAS) {
12384#if ENABLE_ASH_ALIAS
12385 struct alias *ap;
12386 ap = lookupalias(wordtext, 1);
12387 if (ap != NULL) {
12388 if (*ap->val) {
12389 pushstring(ap->val, ap);
12390 }
12391 goto top;
12392 }
12393#endif
12394 }
12395 out:
12396 checkkwd = 0;
12397#if DEBUG
12398 if (!alreadyseen)
Denys Vlasenko888527c2016-10-02 16:54:17 +020012399 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012400 else
Denys Vlasenko888527c2016-10-02 16:54:17 +020012401 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012402#endif
12403 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012404}
12405
Ron Yorstonc0e00762015-10-29 11:30:55 +000012406static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012407peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012408{
12409 int t;
12410
12411 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012412 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012413 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012414}
Eric Andersencb57d552001-06-28 07:25:16 +000012415
12416/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012417 * Read and parse a command. Returns NODE_EOF on end of file.
12418 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012419 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012420static union node *
12421parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012422{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012423 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012424 checkkwd = 0;
12425 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012426 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012427 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012428 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012429 return list(1);
12430}
12431
12432/*
12433 * Input any here documents.
12434 */
12435static void
12436parseheredoc(void)
12437{
12438 struct heredoc *here;
12439 union node *n;
12440
12441 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012442 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012443
12444 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012445 setprompt_if(needprompt, 2);
12446 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012447 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012448 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012449 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012450 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012451 n->narg.text = wordtext;
12452 n->narg.backquote = backquotelist;
12453 here->here->nhere.doc = n;
12454 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012455 }
Eric Andersencb57d552001-06-28 07:25:16 +000012456}
12457
12458
12459/*
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012460 * called by editline -- any expansions to the prompt should be added here.
Eric Andersencb57d552001-06-28 07:25:16 +000012461 */
Denis Vlasenko131ae172007-02-18 13:00:19 +000012462#if ENABLE_ASH_EXPAND_PRMT
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012463static const char *
12464expandstr(const char *ps)
12465{
12466 union node n;
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012467 int saveprompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012468
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000012469 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12470 * and token processing _can_ alter it (delete NULs etc). */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012471 setinputstring((char *)ps);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012472
12473 saveprompt = doprompt;
12474 doprompt = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000012475 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012476 doprompt = saveprompt;
12477
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012478 popfile();
12479
12480 n.narg.type = NARG;
12481 n.narg.next = NULL;
12482 n.narg.text = wordtext;
12483 n.narg.backquote = backquotelist;
12484
Ron Yorston549deab2015-05-18 09:57:51 +020012485 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012486 return stackblock();
12487}
12488#endif
12489
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012490/*
12491 * Execute a command or commands contained in a string.
12492 */
12493static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012494evalstring(char *s, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000012495{
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012496 struct jmploc *volatile savehandler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012497 struct jmploc jmploc;
12498 int ex;
12499
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012500 union node *n;
12501 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012502 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012503
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012504 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012505 setinputstring(s);
12506 setstackmark(&smark);
12507
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012508 status = 0;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012509 /* On exception inside execution loop, we must popfile().
12510 * Try interactively:
12511 * readonly a=a
12512 * command eval "a=b" # throws "is read only" error
12513 * "command BLTIN" is not supposed to abort (even in non-interactive use).
12514 * But if we skip popfile(), we hit EOF in eval's string, and exit.
12515 */
12516 savehandler = exception_handler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012517 ex = setjmp(jmploc.loc);
12518 if (ex)
12519 goto out;
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012520 exception_handler = &jmploc;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012521
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012522 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012523 int i;
12524
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012525 i = evaltree(n, flags);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012526 if (n)
12527 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012528 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012529 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012530 break;
12531 }
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012532 out:
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012533 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012534 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012535 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012536
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012537 exception_handler = savehandler;
12538 if (ex)
12539 longjmp(exception_handler->loc, ex);
12540
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012541 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000012542}
12543
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012544/*
12545 * The eval command.
12546 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012547static int FAST_FUNC
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012548evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012549{
12550 char *p;
12551 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012552
Denis Vlasenko68404f12008-03-17 09:00:54 +000012553 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012554 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012555 argv += 2;
12556 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012557 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012558 for (;;) {
12559 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012560 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012561 if (p == NULL)
12562 break;
12563 STPUTC(' ', concat);
12564 }
12565 STPUTC('\0', concat);
12566 p = grabstackstr(concat);
12567 }
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012568 return evalstring(p, flags & EV_TESTED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012569 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012570 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012571}
12572
12573/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012574 * Read and execute commands.
12575 * "Top" is nonzero for the top level command loop;
12576 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012577 */
12578static int
12579cmdloop(int top)
12580{
12581 union node *n;
12582 struct stackmark smark;
12583 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012584 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012585 int numeof = 0;
12586
12587 TRACE(("cmdloop(%d) called\n", top));
12588 for (;;) {
12589 int skip;
12590
12591 setstackmark(&smark);
12592#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012593 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020012594 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012595#endif
12596 inter = 0;
12597 if (iflag && top) {
12598 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012599 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012600 }
12601 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012602#if DEBUG
12603 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012604 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012605#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012606 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012607 if (!top || numeof >= 50)
12608 break;
12609 if (!stoppedjobs()) {
12610 if (!Iflag)
12611 break;
12612 out2str("\nUse \"exit\" to leave shell.\n");
12613 }
12614 numeof++;
12615 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012616 int i;
12617
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012618 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12619 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012620 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012621 i = evaltree(n, 0);
12622 if (n)
12623 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012624 }
12625 popstackmark(&smark);
12626 skip = evalskip;
12627
12628 if (skip) {
Denys Vlasenko6a0710e2016-09-30 14:18:34 +020012629 evalskip &= ~SKIPFUNC;
Denys Vlasenko0840c912016-10-01 15:27:44 +020012630 break;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012631 }
12632 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012633 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012634}
12635
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012636/*
12637 * Take commands from a file. To be compatible we should do a path
12638 * search for the file, which is necessary to find sub-commands.
12639 */
12640static char *
12641find_dot_file(char *name)
12642{
12643 char *fullname;
12644 const char *path = pathval();
12645 struct stat statb;
12646
12647 /* don't try this for absolute or relative paths */
12648 if (strchr(name, '/'))
12649 return name;
12650
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012651 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012652 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12653 /*
12654 * Don't bother freeing here, since it will
12655 * be freed by the caller.
12656 */
12657 return fullname;
12658 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012659 if (fullname != name)
12660 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012661 }
12662
12663 /* not found in the PATH */
12664 ash_msg_and_raise_error("%s: not found", name);
12665 /* NOTREACHED */
12666}
12667
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012668static int FAST_FUNC
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012669dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012670{
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012671 /* "false; . empty_file; echo $?" should print 0, not 1: */
12672 int status = 0;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012673 char *fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012674 char **argv;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012675 char *args_need_save;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012676 struct strlist *sp;
12677 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012678
12679 for (sp = cmdenviron; sp; sp = sp->next)
Denis Vlasenko4222ae42007-02-25 02:37:49 +000012680 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012681
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012682 nextopt(nullstr); /* handle possible "--" */
12683 argv = argptr;
12684
12685 if (!argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012686 /* bash says: "bash: .: filename argument required" */
12687 return 2; /* bash compat */
12688 }
12689
Denys Vlasenko091f8312013-03-17 14:25:22 +010012690 /* This aborts if file isn't found, which is POSIXly correct.
12691 * bash returns exitcode 1 instead.
12692 */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012693 fullname = find_dot_file(argv[0]);
12694 argv++;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012695 args_need_save = argv[0];
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010012696 if (args_need_save) { /* ". FILE ARGS", and ARGS are not empty */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012697 int argc;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012698 saveparam = shellparam;
12699 shellparam.malloced = 0;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012700 argc = 1;
12701 while (argv[argc])
12702 argc++;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012703 shellparam.nparam = argc;
12704 shellparam.p = argv;
12705 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012706
Denys Vlasenko091f8312013-03-17 14:25:22 +010012707 /* This aborts if file can't be opened, which is POSIXly correct.
12708 * bash returns exitcode 1 instead.
12709 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012710 setinputfile(fullname, INPUT_PUSH_FILE);
12711 commandname = fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012712 status = cmdloop(0);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012713 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012714
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012715 if (args_need_save) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012716 freeparam(&shellparam);
12717 shellparam = saveparam;
12718 };
12719
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012720 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012721}
12722
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012723static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012724exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012725{
12726 if (stoppedjobs())
12727 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012728 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012729 exitstatus = number(argv[1]);
12730 raise_exception(EXEXIT);
12731 /* NOTREACHED */
12732}
12733
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012734/*
12735 * Read a file containing shell functions.
12736 */
12737static void
12738readcmdfile(char *name)
12739{
12740 setinputfile(name, INPUT_PUSH_FILE);
12741 cmdloop(0);
12742 popfile();
12743}
12744
12745
Denis Vlasenkocc571512007-02-23 21:10:35 +000012746/* ============ find_command inplementation */
12747
12748/*
12749 * Resolve a command name. If you change this routine, you may have to
12750 * change the shellexec routine as well.
12751 */
12752static void
12753find_command(char *name, struct cmdentry *entry, int act, const char *path)
12754{
12755 struct tblentry *cmdp;
12756 int idx;
12757 int prev;
12758 char *fullname;
12759 struct stat statb;
12760 int e;
12761 int updatetbl;
12762 struct builtincmd *bcmd;
12763
12764 /* If name contains a slash, don't use PATH or hash table */
12765 if (strchr(name, '/') != NULL) {
12766 entry->u.index = -1;
12767 if (act & DO_ABS) {
12768 while (stat(name, &statb) < 0) {
12769#ifdef SYSV
12770 if (errno == EINTR)
12771 continue;
12772#endif
12773 entry->cmdtype = CMDUNKNOWN;
12774 return;
12775 }
12776 }
12777 entry->cmdtype = CMDNORMAL;
12778 return;
12779 }
12780
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012781/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012782
12783 updatetbl = (path == pathval());
12784 if (!updatetbl) {
12785 act |= DO_ALTPATH;
12786 if (strstr(path, "%builtin") != NULL)
12787 act |= DO_ALTBLTIN;
12788 }
12789
12790 /* If name is in the table, check answer will be ok */
12791 cmdp = cmdlookup(name, 0);
12792 if (cmdp != NULL) {
12793 int bit;
12794
12795 switch (cmdp->cmdtype) {
12796 default:
12797#if DEBUG
12798 abort();
12799#endif
12800 case CMDNORMAL:
12801 bit = DO_ALTPATH;
12802 break;
12803 case CMDFUNCTION:
12804 bit = DO_NOFUNC;
12805 break;
12806 case CMDBUILTIN:
12807 bit = DO_ALTBLTIN;
12808 break;
12809 }
12810 if (act & bit) {
12811 updatetbl = 0;
12812 cmdp = NULL;
12813 } else if (cmdp->rehash == 0)
12814 /* if not invalidated by cd, we're done */
12815 goto success;
12816 }
12817
12818 /* If %builtin not in path, check for builtin next */
12819 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012820 if (bcmd) {
12821 if (IS_BUILTIN_REGULAR(bcmd))
12822 goto builtin_success;
12823 if (act & DO_ALTPATH) {
12824 if (!(act & DO_ALTBLTIN))
12825 goto builtin_success;
12826 } else if (builtinloc <= 0) {
12827 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000012828 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012829 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000012830
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012831#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000012832 {
12833 int applet_no = find_applet_by_name(name);
12834 if (applet_no >= 0) {
12835 entry->cmdtype = CMDNORMAL;
12836 entry->u.index = -2 - applet_no;
12837 return;
12838 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012839 }
12840#endif
12841
Denis Vlasenkocc571512007-02-23 21:10:35 +000012842 /* We have to search path. */
12843 prev = -1; /* where to start */
12844 if (cmdp && cmdp->rehash) { /* doing a rehash */
12845 if (cmdp->cmdtype == CMDBUILTIN)
12846 prev = builtinloc;
12847 else
12848 prev = cmdp->param.index;
12849 }
12850
12851 e = ENOENT;
12852 idx = -1;
12853 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012854 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000012855 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012856 /* NB: code below will still use fullname
12857 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012858 idx++;
12859 if (pathopt) {
12860 if (prefix(pathopt, "builtin")) {
12861 if (bcmd)
12862 goto builtin_success;
12863 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000012864 }
12865 if ((act & DO_NOFUNC)
12866 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020012867 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012868 continue;
12869 }
12870 }
12871 /* if rehash, don't redo absolute path names */
12872 if (fullname[0] == '/' && idx <= prev) {
12873 if (idx < prev)
12874 continue;
12875 TRACE(("searchexec \"%s\": no change\n", name));
12876 goto success;
12877 }
12878 while (stat(fullname, &statb) < 0) {
12879#ifdef SYSV
12880 if (errno == EINTR)
12881 continue;
12882#endif
12883 if (errno != ENOENT && errno != ENOTDIR)
12884 e = errno;
12885 goto loop;
12886 }
12887 e = EACCES; /* if we fail, this will be the error */
12888 if (!S_ISREG(statb.st_mode))
12889 continue;
12890 if (pathopt) { /* this is a %func directory */
12891 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012892 /* NB: stalloc will return space pointed by fullname
12893 * (because we don't have any intervening allocations
12894 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012895 readcmdfile(fullname);
12896 cmdp = cmdlookup(name, 0);
12897 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12898 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12899 stunalloc(fullname);
12900 goto success;
12901 }
12902 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12903 if (!updatetbl) {
12904 entry->cmdtype = CMDNORMAL;
12905 entry->u.index = idx;
12906 return;
12907 }
12908 INT_OFF;
12909 cmdp = cmdlookup(name, 1);
12910 cmdp->cmdtype = CMDNORMAL;
12911 cmdp->param.index = idx;
12912 INT_ON;
12913 goto success;
12914 }
12915
12916 /* We failed. If there was an entry for this command, delete it */
12917 if (cmdp && updatetbl)
12918 delete_cmd_entry();
12919 if (act & DO_ERR)
12920 ash_msg("%s: %s", name, errmsg(e, "not found"));
12921 entry->cmdtype = CMDUNKNOWN;
12922 return;
12923
12924 builtin_success:
12925 if (!updatetbl) {
12926 entry->cmdtype = CMDBUILTIN;
12927 entry->u.cmd = bcmd;
12928 return;
12929 }
12930 INT_OFF;
12931 cmdp = cmdlookup(name, 1);
12932 cmdp->cmdtype = CMDBUILTIN;
12933 cmdp->param.cmd = bcmd;
12934 INT_ON;
12935 success:
12936 cmdp->rehash = 0;
12937 entry->cmdtype = cmdp->cmdtype;
12938 entry->u = cmdp->param;
12939}
12940
12941
Eric Andersencb57d552001-06-28 07:25:16 +000012942/*
Eric Andersencb57d552001-06-28 07:25:16 +000012943 * The trap builtin.
12944 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012945static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012946trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012947{
12948 char *action;
12949 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012950 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012951
Eric Andersenc470f442003-07-28 09:56:35 +000012952 nextopt(nullstr);
12953 ap = argptr;
12954 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012955 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012956 char *tr = trap_ptr[signo];
12957 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012958 /* note: bash adds "SIG", but only if invoked
12959 * as "bash". If called as "sh", or if set -o posix,
12960 * then it prints short signal names.
12961 * We are printing short names: */
12962 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012963 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012964 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012965 /* trap_ptr != trap only if we are in special-cased `trap` code.
12966 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012967 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012968 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000012969 }
12970 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012971 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012972 if (trap_ptr != trap) {
12973 free(trap_ptr);
12974 trap_ptr = trap;
12975 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012976 */
Eric Andersencb57d552001-06-28 07:25:16 +000012977 return 0;
12978 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012979
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012980 action = NULL;
12981 if (ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000012982 action = *ap++;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012983 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012984 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012985 signo = get_signum(*ap);
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012986 if (signo < 0) {
12987 /* Mimic bash message exactly */
12988 ash_msg("%s: invalid signal specification", *ap);
12989 exitcode = 1;
12990 goto next;
12991 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000012992 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000012993 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000012994 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000012995 action = NULL;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020012996 else {
12997 if (action[0]) /* not NULL and not "" and not "-" */
12998 may_have_traps = 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012999 action = ckstrdup(action);
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013000 }
Eric Andersencb57d552001-06-28 07:25:16 +000013001 }
Denis Vlasenko60818682007-09-28 22:07:23 +000013002 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000013003 trap[signo] = action;
13004 if (signo != 0)
13005 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013006 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013007 next:
Eric Andersencb57d552001-06-28 07:25:16 +000013008 ap++;
13009 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013010 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013011}
13012
Eric Andersenc470f442003-07-28 09:56:35 +000013013
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013014/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000013015
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013016#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013017static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013018helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013019{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000013020 unsigned col;
13021 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000013022
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020013023 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000013024 "Built-in commands:\n"
13025 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000013026 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013027 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000013028 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013029 if (col > 60) {
13030 out1fmt("\n");
13031 col = 0;
13032 }
13033 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013034# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000013035 {
13036 const char *a = applet_names;
13037 while (*a) {
13038 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
13039 if (col > 60) {
13040 out1fmt("\n");
13041 col = 0;
13042 }
Ron Yorston2b919582016-04-08 11:57:20 +010013043 while (*a++ != '\0')
13044 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013045 }
13046 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013047# endif
Denys Vlasenkoebedb942016-10-02 18:45:09 +020013048 newline_and_flush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000013049 return EXIT_SUCCESS;
13050}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013051#endif
Eric Andersenc470f442003-07-28 09:56:35 +000013052
Flemming Madsend96ffda2013-04-07 18:47:24 +020013053#if MAX_HISTORY
13054static int FAST_FUNC
13055historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13056{
13057 show_history(line_input_state);
13058 return EXIT_SUCCESS;
13059}
13060#endif
13061
Eric Andersencb57d552001-06-28 07:25:16 +000013062/*
Eric Andersencb57d552001-06-28 07:25:16 +000013063 * The export and readonly commands.
13064 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013065static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013066exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000013067{
13068 struct var *vp;
13069 char *name;
13070 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000013071 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020013072 char opt;
13073 int flag;
13074 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000013075
Denys Vlasenkod5275882012-10-01 13:41:17 +020013076 /* "readonly" in bash accepts, but ignores -n.
13077 * We do the same: it saves a conditional in nextopt's param.
13078 */
13079 flag_off = 0;
13080 while ((opt = nextopt("np")) != '\0') {
13081 if (opt == 'n')
13082 flag_off = VEXPORT;
13083 }
13084 flag = VEXPORT;
13085 if (argv[0][0] == 'r') {
13086 flag = VREADONLY;
13087 flag_off = 0; /* readonly ignores -n */
13088 }
13089 flag_off = ~flag_off;
13090
Denys Vlasenko10ad6222017-04-17 16:13:32 +020013091 /*if (opt_p_not_specified) - bash doesn't check this. Try "export -p NAME" */
Denys Vlasenkod5275882012-10-01 13:41:17 +020013092 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013093 aptr = argptr;
13094 name = *aptr;
13095 if (name) {
13096 do {
13097 p = strchr(name, '=');
13098 if (p != NULL) {
13099 p++;
13100 } else {
13101 vp = *findvar(hashvar(name), name);
13102 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020013103 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013104 continue;
13105 }
Eric Andersencb57d552001-06-28 07:25:16 +000013106 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013107 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013108 } while ((name = *++aptr) != NULL);
13109 return 0;
13110 }
Eric Andersencb57d552001-06-28 07:25:16 +000013111 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013112
13113 /* No arguments. Show the list of exported or readonly vars.
13114 * -n is ignored.
13115 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013116 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000013117 return 0;
13118}
13119
Eric Andersencb57d552001-06-28 07:25:16 +000013120/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013121 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000013122 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013123static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013124unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000013125{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013126 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000013127
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013128 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013129 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013130 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000013131}
13132
Eric Andersencb57d552001-06-28 07:25:16 +000013133/*
Eric Andersencb57d552001-06-28 07:25:16 +000013134 * The unset builtin command. We unset the function before we unset the
13135 * variable to allow a function to be unset when there is a readonly variable
13136 * with the same name.
13137 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013138static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013139unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013140{
13141 char **ap;
13142 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013143 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013144 int ret = 0;
13145
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013146 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000013147 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000013148 }
Eric Andersencb57d552001-06-28 07:25:16 +000013149
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013150 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013151 if (flag != 'f') {
13152 i = unsetvar(*ap);
13153 ret |= i;
13154 if (!(i & 2))
13155 continue;
13156 }
13157 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000013158 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000013159 }
Eric Andersenc470f442003-07-28 09:56:35 +000013160 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000013161}
13162
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000013163static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013164 ' ', offsetof(struct tms, tms_utime),
13165 '\n', offsetof(struct tms, tms_stime),
13166 ' ', offsetof(struct tms, tms_cutime),
13167 '\n', offsetof(struct tms, tms_cstime),
13168 0
13169};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013170static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013171timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013172{
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020013173 unsigned long clk_tck, s, t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013174 const unsigned char *p;
13175 struct tms buf;
13176
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020013177 clk_tck = bb_clk_tck();
Eric Andersencb57d552001-06-28 07:25:16 +000013178 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013179
13180 p = timescmd_str;
13181 do {
13182 t = *(clock_t *)(((char *) &buf) + p[1]);
13183 s = t / clk_tck;
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020013184 t = t % clk_tck;
13185 out1fmt("%lum%lu.%03lus%c",
13186 s / 60, s % 60,
13187 (t * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013188 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013189 p += 2;
13190 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013191
Eric Andersencb57d552001-06-28 07:25:16 +000013192 return 0;
13193}
13194
Denys Vlasenko0b883582016-12-23 16:49:07 +010013195#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000013196/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013197 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013198 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000013199 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013200 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000013201 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013202static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013203letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013204{
Denis Vlasenko68404f12008-03-17 09:00:54 +000013205 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000013206
Denis Vlasenko68404f12008-03-17 09:00:54 +000013207 argv++;
13208 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000013209 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000013210 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013211 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013212 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013213
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000013214 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000013215}
Eric Andersenc470f442003-07-28 09:56:35 +000013216#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013217
Eric Andersenc470f442003-07-28 09:56:35 +000013218/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013219 * The read builtin. Options:
13220 * -r Do not interpret '\' specially
13221 * -s Turn off echo (tty only)
13222 * -n NCHARS Read NCHARS max
13223 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13224 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13225 * -u FD Read from given FD instead of fd 0
Eric Andersenc470f442003-07-28 09:56:35 +000013226 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013227 * TODO: bash also has:
13228 * -a ARRAY Read into array[0],[1],etc
13229 * -d DELIM End on DELIM char, not newline
13230 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000013231 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013232static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013233readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013234{
Denys Vlasenko73067272010-01-12 22:11:24 +010013235 char *opt_n = NULL;
13236 char *opt_p = NULL;
13237 char *opt_t = NULL;
13238 char *opt_u = NULL;
13239 int read_flags = 0;
13240 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000013241 int i;
13242
Denys Vlasenko73067272010-01-12 22:11:24 +010013243 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000013244 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000013245 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010013246 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013247 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013248 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010013249 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013250 break;
13251 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010013252 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000013253 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013254 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010013255 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013256 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013257 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010013258 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000013259 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013260 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010013261 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013262 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013263 default:
13264 break;
13265 }
Eric Andersenc470f442003-07-28 09:56:35 +000013266 }
Paul Fox02eb9342005-09-07 16:56:02 +000013267
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013268 /* "read -s" needs to save/restore termios, can't allow ^C
13269 * to jump out of it.
13270 */
13271 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013272 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010013273 argptr,
13274 bltinlookup("IFS"), /* can be NULL */
13275 read_flags,
13276 opt_n,
13277 opt_p,
13278 opt_t,
13279 opt_u
13280 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013281 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000013282
Denys Vlasenko73067272010-01-12 22:11:24 +010013283 if ((uintptr_t)r > 1)
13284 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000013285
Denys Vlasenko73067272010-01-12 22:11:24 +010013286 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000013287}
13288
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013289static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020013290umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013291{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013292 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000013293
Eric Andersenc470f442003-07-28 09:56:35 +000013294 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000013295 int symbolic_mode = 0;
13296
13297 while (nextopt("S") != '\0') {
13298 symbolic_mode = 1;
13299 }
13300
Denis Vlasenkob012b102007-02-19 22:43:01 +000013301 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013302 mask = umask(0);
13303 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013304 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013305
Denys Vlasenko6283f982015-10-07 16:56:20 +020013306 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013307 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013308 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013309 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013310 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013311
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013312 i = 2;
13313 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013314 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013315 *p++ = permuser[i];
13316 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013317 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013318 if (!(mask & 0400)) *p++ = 'r';
13319 if (!(mask & 0200)) *p++ = 'w';
13320 if (!(mask & 0100)) *p++ = 'x';
13321 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013322 if (--i < 0)
13323 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013324 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013325 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013326 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013327 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013328 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013329 }
13330 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013331 char *modestr = *argptr;
13332 /* numeric umasks are taken as-is */
13333 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
13334 if (!isdigit(modestr[0]))
13335 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013336 mask = bb_parse_mode(modestr, mask);
13337 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013338 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013339 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013340 if (!isdigit(modestr[0]))
13341 mask ^= 0777;
13342 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013343 }
13344 return 0;
13345}
13346
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013347static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013348ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013349{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013350 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013351}
13352
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013353/* ============ main() and helpers */
13354
13355/*
13356 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013357 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013358static void
13359exitshell(void)
13360{
13361 struct jmploc loc;
13362 char *p;
13363 int status;
13364
Denys Vlasenkobede2152011-09-04 16:12:33 +020013365#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13366 save_history(line_input_state);
13367#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013368 status = exitstatus;
13369 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13370 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013371 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013372 status = exitstatus;
13373 goto out;
13374 }
13375 exception_handler = &loc;
13376 p = trap[0];
13377 if (p) {
13378 trap[0] = NULL;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013379 evalskip = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013380 evalstring(p, 0);
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013381 /*free(p); - we'll exit soon */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013382 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013383 out:
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013384 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13385 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13386 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013387 setjobctl(0);
Denys Vlasenkocaee80c2016-10-25 20:49:53 +020013388 flush_stdout_stderr();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013389 _exit(status);
13390 /* NOTREACHED */
13391}
13392
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013393static void
13394init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013395{
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013396 /* we will never free this */
13397 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013398
Denys Vlasenko458c1f22016-10-27 23:51:19 +020013399 sigmode[SIGCHLD - 1] = S_DFL;
13400 setsignal(SIGCHLD);
13401
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013402 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13403 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13404 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013405 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013406
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013407 {
13408 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013409 const char *p;
13410 struct stat st1, st2;
13411
13412 initvar();
13413 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenkob6838b52016-09-30 11:33:47 +020013414 p = endofname(*envp);
13415 if (p != *envp && *p == '=') {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013416 setvareq(*envp, VEXPORT|VTEXTFIXED);
13417 }
13418 }
13419
Denys Vlasenkoe627ac92016-09-30 14:36:59 +020013420 setvareq((char*)defoptindvar, VTEXTFIXED);
13421
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013422 setvar0("PPID", utoa(getppid()));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013423#if BASH_SHLVL_VAR
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013424 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013425 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013426#endif
13427#if BASH_HOSTNAME_VAR
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013428 if (!lookupvar("HOSTNAME")) {
13429 struct utsname uts;
13430 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013431 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013432 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013433#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013434 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013435 if (p) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013436 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013437 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13438 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013439 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013440 }
13441 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013442 setpwd(p, 0);
13443 }
13444}
13445
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013446
13447//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013448//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013449//usage:#define ash_full_usage "\n\n"
13450//usage: "Unix shell interpreter"
13451
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013452/*
13453 * Process the shell command line arguments.
13454 */
13455static void
Denis Vlasenko68404f12008-03-17 09:00:54 +000013456procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013457{
13458 int i;
13459 const char *xminusc;
13460 char **xargv;
13461
13462 xargv = argv;
13463 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013464 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013465 xargv++;
13466 for (i = 0; i < NOPTS; i++)
13467 optlist[i] = 2;
13468 argptr = xargv;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013469 if (options(/*cmdline:*/ 1)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013470 /* it already printed err message */
13471 raise_exception(EXERROR);
13472 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013473 xargv = argptr;
13474 xminusc = minusc;
13475 if (*xargv == NULL) {
13476 if (xminusc)
13477 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13478 sflag = 1;
13479 }
13480 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13481 iflag = 1;
13482 if (mflag == 2)
13483 mflag = iflag;
13484 for (i = 0; i < NOPTS; i++)
13485 if (optlist[i] == 2)
13486 optlist[i] = 0;
13487#if DEBUG == 2
13488 debug = 1;
13489#endif
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013490 /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013491 if (xminusc) {
13492 minusc = *xargv++;
13493 if (*xargv)
13494 goto setarg0;
13495 } else if (!sflag) {
13496 setinputfile(*xargv, 0);
13497 setarg0:
13498 arg0 = *xargv++;
13499 commandname = arg0;
13500 }
13501
13502 shellparam.p = xargv;
13503#if ENABLE_ASH_GETOPTS
13504 shellparam.optind = 1;
13505 shellparam.optoff = -1;
13506#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013507 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013508 while (*xargv) {
13509 shellparam.nparam++;
13510 xargv++;
13511 }
13512 optschanged();
13513}
13514
13515/*
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013516 * Read /etc/profile, ~/.profile, $ENV.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013517 */
13518static void
13519read_profile(const char *name)
13520{
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013521 name = expandstr(name);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013522 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13523 return;
Denys Vlasenko0840c912016-10-01 15:27:44 +020013524 cmdloop(0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013525 popfile();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013526}
13527
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013528/*
13529 * This routine is called when an error or an interrupt occurs in an
13530 * interactive shell and control is returned to the main command loop.
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013531 * (In dash, this function is auto-generated by build machinery).
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013532 */
13533static void
13534reset(void)
13535{
13536 /* from eval.c: */
13537 evalskip = 0;
13538 loopnest = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013539
13540 /* from expand.c: */
13541 ifsfree();
13542
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013543 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013544 g_parsefile->left_in_buffer = 0;
13545 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013546 popallfiles();
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013547
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013548 /* from redir.c: */
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020013549 while (redirlist)
13550 popredir(/*drop:*/ 0, /*restore:*/ 0);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013551}
13552
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013553#if PROFILE
13554static short profile_buf[16384];
13555extern int etext();
13556#endif
13557
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013558/*
13559 * Main routine. We initialize things, parse the arguments, execute
13560 * profiles if we're a login shell, and then call cmdloop to execute
13561 * commands. The setjmp call sets up the location to jump to when an
13562 * exception occurs. When an exception occurs the variable "state"
13563 * is used to figure out how far we had gotten.
13564 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013565int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013566int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013567{
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013568 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013569 struct jmploc jmploc;
13570 struct stackmark smark;
13571
Denis Vlasenko01631112007-12-16 17:20:38 +000013572 /* Initialize global data */
13573 INIT_G_misc();
13574 INIT_G_memstack();
13575 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013576#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013577 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013578#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013579 INIT_G_cmdtable();
13580
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013581#if PROFILE
13582 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13583#endif
13584
13585#if ENABLE_FEATURE_EDITING
13586 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13587#endif
13588 state = 0;
13589 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013590 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013591 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013592
13593 reset();
13594
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013595 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013596 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013597 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013598 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013599 }
13600 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020013601 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013602 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013603
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013604 popstackmark(&smark);
13605 FORCE_INT_ON; /* enable interrupts */
13606 if (s == 1)
13607 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013608 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013609 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013610 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013611 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013612 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013613 }
13614 exception_handler = &jmploc;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013615 rootpid = getpid();
13616
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013617 init();
13618 setstackmark(&smark);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013619 procargs(argv);
Denys Vlasenko474ed062016-10-30 18:30:29 +010013620#if DEBUG
13621 TRACE(("Shell args: "));
13622 trace_puts_args(argv);
13623#endif
Denis Vlasenko68404f12008-03-17 09:00:54 +000013624
Denys Vlasenko6088e132010-12-25 23:58:42 +010013625 if (argv[0] && argv[0][0] == '-')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013626 isloginsh = 1;
13627 if (isloginsh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013628 const char *hp;
13629
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013630 state = 1;
13631 read_profile("/etc/profile");
13632 state1:
13633 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013634 hp = lookupvar("HOME");
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013635 if (hp)
13636 read_profile("$HOME/.profile");
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013637 }
13638 state2:
13639 state = 3;
13640 if (
13641#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013642 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013643#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013644 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013645 ) {
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013646 const char *shinit = lookupvar("ENV");
13647 if (shinit != NULL && *shinit != '\0')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013648 read_profile(shinit);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013649 }
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013650 popstackmark(&smark);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013651 state3:
13652 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013653 if (minusc) {
13654 /* evalstring pushes parsefile stack.
13655 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013656 * is one of stacked source fds.
13657 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013658 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013659 // ^^ not necessary since now we special-case fd 0
13660 // in is_hidden_fd() to not be considered "hidden fd"
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013661 evalstring(minusc, 0);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013662 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013663
13664 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020013665#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013666 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013667 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013668 if (!hp) {
13669 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013670 if (hp) {
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013671 INT_OFF;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013672 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013673 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013674 free((char*)hp);
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013675 INT_ON;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013676 hp = lookupvar("HISTFILE");
13677 }
13678 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013679 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013680 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013681# if ENABLE_FEATURE_SH_HISTFILESIZE
13682 hp = lookupvar("HISTFILESIZE");
13683 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13684# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013685 }
13686#endif
13687 state4: /* XXX ??? - why isn't this before the "if" statement */
13688 cmdloop(1);
13689 }
13690#if PROFILE
13691 monitor(0);
13692#endif
13693#ifdef GPROF
13694 {
13695 extern void _mcleanup(void);
13696 _mcleanup();
13697 }
13698#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013699 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013700 exitshell();
13701 /* NOTREACHED */
13702}
13703
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013704
Eric Andersendf82f612001-06-28 07:46:40 +000013705/*-
13706 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013707 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013708 *
13709 * This code is derived from software contributed to Berkeley by
13710 * Kenneth Almquist.
13711 *
13712 * Redistribution and use in source and binary forms, with or without
13713 * modification, are permitted provided that the following conditions
13714 * are met:
13715 * 1. Redistributions of source code must retain the above copyright
13716 * notice, this list of conditions and the following disclaimer.
13717 * 2. Redistributions in binary form must reproduce the above copyright
13718 * notice, this list of conditions and the following disclaimer in the
13719 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013720 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013721 * may be used to endorse or promote products derived from this software
13722 * without specific prior written permission.
13723 *
13724 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13725 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13726 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13727 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13728 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13729 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13730 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13731 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13732 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13733 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13734 * SUCH DAMAGE.
13735 */