blob: b7635a82332c3f108becf4a83b8f5dcb57dbaa54 [file] [log] [blame]
Eric Andersendf82f612001-06-28 07:46:40 +00001/* vi: set sw=4 ts=4: */
2/*
3 * ash shell port for busybox
4 *
Denys Vlasenko73067272010-01-12 22:11:24 +01005 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
8 * Original BSD copyright notice is retained at the end of this file.
9 *
Eric Andersendf82f612001-06-28 07:46:40 +000010 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000011 * The Regents of the University of California. All rights reserved.
Eric Andersencb57d552001-06-28 07:25:16 +000012 *
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
Eric Andersen81fe1232003-07-29 06:38:40 +000014 * was re-ported from NetBSD and debianized.
15 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +020016 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Eric Andersencb57d552001-06-28 07:25:16 +000017 */
Denys Vlasenko771f1992010-07-16 14:31:34 +020018//config:config ASH
19//config: bool "ash"
20//config: default y
21//config: depends on !NOMMU
22//config: help
23//config: Tha 'ash' shell adds about 60k in the default configuration and is
24//config: the most complete and most pedantically correct shell included with
25//config: busybox. This shell is actually a derivative of the Debian 'dash'
26//config: shell (by Herbert Xu), which was created by porting the 'ash' shell
27//config: (written by Kenneth Almquist) from NetBSD.
28//config:
Kang-Che Sung6cd02942017-01-06 17:02:03 +010029//config:# ash options
30//config:# note: Don't remove !NOMMU part in the next line; it would break
31//config:# menuconfig's indenting.
32//config:if !NOMMU && (ASH || SH_IS_ASH || BASH_IS_ASH)
33//config:
Denys Vlasenko514b51d2016-10-01 14:33:08 +020034//config:config ASH_OPTIMIZE_FOR_SIZE
35//config: bool "Optimize for size instead of speed"
36//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010037//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020038//config:
39//config:config ASH_INTERNAL_GLOB
40//config: bool "Use internal glob() implementation"
Denys Vlasenko326edc32016-12-22 14:36:49 +010041//config: default y # Y is bigger, but because of uclibc glob() bug, let Y be default for now
Denys Vlasenko0b883582016-12-23 16:49:07 +010042//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020043//config: help
44//config: Do not use glob() function from libc, use internal implementation.
45//config: Use this if you are getting "glob.h: No such file or directory"
46//config: or similar build errors.
Denys Vlasenkof5604222017-01-10 14:58:54 +010047//config: Note that as of now (2017-01), uclibc and musl glob() both have bugs
48//config: which would break ash if you select N here.
49//config:
50//config:config ASH_BASH_COMPAT
51//config: bool "bash-compatible extensions"
52//config: default y
53//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
54//config:
55//config:config ASH_JOB_CONTROL
56//config: bool "Job control"
57//config: default y
58//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
59//config:
60//config:config ASH_ALIAS
61//config: bool "Alias support"
62//config: default y
63//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020064//config:
65//config:config ASH_RANDOM_SUPPORT
66//config: bool "Pseudorandom generator and $RANDOM variable"
67//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010068//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020069//config: help
70//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
71//config: Each read of "$RANDOM" will generate a new pseudorandom value.
72//config: You can reset the generator by using a specified start value.
73//config: After "unset RANDOM" the generator will switch off and this
74//config: variable will no longer have special treatment.
75//config:
76//config:config ASH_EXPAND_PRMT
77//config: bool "Expand prompt string"
78//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010079//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020080//config: help
Denys Vlasenkof5604222017-01-10 14:58:54 +010081//config: $PS# may contain volatile content, such as backquote commands.
Denys Vlasenko514b51d2016-10-01 14:33:08 +020082//config: This option recreates the prompt string from the environment
83//config: variable each time it is displayed.
84//config:
Denys Vlasenko046341e2011-02-04 17:53:59 +010085//config:config ASH_IDLE_TIMEOUT
Denys Vlasenkof5604222017-01-10 14:58:54 +010086//config: bool "Idle timeout variable $TMOUT"
Denys Vlasenko771f1992010-07-16 14:31:34 +020087//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010088//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +020089//config: help
Denys Vlasenkof5604222017-01-10 14:58:54 +010090//config: Enable bash-like auto-logout after $TMOUT seconds of idle time.
Denys Vlasenko771f1992010-07-16 14:31:34 +020091//config:
Denys Vlasenkof5604222017-01-10 14:58:54 +010092//config:config ASH_MAIL
93//config: bool "Check for new mail in interactive shell"
Denys Vlasenko771f1992010-07-16 14:31:34 +020094//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010095//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +020096//config: help
Denys Vlasenkof5604222017-01-10 14:58:54 +010097//config: Enable "check for new mail" function:
98//config: if set, $MAIL file and $MAILPATH list of files
99//config: are checked for mtime changes, and "you have mail"
100//config: message is printed if change is detected.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200101//config:
Denys Vlasenko265062d2017-01-10 15:13:30 +0100102//config:config ASH_ECHO
Denys Vlasenkof5604222017-01-10 14:58:54 +0100103//config: bool "echo builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200104//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100105//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200106//config:
Denys Vlasenko265062d2017-01-10 15:13:30 +0100107//config:config ASH_PRINTF
Denys Vlasenkof5604222017-01-10 14:58:54 +0100108//config: bool "printf builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200109//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100110//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200111//config:
Denys Vlasenko265062d2017-01-10 15:13:30 +0100112//config:config ASH_TEST
Denys Vlasenkof5604222017-01-10 14:58:54 +0100113//config: bool "test builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200114//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100115//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200116//config:
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200117//config:config ASH_HELP
118//config: bool "help builtin"
119//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100120//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenkof5604222017-01-10 14:58:54 +0100121//config:
122//config:config ASH_GETOPTS
123//config: bool "getopts builtin"
124//config: default y
125//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200126//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200127//config:config ASH_CMDCMD
Denys Vlasenkof5604222017-01-10 14:58:54 +0100128//config: bool "command builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200129//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100130//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200131//config: help
Denys Vlasenkof5604222017-01-10 14:58:54 +0100132//config: Enable support for the 'command' builtin, which allows
133//config: you to run the specified command or builtin,
134//config: even when there is a function with the same name.
Kang-Che Sung6cd02942017-01-06 17:02:03 +0100135//config:
136//config:endif # ash options
Denys Vlasenko771f1992010-07-16 14:31:34 +0200137
Denys Vlasenko20704f02011-03-23 17:59:27 +0100138//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
Denys Vlasenko205d48e2017-01-29 14:57:33 +0100139// APPLET_ODDNAME:name main location suid_type help
140//applet:IF_SH_IS_ASH( APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
Denys Vlasenko0b883582016-12-23 16:49:07 +0100141//applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
Denys Vlasenko20704f02011-03-23 17:59:27 +0100142
143//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
Denys Vlasenko0b883582016-12-23 16:49:07 +0100144//kbuild:lib-$(CONFIG_SH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
145//kbuild:lib-$(CONFIG_BASH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
Denys Vlasenko20704f02011-03-23 17:59:27 +0100146//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
147
Denys Vlasenko67047462016-12-22 15:21:58 +0100148/*
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100149 * DEBUG=1 to compile in debugging ('set -o debug' turns on)
150 * DEBUG=2 to compile in and turn on debugging.
151 * When debugging is on ("set -o debug" was executed, or DEBUG=2),
152 * debugging info is written to ./trace, quit signal generates core dump.
Denys Vlasenko67047462016-12-22 15:21:58 +0100153 */
154#define DEBUG 0
155/* Tweak debug output verbosity here */
156#define DEBUG_TIME 0
157#define DEBUG_PID 1
158#define DEBUG_SIG 1
159#define DEBUG_INTONOFF 0
160
161#define PROFILE 0
162
163#define JOBS ENABLE_ASH_JOB_CONTROL
164
165#include <setjmp.h>
166#include <fnmatch.h>
167#include <sys/times.h>
168#include <sys/utsname.h> /* for setting $HOSTNAME */
Denys Vlasenko67047462016-12-22 15:21:58 +0100169#include "busybox.h" /* for applet_names */
170
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100171/* So far, all bash compat is controlled by one config option */
172/* Separate defines document which part of code implements what */
173/* function keyword */
174#define BASH_FUNCTION ENABLE_ASH_BASH_COMPAT
175#define IF_BASH_FUNCTION IF_ASH_BASH_COMPAT
176/* &>file */
177#define BASH_REDIR_OUTPUT ENABLE_ASH_BASH_COMPAT
178#define IF_BASH_REDIR_OUTPUT IF_ASH_BASH_COMPAT
179/* $'...' */
180#define BASH_DOLLAR_SQUOTE ENABLE_ASH_BASH_COMPAT
181#define IF_BASH_DOLLAR_SQUOTE IF_ASH_BASH_COMPAT
182#define BASH_PATTERN_SUBST ENABLE_ASH_BASH_COMPAT
183#define IF_BASH_PATTERN_SUBST IF_ASH_BASH_COMPAT
184#define BASH_SUBSTR ENABLE_ASH_BASH_COMPAT
185#define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT
186/* [[ EXPR ]] */
187#define BASH_TEST2 (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST)
188#define BASH_SOURCE ENABLE_ASH_BASH_COMPAT
189#define BASH_PIPEFAIL ENABLE_ASH_BASH_COMPAT
190#define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT
191#define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT
192
Denys Vlasenko67047462016-12-22 15:21:58 +0100193#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
194/* Bionic at least up to version 24 has no glob() */
195# undef ENABLE_ASH_INTERNAL_GLOB
196# define ENABLE_ASH_INTERNAL_GLOB 1
197#endif
198
199#if !ENABLE_ASH_INTERNAL_GLOB && defined(__UCLIBC__)
200# error uClibc glob() is buggy, use ASH_INTERNAL_GLOB.
201# error The bug is: for "$PWD"/<pattern> ash will escape e.g. dashes in "$PWD"
202# error with backslash, even ones which do not need to be: "/a-b" -> "/a\-b"
203# error glob() should unbackslash them and match. uClibc does not unbackslash,
204# error fails to match dirname, subsequently not expanding <pattern> in it.
205// Testcase:
206// if (glob("/etc/polkit\\-1", 0, NULL, &pglob)) - this returns 0 on uclibc, no bug
207// if (glob("/etc/polkit\\-1/*", 0, NULL, &pglob)) printf("uclibc bug!\n");
208#endif
209
210#if !ENABLE_ASH_INTERNAL_GLOB
211# include <glob.h>
212#endif
213
214#include "unicode.h"
215#include "shell_common.h"
Denys Vlasenko0b883582016-12-23 16:49:07 +0100216#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko67047462016-12-22 15:21:58 +0100217# include "math.h"
218#endif
219#if ENABLE_ASH_RANDOM_SUPPORT
220# include "random.h"
221#else
222# define CLEAR_RANDOM_T(rnd) ((void)0)
223#endif
224
225#include "NUM_APPLETS.h"
226#if NUM_APPLETS == 1
227/* STANDALONE does not make sense, and won't compile */
228# undef CONFIG_FEATURE_SH_STANDALONE
229# undef ENABLE_FEATURE_SH_STANDALONE
230# undef IF_FEATURE_SH_STANDALONE
231# undef IF_NOT_FEATURE_SH_STANDALONE
232# define ENABLE_FEATURE_SH_STANDALONE 0
233# define IF_FEATURE_SH_STANDALONE(...)
234# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
235#endif
236
237#ifndef PIPE_BUF
238# define PIPE_BUF 4096 /* amount of buffering in a pipe */
239#endif
240
241#if !BB_MMU
242# error "Do not even bother, ash will not run on NOMMU machine"
243#endif
244
Denis Vlasenkob012b102007-02-19 22:43:01 +0000245
Denis Vlasenko01631112007-12-16 17:20:38 +0000246/* ============ Hash table sizes. Configurable. */
247
248#define VTABSIZE 39
249#define ATABSIZE 39
250#define CMDTABLESIZE 31 /* should be prime */
251
252
Denis Vlasenkob012b102007-02-19 22:43:01 +0000253/* ============ Shell options */
254
255static const char *const optletters_optnames[] = {
256 "e" "errexit",
257 "f" "noglob",
258 "I" "ignoreeof",
259 "i" "interactive",
260 "m" "monitor",
261 "n" "noexec",
262 "s" "stdin",
263 "x" "xtrace",
264 "v" "verbose",
265 "C" "noclobber",
266 "a" "allexport",
267 "b" "notify",
268 "u" "nounset",
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100269 "\0" "vi"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100270#if BASH_PIPEFAIL
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100271 ,"\0" "pipefail"
Michael Abbott359da5e2009-12-04 23:03:29 +0100272#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000273#if DEBUG
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000274 ,"\0" "nolog"
275 ,"\0" "debug"
Denis Vlasenkob012b102007-02-19 22:43:01 +0000276#endif
277};
278
Denys Vlasenko285ad152009-12-04 23:02:27 +0100279#define optletters(n) optletters_optnames[n][0]
280#define optnames(n) (optletters_optnames[n] + 1)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000281
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000282enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
Denis Vlasenkob012b102007-02-19 22:43:01 +0000283
Eric Andersenc470f442003-07-28 09:56:35 +0000284
Denis Vlasenkob012b102007-02-19 22:43:01 +0000285/* ============ Misc data */
Eric Andersenc470f442003-07-28 09:56:35 +0000286
Denys Vlasenkoea8b2522010-06-02 12:57:26 +0200287#define msg_illnum "Illegal number: %s"
Denis Vlasenkoaa744452007-02-23 01:04:22 +0000288
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +0000289/*
Eric Andersenc470f442003-07-28 09:56:35 +0000290 * We enclose jmp_buf in a structure so that we can declare pointers to
291 * jump locations. The global variable handler contains the location to
Denis Vlasenkof1733952009-03-19 23:21:55 +0000292 * jump to when an exception occurs, and the global variable exception_type
Eric Andersenaff114c2004-04-14 17:51:38 +0000293 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000294 * exception handlers, the user should save the value of handler on entry
295 * to an inner scope, set handler to point to a jmploc structure for the
296 * inner scope, and restore handler on exit from the scope.
297 */
Eric Andersenc470f442003-07-28 09:56:35 +0000298struct jmploc {
299 jmp_buf loc;
300};
Denis Vlasenko01631112007-12-16 17:20:38 +0000301
302struct globals_misc {
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200303 uint8_t exitstatus; /* exit status of last command */
304 uint8_t back_exitstatus;/* exit status of backquoted command */
305 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
306 int rootpid; /* pid of main shell */
Denis Vlasenko01631112007-12-16 17:20:38 +0000307 /* shell level: 0 for the main shell, 1 for its children, and so on */
308 int shlvl;
309#define rootshell (!shlvl)
310 char *minusc; /* argument to -c option */
311
312 char *curdir; // = nullstr; /* current working directory */
313 char *physdir; // = nullstr; /* physical working directory */
314
315 char *arg0; /* value of $0 */
316
317 struct jmploc *exception_handler;
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000318
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200319 volatile int suppress_int; /* counter */
320 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200321 volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +0200322 volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000323 smallint exception_type; /* kind of exception (0..5) */
Denis Vlasenko01631112007-12-16 17:20:38 +0000324 /* exceptions */
Eric Andersenc470f442003-07-28 09:56:35 +0000325#define EXINT 0 /* SIGINT received */
326#define EXERROR 1 /* a generic error */
Eric Andersenc470f442003-07-28 09:56:35 +0000327#define EXEXIT 4 /* exit the shell */
Eric Andersen2870d962001-07-02 17:27:21 +0000328
Denis Vlasenko01631112007-12-16 17:20:38 +0000329 smallint isloginsh;
Denis Vlasenkob07a4962008-06-22 13:16:23 +0000330 char nullstr[1]; /* zero length string */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000331
332 char optlist[NOPTS];
333#define eflag optlist[0]
334#define fflag optlist[1]
335#define Iflag optlist[2]
336#define iflag optlist[3]
337#define mflag optlist[4]
338#define nflag optlist[5]
339#define sflag optlist[6]
340#define xflag optlist[7]
341#define vflag optlist[8]
342#define Cflag optlist[9]
343#define aflag optlist[10]
344#define bflag optlist[11]
345#define uflag optlist[12]
346#define viflag optlist[13]
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100347#if BASH_PIPEFAIL
Michael Abbott359da5e2009-12-04 23:03:29 +0100348# define pipefail optlist[14]
349#else
350# define pipefail 0
351#endif
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000352#if DEBUG
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100353# define nolog optlist[14 + BASH_PIPEFAIL]
354# define debug optlist[15 + BASH_PIPEFAIL]
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000355#endif
356
357 /* trap handler commands */
Denis Vlasenko01631112007-12-16 17:20:38 +0000358 /*
359 * Sigmode records the current value of the signal handlers for the various
360 * modes. A value of zero means that the current handler is not known.
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000361 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
Denis Vlasenko01631112007-12-16 17:20:38 +0000362 */
363 char sigmode[NSIG - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000364#define S_DFL 1 /* default signal handling (SIG_DFL) */
365#define S_CATCH 2 /* signal is caught */
366#define S_IGN 3 /* signal is ignored (SIG_IGN) */
Denys Vlasenkoe5814a52016-07-16 18:33:55 +0200367#define S_HARD_IGN 4 /* signal is ignored permanently */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000368
Denis Vlasenko01631112007-12-16 17:20:38 +0000369 /* indicates specified signal received */
Denis Vlasenko4b875702009-03-19 13:30:04 +0000370 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
Denys Vlasenko238bf182010-05-18 15:49:07 +0200371 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000372 char *trap[NSIG];
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200373 char **trap_ptr; /* used only by "trap hack" */
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000374
375 /* Rarely referenced stuff */
376#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200377 random_t random_gen;
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000378#endif
379 pid_t backgndpid; /* pid of last background process */
Denis Vlasenko01631112007-12-16 17:20:38 +0000380};
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000381extern struct globals_misc *const ash_ptr_to_globals_misc;
382#define G_misc (*ash_ptr_to_globals_misc)
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200383#define exitstatus (G_misc.exitstatus )
384#define back_exitstatus (G_misc.back_exitstatus )
385#define job_warning (G_misc.job_warning)
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000386#define rootpid (G_misc.rootpid )
387#define shlvl (G_misc.shlvl )
388#define minusc (G_misc.minusc )
389#define curdir (G_misc.curdir )
390#define physdir (G_misc.physdir )
391#define arg0 (G_misc.arg0 )
Denis Vlasenko01631112007-12-16 17:20:38 +0000392#define exception_handler (G_misc.exception_handler)
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000393#define exception_type (G_misc.exception_type )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200394#define suppress_int (G_misc.suppress_int )
395#define pending_int (G_misc.pending_int )
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200396#define got_sigchld (G_misc.got_sigchld )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200397#define pending_sig (G_misc.pending_sig )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000398#define isloginsh (G_misc.isloginsh )
399#define nullstr (G_misc.nullstr )
400#define optlist (G_misc.optlist )
401#define sigmode (G_misc.sigmode )
402#define gotsig (G_misc.gotsig )
Denys Vlasenko238bf182010-05-18 15:49:07 +0200403#define may_have_traps (G_misc.may_have_traps )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000404#define trap (G_misc.trap )
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200405#define trap_ptr (G_misc.trap_ptr )
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200406#define random_gen (G_misc.random_gen )
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000407#define backgndpid (G_misc.backgndpid )
Denis Vlasenko01631112007-12-16 17:20:38 +0000408#define INIT_G_misc() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000409 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
410 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +0000411 curdir = nullstr; \
412 physdir = nullstr; \
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200413 trap_ptr = trap; \
Denis Vlasenko01631112007-12-16 17:20:38 +0000414} while (0)
415
416
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000417/* ============ DEBUG */
418#if DEBUG
419static void trace_printf(const char *fmt, ...);
420static void trace_vprintf(const char *fmt, va_list va);
421# define TRACE(param) trace_printf param
422# define TRACEV(param) trace_vprintf param
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000423# define close(fd) do { \
424 int dfd = (fd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000425 if (close(dfd) < 0) \
Denys Vlasenko883cea42009-07-11 15:31:59 +0200426 bb_error_msg("bug on %d: closing %d(0x%x)", \
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000427 __LINE__, dfd, dfd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000428} while (0)
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000429#else
430# define TRACE(param)
431# define TRACEV(param)
432#endif
433
434
Denis Vlasenko559691a2008-10-05 18:39:31 +0000435/* ============ Utility functions */
Denys Vlasenko1961aea2013-02-26 00:36:53 +0100436#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
437#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
438
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200439static int
440isdigit_str9(const char *str)
Denis Vlasenko559691a2008-10-05 18:39:31 +0000441{
442 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
443 while (--maxlen && isdigit(*str))
444 str++;
445 return (*str == '\0');
446}
Denis Vlasenko01631112007-12-16 17:20:38 +0000447
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200448static const char *
449var_end(const char *var)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +0200450{
451 while (*var)
452 if (*var++ == '=')
453 break;
454 return var;
455}
456
Denis Vlasenko559691a2008-10-05 18:39:31 +0000457
458/* ============ Interrupts / exceptions */
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100459
460static void exitshell(void) NORETURN;
461
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000462/*
Eric Andersen2870d962001-07-02 17:27:21 +0000463 * These macros allow the user to suspend the handling of interrupt signals
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000464 * over a period of time. This is similar to SIGHOLD or to sigblock, but
Eric Andersen2870d962001-07-02 17:27:21 +0000465 * much more efficient and portable. (But hacking the kernel is so much
466 * more fun than worrying about efficiency and portability. :-))
467 */
Denys Vlasenko06b11492016-11-04 16:43:18 +0100468#if DEBUG_INTONOFF
469# define INT_OFF do { \
470 TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200471 suppress_int++; \
Denys Vlasenkode892052016-10-02 01:49:13 +0200472 barrier(); \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000473} while (0)
Denys Vlasenko06b11492016-11-04 16:43:18 +0100474#else
475# define INT_OFF do { \
476 suppress_int++; \
477 barrier(); \
478} while (0)
479#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000480
481/*
482 * Called to raise an exception. Since C doesn't include exceptions, we
483 * just do a longjmp to the exception handler. The type of exception is
Denis Vlasenko4b875702009-03-19 13:30:04 +0000484 * stored in the global variable "exception_type".
Denis Vlasenkob012b102007-02-19 22:43:01 +0000485 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000486static void raise_exception(int) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000487static void
488raise_exception(int e)
489{
490#if DEBUG
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000491 if (exception_handler == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000492 abort();
493#endif
494 INT_OFF;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000495 exception_type = e;
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000496 longjmp(exception_handler->loc, 1);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000497}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000498#if DEBUG
499#define raise_exception(e) do { \
500 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
501 raise_exception(e); \
502} while (0)
503#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000504
505/*
Denys Vlasenkof37e1152016-10-07 03:17:28 +0200506 * Called when a SIGINT is received. (If the user specifies
Denis Vlasenkob012b102007-02-19 22:43:01 +0000507 * that SIGINT is to be trapped or ignored using the trap builtin, then
508 * this routine is not called.) Suppressint is nonzero when interrupts
509 * are held using the INT_OFF macro. (The test for iflag is just
510 * defensive programming.)
511 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000512static void raise_interrupt(void) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000513static void
514raise_interrupt(void)
515{
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200516 pending_int = 0;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000517 /* Signal is not automatically unmasked after it is raised,
518 * do it ourself - unmask all signals */
Denis Vlasenko3f165fa2008-03-17 08:29:08 +0000519 sigprocmask_allsigs(SIG_UNBLOCK);
Denys Vlasenko238bf182010-05-18 15:49:07 +0200520 /* pending_sig = 0; - now done in signal_handler() */
Denis Vlasenko7c139b42007-03-21 20:17:27 +0000521
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200522 if (!(rootshell && iflag)) {
523 /* Kill ourself with SIGINT */
524 signal(SIGINT, SIG_DFL);
525 raise(SIGINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000526 }
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200527 /* bash: ^C even on empty command line sets $? */
528 exitstatus = SIGINT + 128;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200529 raise_exception(EXINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000530 /* NOTREACHED */
531}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000532#if DEBUG
533#define raise_interrupt() do { \
534 TRACE(("raising interrupt on line %d\n", __LINE__)); \
535 raise_interrupt(); \
536} while (0)
537#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000538
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000539static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000540int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000541{
Denys Vlasenkode892052016-10-02 01:49:13 +0200542 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200543 if (--suppress_int == 0 && pending_int) {
Denis Vlasenkob012b102007-02-19 22:43:01 +0000544 raise_interrupt();
545 }
546}
Denys Vlasenko06b11492016-11-04 16:43:18 +0100547#if DEBUG_INTONOFF
548# define INT_ON do { \
549 TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
550 int_on(); \
551} while (0)
552#else
553# define INT_ON int_on()
554#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000555static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000556force_int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000557{
Denys Vlasenkode892052016-10-02 01:49:13 +0200558 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200559 suppress_int = 0;
560 if (pending_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000561 raise_interrupt();
562}
563#define FORCE_INT_ON force_int_on()
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000564
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200565#define SAVE_INT(v) ((v) = suppress_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000566
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000567#define RESTORE_INT(v) do { \
Denys Vlasenkode892052016-10-02 01:49:13 +0200568 barrier(); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200569 suppress_int = (v); \
570 if (suppress_int == 0 && pending_int) \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000571 raise_interrupt(); \
572} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000573
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000574
Denis Vlasenkobc54cff2007-02-23 01:05:52 +0000575/* ============ Stdout/stderr output */
Eric Andersenc470f442003-07-28 09:56:35 +0000576
Eric Andersenc470f442003-07-28 09:56:35 +0000577static void
Denis Vlasenkob012b102007-02-19 22:43:01 +0000578outstr(const char *p, FILE *file)
Denis Vlasenkoe5570da2007-02-19 22:41:55 +0000579{
Denis Vlasenkob012b102007-02-19 22:43:01 +0000580 INT_OFF;
581 fputs(p, file);
582 INT_ON;
583}
584
585static void
586flush_stdout_stderr(void)
587{
588 INT_OFF;
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100589 fflush_all();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000590 INT_ON;
591}
592
Denys Vlasenko9c541002015-10-07 15:44:36 +0200593/* Was called outcslow(c,FILE*), but c was always '\n' */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000594static void
Denys Vlasenko9c541002015-10-07 15:44:36 +0200595newline_and_flush(FILE *dest)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000596{
597 INT_OFF;
Denys Vlasenko9c541002015-10-07 15:44:36 +0200598 putc('\n', dest);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000599 fflush(dest);
600 INT_ON;
601}
602
603static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
604static int
605out1fmt(const char *fmt, ...)
606{
607 va_list ap;
608 int r;
609
610 INT_OFF;
611 va_start(ap, fmt);
612 r = vprintf(fmt, ap);
613 va_end(ap);
614 INT_ON;
615 return r;
616}
617
618static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
619static int
620fmtstr(char *outbuf, size_t length, const char *fmt, ...)
621{
622 va_list ap;
623 int ret;
624
625 va_start(ap, fmt);
626 INT_OFF;
627 ret = vsnprintf(outbuf, length, fmt, ap);
628 va_end(ap);
629 INT_ON;
630 return ret;
631}
632
633static void
634out1str(const char *p)
635{
636 outstr(p, stdout);
637}
638
639static void
640out2str(const char *p)
641{
642 outstr(p, stderr);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100643 flush_stdout_stderr();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000644}
645
646
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000647/* ============ Parser structures */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +0000648
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000649/* control characters in argument strings */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100650#define CTL_FIRST CTLESC
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200651#define CTLESC ((unsigned char)'\201') /* escape next character */
652#define CTLVAR ((unsigned char)'\202') /* variable defn */
653#define CTLENDVAR ((unsigned char)'\203')
654#define CTLBACKQ ((unsigned char)'\204')
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200655#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
656#define CTLENDARI ((unsigned char)'\207')
657#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100658#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000659
660/* variable substitution byte (follows CTLVAR) */
661#define VSTYPE 0x0f /* type of variable substitution */
662#define VSNUL 0x10 /* colon--treat the empty string as unset */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000663
664/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000665#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
666#define VSMINUS 0x2 /* ${var-text} */
667#define VSPLUS 0x3 /* ${var+text} */
668#define VSQUESTION 0x4 /* ${var?message} */
669#define VSASSIGN 0x5 /* ${var=text} */
670#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
671#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
672#define VSTRIMLEFT 0x8 /* ${var#pattern} */
673#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
674#define VSLENGTH 0xa /* ${#var} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100675#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000676#define VSSUBSTR 0xc /* ${var:position:length} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100677#endif
678#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000679#define VSREPLACE 0xd /* ${var/pattern/replacement} */
680#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
681#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000682
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000683static const char dolatstr[] ALIGN1 = {
Ron Yorston549deab2015-05-18 09:57:51 +0200684 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000685};
Ron Yorston549deab2015-05-18 09:57:51 +0200686#define DOLATSTRLEN 6
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000687
Denis Vlasenko559691a2008-10-05 18:39:31 +0000688#define NCMD 0
689#define NPIPE 1
690#define NREDIR 2
691#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000692#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000693#define NAND 5
694#define NOR 6
695#define NSEMI 7
696#define NIF 8
697#define NWHILE 9
698#define NUNTIL 10
699#define NFOR 11
700#define NCASE 12
701#define NCLIST 13
702#define NDEFUN 14
703#define NARG 15
704#define NTO 16
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100705#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +0000706#define NTO2 17
707#endif
708#define NCLOBBER 18
709#define NFROM 19
710#define NFROMTO 20
711#define NAPPEND 21
712#define NTOFD 22
713#define NFROMFD 23
714#define NHERE 24
715#define NXHERE 25
716#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000717#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000718
719union node;
720
721struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000722 smallint type; /* Nxxxx */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000723 union node *assign;
724 union node *args;
725 union node *redirect;
726};
727
728struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000729 smallint type;
730 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000731 struct nodelist *cmdlist;
732};
733
734struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000735 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000736 union node *n;
737 union node *redirect;
738};
739
740struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000741 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000742 union node *ch1;
743 union node *ch2;
744};
745
746struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000747 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000748 union node *test;
749 union node *ifpart;
750 union node *elsepart;
751};
752
753struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000754 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000755 union node *args;
756 union node *body;
757 char *var;
758};
759
760struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000761 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000762 union node *expr;
763 union node *cases;
764};
765
766struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000767 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000768 union node *next;
769 union node *pattern;
770 union node *body;
771};
772
773struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000774 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000775 union node *next;
776 char *text;
777 struct nodelist *backquote;
778};
779
Denis Vlasenko559691a2008-10-05 18:39:31 +0000780/* nfile and ndup layout must match!
781 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
782 * that it is actually NTO2 (>&file), and change its type.
783 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000784struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000785 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000786 union node *next;
787 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000788 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000789 union node *fname;
790 char *expfname;
791};
792
793struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000794 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000795 union node *next;
796 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000797 int dupfd;
798 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000799 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000800};
801
802struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000803 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000804 union node *next;
805 int fd;
806 union node *doc;
807};
808
809struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000810 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000811 union node *com;
812};
813
814union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000815 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000816 struct ncmd ncmd;
817 struct npipe npipe;
818 struct nredir nredir;
819 struct nbinary nbinary;
820 struct nif nif;
821 struct nfor nfor;
822 struct ncase ncase;
823 struct nclist nclist;
824 struct narg narg;
825 struct nfile nfile;
826 struct ndup ndup;
827 struct nhere nhere;
828 struct nnot nnot;
829};
830
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200831/*
832 * NODE_EOF is returned by parsecmd when it encounters an end of file.
833 * It must be distinct from NULL.
834 */
835#define NODE_EOF ((union node *) -1L)
836
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000837struct nodelist {
838 struct nodelist *next;
839 union node *n;
840};
841
842struct funcnode {
843 int count;
844 union node n;
845};
846
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000847/*
848 * Free a parse tree.
849 */
850static void
851freefunc(struct funcnode *f)
852{
853 if (f && --f->count < 0)
854 free(f);
855}
856
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000857
858/* ============ Debugging output */
859
860#if DEBUG
861
862static FILE *tracefile;
863
864static void
865trace_printf(const char *fmt, ...)
866{
867 va_list va;
868
869 if (debug != 1)
870 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000871 if (DEBUG_TIME)
872 fprintf(tracefile, "%u ", (int) time(NULL));
873 if (DEBUG_PID)
874 fprintf(tracefile, "[%u] ", (int) getpid());
875 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200876 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000877 va_start(va, fmt);
878 vfprintf(tracefile, fmt, va);
879 va_end(va);
880}
881
882static void
883trace_vprintf(const char *fmt, va_list va)
884{
885 if (debug != 1)
886 return;
887 vfprintf(tracefile, fmt, va);
Denys Vlasenko474ed062016-10-30 18:30:29 +0100888 fprintf(tracefile, "\n");
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000889}
890
891static void
892trace_puts(const char *s)
893{
894 if (debug != 1)
895 return;
896 fputs(s, tracefile);
897}
898
899static void
900trace_puts_quoted(char *s)
901{
902 char *p;
903 char c;
904
905 if (debug != 1)
906 return;
907 putc('"', tracefile);
908 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100909 switch ((unsigned char)*p) {
910 case '\n': c = 'n'; goto backslash;
911 case '\t': c = 't'; goto backslash;
912 case '\r': c = 'r'; goto backslash;
913 case '\"': c = '\"'; goto backslash;
914 case '\\': c = '\\'; goto backslash;
915 case CTLESC: c = 'e'; goto backslash;
916 case CTLVAR: c = 'v'; goto backslash;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100917 case CTLBACKQ: c = 'q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000918 backslash:
919 putc('\\', tracefile);
920 putc(c, tracefile);
921 break;
922 default:
923 if (*p >= ' ' && *p <= '~')
924 putc(*p, tracefile);
925 else {
926 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +0100927 putc((*p >> 6) & 03, tracefile);
928 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000929 putc(*p & 07, tracefile);
930 }
931 break;
932 }
933 }
934 putc('"', tracefile);
935}
936
937static void
938trace_puts_args(char **ap)
939{
940 if (debug != 1)
941 return;
942 if (!*ap)
943 return;
944 while (1) {
945 trace_puts_quoted(*ap);
946 if (!*++ap) {
947 putc('\n', tracefile);
948 break;
949 }
950 putc(' ', tracefile);
951 }
952}
953
954static void
955opentrace(void)
956{
957 char s[100];
958#ifdef O_APPEND
959 int flags;
960#endif
961
962 if (debug != 1) {
963 if (tracefile)
964 fflush(tracefile);
965 /* leave open because libedit might be using it */
966 return;
967 }
968 strcpy(s, "./trace");
969 if (tracefile) {
970 if (!freopen(s, "a", tracefile)) {
971 fprintf(stderr, "Can't re-open %s\n", s);
972 debug = 0;
973 return;
974 }
975 } else {
976 tracefile = fopen(s, "a");
977 if (tracefile == NULL) {
978 fprintf(stderr, "Can't open %s\n", s);
979 debug = 0;
980 return;
981 }
982 }
983#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000984 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000985 if (flags >= 0)
986 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
987#endif
988 setlinebuf(tracefile);
989 fputs("\nTracing started.\n", tracefile);
990}
991
992static void
993indent(int amount, char *pfx, FILE *fp)
994{
995 int i;
996
997 for (i = 0; i < amount; i++) {
998 if (pfx && i == amount - 1)
999 fputs(pfx, fp);
1000 putc('\t', fp);
1001 }
1002}
1003
1004/* little circular references here... */
1005static void shtree(union node *n, int ind, char *pfx, FILE *fp);
1006
1007static void
1008sharg(union node *arg, FILE *fp)
1009{
1010 char *p;
1011 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001012 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001013
1014 if (arg->type != NARG) {
1015 out1fmt("<node type %d>\n", arg->type);
1016 abort();
1017 }
1018 bqlist = arg->narg.backquote;
1019 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01001020 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001021 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -07001022 p++;
1023 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001024 break;
1025 case CTLVAR:
1026 putc('$', fp);
1027 putc('{', fp);
1028 subtype = *++p;
1029 if (subtype == VSLENGTH)
1030 putc('#', fp);
1031
Dan Fandrich77d48722010-09-07 23:38:28 -07001032 while (*p != '=') {
1033 putc(*p, fp);
1034 p++;
1035 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001036
1037 if (subtype & VSNUL)
1038 putc(':', fp);
1039
1040 switch (subtype & VSTYPE) {
1041 case VSNORMAL:
1042 putc('}', fp);
1043 break;
1044 case VSMINUS:
1045 putc('-', fp);
1046 break;
1047 case VSPLUS:
1048 putc('+', fp);
1049 break;
1050 case VSQUESTION:
1051 putc('?', fp);
1052 break;
1053 case VSASSIGN:
1054 putc('=', fp);
1055 break;
1056 case VSTRIMLEFT:
1057 putc('#', fp);
1058 break;
1059 case VSTRIMLEFTMAX:
1060 putc('#', fp);
1061 putc('#', fp);
1062 break;
1063 case VSTRIMRIGHT:
1064 putc('%', fp);
1065 break;
1066 case VSTRIMRIGHTMAX:
1067 putc('%', fp);
1068 putc('%', fp);
1069 break;
1070 case VSLENGTH:
1071 break;
1072 default:
1073 out1fmt("<subtype %d>", subtype);
1074 }
1075 break;
1076 case CTLENDVAR:
1077 putc('}', fp);
1078 break;
1079 case CTLBACKQ:
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001080 putc('$', fp);
1081 putc('(', fp);
1082 shtree(bqlist->n, -1, NULL, fp);
1083 putc(')', fp);
1084 break;
1085 default:
1086 putc(*p, fp);
1087 break;
1088 }
1089 }
1090}
1091
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001092static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001093shcmd(union node *cmd, FILE *fp)
1094{
1095 union node *np;
1096 int first;
1097 const char *s;
1098 int dftfd;
1099
1100 first = 1;
1101 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001102 if (!first)
1103 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001104 sharg(np, fp);
1105 first = 0;
1106 }
1107 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001108 if (!first)
1109 putc(' ', fp);
1110 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001111 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001112 case NTO: s = ">>"+1; dftfd = 1; break;
1113 case NCLOBBER: s = ">|"; dftfd = 1; break;
1114 case NAPPEND: s = ">>"; dftfd = 1; break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01001115#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00001116 case NTO2:
1117#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001118 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001119 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001120 case NFROMFD: s = "<&"; break;
1121 case NFROMTO: s = "<>"; break;
1122 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001123 }
1124 if (np->nfile.fd != dftfd)
1125 fprintf(fp, "%d", np->nfile.fd);
1126 fputs(s, fp);
1127 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1128 fprintf(fp, "%d", np->ndup.dupfd);
1129 } else {
1130 sharg(np->nfile.fname, fp);
1131 }
1132 first = 0;
1133 }
1134}
1135
1136static void
1137shtree(union node *n, int ind, char *pfx, FILE *fp)
1138{
1139 struct nodelist *lp;
1140 const char *s;
1141
1142 if (n == NULL)
1143 return;
1144
1145 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001146
1147 if (n == NODE_EOF) {
1148 fputs("<EOF>", fp);
1149 return;
1150 }
1151
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001152 switch (n->type) {
1153 case NSEMI:
1154 s = "; ";
1155 goto binop;
1156 case NAND:
1157 s = " && ";
1158 goto binop;
1159 case NOR:
1160 s = " || ";
1161 binop:
1162 shtree(n->nbinary.ch1, ind, NULL, fp);
1163 /* if (ind < 0) */
1164 fputs(s, fp);
1165 shtree(n->nbinary.ch2, ind, NULL, fp);
1166 break;
1167 case NCMD:
1168 shcmd(n, fp);
1169 if (ind >= 0)
1170 putc('\n', fp);
1171 break;
1172 case NPIPE:
1173 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001174 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001175 if (lp->next)
1176 fputs(" | ", fp);
1177 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001178 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001179 fputs(" &", fp);
1180 if (ind >= 0)
1181 putc('\n', fp);
1182 break;
1183 default:
1184 fprintf(fp, "<node type %d>", n->type);
1185 if (ind >= 0)
1186 putc('\n', fp);
1187 break;
1188 }
1189}
1190
1191static void
1192showtree(union node *n)
1193{
1194 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001195 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001196}
1197
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001198#endif /* DEBUG */
1199
1200
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001201/* ============ Parser data */
1202
1203/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001204 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1205 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001206struct strlist {
1207 struct strlist *next;
1208 char *text;
1209};
1210
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001211struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001212
Denis Vlasenkob012b102007-02-19 22:43:01 +00001213struct strpush {
1214 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001215 char *prev_string;
1216 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001217#if ENABLE_ASH_ALIAS
1218 struct alias *ap; /* if push was associated with an alias */
1219#endif
1220 char *string; /* remember the string since it may change */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001221
1222 /* Remember last two characters for pungetc. */
1223 int lastc[2];
1224
1225 /* Number of outstanding calls to pungetc. */
1226 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001227};
1228
1229struct parsefile {
1230 struct parsefile *prev; /* preceding file on stack */
1231 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001232 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001233 int left_in_line; /* number of chars left in this line */
1234 int left_in_buffer; /* number of chars left in this buffer past the line */
1235 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001236 char *buf; /* input buffer */
1237 struct strpush *strpush; /* for pushing strings at this level */
1238 struct strpush basestrpush; /* so pushing one is fast */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001239
1240 /* Remember last two characters for pungetc. */
1241 int lastc[2];
1242
1243 /* Number of outstanding calls to pungetc. */
1244 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001245};
1246
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001247static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001248static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001249static int startlinno; /* line # where last token started */
1250static char *commandname; /* currently executing command */
1251static struct strlist *cmdenviron; /* environment for builtin command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001252
1253
1254/* ============ Message printing */
1255
1256static void
1257ash_vmsg(const char *msg, va_list ap)
1258{
1259 fprintf(stderr, "%s: ", arg0);
1260 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001261 if (strcmp(arg0, commandname))
1262 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001263 if (!iflag || g_parsefile->pf_fd > 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001264 fprintf(stderr, "line %d: ", startlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001265 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001266 vfprintf(stderr, msg, ap);
Denys Vlasenko9c541002015-10-07 15:44:36 +02001267 newline_and_flush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001268}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001269
1270/*
1271 * Exverror is called to raise the error exception. If the second argument
1272 * is not NULL then error prints an error message using printf style
1273 * formatting. It then raises the error exception.
1274 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001275static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001276static void
1277ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001278{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001279#if DEBUG
1280 if (msg) {
Denys Vlasenko474ed062016-10-30 18:30:29 +01001281 TRACE(("ash_vmsg_and_raise(%d):", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001282 TRACEV((msg, ap));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001283 } else
Denys Vlasenko474ed062016-10-30 18:30:29 +01001284 TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001285 if (msg)
1286#endif
1287 ash_vmsg(msg, ap);
1288
1289 flush_stdout_stderr();
1290 raise_exception(cond);
1291 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001292}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001293
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001294static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001295static void
1296ash_msg_and_raise_error(const char *msg, ...)
1297{
1298 va_list ap;
1299
Ron Yorstonea7d2f62017-01-03 11:18:23 +01001300 exitstatus = 2;
1301
Denis Vlasenkob012b102007-02-19 22:43:01 +00001302 va_start(ap, msg);
1303 ash_vmsg_and_raise(EXERROR, msg, ap);
1304 /* NOTREACHED */
1305 va_end(ap);
1306}
1307
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001308static void raise_error_syntax(const char *) NORETURN;
1309static void
1310raise_error_syntax(const char *msg)
1311{
1312 ash_msg_and_raise_error("syntax error: %s", msg);
1313 /* NOTREACHED */
1314}
1315
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001316static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001317static void
1318ash_msg_and_raise(int cond, const char *msg, ...)
1319{
1320 va_list ap;
1321
1322 va_start(ap, msg);
1323 ash_vmsg_and_raise(cond, msg, ap);
1324 /* NOTREACHED */
1325 va_end(ap);
1326}
1327
1328/*
1329 * error/warning routines for external builtins
1330 */
1331static void
1332ash_msg(const char *fmt, ...)
1333{
1334 va_list ap;
1335
1336 va_start(ap, fmt);
1337 ash_vmsg(fmt, ap);
1338 va_end(ap);
1339}
1340
1341/*
1342 * Return a string describing an error. The returned string may be a
1343 * pointer to a static buffer that will be overwritten on the next call.
1344 * Action describes the operation that got the error.
1345 */
1346static const char *
1347errmsg(int e, const char *em)
1348{
1349 if (e == ENOENT || e == ENOTDIR) {
1350 return em;
1351 }
1352 return strerror(e);
1353}
1354
1355
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001356/* ============ Memory allocation */
1357
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001358#if 0
1359/* I consider these wrappers nearly useless:
1360 * ok, they return you to nearest exception handler, but
1361 * how much memory do you leak in the process, making
1362 * memory starvation worse?
1363 */
1364static void *
1365ckrealloc(void * p, size_t nbytes)
1366{
1367 p = realloc(p, nbytes);
1368 if (!p)
1369 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1370 return p;
1371}
1372
1373static void *
1374ckmalloc(size_t nbytes)
1375{
1376 return ckrealloc(NULL, nbytes);
1377}
1378
1379static void *
1380ckzalloc(size_t nbytes)
1381{
1382 return memset(ckmalloc(nbytes), 0, nbytes);
1383}
1384
1385static char *
1386ckstrdup(const char *s)
1387{
1388 char *p = strdup(s);
1389 if (!p)
1390 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1391 return p;
1392}
1393#else
1394/* Using bbox equivalents. They exit if out of memory */
1395# define ckrealloc xrealloc
1396# define ckmalloc xmalloc
1397# define ckzalloc xzalloc
1398# define ckstrdup xstrdup
1399#endif
1400
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001401/*
1402 * It appears that grabstackstr() will barf with such alignments
1403 * because stalloc() will return a string allocated in a new stackblock.
1404 */
1405#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1406enum {
1407 /* Most machines require the value returned from malloc to be aligned
1408 * in some way. The following macro will get this right
1409 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001410 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001411 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001412 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001413};
1414
1415struct stack_block {
1416 struct stack_block *prev;
1417 char space[MINSIZE];
1418};
1419
1420struct stackmark {
1421 struct stack_block *stackp;
1422 char *stacknxt;
1423 size_t stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001424};
1425
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001426
Denis Vlasenko01631112007-12-16 17:20:38 +00001427struct globals_memstack {
1428 struct stack_block *g_stackp; // = &stackbase;
Denis Vlasenko01631112007-12-16 17:20:38 +00001429 char *g_stacknxt; // = stackbase.space;
1430 char *sstrend; // = stackbase.space + MINSIZE;
1431 size_t g_stacknleft; // = MINSIZE;
Denis Vlasenko01631112007-12-16 17:20:38 +00001432 struct stack_block stackbase;
1433};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001434extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1435#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001436#define g_stackp (G_memstack.g_stackp )
Denis Vlasenko01631112007-12-16 17:20:38 +00001437#define g_stacknxt (G_memstack.g_stacknxt )
1438#define sstrend (G_memstack.sstrend )
1439#define g_stacknleft (G_memstack.g_stacknleft)
Denis Vlasenko01631112007-12-16 17:20:38 +00001440#define stackbase (G_memstack.stackbase )
1441#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001442 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1443 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001444 g_stackp = &stackbase; \
1445 g_stacknxt = stackbase.space; \
1446 g_stacknleft = MINSIZE; \
1447 sstrend = stackbase.space + MINSIZE; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001448} while (0)
1449
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001450
Denis Vlasenko01631112007-12-16 17:20:38 +00001451#define stackblock() ((void *)g_stacknxt)
1452#define stackblocksize() g_stacknleft
1453
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001454/*
1455 * Parse trees for commands are allocated in lifo order, so we use a stack
1456 * to make this more efficient, and also to avoid all sorts of exception
1457 * handling code to handle interrupts in the middle of a parse.
1458 *
1459 * The size 504 was chosen because the Ultrix malloc handles that size
1460 * well.
1461 */
1462static void *
1463stalloc(size_t nbytes)
1464{
1465 char *p;
1466 size_t aligned;
1467
1468 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001469 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001470 size_t len;
1471 size_t blocksize;
1472 struct stack_block *sp;
1473
1474 blocksize = aligned;
1475 if (blocksize < MINSIZE)
1476 blocksize = MINSIZE;
1477 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1478 if (len < blocksize)
1479 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1480 INT_OFF;
1481 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001482 sp->prev = g_stackp;
1483 g_stacknxt = sp->space;
1484 g_stacknleft = blocksize;
1485 sstrend = g_stacknxt + blocksize;
1486 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001487 INT_ON;
1488 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001489 p = g_stacknxt;
1490 g_stacknxt += aligned;
1491 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001492 return p;
1493}
1494
Denis Vlasenko597906c2008-02-20 16:38:54 +00001495static void *
1496stzalloc(size_t nbytes)
1497{
1498 return memset(stalloc(nbytes), 0, nbytes);
1499}
1500
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001501static void
1502stunalloc(void *p)
1503{
1504#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001505 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001506 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001507 abort();
1508 }
1509#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001510 g_stacknleft += g_stacknxt - (char *)p;
1511 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001512}
1513
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001514/*
1515 * Like strdup but works with the ash stack.
1516 */
1517static char *
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02001518sstrdup(const char *p)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001519{
1520 size_t len = strlen(p) + 1;
1521 return memcpy(stalloc(len), p, len);
1522}
1523
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001524static inline void
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001525grabstackblock(size_t len)
1526{
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001527 stalloc(len);
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001528}
1529
1530static void
1531pushstackmark(struct stackmark *mark, size_t len)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001532{
Denis Vlasenko01631112007-12-16 17:20:38 +00001533 mark->stackp = g_stackp;
1534 mark->stacknxt = g_stacknxt;
1535 mark->stacknleft = g_stacknleft;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001536 grabstackblock(len);
1537}
1538
1539static void
1540setstackmark(struct stackmark *mark)
1541{
1542 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001543}
1544
1545static void
1546popstackmark(struct stackmark *mark)
1547{
1548 struct stack_block *sp;
1549
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001550 if (!mark->stackp)
1551 return;
1552
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001553 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001554 while (g_stackp != mark->stackp) {
1555 sp = g_stackp;
1556 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001557 free(sp);
1558 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001559 g_stacknxt = mark->stacknxt;
1560 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001561 sstrend = mark->stacknxt + mark->stacknleft;
1562 INT_ON;
1563}
1564
1565/*
1566 * When the parser reads in a string, it wants to stick the string on the
1567 * stack and only adjust the stack pointer when it knows how big the
1568 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1569 * of space on top of the stack and stackblocklen returns the length of
1570 * this block. Growstackblock will grow this space by at least one byte,
1571 * possibly moving it (like realloc). Grabstackblock actually allocates the
1572 * part of the block that has been used.
1573 */
1574static void
1575growstackblock(void)
1576{
1577 size_t newlen;
1578
Denis Vlasenko01631112007-12-16 17:20:38 +00001579 newlen = g_stacknleft * 2;
1580 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001581 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1582 if (newlen < 128)
1583 newlen += 128;
1584
Denis Vlasenko01631112007-12-16 17:20:38 +00001585 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001586 struct stack_block *sp;
1587 struct stack_block *prevstackp;
1588 size_t grosslen;
1589
1590 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001591 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001592 prevstackp = sp->prev;
1593 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1594 sp = ckrealloc(sp, grosslen);
1595 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001596 g_stackp = sp;
1597 g_stacknxt = sp->space;
1598 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001599 sstrend = sp->space + newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001600 INT_ON;
1601 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001602 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001603 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001604 char *p = stalloc(newlen);
1605
1606 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001607 g_stacknxt = memcpy(p, oldspace, oldlen);
1608 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001609 }
1610}
1611
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001612/*
1613 * The following routines are somewhat easier to use than the above.
1614 * The user declares a variable of type STACKSTR, which may be declared
1615 * to be a register. The macro STARTSTACKSTR initializes things. Then
1616 * the user uses the macro STPUTC to add characters to the string. In
1617 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1618 * grown as necessary. When the user is done, she can just leave the
1619 * string there and refer to it using stackblock(). Or she can allocate
1620 * the space for it using grabstackstr(). If it is necessary to allow
1621 * someone else to use the stack temporarily and then continue to grow
1622 * the string, the user should use grabstack to allocate the space, and
1623 * then call ungrabstr(p) to return to the previous mode of operation.
1624 *
1625 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1626 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1627 * is space for at least one character.
1628 */
1629static void *
1630growstackstr(void)
1631{
1632 size_t len = stackblocksize();
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001633 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001634 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001635}
1636
1637/*
1638 * Called from CHECKSTRSPACE.
1639 */
1640static char *
1641makestrspace(size_t newlen, char *p)
1642{
Denis Vlasenko01631112007-12-16 17:20:38 +00001643 size_t len = p - g_stacknxt;
Denys Vlasenko53d6e032016-09-30 11:24:12 +02001644 size_t size;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001645
1646 for (;;) {
1647 size_t nleft;
1648
1649 size = stackblocksize();
1650 nleft = size - len;
1651 if (nleft >= newlen)
1652 break;
1653 growstackblock();
1654 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001655 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001656}
1657
1658static char *
1659stack_nputstr(const char *s, size_t n, char *p)
1660{
1661 p = makestrspace(n, p);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001662 p = (char *)memcpy(p, s, n) + n;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001663 return p;
1664}
1665
1666static char *
1667stack_putstr(const char *s, char *p)
1668{
1669 return stack_nputstr(s, strlen(s), p);
1670}
1671
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001672static char *
1673_STPUTC(int c, char *p)
1674{
1675 if (p == sstrend)
1676 p = growstackstr();
1677 *p++ = c;
1678 return p;
1679}
1680
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001681#define STARTSTACKSTR(p) ((p) = stackblock())
1682#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001683#define CHECKSTRSPACE(n, p) do { \
1684 char *q = (p); \
1685 size_t l = (n); \
1686 size_t m = sstrend - q; \
1687 if (l > m) \
1688 (p) = makestrspace(l, q); \
1689} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001690#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001691#define STACKSTRNUL(p) do { \
1692 if ((p) == sstrend) \
1693 (p) = growstackstr(); \
1694 *(p) = '\0'; \
1695} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001696#define STUNPUTC(p) (--(p))
1697#define STTOPC(p) ((p)[-1])
1698#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001699
1700#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001701#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001702#define stackstrend() ((void *)sstrend)
1703
1704
1705/* ============ String helpers */
1706
1707/*
1708 * prefix -- see if pfx is a prefix of string.
1709 */
1710static char *
1711prefix(const char *string, const char *pfx)
1712{
1713 while (*pfx) {
1714 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001715 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001716 }
1717 return (char *) string;
1718}
1719
1720/*
1721 * Check for a valid number. This should be elsewhere.
1722 */
1723static int
1724is_number(const char *p)
1725{
1726 do {
1727 if (!isdigit(*p))
1728 return 0;
1729 } while (*++p != '\0');
1730 return 1;
1731}
1732
1733/*
1734 * Convert a string of digits to an integer, printing an error message on
1735 * failure.
1736 */
1737static int
1738number(const char *s)
1739{
1740 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001741 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001742 return atoi(s);
1743}
1744
1745/*
1746 * Produce a possibly single quoted string suitable as input to the shell.
1747 * The return string is allocated on the stack.
1748 */
1749static char *
1750single_quote(const char *s)
1751{
1752 char *p;
1753
1754 STARTSTACKSTR(p);
1755
1756 do {
1757 char *q;
1758 size_t len;
1759
1760 len = strchrnul(s, '\'') - s;
1761
1762 q = p = makestrspace(len + 3, p);
1763
1764 *q++ = '\'';
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001765 q = (char *)memcpy(q, s, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001766 *q++ = '\'';
1767 s += len;
1768
1769 STADJUST(q - p, p);
1770
Denys Vlasenkocd716832009-11-28 22:14:02 +01001771 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001772 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001773 len = 0;
1774 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001775
1776 q = p = makestrspace(len + 3, p);
1777
1778 *q++ = '"';
Denys Vlasenkocd716832009-11-28 22:14:02 +01001779 q = (char *)memcpy(q, s - len, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001780 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001781
1782 STADJUST(q - p, p);
1783 } while (*s);
1784
Denys Vlasenkocd716832009-11-28 22:14:02 +01001785 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001786
1787 return stackblock();
1788}
1789
1790
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001791/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001792
1793static char **argptr; /* argument list for builtin commands */
1794static char *optionarg; /* set by nextopt (like getopt) */
1795static char *optptr; /* used by nextopt */
1796
1797/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001798 * XXX - should get rid of. Have all builtins use getopt(3).
1799 * The library getopt must have the BSD extension static variable
1800 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001801 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001802 * Standard option processing (a la getopt) for builtin routines.
1803 * The only argument that is passed to nextopt is the option string;
1804 * the other arguments are unnecessary. It returns the character,
1805 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001806 */
1807static int
1808nextopt(const char *optstring)
1809{
1810 char *p;
1811 const char *q;
1812 char c;
1813
1814 p = optptr;
1815 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001816 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001817 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001818 if (p == NULL)
1819 return '\0';
1820 if (*p != '-')
1821 return '\0';
1822 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001823 return '\0';
1824 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001825 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001826 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001827 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001828 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001829 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001830 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001831 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001832 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001833 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001834 if (*++q == ':')
1835 q++;
1836 }
1837 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001838 if (*p == '\0') {
1839 p = *argptr++;
1840 if (p == NULL)
1841 ash_msg_and_raise_error("no arg for -%c option", c);
1842 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001843 optionarg = p;
1844 p = NULL;
1845 }
1846 optptr = p;
1847 return c;
1848}
1849
1850
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001851/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001852
Denis Vlasenko01631112007-12-16 17:20:38 +00001853/*
1854 * The parsefile structure pointed to by the global variable parsefile
1855 * contains information about the current file being read.
1856 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001857struct shparam {
1858 int nparam; /* # of positional parameters (without $0) */
1859#if ENABLE_ASH_GETOPTS
1860 int optind; /* next parameter to be processed by getopts */
1861 int optoff; /* used by getopts */
1862#endif
1863 unsigned char malloced; /* if parameter list dynamically allocated */
1864 char **p; /* parameter list */
1865};
1866
1867/*
1868 * Free the list of positional parameters.
1869 */
1870static void
1871freeparam(volatile struct shparam *param)
1872{
Denis Vlasenko01631112007-12-16 17:20:38 +00001873 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001874 char **ap, **ap1;
1875 ap = ap1 = param->p;
1876 while (*ap)
1877 free(*ap++);
1878 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001879 }
1880}
1881
1882#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001883static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001884#endif
1885
1886struct var {
1887 struct var *next; /* next entry in hash list */
1888 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001889 const char *var_text; /* name=value */
1890 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001891 /* the variable gets set/unset */
1892};
1893
1894struct localvar {
1895 struct localvar *next; /* next local variable in list */
1896 struct var *vp; /* the variable that was made local */
1897 int flags; /* saved flags */
1898 const char *text; /* saved text */
1899};
1900
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001901/* flags */
1902#define VEXPORT 0x01 /* variable is exported */
1903#define VREADONLY 0x02 /* variable cannot be modified */
1904#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1905#define VTEXTFIXED 0x08 /* text is statically allocated */
1906#define VSTACK 0x10 /* text is allocated on the stack */
1907#define VUNSET 0x20 /* the variable is not set */
1908#define VNOFUNC 0x40 /* don't call the callback function */
1909#define VNOSET 0x80 /* do not set variable - just readonly test */
1910#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001911#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001912# define VDYNAMIC 0x200 /* dynamic variable */
1913#else
1914# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001915#endif
1916
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001917
Denis Vlasenko01631112007-12-16 17:20:38 +00001918/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001919#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001920static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001921change_lc_all(const char *value)
1922{
1923 if (value && *value != '\0')
1924 setlocale(LC_ALL, value);
1925}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001926static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001927change_lc_ctype(const char *value)
1928{
1929 if (value && *value != '\0')
1930 setlocale(LC_CTYPE, value);
1931}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001932#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001933#if ENABLE_ASH_MAIL
1934static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01001935static void changemail(const char *var_value) FAST_FUNC;
1936#else
1937# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001938#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001939static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001940#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001941static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001942#endif
1943
Denis Vlasenko01631112007-12-16 17:20:38 +00001944static const struct {
1945 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001946 const char *var_text;
1947 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00001948} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02001949 /*
1950 * Note: VEXPORT would not work correctly here for NOFORK applets:
1951 * some environment strings may be constant.
1952 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001953 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001954#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001955 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
1956 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001957#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001958 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1959 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1960 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1961 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001962#if ENABLE_ASH_GETOPTS
Denys Vlasenkoe627ac92016-09-30 14:36:59 +02001963 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001964#endif
1965#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001966 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001967#endif
1968#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001969 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
1970 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001971#endif
1972#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001973 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001974#endif
1975};
1976
Denis Vlasenko0b769642008-07-24 07:54:57 +00001977struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00001978
1979struct globals_var {
1980 struct shparam shellparam; /* $@ current positional parameters */
1981 struct redirtab *redirlist;
Denis Vlasenko01631112007-12-16 17:20:38 +00001982 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1983 struct var *vartab[VTABSIZE];
1984 struct var varinit[ARRAY_SIZE(varinit_data)];
1985};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001986extern struct globals_var *const ash_ptr_to_globals_var;
1987#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00001988#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00001989//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00001990#define preverrout_fd (G_var.preverrout_fd)
1991#define vartab (G_var.vartab )
1992#define varinit (G_var.varinit )
1993#define INIT_G_var() do { \
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00001994 unsigned i; \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001995 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1996 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001997 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001998 varinit[i].flags = varinit_data[i].flags; \
1999 varinit[i].var_text = varinit_data[i].var_text; \
2000 varinit[i].var_func = varinit_data[i].var_func; \
Denis Vlasenko01631112007-12-16 17:20:38 +00002001 } \
2002} while (0)
2003
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002004#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002005#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002006# define vmail (&vifs)[1]
2007# define vmpath (&vmail)[1]
2008# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002009#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002010# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002011#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002012#define vps1 (&vpath)[1]
2013#define vps2 (&vps1)[1]
2014#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002015#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002016# define voptind (&vps4)[1]
2017# if ENABLE_ASH_RANDOM_SUPPORT
2018# define vrandom (&voptind)[1]
2019# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002020#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002021# if ENABLE_ASH_RANDOM_SUPPORT
2022# define vrandom (&vps4)[1]
2023# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002024#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002025
2026/*
2027 * The following macros access the values of the above variables.
2028 * They have to skip over the name. They return the null string
2029 * for unset variables.
2030 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002031#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002032#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002033#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002034# define mailval() (vmail.var_text + 5)
2035# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002036# define mpathset() ((vmpath.flags & VUNSET) == 0)
2037#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002038#define pathval() (vpath.var_text + 5)
2039#define ps1val() (vps1.var_text + 4)
2040#define ps2val() (vps2.var_text + 4)
2041#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002042#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002043# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002044#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002045
Denis Vlasenko01631112007-12-16 17:20:38 +00002046#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002047static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002048getoptsreset(const char *value)
2049{
Denys Vlasenkoa513bf32016-10-26 02:03:37 +02002050 shellparam.optind = number(value) ?: 1;
Denis Vlasenko01631112007-12-16 17:20:38 +00002051 shellparam.optoff = -1;
2052}
2053#endif
2054
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002055/*
2056 * Compares two strings up to the first = or '\0'. The first
2057 * string must be terminated by '='; the second may be terminated by
2058 * either '=' or '\0'.
2059 */
2060static int
2061varcmp(const char *p, const char *q)
2062{
2063 int c, d;
2064
2065 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002066 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002067 goto out;
2068 p++;
2069 q++;
2070 }
2071 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002072 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002073 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002074 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002075 out:
2076 return c - d;
2077}
2078
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002079/*
2080 * Find the appropriate entry in the hash table from the name.
2081 */
2082static struct var **
2083hashvar(const char *p)
2084{
2085 unsigned hashval;
2086
2087 hashval = ((unsigned char) *p) << 4;
2088 while (*p && *p != '=')
2089 hashval += (unsigned char) *p++;
2090 return &vartab[hashval % VTABSIZE];
2091}
2092
2093static int
2094vpcmp(const void *a, const void *b)
2095{
2096 return varcmp(*(const char **)a, *(const char **)b);
2097}
2098
2099/*
2100 * This routine initializes the builtin variables.
2101 */
2102static void
2103initvar(void)
2104{
2105 struct var *vp;
2106 struct var *end;
2107 struct var **vpp;
2108
2109 /*
2110 * PS1 depends on uid
2111 */
2112#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002113 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002114#else
2115 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002116 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002117#endif
2118 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002119 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002120 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002121 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002122 vp->next = *vpp;
2123 *vpp = vp;
2124 } while (++vp < end);
2125}
2126
2127static struct var **
2128findvar(struct var **vpp, const char *name)
2129{
2130 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002131 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002132 break;
2133 }
2134 }
2135 return vpp;
2136}
2137
2138/*
2139 * Find the value of a variable. Returns NULL if not set.
2140 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002141static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002142lookupvar(const char *name)
2143{
2144 struct var *v;
2145
2146 v = *findvar(hashvar(name), name);
2147 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002148#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002149 /*
2150 * Dynamic variables are implemented roughly the same way they are
2151 * in bash. Namely, they're "special" so long as they aren't unset.
2152 * As soon as they're unset, they're no longer dynamic, and dynamic
2153 * lookup will no longer happen at that point. -- PFM.
2154 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002155 if (v->flags & VDYNAMIC)
2156 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002157#endif
2158 if (!(v->flags & VUNSET))
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002159 return var_end(v->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002160 }
2161 return NULL;
2162}
2163
Denys Vlasenko0b883582016-12-23 16:49:07 +01002164#if ENABLE_UNICODE_SUPPORT
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02002165static void
2166reinit_unicode_for_ash(void)
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002167{
2168 /* Unicode support should be activated even if LANG is set
2169 * _during_ shell execution, not only if it was set when
2170 * shell was started. Therefore, re-check LANG every time:
2171 */
2172 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2173 || ENABLE_UNICODE_USING_LOCALE
2174 ) {
2175 const char *s = lookupvar("LC_ALL");
2176 if (!s) s = lookupvar("LC_CTYPE");
2177 if (!s) s = lookupvar("LANG");
2178 reinit_unicode(s);
2179 }
2180}
Denys Vlasenko0b883582016-12-23 16:49:07 +01002181#else
2182# define reinit_unicode_for_ash() ((void)0)
2183#endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002184
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002185/*
2186 * Search the environment of a builtin command.
2187 */
Mike Frysinger98c52642009-04-02 10:02:37 +00002188static const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002189bltinlookup(const char *name)
2190{
2191 struct strlist *sp;
2192
2193 for (sp = cmdenviron; sp; sp = sp->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002194 if (varcmp(sp->text, name) == 0)
2195 return var_end(sp->text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002196 }
2197 return lookupvar(name);
2198}
2199
2200/*
2201 * Same as setvar except that the variable and value are passed in
2202 * the first argument as name=value. Since the first argument will
2203 * be actually stored in the table, it should not be a string that
2204 * will go away.
2205 * Called with interrupts off.
2206 */
2207static void
2208setvareq(char *s, int flags)
2209{
2210 struct var *vp, **vpp;
2211
2212 vpp = hashvar(s);
2213 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2214 vp = *findvar(vpp, s);
2215 if (vp) {
2216 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2217 const char *n;
2218
2219 if (flags & VNOSAVE)
2220 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002221 n = vp->var_text;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02002222 exitstatus = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002223 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2224 }
2225
2226 if (flags & VNOSET)
2227 return;
2228
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002229 if (vp->var_func && !(flags & VNOFUNC))
2230 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002231
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002232 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2233 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002234
2235 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2236 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002237 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002238 if (flags & VNOSET)
2239 return;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002240 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002241 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002242 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002243 *vpp = vp;
2244 }
2245 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2246 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002247 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002248 vp->flags = flags;
2249}
2250
2251/*
2252 * Set the value of a variable. The flags argument is ored with the
2253 * flags of the variable. If val is NULL, the variable is unset.
2254 */
2255static void
2256setvar(const char *name, const char *val, int flags)
2257{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002258 const char *q;
2259 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002260 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002261 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002262 size_t vallen;
2263
2264 q = endofname(name);
2265 p = strchrnul(q, '=');
2266 namelen = p - name;
2267 if (!namelen || p != q)
2268 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2269 vallen = 0;
2270 if (val == NULL) {
2271 flags |= VUNSET;
2272 } else {
2273 vallen = strlen(val);
2274 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002275
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002276 INT_OFF;
2277 nameeq = ckmalloc(namelen + vallen + 2);
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002278 p = memcpy(nameeq, name, namelen) + namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002279 if (val) {
2280 *p++ = '=';
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002281 p = memcpy(p, val, vallen) + vallen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002282 }
2283 *p = '\0';
2284 setvareq(nameeq, flags | VNOSAVE);
2285 INT_ON;
2286}
2287
Denys Vlasenko03dad222010-01-12 23:29:57 +01002288static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002289setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002290{
2291 setvar(name, val, 0);
2292}
2293
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002294/*
2295 * Unset the specified variable.
2296 */
2297static int
2298unsetvar(const char *s)
2299{
2300 struct var **vpp;
2301 struct var *vp;
2302 int retval;
2303
2304 vpp = findvar(hashvar(s), s);
2305 vp = *vpp;
2306 retval = 2;
2307 if (vp) {
2308 int flags = vp->flags;
2309
2310 retval = 1;
2311 if (flags & VREADONLY)
2312 goto out;
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002313#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002314 vp->flags &= ~VDYNAMIC;
2315#endif
2316 if (flags & VUNSET)
2317 goto ok;
2318 if ((flags & VSTRFIXED) == 0) {
2319 INT_OFF;
2320 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002321 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002322 *vpp = vp->next;
2323 free(vp);
2324 INT_ON;
2325 } else {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002326 setvar0(s, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002327 vp->flags &= ~VEXPORT;
2328 }
2329 ok:
2330 retval = 0;
2331 }
2332 out:
2333 return retval;
2334}
2335
2336/*
2337 * Process a linked list of variable assignments.
2338 */
2339static void
2340listsetvar(struct strlist *list_set_var, int flags)
2341{
2342 struct strlist *lp = list_set_var;
2343
2344 if (!lp)
2345 return;
2346 INT_OFF;
2347 do {
2348 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002349 lp = lp->next;
2350 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002351 INT_ON;
2352}
2353
2354/*
2355 * Generate a list of variables satisfying the given conditions.
2356 */
2357static char **
2358listvars(int on, int off, char ***end)
2359{
2360 struct var **vpp;
2361 struct var *vp;
2362 char **ep;
2363 int mask;
2364
2365 STARTSTACKSTR(ep);
2366 vpp = vartab;
2367 mask = on | off;
2368 do {
2369 for (vp = *vpp; vp; vp = vp->next) {
2370 if ((vp->flags & mask) == on) {
2371 if (ep == stackstrend())
2372 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002373 *ep++ = (char*)vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002374 }
2375 }
2376 } while (++vpp < vartab + VTABSIZE);
2377 if (ep == stackstrend())
2378 ep = growstackstr();
2379 if (end)
2380 *end = ep;
2381 *ep++ = NULL;
2382 return grabstackstr(ep);
2383}
2384
2385
2386/* ============ Path search helper
2387 *
2388 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002389 * of the path before the first call; path_advance will update
2390 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002391 * the possible path expansions in sequence. If an option (indicated by
2392 * a percent sign) appears in the path entry then the global variable
2393 * pathopt will be set to point to it; otherwise pathopt will be set to
2394 * NULL.
2395 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002396static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002397
2398static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002399path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002400{
2401 const char *p;
2402 char *q;
2403 const char *start;
2404 size_t len;
2405
2406 if (*path == NULL)
2407 return NULL;
2408 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002409 for (p = start; *p && *p != ':' && *p != '%'; p++)
2410 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002411 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2412 while (stackblocksize() < len)
2413 growstackblock();
2414 q = stackblock();
2415 if (p != start) {
2416 memcpy(q, start, p - start);
2417 q += p - start;
2418 *q++ = '/';
2419 }
2420 strcpy(q, name);
2421 pathopt = NULL;
2422 if (*p == '%') {
2423 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002424 while (*p && *p != ':')
2425 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002426 }
2427 if (*p == ':')
2428 *path = p + 1;
2429 else
2430 *path = NULL;
2431 return stalloc(len);
2432}
2433
2434
2435/* ============ Prompt */
2436
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002437static smallint doprompt; /* if set, prompt the user */
2438static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002439
2440#if ENABLE_FEATURE_EDITING
2441static line_input_t *line_input_state;
2442static const char *cmdedit_prompt;
2443static void
2444putprompt(const char *s)
2445{
2446 if (ENABLE_ASH_EXPAND_PRMT) {
2447 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002448 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002449 return;
2450 }
2451 cmdedit_prompt = s;
2452}
2453#else
2454static void
2455putprompt(const char *s)
2456{
2457 out2str(s);
2458}
2459#endif
2460
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002461/* expandstr() needs parsing machinery, so it is far away ahead... */
2462static const char *expandstr(const char *ps);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002463
2464static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002465setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002466{
2467 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002468 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2469
2470 if (!do_set)
2471 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002472
2473 needprompt = 0;
2474
2475 switch (whichprompt) {
2476 case 1:
2477 prompt = ps1val();
2478 break;
2479 case 2:
2480 prompt = ps2val();
2481 break;
2482 default: /* 0 */
2483 prompt = nullstr;
2484 }
2485#if ENABLE_ASH_EXPAND_PRMT
Denys Vlasenko60ca8342016-09-30 11:21:21 +02002486 pushstackmark(&smark, stackblocksize());
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002487 putprompt(expandstr(prompt));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002488 popstackmark(&smark);
Denys Vlasenko48c803a2017-07-01 23:24:48 +02002489#else
2490 putprompt(prompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002491#endif
2492}
2493
2494
2495/* ============ The cd and pwd commands */
2496
2497#define CD_PHYSICAL 1
2498#define CD_PRINT 2
2499
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002500static int
2501cdopt(void)
2502{
2503 int flags = 0;
2504 int i, j;
2505
2506 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002507 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002508 if (i != j) {
2509 flags ^= CD_PHYSICAL;
2510 j = i;
2511 }
2512 }
2513
2514 return flags;
2515}
2516
2517/*
2518 * Update curdir (the name of the current directory) in response to a
2519 * cd command.
2520 */
2521static const char *
2522updatepwd(const char *dir)
2523{
2524 char *new;
2525 char *p;
2526 char *cdcomppath;
2527 const char *lim;
2528
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02002529 cdcomppath = sstrdup(dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002530 STARTSTACKSTR(new);
2531 if (*dir != '/') {
2532 if (curdir == nullstr)
2533 return 0;
2534 new = stack_putstr(curdir, new);
2535 }
2536 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002537 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002538 if (*dir != '/') {
2539 if (new[-1] != '/')
2540 USTPUTC('/', new);
2541 if (new > lim && *lim == '/')
2542 lim++;
2543 } else {
2544 USTPUTC('/', new);
2545 cdcomppath++;
2546 if (dir[1] == '/' && dir[2] != '/') {
2547 USTPUTC('/', new);
2548 cdcomppath++;
2549 lim++;
2550 }
2551 }
2552 p = strtok(cdcomppath, "/");
2553 while (p) {
2554 switch (*p) {
2555 case '.':
2556 if (p[1] == '.' && p[2] == '\0') {
2557 while (new > lim) {
2558 STUNPUTC(new);
2559 if (new[-1] == '/')
2560 break;
2561 }
2562 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002563 }
2564 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002565 break;
2566 /* fall through */
2567 default:
2568 new = stack_putstr(p, new);
2569 USTPUTC('/', new);
2570 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002571 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002572 }
2573 if (new > lim)
2574 STUNPUTC(new);
2575 *new = 0;
2576 return stackblock();
2577}
2578
2579/*
2580 * Find out what the current directory is. If we already know the current
2581 * directory, this routine returns immediately.
2582 */
2583static char *
2584getpwd(void)
2585{
Denis Vlasenko01631112007-12-16 17:20:38 +00002586 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002587 return dir ? dir : nullstr;
2588}
2589
2590static void
2591setpwd(const char *val, int setold)
2592{
2593 char *oldcur, *dir;
2594
2595 oldcur = dir = curdir;
2596
2597 if (setold) {
2598 setvar("OLDPWD", oldcur, VEXPORT);
2599 }
2600 INT_OFF;
2601 if (physdir != nullstr) {
2602 if (physdir != oldcur)
2603 free(physdir);
2604 physdir = nullstr;
2605 }
2606 if (oldcur == val || !val) {
2607 char *s = getpwd();
2608 physdir = s;
2609 if (!val)
2610 dir = s;
2611 } else
2612 dir = ckstrdup(val);
2613 if (oldcur != dir && oldcur != nullstr) {
2614 free(oldcur);
2615 }
2616 curdir = dir;
2617 INT_ON;
2618 setvar("PWD", dir, VEXPORT);
2619}
2620
2621static void hashcd(void);
2622
2623/*
Denys Vlasenko70392332016-10-27 02:31:55 +02002624 * Actually do the chdir. We also call hashcd to let other routines
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002625 * know that the current directory has changed.
2626 */
2627static int
2628docd(const char *dest, int flags)
2629{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002630 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002631 int err;
2632
2633 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2634
2635 INT_OFF;
2636 if (!(flags & CD_PHYSICAL)) {
2637 dir = updatepwd(dest);
2638 if (dir)
2639 dest = dir;
2640 }
2641 err = chdir(dest);
2642 if (err)
2643 goto out;
2644 setpwd(dir, 1);
2645 hashcd();
2646 out:
2647 INT_ON;
2648 return err;
2649}
2650
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002651static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002652cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002653{
2654 const char *dest;
2655 const char *path;
2656 const char *p;
2657 char c;
2658 struct stat statb;
2659 int flags;
2660
2661 flags = cdopt();
2662 dest = *argptr;
2663 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002664 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002665 else if (LONE_DASH(dest)) {
2666 dest = bltinlookup("OLDPWD");
2667 flags |= CD_PRINT;
2668 }
2669 if (!dest)
2670 dest = nullstr;
2671 if (*dest == '/')
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002672 goto step6;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002673 if (*dest == '.') {
2674 c = dest[1];
2675 dotdot:
2676 switch (c) {
2677 case '\0':
2678 case '/':
2679 goto step6;
2680 case '.':
2681 c = dest[2];
2682 if (c != '.')
2683 goto dotdot;
2684 }
2685 }
2686 if (!*dest)
2687 dest = ".";
2688 path = bltinlookup("CDPATH");
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002689 while (path) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002690 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002691 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002692 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2693 if (c && c != ':')
2694 flags |= CD_PRINT;
2695 docd:
2696 if (!docd(p, flags))
2697 goto out;
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002698 goto err;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002699 }
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002700 }
2701
2702 step6:
2703 p = dest;
2704 goto docd;
2705
2706 err:
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002707 ash_msg_and_raise_error("can't cd to %s", dest);
2708 /* NOTREACHED */
2709 out:
2710 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002711 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002712 return 0;
2713}
2714
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002715static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002716pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002717{
2718 int flags;
2719 const char *dir = curdir;
2720
2721 flags = cdopt();
2722 if (flags) {
2723 if (physdir == nullstr)
2724 setpwd(dir, 0);
2725 dir = physdir;
2726 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002727 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002728 return 0;
2729}
2730
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002731
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002732/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002733
Denis Vlasenko834dee72008-10-07 09:18:30 +00002734
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002735#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002736
Eric Andersenc470f442003-07-28 09:56:35 +00002737/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002738#define CWORD 0 /* character is nothing special */
2739#define CNL 1 /* newline character */
2740#define CBACK 2 /* a backslash character */
2741#define CSQUOTE 3 /* single quote */
2742#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002743#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002744#define CBQUOTE 6 /* backwards single quote */
2745#define CVAR 7 /* a dollar sign */
2746#define CENDVAR 8 /* a '}' character */
2747#define CLP 9 /* a left paren in arithmetic */
2748#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002749#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002750#define CCTL 12 /* like CWORD, except it must be escaped */
2751#define CSPCL 13 /* these terminate a word */
2752#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002753
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002754#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002755#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002756# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002757#endif
2758
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002759#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002760
Denys Vlasenko0b883582016-12-23 16:49:07 +01002761#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002762# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002763#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002764# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002765#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002766static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002767#if ENABLE_ASH_ALIAS
2768 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2769#endif
2770 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2771 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2772 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2773 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2774 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2775 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2776 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2777 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2778 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2779 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2780 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002781#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002782 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2783 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2784 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2785#endif
2786#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002787};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002788/* Constants below must match table above */
2789enum {
2790#if ENABLE_ASH_ALIAS
2791 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2792#endif
2793 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2794 CNL_CNL_CNL_CNL , /* 2 */
2795 CWORD_CCTL_CCTL_CWORD , /* 3 */
2796 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2797 CVAR_CVAR_CWORD_CVAR , /* 5 */
2798 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2799 CSPCL_CWORD_CWORD_CLP , /* 7 */
2800 CSPCL_CWORD_CWORD_CRP , /* 8 */
2801 CBACK_CBACK_CCTL_CBACK , /* 9 */
2802 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2803 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2804 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2805 CWORD_CWORD_CWORD_CWORD , /* 13 */
2806 CCTL_CCTL_CCTL_CCTL , /* 14 */
2807};
Eric Andersen2870d962001-07-02 17:27:21 +00002808
Denys Vlasenkocd716832009-11-28 22:14:02 +01002809/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2810 * caller must ensure proper cast on it if c is *char_ptr!
2811 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002812/* Values for syntax param */
2813#define BASESYNTAX 0 /* not in quotes */
2814#define DQSYNTAX 1 /* in double quotes */
2815#define SQSYNTAX 2 /* in single quotes */
2816#define ARISYNTAX 3 /* in arithmetic */
2817#define PSSYNTAX 4 /* prompt. never passed to SIT() */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002818
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002819#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002820
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002821static int
2822SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002823{
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002824 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2825 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2826 /*
2827 * This causes '/' to be prepended with CTLESC in dquoted string,
2828 * making "./file"* treated incorrectly because we feed
2829 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2830 * The "homegrown" glob implementation is okay with that,
2831 * but glibc one isn't. With '/' always treated as CWORD,
2832 * both work fine.
2833 */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002834# if ENABLE_ASH_ALIAS
2835 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002836 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002837 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002838 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2839 11, 3 /* "}~" */
2840 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002841# else
2842 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002843 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002844 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002845 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2846 10, 2 /* "}~" */
2847 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002848# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002849 const char *s;
2850 int indx;
2851
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002852 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002853 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002854# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002855 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002856 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002857 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002858# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002859 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002860 /* Cast is purely for paranoia here,
2861 * just in case someone passed signed char to us */
2862 if ((unsigned char)c >= CTL_FIRST
2863 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002864 ) {
2865 return CCTL;
2866 }
2867 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002868 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002869 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002870 indx = syntax_index_table[s - spec_symbls];
2871 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002872 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002873}
2874
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002875#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002876
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002877static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002878 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002879 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2889 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2890 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2891 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2892 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2893 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2894 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2895 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2896 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2897 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2898 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2899 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2900 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2901 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2902 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2903 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2904 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2905 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2906 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2907 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2908 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2909 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2910 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2911 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2912 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2913 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2914 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2915 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2916 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2917 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2918 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2919 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2920 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2921 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2922 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2923 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2924 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2925 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002926/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
2927 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkocd716832009-11-28 22:14:02 +01002928 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2929 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2939 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2940 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2941 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2942 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2943 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2944 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2972 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2973 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2974 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2977 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2983 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2986 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2987 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2988 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2989 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2990 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2991 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2992 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2993 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2994 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2995 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2996 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2997 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2998 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2999 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
3000 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
3001 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
3002 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
3003 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
3004 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
3005 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3006 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
3007 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
3008 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
3009 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
3010 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
3011 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
3012 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
3013 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
3014 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
3015 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
3016 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3017 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3018 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3019 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3020 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3021 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3029 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3042 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3047 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3112 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3113 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3114 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3115 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3116 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3117 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3118 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3119 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3120 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3121 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3122 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3123 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3124 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3125 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3126 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3127 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3128 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3129 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3130 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3131 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3132 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3133 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3134 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3135 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003136 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003137# if ENABLE_ASH_ALIAS
3138 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3139# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003140};
3141
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003142#if 1
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003143# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003144#else /* debug version, caught one signed char bug */
3145# define SIT(c, syntax) \
3146 ({ \
3147 if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3148 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
Denys Vlasenko0b883582016-12-23 16:49:07 +01003149 if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003150 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3151 ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3152 })
3153#endif
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003154
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003155#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003156
Eric Andersen2870d962001-07-02 17:27:21 +00003157
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003158/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003159
Denis Vlasenko131ae172007-02-18 13:00:19 +00003160#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003161
3162#define ALIASINUSE 1
3163#define ALIASDEAD 2
3164
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003165struct alias {
3166 struct alias *next;
3167 char *name;
3168 char *val;
3169 int flag;
3170};
3171
Denis Vlasenko01631112007-12-16 17:20:38 +00003172
3173static struct alias **atab; // [ATABSIZE];
3174#define INIT_G_alias() do { \
3175 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3176} while (0)
3177
Eric Andersen2870d962001-07-02 17:27:21 +00003178
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003179static struct alias **
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02003180__lookupalias(const char *name)
3181{
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003182 unsigned int hashval;
3183 struct alias **app;
3184 const char *p;
3185 unsigned int ch;
3186
3187 p = name;
3188
3189 ch = (unsigned char)*p;
3190 hashval = ch << 4;
3191 while (ch) {
3192 hashval += ch;
3193 ch = (unsigned char)*++p;
3194 }
3195 app = &atab[hashval % ATABSIZE];
3196
3197 for (; *app; app = &(*app)->next) {
3198 if (strcmp(name, (*app)->name) == 0) {
3199 break;
3200 }
3201 }
3202
3203 return app;
3204}
3205
3206static struct alias *
3207lookupalias(const char *name, int check)
3208{
3209 struct alias *ap = *__lookupalias(name);
3210
3211 if (check && ap && (ap->flag & ALIASINUSE))
3212 return NULL;
3213 return ap;
3214}
3215
3216static struct alias *
3217freealias(struct alias *ap)
3218{
3219 struct alias *next;
3220
3221 if (ap->flag & ALIASINUSE) {
3222 ap->flag |= ALIASDEAD;
3223 return ap;
3224 }
3225
3226 next = ap->next;
3227 free(ap->name);
3228 free(ap->val);
3229 free(ap);
3230 return next;
3231}
Eric Andersencb57d552001-06-28 07:25:16 +00003232
Eric Andersenc470f442003-07-28 09:56:35 +00003233static void
3234setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003235{
3236 struct alias *ap, **app;
3237
3238 app = __lookupalias(name);
3239 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003240 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003241 if (ap) {
3242 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003243 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003244 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003245 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003246 ap->flag &= ~ALIASDEAD;
3247 } else {
3248 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003249 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003250 ap->name = ckstrdup(name);
3251 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003252 /*ap->flag = 0; - ckzalloc did it */
3253 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003254 *app = ap;
3255 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003256 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003257}
3258
Eric Andersenc470f442003-07-28 09:56:35 +00003259static int
3260unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003261{
Eric Andersencb57d552001-06-28 07:25:16 +00003262 struct alias **app;
3263
3264 app = __lookupalias(name);
3265
3266 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003267 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003268 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003269 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003270 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003271 }
3272
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003273 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003274}
3275
Eric Andersenc470f442003-07-28 09:56:35 +00003276static void
3277rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003278{
Eric Andersencb57d552001-06-28 07:25:16 +00003279 struct alias *ap, **app;
3280 int i;
3281
Denis Vlasenkob012b102007-02-19 22:43:01 +00003282 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003283 for (i = 0; i < ATABSIZE; i++) {
3284 app = &atab[i];
3285 for (ap = *app; ap; ap = *app) {
3286 *app = freealias(*app);
3287 if (ap == *app) {
3288 app = &ap->next;
3289 }
3290 }
3291 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003292 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003293}
3294
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003295static void
3296printalias(const struct alias *ap)
3297{
3298 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3299}
3300
Eric Andersencb57d552001-06-28 07:25:16 +00003301/*
3302 * TODO - sort output
3303 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003304static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003305aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003306{
3307 char *n, *v;
3308 int ret = 0;
3309 struct alias *ap;
3310
Denis Vlasenko68404f12008-03-17 09:00:54 +00003311 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003312 int i;
3313
Denis Vlasenko68404f12008-03-17 09:00:54 +00003314 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003315 for (ap = atab[i]; ap; ap = ap->next) {
3316 printalias(ap);
3317 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003318 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003319 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003320 }
3321 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003322 v = strchr(n+1, '=');
3323 if (v == NULL) { /* n+1: funny ksh stuff */
3324 ap = *__lookupalias(n);
3325 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003326 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003327 ret = 1;
3328 } else
3329 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003330 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003331 *v++ = '\0';
3332 setalias(n, v);
3333 }
3334 }
3335
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003336 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003337}
3338
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003339static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003340unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003341{
3342 int i;
3343
Denys Vlasenko6c149f42017-04-12 21:31:32 +02003344 while (nextopt("a") != '\0') {
3345 rmaliases();
3346 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003347 }
3348 for (i = 0; *argptr; argptr++) {
3349 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003350 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003351 i = 1;
3352 }
3353 }
3354
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003355 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003356}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003357
Denis Vlasenko131ae172007-02-18 13:00:19 +00003358#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003359
Eric Andersenc470f442003-07-28 09:56:35 +00003360
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003361/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003362#define FORK_FG 0
3363#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003364#define FORK_NOJOB 2
3365
3366/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003367#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3368#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3369#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003370#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003371
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003372/*
3373 * A job structure contains information about a job. A job is either a
3374 * single process or a set of processes contained in a pipeline. In the
3375 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3376 * array of pids.
3377 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003378struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003379 pid_t ps_pid; /* process id */
3380 int ps_status; /* last process status from wait() */
3381 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003382};
3383
3384struct job {
3385 struct procstat ps0; /* status of process */
3386 struct procstat *ps; /* status or processes when more than one */
3387#if JOBS
3388 int stopstatus; /* status of a stopped job */
3389#endif
Denys Vlasenko4c179372017-01-11 18:44:15 +01003390 unsigned nprocs; /* number of processes */
3391
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003392#define JOBRUNNING 0 /* at least one proc running */
3393#define JOBSTOPPED 1 /* all procs are stopped */
3394#define JOBDONE 2 /* all procs are completed */
Denys Vlasenko4c179372017-01-11 18:44:15 +01003395 unsigned
3396 state: 8,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003397#if JOBS
3398 sigint: 1, /* job was killed by SIGINT */
3399 jobctl: 1, /* job running under job control */
3400#endif
3401 waited: 1, /* true if this entry has been waited for */
3402 used: 1, /* true if this entry is in used */
3403 changed: 1; /* true if status has changed */
3404 struct job *prev_job; /* previous job */
3405};
3406
Denis Vlasenko68404f12008-03-17 09:00:54 +00003407static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003408static int forkshell(struct job *, union node *, int);
3409static int waitforjob(struct job *);
3410
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003411#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003412enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003413#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003414#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003415static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003416static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003417#endif
3418
3419/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003420 * Ignore a signal.
3421 */
3422static void
3423ignoresig(int signo)
3424{
3425 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3426 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3427 /* No, need to do it */
3428 signal(signo, SIG_IGN);
3429 }
3430 sigmode[signo - 1] = S_HARD_IGN;
3431}
3432
3433/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003434 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003435 */
3436static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003437signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003438{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003439 if (signo == SIGCHLD) {
3440 got_sigchld = 1;
3441 if (!trap[SIGCHLD])
3442 return;
3443 }
3444
Denis Vlasenko4b875702009-03-19 13:30:04 +00003445 gotsig[signo - 1] = 1;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003446 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003447
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003448 if (signo == SIGINT && !trap[SIGINT]) {
3449 if (!suppress_int) {
3450 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003451 raise_interrupt(); /* does not return */
3452 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003453 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003454 }
3455}
3456
3457/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003458 * Set the signal handler for the specified signal. The routine figures
3459 * out what it should be set to.
3460 */
3461static void
3462setsignal(int signo)
3463{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003464 char *t;
3465 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003466 struct sigaction act;
3467
3468 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003469 new_act = S_DFL;
3470 if (t != NULL) { /* trap for this sig is set */
3471 new_act = S_CATCH;
3472 if (t[0] == '\0') /* trap is "": ignore this sig */
3473 new_act = S_IGN;
3474 }
3475
3476 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003477 switch (signo) {
3478 case SIGINT:
3479 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003480 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003481 break;
3482 case SIGQUIT:
3483#if DEBUG
3484 if (debug)
3485 break;
3486#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003487 /* man bash:
3488 * "In all cases, bash ignores SIGQUIT. Non-builtin
3489 * commands run by bash have signal handlers
3490 * set to the values inherited by the shell
3491 * from its parent". */
3492 new_act = S_IGN;
3493 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003494 case SIGTERM:
3495 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003496 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003497 break;
3498#if JOBS
3499 case SIGTSTP:
3500 case SIGTTOU:
3501 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003502 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003503 break;
3504#endif
3505 }
3506 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003507//TODO: if !rootshell, we reset SIGQUIT to DFL,
3508//whereas we have to restore it to what shell got on entry
3509//from the parent. See comment above
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003510
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003511 if (signo == SIGCHLD)
3512 new_act = S_CATCH;
3513
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003514 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003515 cur_act = *t;
3516 if (cur_act == 0) {
3517 /* current setting is not yet known */
3518 if (sigaction(signo, NULL, &act)) {
3519 /* pretend it worked; maybe we should give a warning,
3520 * but other shells don't. We don't alter sigmode,
3521 * so we retry every time.
3522 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003523 return;
3524 }
3525 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003526 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003527 if (mflag
3528 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3529 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003530 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003531 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003532 }
3533 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003534 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003535 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003536
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003537 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003538 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003539 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003540 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003541 break;
3542 case S_IGN:
3543 act.sa_handler = SIG_IGN;
3544 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003545 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003546
3547 /* flags and mask matter only if !DFL and !IGN, but we do it
3548 * for all cases for more deterministic behavior:
3549 */
3550 act.sa_flags = 0;
3551 sigfillset(&act.sa_mask);
3552
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003553 sigaction_set(signo, &act);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003554
3555 *t = new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003556}
3557
3558/* mode flags for set_curjob */
3559#define CUR_DELETE 2
3560#define CUR_RUNNING 1
3561#define CUR_STOPPED 0
3562
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003563#if JOBS
3564/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003565static int initialpgrp; //references:2
3566static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003567#endif
3568/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003569static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003570/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003571static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003572/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003573static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003574/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003575static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003576
Denys Vlasenko098b7132017-01-11 19:59:03 +01003577#if 0
3578/* Bash has a feature: it restores termios after a successful wait for
3579 * a foreground job which had at least one stopped or sigkilled member.
3580 * The probable rationale is that SIGSTOP and SIGKILL can preclude task from
3581 * properly restoring tty state. Should we do this too?
3582 * A reproducer: ^Z an interactive python:
3583 *
3584 * # python
3585 * Python 2.7.12 (...)
3586 * >>> ^Z
3587 * { python leaves tty in -icanon -echo state. We do survive that... }
3588 * [1]+ Stopped python
3589 * { ...however, next program (python #2) does not survive it well: }
3590 * # python
3591 * Python 2.7.12 (...)
3592 * >>> Traceback (most recent call last):
3593 * { above, I typed "qwerty<CR>", but -echo state is still in effect }
3594 * File "<stdin>", line 1, in <module>
3595 * NameError: name 'qwerty' is not defined
3596 *
3597 * The implementation below is modeled on bash code and seems to work.
3598 * However, I'm not sure we should do this. For one: what if I'd fg
3599 * the stopped python instead? It'll be confused by "restored" tty state.
3600 */
3601static struct termios shell_tty_info;
3602static void
3603get_tty_state(void)
3604{
3605 if (rootshell && ttyfd >= 0)
3606 tcgetattr(ttyfd, &shell_tty_info);
3607}
3608static void
3609set_tty_state(void)
3610{
3611 /* if (rootshell) - caller ensures this */
3612 if (ttyfd >= 0)
3613 tcsetattr(ttyfd, TCSADRAIN, &shell_tty_info);
3614}
3615static int
3616job_signal_status(struct job *jp)
3617{
3618 int status;
3619 unsigned i;
3620 struct procstat *ps = jp->ps;
3621 for (i = 0; i < jp->nprocs; i++) {
3622 status = ps[i].ps_status;
3623 if (WIFSIGNALED(status) || WIFSTOPPED(status))
3624 return status;
3625 }
3626 return 0;
3627}
3628static void
3629restore_tty_if_stopped_or_signaled(struct job *jp)
3630{
3631//TODO: check what happens if we come from waitforjob() in expbackq()
3632 if (rootshell) {
3633 int s = job_signal_status(jp);
3634 if (s) /* WIFSIGNALED(s) || WIFSTOPPED(s) */
3635 set_tty_state();
3636 }
3637}
3638#else
3639# define get_tty_state() ((void)0)
3640# define restore_tty_if_stopped_or_signaled(jp) ((void)0)
3641#endif
3642
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003643static void
3644set_curjob(struct job *jp, unsigned mode)
3645{
3646 struct job *jp1;
3647 struct job **jpp, **curp;
3648
3649 /* first remove from list */
3650 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003651 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003652 jp1 = *jpp;
3653 if (jp1 == jp)
3654 break;
3655 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003656 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003657 *jpp = jp1->prev_job;
3658
3659 /* Then re-insert in correct position */
3660 jpp = curp;
3661 switch (mode) {
3662 default:
3663#if DEBUG
3664 abort();
3665#endif
3666 case CUR_DELETE:
3667 /* job being deleted */
3668 break;
3669 case CUR_RUNNING:
3670 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003671 * put after all stopped jobs.
3672 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003673 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003674 jp1 = *jpp;
3675#if JOBS
3676 if (!jp1 || jp1->state != JOBSTOPPED)
3677#endif
3678 break;
3679 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003680 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003681 /* FALLTHROUGH */
3682#if JOBS
3683 case CUR_STOPPED:
3684#endif
3685 /* newly stopped job - becomes curjob */
3686 jp->prev_job = *jpp;
3687 *jpp = jp;
3688 break;
3689 }
3690}
3691
3692#if JOBS || DEBUG
3693static int
3694jobno(const struct job *jp)
3695{
3696 return jp - jobtab + 1;
3697}
3698#endif
3699
3700/*
3701 * Convert a job name to a job structure.
3702 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003703#if !JOBS
3704#define getjob(name, getctl) getjob(name)
3705#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003706static struct job *
3707getjob(const char *name, int getctl)
3708{
3709 struct job *jp;
3710 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003711 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003712 unsigned num;
3713 int c;
3714 const char *p;
3715 char *(*match)(const char *, const char *);
3716
3717 jp = curjob;
3718 p = name;
3719 if (!p)
3720 goto currentjob;
3721
3722 if (*p != '%')
3723 goto err;
3724
3725 c = *++p;
3726 if (!c)
3727 goto currentjob;
3728
3729 if (!p[1]) {
3730 if (c == '+' || c == '%') {
3731 currentjob:
3732 err_msg = "No current job";
3733 goto check;
3734 }
3735 if (c == '-') {
3736 if (jp)
3737 jp = jp->prev_job;
3738 err_msg = "No previous job";
3739 check:
3740 if (!jp)
3741 goto err;
3742 goto gotit;
3743 }
3744 }
3745
3746 if (is_number(p)) {
3747 num = atoi(p);
Denys Vlasenko46a45ce2016-09-29 01:10:08 +02003748 if (num > 0 && num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003749 jp = jobtab + num - 1;
3750 if (jp->used)
3751 goto gotit;
3752 goto err;
3753 }
3754 }
3755
3756 match = prefix;
3757 if (*p == '?') {
3758 match = strstr;
3759 p++;
3760 }
3761
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003762 found = NULL;
3763 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003764 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003765 if (found)
3766 goto err;
3767 found = jp;
3768 err_msg = "%s: ambiguous";
3769 }
3770 jp = jp->prev_job;
3771 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003772 if (!found)
3773 goto err;
3774 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003775
3776 gotit:
3777#if JOBS
3778 err_msg = "job %s not created under job control";
3779 if (getctl && jp->jobctl == 0)
3780 goto err;
3781#endif
3782 return jp;
3783 err:
3784 ash_msg_and_raise_error(err_msg, name);
3785}
3786
3787/*
3788 * Mark a job structure as unused.
3789 */
3790static void
3791freejob(struct job *jp)
3792{
3793 struct procstat *ps;
3794 int i;
3795
3796 INT_OFF;
3797 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003798 if (ps->ps_cmd != nullstr)
3799 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003800 }
3801 if (jp->ps != &jp->ps0)
3802 free(jp->ps);
3803 jp->used = 0;
3804 set_curjob(jp, CUR_DELETE);
3805 INT_ON;
3806}
3807
3808#if JOBS
3809static void
3810xtcsetpgrp(int fd, pid_t pgrp)
3811{
3812 if (tcsetpgrp(fd, pgrp))
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003813 ash_msg_and_raise_error("can't set tty process group (%m)");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003814}
3815
3816/*
3817 * Turn job control on and off.
3818 *
3819 * Note: This code assumes that the third arg to ioctl is a character
3820 * pointer, which is true on Berkeley systems but not System V. Since
3821 * System V doesn't have job control yet, this isn't a problem now.
3822 *
3823 * Called with interrupts off.
3824 */
3825static void
3826setjobctl(int on)
3827{
3828 int fd;
3829 int pgrp;
3830
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003831 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003832 return;
3833 if (on) {
3834 int ofd;
3835 ofd = fd = open(_PATH_TTY, O_RDWR);
3836 if (fd < 0) {
3837 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3838 * That sometimes helps to acquire controlling tty.
3839 * Obviously, a workaround for bugs when someone
3840 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003841 fd = 2;
3842 while (!isatty(fd))
3843 if (--fd < 0)
3844 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003845 }
Denys Vlasenko64774602016-10-26 15:24:30 +02003846 /* fd is a tty at this point */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003847 fd = fcntl(fd, F_DUPFD, 10);
Denys Vlasenko10ad6222017-04-17 16:13:32 +02003848 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, don't */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003849 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003850 if (fd < 0)
Denys Vlasenko64774602016-10-26 15:24:30 +02003851 goto out; /* F_DUPFD failed */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003852 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003853 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003854 pgrp = tcgetpgrp(fd);
3855 if (pgrp < 0) {
3856 out:
3857 ash_msg("can't access tty; job control turned off");
3858 mflag = on = 0;
3859 goto close;
3860 }
3861 if (pgrp == getpgrp())
3862 break;
3863 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003864 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003865 initialpgrp = pgrp;
3866
3867 setsignal(SIGTSTP);
3868 setsignal(SIGTTOU);
3869 setsignal(SIGTTIN);
3870 pgrp = rootpid;
3871 setpgid(0, pgrp);
3872 xtcsetpgrp(fd, pgrp);
3873 } else {
3874 /* turning job control off */
3875 fd = ttyfd;
3876 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003877 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003878 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003879 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003880 setpgid(0, pgrp);
3881 setsignal(SIGTSTP);
3882 setsignal(SIGTTOU);
3883 setsignal(SIGTTIN);
3884 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003885 if (fd >= 0)
3886 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003887 fd = -1;
3888 }
3889 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003890 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003891}
3892
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003893static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003894killcmd(int argc, char **argv)
3895{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003896 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003897 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003898 do {
3899 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003900 /*
3901 * "kill %N" - job kill
3902 * Converting to pgrp / pid kill
3903 */
3904 struct job *jp;
3905 char *dst;
3906 int j, n;
3907
3908 jp = getjob(argv[i], 0);
3909 /*
3910 * In jobs started under job control, we signal
3911 * entire process group by kill -PGRP_ID.
3912 * This happens, f.e., in interactive shell.
3913 *
3914 * Otherwise, we signal each child via
3915 * kill PID1 PID2 PID3.
3916 * Testcases:
3917 * sh -c 'sleep 1|sleep 1 & kill %1'
3918 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3919 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3920 */
3921 n = jp->nprocs; /* can't be 0 (I hope) */
3922 if (jp->jobctl)
3923 n = 1;
3924 dst = alloca(n * sizeof(int)*4);
3925 argv[i] = dst;
3926 for (j = 0; j < n; j++) {
3927 struct procstat *ps = &jp->ps[j];
3928 /* Skip non-running and not-stopped members
3929 * (i.e. dead members) of the job
3930 */
3931 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3932 continue;
3933 /*
3934 * kill_main has matching code to expect
3935 * leading space. Needed to not confuse
3936 * negative pids with "kill -SIGNAL_NO" syntax
3937 */
3938 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3939 }
3940 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003941 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003942 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003943 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003944 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003945}
3946
3947static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01003948showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003949{
Denys Vlasenko285ad152009-12-04 23:02:27 +01003950 struct procstat *ps;
3951 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003952
Denys Vlasenko285ad152009-12-04 23:02:27 +01003953 psend = jp->ps + jp->nprocs;
3954 for (ps = jp->ps + 1; ps < psend; ps++)
3955 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003956 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003957 flush_stdout_stderr();
3958}
3959
3960
3961static int
3962restartjob(struct job *jp, int mode)
3963{
3964 struct procstat *ps;
3965 int i;
3966 int status;
3967 pid_t pgid;
3968
3969 INT_OFF;
3970 if (jp->state == JOBDONE)
3971 goto out;
3972 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003973 pgid = jp->ps[0].ps_pid;
Denys Vlasenko098b7132017-01-11 19:59:03 +01003974 if (mode == FORK_FG) {
3975 get_tty_state();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003976 xtcsetpgrp(ttyfd, pgid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01003977 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003978 killpg(pgid, SIGCONT);
3979 ps = jp->ps;
3980 i = jp->nprocs;
3981 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003982 if (WIFSTOPPED(ps->ps_status)) {
3983 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003984 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003985 ps++;
3986 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003987 out:
3988 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3989 INT_ON;
3990 return status;
3991}
3992
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003993static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003994fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003995{
3996 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003997 int mode;
3998 int retval;
3999
4000 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
4001 nextopt(nullstr);
4002 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004003 do {
4004 jp = getjob(*argv, 1);
4005 if (mode == FORK_BG) {
4006 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004007 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004008 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004009 out1str(jp->ps[0].ps_cmd);
4010 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004011 retval = restartjob(jp, mode);
4012 } while (*argv && *++argv);
4013 return retval;
4014}
4015#endif
4016
4017static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02004018sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004019{
4020 int col;
4021 int st;
4022
4023 col = 0;
4024 if (!WIFEXITED(status)) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004025 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004026 st = WSTOPSIG(status);
4027 else
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004028 st = WTERMSIG(status);
4029 if (sigonly) {
4030 if (st == SIGINT || st == SIGPIPE)
4031 goto out;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004032 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004033 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004034 }
4035 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01004036//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004037 col = fmtstr(s, 32, strsignal(st));
4038 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004039 strcpy(s + col, " (core dumped)");
4040 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004041 }
4042 } else if (!sigonly) {
4043 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004044 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004045 }
4046 out:
4047 return col;
4048}
4049
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004050static int
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004051wait_block_or_sig(int *status)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004052{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004053 int pid;
4054
4055 do {
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004056 sigset_t mask;
4057
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004058 /* Poll all children for changes in their state */
4059 got_sigchld = 0;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004060 /* if job control is active, accept stopped processes too */
4061 pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004062 if (pid != 0)
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004063 break; /* Error (e.g. EINTR, ECHILD) or pid */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004064
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004065 /* Children exist, but none are ready. Sleep until interesting signal */
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004066#if 1
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004067 sigfillset(&mask);
4068 sigprocmask(SIG_SETMASK, &mask, &mask);
4069 while (!got_sigchld && !pending_sig)
4070 sigsuspend(&mask);
4071 sigprocmask(SIG_SETMASK, &mask, NULL);
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004072#else /* unsafe: a signal can set pending_sig after check, but before pause() */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004073 while (!got_sigchld && !pending_sig)
4074 pause();
4075#endif
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004076
4077 /* If it was SIGCHLD, poll children again */
4078 } while (got_sigchld);
4079
4080 return pid;
4081}
4082
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004083#define DOWAIT_NONBLOCK 0
4084#define DOWAIT_BLOCK 1
4085#define DOWAIT_BLOCK_OR_SIG 2
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004086
4087static int
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004088dowait(int block, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004089{
4090 int pid;
4091 int status;
4092 struct job *jp;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004093 struct job *thisjob = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004094
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004095 TRACE(("dowait(0x%x) called\n", block));
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00004096
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004097 /* It's wrong to call waitpid() outside of INT_OFF region:
4098 * signal can arrive just after syscall return and handler can
4099 * longjmp away, losing stop/exit notification processing.
4100 * Thus, for "jobs" builtin, and for waiting for a fg job,
4101 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4102 *
4103 * However, for "wait" builtin it is wrong to simply call waitpid()
4104 * in INT_OFF region: "wait" needs to wait for any running job
4105 * to change state, but should exit on any trap too.
4106 * In INT_OFF region, a signal just before syscall entry can set
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004107 * pending_sig variables, but we can't check them, and we would
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004108 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004109 *
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004110 * Because of this, we run inside INT_OFF, but use a special routine
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004111 * which combines waitpid() and sigsuspend().
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004112 * This is the reason why we need to have a handler for SIGCHLD:
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004113 * SIG_DFL handler does not wake sigsuspend().
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004114 */
4115 INT_OFF;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004116 if (block == DOWAIT_BLOCK_OR_SIG) {
4117 pid = wait_block_or_sig(&status);
4118 } else {
4119 int wait_flags = 0;
4120 if (block == DOWAIT_NONBLOCK)
4121 wait_flags = WNOHANG;
4122 /* if job control is active, accept stopped processes too */
4123 if (doing_jobctl)
4124 wait_flags |= WUNTRACED;
4125 /* NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004126 pid = waitpid(-1, &status, wait_flags);
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004127 }
Denis Vlasenkob21f3792009-03-19 23:09:58 +00004128 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4129 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004130 if (pid <= 0)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004131 goto out;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004132
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004133 thisjob = NULL;
4134 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004135 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004136 struct procstat *ps;
4137 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004138 if (jp->state == JOBDONE)
4139 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004140 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004141 ps = jp->ps;
4142 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004143 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004144 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004145 TRACE(("Job %d: changing status of proc %d "
4146 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01004147 jobno(jp), pid, ps->ps_status, status));
4148 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004149 thisjob = jp;
4150 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004151 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004152 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004153#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004154 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004155 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004156 if (WIFSTOPPED(ps->ps_status)) {
4157 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004158 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004159 }
4160#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004161 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004162 if (!thisjob)
4163 continue;
4164
4165 /* Found the job where one of its processes changed its state.
4166 * Is there at least one live and running process in this job? */
4167 if (jobstate != JOBRUNNING) {
4168 /* No. All live processes in the job are stopped
4169 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4170 */
4171 thisjob->changed = 1;
4172 if (thisjob->state != jobstate) {
4173 TRACE(("Job %d: changing state from %d to %d\n",
4174 jobno(thisjob), thisjob->state, jobstate));
4175 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004176#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004177 if (jobstate == JOBSTOPPED)
4178 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004179#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004180 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004181 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004182 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004183 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004184 /* The process wasn't found in job list */
4185 if (JOBS && !WIFSTOPPED(status))
4186 jobless--;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004187 out:
4188 INT_ON;
4189
4190 if (thisjob && thisjob == job) {
4191 char s[48 + 1];
4192 int len;
4193
Denys Vlasenko9c541002015-10-07 15:44:36 +02004194 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004195 if (len) {
4196 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004197 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004198 out2str(s);
4199 }
4200 }
4201 return pid;
4202}
4203
4204#if JOBS
4205static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004206showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004207{
4208 struct procstat *ps;
4209 struct procstat *psend;
4210 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004211 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004212 char s[16 + 16 + 48];
4213 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004214
4215 ps = jp->ps;
4216
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004217 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004218 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004219 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004220 return;
4221 }
4222
4223 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004224 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004225
4226 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004227 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004228 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004229 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004230
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004231 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004232 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004233
4234 psend = ps + jp->nprocs;
4235
4236 if (jp->state == JOBRUNNING) {
4237 strcpy(s + col, "Running");
4238 col += sizeof("Running") - 1;
4239 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004240 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004241 if (jp->state == JOBSTOPPED)
4242 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004243 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004244 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004245 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004246
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004247 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4248 * or prints several "PID | <cmdN>" lines,
4249 * depending on SHOW_PIDS bit.
4250 * We do not print status of individual processes
4251 * between PID and <cmdN>. bash does it, but not very well:
4252 * first line shows overall job status, not process status,
4253 * making it impossible to know 1st process status.
4254 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004255 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004256 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004257 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004258 s[0] = '\0';
4259 col = 33;
4260 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004261 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004262 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004263 fprintf(out, "%s%*c%s%s",
4264 s,
4265 33 - col >= 0 ? 33 - col : 0, ' ',
4266 ps == jp->ps ? "" : "| ",
4267 ps->ps_cmd
4268 );
4269 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004270 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004271
4272 jp->changed = 0;
4273
4274 if (jp->state == JOBDONE) {
4275 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4276 freejob(jp);
4277 }
4278}
4279
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004280/*
4281 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4282 * statuses have changed since the last call to showjobs.
4283 */
4284static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004285showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004286{
4287 struct job *jp;
4288
Denys Vlasenko883cea42009-07-11 15:31:59 +02004289 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004290
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004291 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004292 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004293 continue;
4294
4295 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004296 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004297 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004298 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004299 }
4300}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004301
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004302static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004303jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004304{
4305 int mode, m;
4306
4307 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004308 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004309 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004310 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004311 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004312 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004313 }
4314
4315 argv = argptr;
4316 if (*argv) {
4317 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004318 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004319 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004320 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004321 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004322 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004323
4324 return 0;
4325}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004326#endif /* JOBS */
4327
Michael Abbott359da5e2009-12-04 23:03:29 +01004328/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004329static int
4330getstatus(struct job *job)
4331{
4332 int status;
4333 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004334 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004335
Michael Abbott359da5e2009-12-04 23:03:29 +01004336 /* Fetch last member's status */
4337 ps = job->ps + job->nprocs - 1;
4338 status = ps->ps_status;
4339 if (pipefail) {
4340 /* "set -o pipefail" mode: use last _nonzero_ status */
4341 while (status == 0 && --ps >= job->ps)
4342 status = ps->ps_status;
4343 }
4344
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004345 retval = WEXITSTATUS(status);
4346 if (!WIFEXITED(status)) {
4347#if JOBS
4348 retval = WSTOPSIG(status);
4349 if (!WIFSTOPPED(status))
4350#endif
4351 {
4352 /* XXX: limits number of signals */
4353 retval = WTERMSIG(status);
4354#if JOBS
4355 if (retval == SIGINT)
4356 job->sigint = 1;
4357#endif
4358 }
4359 retval += 128;
4360 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004361 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004362 jobno(job), job->nprocs, status, retval));
4363 return retval;
4364}
4365
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004366static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004367waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004368{
4369 struct job *job;
4370 int retval;
4371 struct job *jp;
4372
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004373 nextopt(nullstr);
4374 retval = 0;
4375
4376 argv = argptr;
4377 if (!*argv) {
4378 /* wait for all jobs */
4379 for (;;) {
4380 jp = curjob;
4381 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004382 if (!jp) /* no running procs */
4383 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004384 if (jp->state == JOBRUNNING)
4385 break;
4386 jp->waited = 1;
4387 jp = jp->prev_job;
4388 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004389 /* man bash:
4390 * "When bash is waiting for an asynchronous command via
4391 * the wait builtin, the reception of a signal for which a trap
4392 * has been set will cause the wait builtin to return immediately
4393 * with an exit status greater than 128, immediately after which
4394 * the trap is executed."
Denys Vlasenko69188112016-10-27 20:18:18 +02004395 */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004396 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004397 /* if child sends us a signal *and immediately exits*,
4398 * dowait() returns pid > 0. Check this case,
4399 * not "if (dowait() < 0)"!
4400 */
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004401 if (pending_sig)
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004402 goto sigout;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004403 }
4404 }
4405
4406 retval = 127;
4407 do {
4408 if (**argv != '%') {
4409 pid_t pid = number(*argv);
4410 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004411 while (1) {
4412 if (!job)
4413 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004414 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004415 break;
4416 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004417 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004418 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004419 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004420 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004421 /* loop until process terminated or stopped */
Denys Vlasenko69188112016-10-27 20:18:18 +02004422 while (job->state == JOBRUNNING) {
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004423 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004424 if (pending_sig)
4425 goto sigout;
Denys Vlasenko69188112016-10-27 20:18:18 +02004426 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004427 job->waited = 1;
4428 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004429 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004430 } while (*++argv);
4431
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004432 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004433 return retval;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004434 sigout:
4435 retval = 128 + pending_sig;
4436 return retval;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004437}
4438
4439static struct job *
4440growjobtab(void)
4441{
4442 size_t len;
4443 ptrdiff_t offset;
4444 struct job *jp, *jq;
4445
4446 len = njobs * sizeof(*jp);
4447 jq = jobtab;
4448 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4449
4450 offset = (char *)jp - (char *)jq;
4451 if (offset) {
4452 /* Relocate pointers */
4453 size_t l = len;
4454
4455 jq = (struct job *)((char *)jq + l);
4456 while (l) {
4457 l -= sizeof(*jp);
4458 jq--;
4459#define joff(p) ((struct job *)((char *)(p) + l))
4460#define jmove(p) (p) = (void *)((char *)(p) + offset)
4461 if (joff(jp)->ps == &jq->ps0)
4462 jmove(joff(jp)->ps);
4463 if (joff(jp)->prev_job)
4464 jmove(joff(jp)->prev_job);
4465 }
4466 if (curjob)
4467 jmove(curjob);
4468#undef joff
4469#undef jmove
4470 }
4471
4472 njobs += 4;
4473 jobtab = jp;
4474 jp = (struct job *)((char *)jp + len);
4475 jq = jp + 3;
4476 do {
4477 jq->used = 0;
4478 } while (--jq >= jp);
4479 return jp;
4480}
4481
4482/*
4483 * Return a new job structure.
4484 * Called with interrupts off.
4485 */
4486static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004487makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004488{
4489 int i;
4490 struct job *jp;
4491
4492 for (i = njobs, jp = jobtab; ; jp++) {
4493 if (--i < 0) {
4494 jp = growjobtab();
4495 break;
4496 }
4497 if (jp->used == 0)
4498 break;
4499 if (jp->state != JOBDONE || !jp->waited)
4500 continue;
4501#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004502 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004503 continue;
4504#endif
4505 freejob(jp);
4506 break;
4507 }
4508 memset(jp, 0, sizeof(*jp));
4509#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004510 /* jp->jobctl is a bitfield.
Denys Vlasenko098b7132017-01-11 19:59:03 +01004511 * "jp->jobctl |= doing_jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004512 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004513 jp->jobctl = 1;
4514#endif
4515 jp->prev_job = curjob;
4516 curjob = jp;
4517 jp->used = 1;
4518 jp->ps = &jp->ps0;
4519 if (nprocs > 1) {
4520 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4521 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004522 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004523 jobno(jp)));
4524 return jp;
4525}
4526
4527#if JOBS
4528/*
4529 * Return a string identifying a command (to be printed by the
4530 * jobs command).
4531 */
4532static char *cmdnextc;
4533
4534static void
4535cmdputs(const char *s)
4536{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004537 static const char vstype[VSTYPE + 1][3] = {
4538 "", "}", "-", "+", "?", "=",
4539 "%", "%%", "#", "##"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004540 IF_BASH_SUBSTR(, ":")
4541 IF_BASH_PATTERN_SUBST(, "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004542 };
4543
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004544 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004545 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004546 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004547 unsigned char c;
4548 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004549 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004550
Denys Vlasenko46a14772009-12-10 21:27:13 +01004551 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004552 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4553 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004554 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004555 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004556 switch (c) {
4557 case CTLESC:
4558 c = *p++;
4559 break;
4560 case CTLVAR:
4561 subtype = *p++;
4562 if ((subtype & VSTYPE) == VSLENGTH)
4563 str = "${#";
4564 else
4565 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004566 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004567 case CTLENDVAR:
4568 str = "\"}" + !(quoted & 1);
4569 quoted >>= 1;
4570 subtype = 0;
4571 goto dostr;
4572 case CTLBACKQ:
4573 str = "$(...)";
4574 goto dostr;
Denys Vlasenko0b883582016-12-23 16:49:07 +01004575#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004576 case CTLARI:
4577 str = "$((";
4578 goto dostr;
4579 case CTLENDARI:
4580 str = "))";
4581 goto dostr;
4582#endif
4583 case CTLQUOTEMARK:
4584 quoted ^= 1;
4585 c = '"';
4586 break;
4587 case '=':
4588 if (subtype == 0)
4589 break;
4590 if ((subtype & VSTYPE) != VSNORMAL)
4591 quoted <<= 1;
4592 str = vstype[subtype & VSTYPE];
4593 if (subtype & VSNUL)
4594 c = ':';
4595 else
4596 goto checkstr;
4597 break;
4598 case '\'':
4599 case '\\':
4600 case '"':
4601 case '$':
4602 /* These can only happen inside quotes */
4603 cc[0] = c;
4604 str = cc;
4605 c = '\\';
4606 break;
4607 default:
4608 break;
4609 }
4610 USTPUTC(c, nextc);
4611 checkstr:
4612 if (!str)
4613 continue;
4614 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004615 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004616 USTPUTC(c, nextc);
4617 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004618 } /* while *p++ not NUL */
4619
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004620 if (quoted & 1) {
4621 USTPUTC('"', nextc);
4622 }
4623 *nextc = 0;
4624 cmdnextc = nextc;
4625}
4626
4627/* cmdtxt() and cmdlist() call each other */
4628static void cmdtxt(union node *n);
4629
4630static void
4631cmdlist(union node *np, int sep)
4632{
4633 for (; np; np = np->narg.next) {
4634 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004635 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004636 cmdtxt(np);
4637 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004638 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004639 }
4640}
4641
4642static void
4643cmdtxt(union node *n)
4644{
4645 union node *np;
4646 struct nodelist *lp;
4647 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004648
4649 if (!n)
4650 return;
4651 switch (n->type) {
4652 default:
4653#if DEBUG
4654 abort();
4655#endif
4656 case NPIPE:
4657 lp = n->npipe.cmdlist;
4658 for (;;) {
4659 cmdtxt(lp->n);
4660 lp = lp->next;
4661 if (!lp)
4662 break;
4663 cmdputs(" | ");
4664 }
4665 break;
4666 case NSEMI:
4667 p = "; ";
4668 goto binop;
4669 case NAND:
4670 p = " && ";
4671 goto binop;
4672 case NOR:
4673 p = " || ";
4674 binop:
4675 cmdtxt(n->nbinary.ch1);
4676 cmdputs(p);
4677 n = n->nbinary.ch2;
4678 goto donode;
4679 case NREDIR:
4680 case NBACKGND:
4681 n = n->nredir.n;
4682 goto donode;
4683 case NNOT:
4684 cmdputs("!");
4685 n = n->nnot.com;
4686 donode:
4687 cmdtxt(n);
4688 break;
4689 case NIF:
4690 cmdputs("if ");
4691 cmdtxt(n->nif.test);
4692 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004693 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004694 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004695 cmdputs("; else ");
4696 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004697 } else {
4698 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004699 }
4700 p = "; fi";
4701 goto dotail;
4702 case NSUBSHELL:
4703 cmdputs("(");
4704 n = n->nredir.n;
4705 p = ")";
4706 goto dotail;
4707 case NWHILE:
4708 p = "while ";
4709 goto until;
4710 case NUNTIL:
4711 p = "until ";
4712 until:
4713 cmdputs(p);
4714 cmdtxt(n->nbinary.ch1);
4715 n = n->nbinary.ch2;
4716 p = "; done";
4717 dodo:
4718 cmdputs("; do ");
4719 dotail:
4720 cmdtxt(n);
4721 goto dotail2;
4722 case NFOR:
4723 cmdputs("for ");
4724 cmdputs(n->nfor.var);
4725 cmdputs(" in ");
4726 cmdlist(n->nfor.args, 1);
4727 n = n->nfor.body;
4728 p = "; done";
4729 goto dodo;
4730 case NDEFUN:
4731 cmdputs(n->narg.text);
4732 p = "() { ... }";
4733 goto dotail2;
4734 case NCMD:
4735 cmdlist(n->ncmd.args, 1);
4736 cmdlist(n->ncmd.redirect, 0);
4737 break;
4738 case NARG:
4739 p = n->narg.text;
4740 dotail2:
4741 cmdputs(p);
4742 break;
4743 case NHERE:
4744 case NXHERE:
4745 p = "<<...";
4746 goto dotail2;
4747 case NCASE:
4748 cmdputs("case ");
4749 cmdputs(n->ncase.expr->narg.text);
4750 cmdputs(" in ");
4751 for (np = n->ncase.cases; np; np = np->nclist.next) {
4752 cmdtxt(np->nclist.pattern);
4753 cmdputs(") ");
4754 cmdtxt(np->nclist.body);
4755 cmdputs(";; ");
4756 }
4757 p = "esac";
4758 goto dotail2;
4759 case NTO:
4760 p = ">";
4761 goto redir;
4762 case NCLOBBER:
4763 p = ">|";
4764 goto redir;
4765 case NAPPEND:
4766 p = ">>";
4767 goto redir;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004768#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00004769 case NTO2:
4770#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004771 case NTOFD:
4772 p = ">&";
4773 goto redir;
4774 case NFROM:
4775 p = "<";
4776 goto redir;
4777 case NFROMFD:
4778 p = "<&";
4779 goto redir;
4780 case NFROMTO:
4781 p = "<>";
4782 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004783 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004784 cmdputs(p);
4785 if (n->type == NTOFD || n->type == NFROMFD) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004786 cmdputs(utoa(n->ndup.dupfd));
4787 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004788 }
4789 n = n->nfile.fname;
4790 goto donode;
4791 }
4792}
4793
4794static char *
4795commandtext(union node *n)
4796{
4797 char *name;
4798
4799 STARTSTACKSTR(cmdnextc);
4800 cmdtxt(n);
4801 name = stackblock();
Denys Vlasenko6a94cee2016-10-25 17:40:25 +02004802 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004803 return ckstrdup(name);
4804}
4805#endif /* JOBS */
4806
4807/*
4808 * Fork off a subshell. If we are doing job control, give the subshell its
4809 * own process group. Jp is a job structure that the job is to be added to.
4810 * N is the command that will be evaluated by the child. Both jp and n may
4811 * be NULL. The mode parameter can be one of the following:
4812 * FORK_FG - Fork off a foreground process.
4813 * FORK_BG - Fork off a background process.
4814 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4815 * process group even if job control is on.
4816 *
4817 * When job control is turned off, background processes have their standard
4818 * input redirected to /dev/null (except for the second and later processes
4819 * in a pipeline).
4820 *
4821 * Called with interrupts off.
4822 */
4823/*
4824 * Clear traps on a fork.
4825 */
4826static void
4827clear_traps(void)
4828{
4829 char **tp;
4830
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004831 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004832 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004833 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004834 if (trap_ptr == trap)
4835 free(*tp);
4836 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004837 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004838 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004839 setsignal(tp - trap);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004840 }
4841 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004842 may_have_traps = 0;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004843 INT_ON;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004844}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004845
4846/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004847static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004848
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004849/* Called after fork(), in child */
Denys Vlasenko70392332016-10-27 02:31:55 +02004850/* jp and n are NULL when called by openhere() for heredoc support */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004851static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004852forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004853{
4854 int oldlvl;
4855
4856 TRACE(("Child shell %d\n", getpid()));
4857 oldlvl = shlvl;
4858 shlvl++;
4859
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004860 /* man bash: "Non-builtin commands run by bash have signal handlers
4861 * set to the values inherited by the shell from its parent".
4862 * Do we do it correctly? */
4863
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004864 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004865
4866 if (mode == FORK_NOJOB /* is it `xxx` ? */
4867 && n && n->type == NCMD /* is it single cmd? */
4868 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004869 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004870 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4871 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4872 ) {
4873 TRACE(("Trap hack\n"));
4874 /* Awful hack for `trap` or $(trap).
4875 *
4876 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4877 * contains an example where "trap" is executed in a subshell:
4878 *
4879 * save_traps=$(trap)
4880 * ...
4881 * eval "$save_traps"
4882 *
4883 * Standard does not say that "trap" in subshell shall print
4884 * parent shell's traps. It only says that its output
4885 * must have suitable form, but then, in the above example
4886 * (which is not supposed to be normative), it implies that.
4887 *
4888 * bash (and probably other shell) does implement it
4889 * (traps are reset to defaults, but "trap" still shows them),
4890 * but as a result, "trap" logic is hopelessly messed up:
4891 *
4892 * # trap
4893 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4894 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4895 * # true | trap <--- trap is in subshell - no output (ditto)
4896 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4897 * trap -- 'echo Ho' SIGWINCH
4898 * # echo `(trap)` <--- in subshell in subshell - output
4899 * trap -- 'echo Ho' SIGWINCH
4900 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4901 * trap -- 'echo Ho' SIGWINCH
4902 *
4903 * The rules when to forget and when to not forget traps
4904 * get really complex and nonsensical.
4905 *
4906 * Our solution: ONLY bare $(trap) or `trap` is special.
4907 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004908 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02004909 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004910 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004911 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004912 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004913#if JOBS
4914 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004915 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004916 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004917 pid_t pgrp;
4918
4919 if (jp->nprocs == 0)
4920 pgrp = getpid();
4921 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004922 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004923 /* this can fail because we are doing it in the parent also */
4924 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004925 if (mode == FORK_FG)
4926 xtcsetpgrp(ttyfd, pgrp);
4927 setsignal(SIGTSTP);
4928 setsignal(SIGTTOU);
4929 } else
4930#endif
4931 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004932 /* man bash: "When job control is not in effect,
4933 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004934 ignoresig(SIGINT);
4935 ignoresig(SIGQUIT);
4936 if (jp->nprocs == 0) {
4937 close(0);
4938 if (open(bb_dev_null, O_RDONLY) != 0)
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00004939 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004940 }
4941 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004942 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004943 if (iflag) { /* why if iflag only? */
4944 setsignal(SIGINT);
4945 setsignal(SIGTERM);
4946 }
4947 /* man bash:
4948 * "In all cases, bash ignores SIGQUIT. Non-builtin
4949 * commands run by bash have signal handlers
4950 * set to the values inherited by the shell
4951 * from its parent".
4952 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004953 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004954 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004955#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02004956 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01004957 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004958 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004959 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02004960 /* "jobs": we do not want to clear job list for it,
4961 * instead we remove only _its_ own_ job from job list.
4962 * This makes "jobs .... | cat" more useful.
4963 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004964 freejob(curjob);
4965 return;
4966 }
4967#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004968 for (jp = curjob; jp; jp = jp->prev_job)
4969 freejob(jp);
4970 jobless = 0;
4971}
4972
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004973/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00004974#if !JOBS
4975#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4976#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004977static void
4978forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4979{
4980 TRACE(("In parent shell: child = %d\n", pid));
4981 if (!jp) {
Denys Vlasenko70392332016-10-27 02:31:55 +02004982 /* jp is NULL when called by openhere() for heredoc support */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004983 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4984 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004985 jobless++;
4986 return;
4987 }
4988#if JOBS
4989 if (mode != FORK_NOJOB && jp->jobctl) {
4990 int pgrp;
4991
4992 if (jp->nprocs == 0)
4993 pgrp = pid;
4994 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004995 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004996 /* This can fail because we are doing it in the child also */
4997 setpgid(pid, pgrp);
4998 }
4999#endif
5000 if (mode == FORK_BG) {
5001 backgndpid = pid; /* set $! */
5002 set_curjob(jp, CUR_RUNNING);
5003 }
5004 if (jp) {
5005 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01005006 ps->ps_pid = pid;
5007 ps->ps_status = -1;
5008 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005009#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005010 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01005011 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005012#endif
5013 }
5014}
5015
Denys Vlasenko70392332016-10-27 02:31:55 +02005016/* jp and n are NULL when called by openhere() for heredoc support */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005017static int
5018forkshell(struct job *jp, union node *n, int mode)
5019{
5020 int pid;
5021
5022 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5023 pid = fork();
5024 if (pid < 0) {
5025 TRACE(("Fork failed, errno=%d", errno));
5026 if (jp)
5027 freejob(jp);
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +00005028 ash_msg_and_raise_error("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005029 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02005030 if (pid == 0) {
5031 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005032 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005033 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005034 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005035 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005036 return pid;
5037}
5038
5039/*
5040 * Wait for job to finish.
5041 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005042 * Under job control we have the problem that while a child process
5043 * is running interrupts generated by the user are sent to the child
5044 * but not to the shell. This means that an infinite loop started by
5045 * an interactive user may be hard to kill. With job control turned off,
5046 * an interactive user may place an interactive program inside a loop.
5047 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005048 * these interrupts to also abort the loop. The approach we take here
5049 * is to have the shell ignore interrupt signals while waiting for a
5050 * foreground process to terminate, and then send itself an interrupt
5051 * signal if the child process was terminated by an interrupt signal.
5052 * Unfortunately, some programs want to do a bit of cleanup and then
5053 * exit on interrupt; unless these processes terminate themselves by
5054 * sending a signal to themselves (instead of calling exit) they will
5055 * confuse this approach.
5056 *
5057 * Called with interrupts off.
5058 */
5059static int
5060waitforjob(struct job *jp)
5061{
5062 int st;
5063
5064 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005065
5066 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005067 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005068 /* In non-interactive shells, we _can_ get
5069 * a keyboard signal here and be EINTRed,
5070 * but we just loop back, waiting for command to complete.
5071 *
5072 * man bash:
5073 * "If bash is waiting for a command to complete and receives
5074 * a signal for which a trap has been set, the trap
5075 * will not be executed until the command completes."
5076 *
5077 * Reality is that even if trap is not set, bash
5078 * will not act on the signal until command completes.
5079 * Try this. sleep5intoff.c:
5080 * #include <signal.h>
5081 * #include <unistd.h>
5082 * int main() {
5083 * sigset_t set;
5084 * sigemptyset(&set);
5085 * sigaddset(&set, SIGINT);
5086 * sigaddset(&set, SIGQUIT);
5087 * sigprocmask(SIG_BLOCK, &set, NULL);
5088 * sleep(5);
5089 * return 0;
5090 * }
5091 * $ bash -c './sleep5intoff; echo hi'
5092 * ^C^C^C^C <--- pressing ^C once a second
5093 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005094 * $ bash -c './sleep5intoff; echo hi'
5095 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5096 * $ _
5097 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005098 dowait(DOWAIT_BLOCK, jp);
5099 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005100 INT_ON;
5101
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005102 st = getstatus(jp);
5103#if JOBS
5104 if (jp->jobctl) {
5105 xtcsetpgrp(ttyfd, rootpid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01005106 restore_tty_if_stopped_or_signaled(jp);
5107
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005108 /*
5109 * This is truly gross.
5110 * If we're doing job control, then we did a TIOCSPGRP which
5111 * caused us (the shell) to no longer be in the controlling
5112 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
5113 * intuit from the subprocess exit status whether a SIGINT
5114 * occurred, and if so interrupt ourselves. Yuck. - mycroft
5115 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00005116 if (jp->sigint) /* TODO: do the same with all signals */
5117 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005118 }
5119 if (jp->state == JOBDONE)
5120#endif
5121 freejob(jp);
5122 return st;
5123}
5124
5125/*
5126 * return 1 if there are stopped jobs, otherwise 0
5127 */
5128static int
5129stoppedjobs(void)
5130{
5131 struct job *jp;
5132 int retval;
5133
5134 retval = 0;
5135 if (job_warning)
5136 goto out;
5137 jp = curjob;
5138 if (jp && jp->state == JOBSTOPPED) {
5139 out2str("You have stopped jobs.\n");
5140 job_warning = 2;
5141 retval++;
5142 }
5143 out:
5144 return retval;
5145}
5146
5147
Denys Vlasenko70392332016-10-27 02:31:55 +02005148/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005149 * Code for dealing with input/output redirection.
5150 */
5151
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005152#undef EMPTY
5153#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005154#define EMPTY -2 /* marks an unused slot in redirtab */
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005155#define CLOSED -3 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005156
5157/*
5158 * Open a file in noclobber mode.
5159 * The code was copied from bash.
5160 */
5161static int
5162noclobberopen(const char *fname)
5163{
5164 int r, fd;
5165 struct stat finfo, finfo2;
5166
5167 /*
5168 * If the file exists and is a regular file, return an error
5169 * immediately.
5170 */
5171 r = stat(fname, &finfo);
5172 if (r == 0 && S_ISREG(finfo.st_mode)) {
5173 errno = EEXIST;
5174 return -1;
5175 }
5176
5177 /*
5178 * If the file was not present (r != 0), make sure we open it
5179 * exclusively so that if it is created before we open it, our open
5180 * will fail. Make sure that we do not truncate an existing file.
5181 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5182 * file was not a regular file, we leave O_EXCL off.
5183 */
5184 if (r != 0)
5185 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5186 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5187
5188 /* If the open failed, return the file descriptor right away. */
5189 if (fd < 0)
5190 return fd;
5191
5192 /*
5193 * OK, the open succeeded, but the file may have been changed from a
5194 * non-regular file to a regular file between the stat and the open.
5195 * We are assuming that the O_EXCL open handles the case where FILENAME
5196 * did not exist and is symlinked to an existing file between the stat
5197 * and open.
5198 */
5199
5200 /*
5201 * If we can open it and fstat the file descriptor, and neither check
5202 * revealed that it was a regular file, and the file has not been
5203 * replaced, return the file descriptor.
5204 */
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005205 if (fstat(fd, &finfo2) == 0
5206 && !S_ISREG(finfo2.st_mode)
5207 && finfo.st_dev == finfo2.st_dev
5208 && finfo.st_ino == finfo2.st_ino
5209 ) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005210 return fd;
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005211 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005212
5213 /* The file has been replaced. badness. */
5214 close(fd);
5215 errno = EEXIST;
5216 return -1;
5217}
5218
5219/*
5220 * Handle here documents. Normally we fork off a process to write the
5221 * data to a pipe. If the document is short, we can stuff the data in
5222 * the pipe without forking.
5223 */
5224/* openhere needs this forward reference */
5225static void expandhere(union node *arg, int fd);
5226static int
5227openhere(union node *redir)
5228{
5229 int pip[2];
5230 size_t len = 0;
5231
5232 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005233 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005234 if (redir->type == NHERE) {
5235 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005236 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005237 full_write(pip[1], redir->nhere.doc->narg.text, len);
5238 goto out;
5239 }
5240 }
5241 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005242 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005243 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005244 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5245 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5246 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5247 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005248 signal(SIGPIPE, SIG_DFL);
5249 if (redir->type == NHERE)
5250 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005251 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005252 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005253 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005254 }
5255 out:
5256 close(pip[1]);
5257 return pip[0];
5258}
5259
5260static int
5261openredirect(union node *redir)
5262{
5263 char *fname;
5264 int f;
5265
5266 switch (redir->nfile.type) {
Denys Vlasenko557482c2016-09-25 21:24:04 +02005267/* Can't happen, our single caller does this itself */
5268// case NTOFD:
5269// case NFROMFD:
5270// return -1;
5271 case NHERE:
5272 case NXHERE:
5273 return openhere(redir);
5274 }
5275
5276 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5277 * allocated space. Do it only when we know it is safe.
5278 */
5279 fname = redir->nfile.expfname;
5280
5281 switch (redir->nfile.type) {
5282 default:
5283#if DEBUG
5284 abort();
5285#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005286 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005287 f = open(fname, O_RDONLY);
5288 if (f < 0)
5289 goto eopen;
5290 break;
5291 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005292 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005293 if (f < 0)
5294 goto ecreate;
5295 break;
5296 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005297#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005298 case NTO2:
5299#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005300 /* Take care of noclobber mode. */
5301 if (Cflag) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005302 f = noclobberopen(fname);
5303 if (f < 0)
5304 goto ecreate;
5305 break;
5306 }
5307 /* FALLTHROUGH */
5308 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005309 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5310 if (f < 0)
5311 goto ecreate;
5312 break;
5313 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005314 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5315 if (f < 0)
5316 goto ecreate;
5317 break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005318 }
5319
5320 return f;
5321 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005322 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005323 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005324 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005325}
5326
5327/*
Denys Vlasenko64774602016-10-26 15:24:30 +02005328 * Copy a file descriptor to be >= 10. Throws exception on error.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005329 */
5330static int
Denys Vlasenko64774602016-10-26 15:24:30 +02005331savefd(int from)
5332{
5333 int newfd;
5334 int err;
5335
5336 newfd = fcntl(from, F_DUPFD, 10);
5337 err = newfd < 0 ? errno : 0;
5338 if (err != EBADF) {
5339 if (err)
5340 ash_msg_and_raise_error("%d: %m", from);
5341 close(from);
5342 fcntl(newfd, F_SETFD, FD_CLOEXEC);
5343 }
5344
5345 return newfd;
5346}
5347static int
5348dup2_or_raise(int from, int to)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005349{
5350 int newfd;
5351
Denys Vlasenko64774602016-10-26 15:24:30 +02005352 newfd = (from != to) ? dup2(from, to) : to;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005353 if (newfd < 0) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005354 /* Happens when source fd is not open: try "echo >&99" */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005355 ash_msg_and_raise_error("%d: %m", from);
5356 }
5357 return newfd;
5358}
5359
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005360/* Struct def and variable are moved down to the first usage site */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005361struct two_fd_t {
5362 int orig, copy;
5363};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005364struct redirtab {
5365 struct redirtab *next;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005366 int pair_count;
Denys Vlasenko606291b2009-09-23 23:15:43 +02005367 struct two_fd_t two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005368};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005369#define redirlist (G_var.redirlist)
Denys Vlasenko64774602016-10-26 15:24:30 +02005370enum {
5371 COPYFD_RESTORE = (int)~(INT_MAX),
5372};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005373
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005374static int
5375need_to_remember(struct redirtab *rp, int fd)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005376{
5377 int i;
5378
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005379 if (!rp) /* remembering was not requested */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005380 return 0;
5381
5382 for (i = 0; i < rp->pair_count; i++) {
5383 if (rp->two_fd[i].orig == fd) {
5384 /* already remembered */
5385 return 0;
5386 }
5387 }
5388 return 1;
5389}
5390
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005391/* "hidden" fd is a fd used to read scripts, or a copy of such */
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005392static int
5393is_hidden_fd(struct redirtab *rp, int fd)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005394{
5395 int i;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005396 struct parsefile *pf;
5397
5398 if (fd == -1)
5399 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005400 /* Check open scripts' fds */
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005401 pf = g_parsefile;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005402 while (pf) {
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005403 /* We skip pf_fd == 0 case because of the following case:
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005404 * $ ash # running ash interactively
5405 * $ . ./script.sh
5406 * and in script.sh: "exec 9>&0".
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005407 * Even though top-level pf_fd _is_ 0,
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005408 * it's still ok to use it: "read" builtin uses it,
5409 * why should we cripple "exec" builtin?
5410 */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005411 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005412 return 1;
5413 }
5414 pf = pf->prev;
5415 }
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005416
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005417 if (!rp)
5418 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005419 /* Check saved fds of redirects */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005420 fd |= COPYFD_RESTORE;
5421 for (i = 0; i < rp->pair_count; i++) {
5422 if (rp->two_fd[i].copy == fd) {
5423 return 1;
5424 }
5425 }
5426 return 0;
5427}
5428
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005429/*
5430 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5431 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005432 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005433 */
5434/* flags passed to redirect */
5435#define REDIR_PUSH 01 /* save previous values of file descriptors */
5436#define REDIR_SAVEFD2 03 /* set preverrout */
5437static void
5438redirect(union node *redir, int flags)
5439{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005440 struct redirtab *sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005441 int sv_pos;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005442 int i;
5443 int fd;
5444 int newfd;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005445 int copied_fd2 = -1;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005446
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005447 if (!redir) {
5448 return;
5449 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005450
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005451 sv = NULL;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005452 sv_pos = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005453 INT_OFF;
5454 if (flags & REDIR_PUSH) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005455 union node *tmp = redir;
5456 do {
5457 sv_pos++;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005458#if BASH_REDIR_OUTPUT
Chris Metcalfc3c1fb62010-01-08 13:18:06 +01005459 if (tmp->nfile.type == NTO2)
Denis Vlasenko559691a2008-10-05 18:39:31 +00005460 sv_pos++;
5461#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005462 tmp = tmp->nfile.next;
5463 } while (tmp);
5464 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005465 sv->next = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005466 sv->pair_count = sv_pos;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005467 redirlist = sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005468 while (sv_pos > 0) {
5469 sv_pos--;
5470 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5471 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005472 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005473
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005474 do {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005475 int right_fd = -1;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005476 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005477 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005478 right_fd = redir->ndup.dupfd;
5479 //bb_error_msg("doing %d > %d", fd, right_fd);
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005480 /* redirect from/to same file descriptor? */
5481 if (right_fd == fd)
5482 continue;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005483 /* "echo >&10" and 10 is a fd opened to a sh script? */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005484 if (is_hidden_fd(sv, right_fd)) {
5485 errno = EBADF; /* as if it is closed */
5486 ash_msg_and_raise_error("%d: %m", right_fd);
5487 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005488 newfd = -1;
5489 } else {
5490 newfd = openredirect(redir); /* always >= 0 */
5491 if (fd == newfd) {
5492 /* Descriptor wasn't open before redirect.
5493 * Mark it for close in the future */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005494 if (need_to_remember(sv, fd)) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005495 goto remember_to_close;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005496 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005497 continue;
5498 }
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005499 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005500#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005501 redirect_more:
5502#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005503 if (need_to_remember(sv, fd)) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005504 /* Copy old descriptor */
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005505 /* Careful to not accidentally "save"
5506 * to the same fd as right side fd in N>&M */
5507 int minfd = right_fd < 10 ? 10 : right_fd + 1;
Denys Vlasenko86584e12017-01-07 10:15:01 +01005508#if defined(F_DUPFD_CLOEXEC)
5509 i = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
5510#else
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005511 i = fcntl(fd, F_DUPFD, minfd);
Denys Vlasenko86584e12017-01-07 10:15:01 +01005512#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005513 if (i == -1) {
5514 i = errno;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005515 if (i != EBADF) {
5516 /* Strange error (e.g. "too many files" EMFILE?) */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005517 if (newfd >= 0)
5518 close(newfd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005519 errno = i;
5520 ash_msg_and_raise_error("%d: %m", fd);
5521 /* NOTREACHED */
5522 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005523 /* EBADF: it is not open - good, remember to close it */
5524 remember_to_close:
5525 i = CLOSED;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005526 } else { /* fd is open, save its copy */
Denys Vlasenko86584e12017-01-07 10:15:01 +01005527#if !defined(F_DUPFD_CLOEXEC)
5528 fcntl(i, F_SETFD, FD_CLOEXEC);
5529#endif
Denis Vlasenko22f74142008-07-24 22:34:43 +00005530 /* "exec fd>&-" should not close fds
5531 * which point to script file(s).
5532 * Force them to be restored afterwards */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005533 if (is_hidden_fd(sv, fd))
5534 i |= COPYFD_RESTORE;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005535 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005536 if (fd == 2)
5537 copied_fd2 = i;
5538 sv->two_fd[sv_pos].orig = fd;
5539 sv->two_fd[sv_pos].copy = i;
5540 sv_pos++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005541 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005542 if (newfd < 0) {
5543 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005544 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005545 /* Don't want to trigger debugging */
5546 if (fd != -1)
5547 close(fd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005548 } else {
Denys Vlasenko64774602016-10-26 15:24:30 +02005549 dup2_or_raise(redir->ndup.dupfd, fd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005550 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005551 } else if (fd != newfd) { /* move newfd to fd */
Denys Vlasenko64774602016-10-26 15:24:30 +02005552 dup2_or_raise(newfd, fd);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005553#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005554 if (!(redir->nfile.type == NTO2 && fd == 2))
5555#endif
5556 close(newfd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005557 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005558#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005559 if (redir->nfile.type == NTO2 && fd == 1) {
5560 /* We already redirected it to fd 1, now copy it to 2 */
5561 newfd = 1;
5562 fd = 2;
5563 goto redirect_more;
5564 }
5565#endif
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005566 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005567
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005568 INT_ON;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005569 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5570 preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005571}
5572
5573/*
5574 * Undo the effects of the last redirection.
5575 */
5576static void
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005577popredir(int drop, int restore)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005578{
5579 struct redirtab *rp;
5580 int i;
5581
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02005582 if (redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005583 return;
5584 INT_OFF;
5585 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005586 for (i = 0; i < rp->pair_count; i++) {
5587 int fd = rp->two_fd[i].orig;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005588 int copy = rp->two_fd[i].copy;
5589 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005590 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005591 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005592 continue;
5593 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005594 if (copy != EMPTY) {
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005595 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
Denis Vlasenko22f74142008-07-24 22:34:43 +00005596 copy &= ~COPYFD_RESTORE;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005597 /*close(fd);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02005598 dup2_or_raise(copy, fd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005599 }
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005600 close(copy & ~COPYFD_RESTORE);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005601 }
5602 }
5603 redirlist = rp->next;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005604 free(rp);
5605 INT_ON;
5606}
5607
5608/*
5609 * Undo all redirections. Called on error or interrupt.
5610 */
5611
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005612static int
5613redirectsafe(union node *redir, int flags)
5614{
5615 int err;
5616 volatile int saveint;
5617 struct jmploc *volatile savehandler = exception_handler;
5618 struct jmploc jmploc;
5619
5620 SAVE_INT(saveint);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005621 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5622 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005623 if (!err) {
5624 exception_handler = &jmploc;
5625 redirect(redir, flags);
5626 }
5627 exception_handler = savehandler;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00005628 if (err && exception_type != EXERROR)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005629 longjmp(exception_handler->loc, 1);
5630 RESTORE_INT(saveint);
5631 return err;
5632}
5633
5634
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005635/* ============ Routines to expand arguments to commands
5636 *
5637 * We have to deal with backquotes, shell variables, and file metacharacters.
5638 */
5639
Denys Vlasenko0b883582016-12-23 16:49:07 +01005640#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005641static arith_t
5642ash_arith(const char *s)
5643{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005644 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005645 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005646
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005647 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005648 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005649 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005650
5651 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005652 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005653 if (math_state.errmsg)
5654 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005655 INT_ON;
5656
5657 return result;
5658}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005659#endif
5660
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005661/*
5662 * expandarg flags
5663 */
5664#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5665#define EXP_TILDE 0x2 /* do normal tilde expansion */
5666#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5667#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
Denys Vlasenkodb74c6c2016-10-24 21:12:33 +02005668/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5669 * POSIX says for this case:
5670 * Pathname expansion shall not be performed on the word by a
5671 * non-interactive shell; an interactive shell may perform it, but shall
5672 * do so only when the expansion would result in one word.
5673 * Currently, our code complies to the above rule by never globbing
5674 * redirection filenames.
5675 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5676 * (this means that on a typical Linux distro, bash almost always
5677 * performs globbing, and thus diverges from what we do).
5678 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005679#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Ron Yorston549deab2015-05-18 09:57:51 +02005680#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005681#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5682#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005683#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005684/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005685 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005686 */
5687#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5688#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005689#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5690#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Ron Yorston417622c2015-05-18 09:59:14 +02005691#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005692
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005693/* Add CTLESC when necessary. */
Ron Yorston549deab2015-05-18 09:57:51 +02005694#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005695/* Do not skip NUL characters. */
5696#define QUOTES_KEEPNUL EXP_TILDE
5697
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005698/*
5699 * Structure specifying which parts of the string should be searched
5700 * for IFS characters.
5701 */
5702struct ifsregion {
5703 struct ifsregion *next; /* next region in list */
5704 int begoff; /* offset of start of region */
5705 int endoff; /* offset of end of region */
5706 int nulonly; /* search for nul bytes only */
5707};
5708
5709struct arglist {
5710 struct strlist *list;
5711 struct strlist **lastp;
5712};
5713
5714/* output of current string */
5715static char *expdest;
5716/* list of back quote expressions */
5717static struct nodelist *argbackq;
5718/* first struct in list of ifs regions */
5719static struct ifsregion ifsfirst;
5720/* last struct in list */
5721static struct ifsregion *ifslastp;
5722/* holds expanded arg list */
5723static struct arglist exparg;
5724
5725/*
5726 * Our own itoa().
5727 */
Denys Vlasenko0b883582016-12-23 16:49:07 +01005728#if !ENABLE_FEATURE_SH_MATH
Denys Vlasenko26777aa2010-11-22 23:49:10 +01005729/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5730typedef long arith_t;
5731# define ARITH_FMT "%ld"
5732#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005733static int
5734cvtnum(arith_t num)
5735{
5736 int len;
5737
Denys Vlasenko9c541002015-10-07 15:44:36 +02005738 expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest);
5739 len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005740 STADJUST(len, expdest);
5741 return len;
5742}
5743
Denys Vlasenko455e4222016-10-27 14:45:13 +02005744/*
5745 * Break the argument string into pieces based upon IFS and add the
5746 * strings to the argument list. The regions of the string to be
5747 * searched for IFS characters have been stored by recordregion.
5748 */
5749static void
5750ifsbreakup(char *string, struct arglist *arglist)
5751{
5752 struct ifsregion *ifsp;
5753 struct strlist *sp;
5754 char *start;
5755 char *p;
5756 char *q;
5757 const char *ifs, *realifs;
5758 int ifsspc;
5759 int nulonly;
5760
5761 start = string;
5762 if (ifslastp != NULL) {
5763 ifsspc = 0;
5764 nulonly = 0;
5765 realifs = ifsset() ? ifsval() : defifs;
5766 ifsp = &ifsfirst;
5767 do {
5768 p = string + ifsp->begoff;
5769 nulonly = ifsp->nulonly;
5770 ifs = nulonly ? nullstr : realifs;
5771 ifsspc = 0;
5772 while (p < string + ifsp->endoff) {
5773 q = p;
5774 if ((unsigned char)*p == CTLESC)
5775 p++;
5776 if (!strchr(ifs, *p)) {
5777 p++;
5778 continue;
5779 }
5780 if (!nulonly)
5781 ifsspc = (strchr(defifs, *p) != NULL);
5782 /* Ignore IFS whitespace at start */
5783 if (q == start && ifsspc) {
5784 p++;
5785 start = p;
5786 continue;
5787 }
5788 *q = '\0';
5789 sp = stzalloc(sizeof(*sp));
5790 sp->text = start;
5791 *arglist->lastp = sp;
5792 arglist->lastp = &sp->next;
5793 p++;
5794 if (!nulonly) {
5795 for (;;) {
5796 if (p >= string + ifsp->endoff) {
5797 break;
5798 }
5799 q = p;
5800 if ((unsigned char)*p == CTLESC)
5801 p++;
5802 if (strchr(ifs, *p) == NULL) {
5803 p = q;
5804 break;
5805 }
5806 if (strchr(defifs, *p) == NULL) {
5807 if (ifsspc) {
5808 p++;
5809 ifsspc = 0;
5810 } else {
5811 p = q;
5812 break;
5813 }
5814 } else
5815 p++;
5816 }
5817 }
5818 start = p;
5819 } /* while */
5820 ifsp = ifsp->next;
5821 } while (ifsp != NULL);
5822 if (nulonly)
5823 goto add;
5824 }
5825
5826 if (!*start)
5827 return;
5828
5829 add:
5830 sp = stzalloc(sizeof(*sp));
5831 sp->text = start;
5832 *arglist->lastp = sp;
5833 arglist->lastp = &sp->next;
5834}
5835
5836static void
5837ifsfree(void)
5838{
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005839 struct ifsregion *p = ifsfirst.next;
5840
5841 if (!p)
5842 goto out;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005843
5844 INT_OFF;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005845 do {
5846 struct ifsregion *ifsp;
5847 ifsp = p->next;
5848 free(p);
5849 p = ifsp;
5850 } while (p);
Denys Vlasenko455e4222016-10-27 14:45:13 +02005851 ifsfirst.next = NULL;
5852 INT_ON;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005853 out:
5854 ifslastp = NULL;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005855}
5856
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005857static size_t
5858esclen(const char *start, const char *p)
5859{
5860 size_t esc = 0;
5861
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005862 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005863 esc++;
5864 }
5865 return esc;
5866}
5867
5868/*
5869 * Remove any CTLESC characters from a string.
5870 */
5871static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005872rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005873{
Ron Yorston417622c2015-05-18 09:59:14 +02005874 static const char qchars[] ALIGN1 = {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005875 IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005876
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005877 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005878 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005879 unsigned protect_against_glob;
5880 unsigned globbing;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005881 IF_BASH_PATTERN_SUBST(unsigned slash = flag & RMESCAPE_SLASH;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005882
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005883 p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005884 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005885 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005886
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005887 q = p;
5888 r = str;
5889 if (flag & RMESCAPE_ALLOC) {
5890 size_t len = p - str;
5891 size_t fulllen = len + strlen(p) + 1;
5892
5893 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005894 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005895 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005896 /* p and str may be invalidated by makestrspace */
5897 str = (char *)stackblock() + strloc;
5898 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005899 } else if (flag & RMESCAPE_HEAP) {
5900 r = ckmalloc(fulllen);
5901 } else {
5902 r = stalloc(fulllen);
5903 }
5904 q = r;
5905 if (len > 0) {
Denis Vlasenko29eb3592008-05-18 14:06:08 +00005906 q = (char *)memcpy(q, str, len) + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005907 }
5908 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005909
Ron Yorston549deab2015-05-18 09:57:51 +02005910 inquotes = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005911 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005912 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005913 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005914 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005915// Note: both inquotes and protect_against_glob only affect whether
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02005916// CTLESC,<ch> gets converted to <ch> or to \<ch>
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005917 inquotes = ~inquotes;
5918 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005919 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005920 continue;
5921 }
Ron Yorston549deab2015-05-18 09:57:51 +02005922 if ((unsigned char)*p == CTLESC) {
5923 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02005924#if DEBUG
5925 if (*p == '\0')
5926 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
5927#endif
Ron Yorston549deab2015-05-18 09:57:51 +02005928 if (protect_against_glob) {
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02005929 /*
5930 * We used to trust glob() and fnmatch() to eat
5931 * superfluous escapes (\z where z has no
5932 * special meaning anyway). But this causes
5933 * bugs such as string of one greek letter rho
Denys Vlasenkoed79a632017-07-05 19:20:43 +02005934 * (unicode-encoded as two bytes "cf,81")
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02005935 * getting encoded as "cf,CTLESC,81"
5936 * and here, converted to "cf,\,81" -
5937 * which does not go well with some flavors
Denys Vlasenko92b8d9c2017-07-05 19:13:44 +02005938 * of fnmatch() in unicode locales
5939 * (for example, glibc <= 2.22).
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02005940 *
5941 * Lets add "\" only on the chars which need it.
Denys Vlasenko4142f012017-07-05 22:19:28 +02005942 * Testcases for less obvious chars are shown.
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02005943 */
5944 if (*p == '*'
5945 || *p == '?'
5946 || *p == '['
Denys Vlasenko4142f012017-07-05 22:19:28 +02005947 || *p == '\\' /* case '\' in \\ ) echo ok;; *) echo WRONG;; esac */
5948 || *p == ']' /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */
5949 || *p == '-' /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */
5950 || *p == '!' /* case '!' in [\!] ) echo ok;; *) echo WRONG;; esac */
5951 /* Some libc support [^negate], that's why "^" also needs love */
5952 || *p == '^' /* case '^' in [\^] ) echo ok;; *) echo WRONG;; esac */
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02005953 ) {
5954 *q++ = '\\';
5955 }
Ron Yorston549deab2015-05-18 09:57:51 +02005956 }
5957 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005958 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005959 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005960 goto copy;
5961 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005962#if BASH_PATTERN_SUBST
Ron Yorston417622c2015-05-18 09:59:14 +02005963 else if (*p == '/' && slash) {
5964 /* stop handling globbing and mark location of slash */
5965 globbing = slash = 0;
5966 *p = CTLESC;
5967 }
5968#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005969 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005970 copy:
5971 *q++ = *p++;
5972 }
5973 *q = '\0';
5974 if (flag & RMESCAPE_GROW) {
5975 expdest = r;
5976 STADJUST(q - r + 1, expdest);
5977 }
5978 return r;
5979}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005980#define pmatch(a, b) !fnmatch((a), (b), 0)
5981
5982/*
5983 * Prepare a pattern for a expmeta (internal glob(3)) call.
5984 *
5985 * Returns an stalloced string.
5986 */
5987static char *
Ron Yorston549deab2015-05-18 09:57:51 +02005988preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005989{
Ron Yorston549deab2015-05-18 09:57:51 +02005990 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005991}
5992
5993/*
5994 * Put a string on the stack.
5995 */
5996static void
5997memtodest(const char *p, size_t len, int syntax, int quotes)
5998{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005999 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006000
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006001 if (!len)
6002 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006003
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006004 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
6005
6006 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006007 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006008 if (c) {
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01006009 if (quotes & QUOTES_ESC) {
6010 int n = SIT(c, syntax);
6011 if (n == CCTL
6012 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
6013 && n == CBACK
6014 )
6015 ) {
6016 USTPUTC(CTLESC, q);
6017 }
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006018 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006019 } else if (!(quotes & QUOTES_KEEPNUL))
6020 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006021 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006022 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006023
6024 expdest = q;
6025}
6026
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006027static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006028strtodest(const char *p, int syntax, int quotes)
6029{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006030 size_t len = strlen(p);
6031 memtodest(p, len, syntax, quotes);
6032 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006033}
6034
6035/*
6036 * Record the fact that we have to scan this region of the
6037 * string for IFS characters.
6038 */
6039static void
6040recordregion(int start, int end, int nulonly)
6041{
6042 struct ifsregion *ifsp;
6043
6044 if (ifslastp == NULL) {
6045 ifsp = &ifsfirst;
6046 } else {
6047 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00006048 ifsp = ckzalloc(sizeof(*ifsp));
6049 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006050 ifslastp->next = ifsp;
6051 INT_ON;
6052 }
6053 ifslastp = ifsp;
6054 ifslastp->begoff = start;
6055 ifslastp->endoff = end;
6056 ifslastp->nulonly = nulonly;
6057}
6058
6059static void
6060removerecordregions(int endoff)
6061{
6062 if (ifslastp == NULL)
6063 return;
6064
6065 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006066 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006067 struct ifsregion *ifsp;
6068 INT_OFF;
6069 ifsp = ifsfirst.next->next;
6070 free(ifsfirst.next);
6071 ifsfirst.next = ifsp;
6072 INT_ON;
6073 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006074 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006075 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006076 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006077 ifslastp = &ifsfirst;
6078 ifsfirst.endoff = endoff;
6079 }
6080 return;
6081 }
6082
6083 ifslastp = &ifsfirst;
6084 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006085 ifslastp = ifslastp->next;
6086 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006087 struct ifsregion *ifsp;
6088 INT_OFF;
6089 ifsp = ifslastp->next->next;
6090 free(ifslastp->next);
6091 ifslastp->next = ifsp;
6092 INT_ON;
6093 }
6094 if (ifslastp->endoff > endoff)
6095 ifslastp->endoff = endoff;
6096}
6097
6098static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006099exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006100{
Denys Vlasenkocd716832009-11-28 22:14:02 +01006101 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006102 char *name;
6103 struct passwd *pw;
6104 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006105 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006106
6107 name = p + 1;
6108
6109 while ((c = *++p) != '\0') {
6110 switch (c) {
6111 case CTLESC:
6112 return startp;
6113 case CTLQUOTEMARK:
6114 return startp;
6115 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006116 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006117 goto done;
6118 break;
6119 case '/':
6120 case CTLENDVAR:
6121 goto done;
6122 }
6123 }
6124 done:
6125 *p = '\0';
6126 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02006127 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006128 } else {
6129 pw = getpwnam(name);
6130 if (pw == NULL)
6131 goto lose;
6132 home = pw->pw_dir;
6133 }
6134 if (!home || !*home)
6135 goto lose;
6136 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006137 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006138 return p;
6139 lose:
6140 *p = c;
6141 return startp;
6142}
6143
6144/*
6145 * Execute a command inside back quotes. If it's a builtin command, we
6146 * want to save its output in a block obtained from malloc. Otherwise
6147 * we fork off a subprocess and get the output of the command via a pipe.
6148 * Should be called with interrupts off.
6149 */
6150struct backcmd { /* result of evalbackcmd */
6151 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006152 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00006153 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006154 struct job *jp; /* job structure for command */
6155};
6156
6157/* These forward decls are needed to use "eval" code for backticks handling: */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006158#define EV_EXIT 01 /* exit after evaluating tree */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02006159static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006160
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02006161static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006162evalbackcmd(union node *n, struct backcmd *result)
6163{
Denys Vlasenko579ad102016-10-25 21:10:20 +02006164 int pip[2];
6165 struct job *jp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006166
6167 result->fd = -1;
6168 result->buf = NULL;
6169 result->nleft = 0;
6170 result->jp = NULL;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006171 if (n == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006172 goto out;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006173 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006174
Denys Vlasenko579ad102016-10-25 21:10:20 +02006175 if (pipe(pip) < 0)
6176 ash_msg_and_raise_error("pipe call failed");
6177 jp = makejob(/*n,*/ 1);
6178 if (forkshell(jp, n, FORK_NOJOB) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02006179 /* child */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006180 FORCE_INT_ON;
6181 close(pip[0]);
6182 if (pip[1] != 1) {
6183 /*close(1);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02006184 dup2_or_raise(pip[1], 1);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006185 close(pip[1]);
6186 }
Denys Vlasenko960ca382016-10-25 18:12:15 +02006187/* TODO: eflag clearing makes the following not abort:
6188 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6189 * which is what bash does (unless it is in POSIX mode).
6190 * dash deleted "eflag = 0" line in the commit
6191 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6192 * [EVAL] Don't clear eflag in evalbackcmd
6193 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6194 */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006195 eflag = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006196 ifsfree();
Denys Vlasenko579ad102016-10-25 21:10:20 +02006197 evaltree(n, EV_EXIT); /* actually evaltreenr... */
6198 /* NOTREACHED */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006199 }
Denys Vlasenko70392332016-10-27 02:31:55 +02006200 /* parent */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006201 close(pip[1]);
6202 result->fd = pip[0];
6203 result->jp = jp;
6204
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006205 out:
6206 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6207 result->fd, result->buf, result->nleft, result->jp));
6208}
6209
6210/*
6211 * Expand stuff in backwards quotes.
6212 */
6213static void
Ron Yorston549deab2015-05-18 09:57:51 +02006214expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006215{
6216 struct backcmd in;
6217 int i;
6218 char buf[128];
6219 char *p;
6220 char *dest;
6221 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02006222 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006223 struct stackmark smark;
6224
6225 INT_OFF;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02006226 startloc = expdest - (char *)stackblock();
6227 pushstackmark(&smark, startloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006228 evalbackcmd(cmd, &in);
6229 popstackmark(&smark);
6230
6231 p = in.buf;
6232 i = in.nleft;
6233 if (i == 0)
6234 goto read;
6235 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02006236 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006237 read:
6238 if (in.fd < 0)
6239 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01006240 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006241 TRACE(("expbackq: read returns %d\n", i));
6242 if (i <= 0)
6243 break;
6244 p = buf;
6245 }
6246
Denis Vlasenko60818682007-09-28 22:07:23 +00006247 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006248 if (in.fd >= 0) {
6249 close(in.fd);
6250 back_exitstatus = waitforjob(in.jp);
6251 }
6252 INT_ON;
6253
6254 /* Eat all trailing newlines */
6255 dest = expdest;
6256 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6257 STUNPUTC(dest);
6258 expdest = dest;
6259
Ron Yorston549deab2015-05-18 09:57:51 +02006260 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006261 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006262 TRACE(("evalbackq: size:%d:'%.*s'\n",
6263 (int)((dest - (char *)stackblock()) - startloc),
6264 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006265 stackblock() + startloc));
6266}
6267
Denys Vlasenko0b883582016-12-23 16:49:07 +01006268#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006269/*
6270 * Expand arithmetic expression. Backup to start of expression,
6271 * evaluate, place result in (backed up) result, adjust string position.
6272 */
6273static void
Ron Yorston549deab2015-05-18 09:57:51 +02006274expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006275{
6276 char *p, *start;
6277 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006278 int len;
6279
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006280 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006281
6282 /*
6283 * This routine is slightly over-complicated for
6284 * efficiency. Next we scan backwards looking for the
6285 * start of arithmetic.
6286 */
6287 start = stackblock();
6288 p = expdest - 1;
6289 *p = '\0';
6290 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006291 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006292 int esc;
6293
Denys Vlasenkocd716832009-11-28 22:14:02 +01006294 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006295 p--;
6296#if DEBUG
6297 if (p < start) {
6298 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6299 }
6300#endif
6301 }
6302
6303 esc = esclen(start, p);
6304 if (!(esc % 2)) {
6305 break;
6306 }
6307
6308 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006309 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006310
6311 begoff = p - start;
6312
6313 removerecordregions(begoff);
6314
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006315 expdest = p;
6316
Ron Yorston549deab2015-05-18 09:57:51 +02006317 if (flag & QUOTES_ESC)
6318 rmescapes(p + 1, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006319
Ron Yorston549deab2015-05-18 09:57:51 +02006320 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006321
Ron Yorston549deab2015-05-18 09:57:51 +02006322 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006323 recordregion(begoff, begoff + len, 0);
6324}
6325#endif
6326
6327/* argstr needs it */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006328static char *evalvar(char *p, int flags, struct strlist *var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006329
6330/*
6331 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6332 * characters to allow for further processing. Otherwise treat
6333 * $@ like $* since no splitting will be performed.
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006334 *
6335 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
Denys Vlasenko10ad6222017-04-17 16:13:32 +02006336 * over shell variables. Needed for "A=a B=$A; echo $B" case - we use it
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006337 * for correct expansion of "B=$A" word.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006338 */
6339static void
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006340argstr(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006341{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006342 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006343 '=',
6344 ':',
6345 CTLQUOTEMARK,
6346 CTLENDVAR,
6347 CTLESC,
6348 CTLVAR,
6349 CTLBACKQ,
Denys Vlasenko0b883582016-12-23 16:49:07 +01006350#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006351 CTLENDARI,
6352#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006353 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006354 };
6355 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006356 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006357 int inquotes;
6358 size_t length;
6359 int startloc;
6360
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006361 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006362 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006363 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006364 reject++;
6365 }
6366 inquotes = 0;
6367 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006368 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006369 char *q;
6370
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006371 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006372 tilde:
6373 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006374 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006375 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006376 }
6377 start:
6378 startloc = expdest - (char *)stackblock();
6379 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006380 unsigned char c;
6381
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006382 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006383 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006384 if (c) {
6385 if (!(c & 0x80)
Denys Vlasenko0b883582016-12-23 16:49:07 +01006386 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006387 ) {
6388 /* c == '=' || c == ':' || c == CTLENDARI */
6389 length++;
6390 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006391 }
6392 if (length > 0) {
6393 int newloc;
6394 expdest = stack_nputstr(p, length, expdest);
6395 newloc = expdest - (char *)stackblock();
6396 if (breakall && !inquotes && newloc > startloc) {
6397 recordregion(startloc, newloc, 0);
6398 }
6399 startloc = newloc;
6400 }
6401 p += length + 1;
6402 length = 0;
6403
6404 switch (c) {
6405 case '\0':
6406 goto breakloop;
6407 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006408 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006409 p--;
6410 continue;
6411 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006412 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006413 reject++;
6414 /* fall through */
6415 case ':':
6416 /*
6417 * sort of a hack - expand tildes in variable
6418 * assignments (after the first '=' and after ':'s).
6419 */
6420 if (*--p == '~') {
6421 goto tilde;
6422 }
6423 continue;
6424 }
6425
6426 switch (c) {
6427 case CTLENDVAR: /* ??? */
6428 goto breakloop;
6429 case CTLQUOTEMARK:
Ron Yorston549deab2015-05-18 09:57:51 +02006430 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006431 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006432 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6433 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006434 goto start;
6435 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006436 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006437 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006438 p--;
6439 length++;
6440 startloc++;
6441 }
6442 break;
6443 case CTLESC:
6444 startloc++;
6445 length++;
Ron Yorston549deab2015-05-18 09:57:51 +02006446
6447 /*
6448 * Quoted parameter expansion pattern: remove quote
6449 * unless inside inner quotes or we have a literal
6450 * backslash.
6451 */
6452 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6453 EXP_QPAT && *p != '\\')
6454 break;
6455
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006456 goto addquote;
6457 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006458 TRACE(("argstr: evalvar('%s')\n", p));
Ron Yorston549deab2015-05-18 09:57:51 +02006459 p = evalvar(p, flags | inquotes, var_str_list);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006460 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006461 goto start;
6462 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006463 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006464 argbackq = argbackq->next;
6465 goto start;
Denys Vlasenko0b883582016-12-23 16:49:07 +01006466#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006467 case CTLENDARI:
6468 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006469 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006470 goto start;
6471#endif
6472 }
6473 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006474 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006475}
6476
6477static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006478scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6479 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006480{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006481 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006482 char c;
6483
6484 loc = startp;
6485 loc2 = rmesc;
6486 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006487 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006488 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006489
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006490 c = *loc2;
6491 if (zero) {
6492 *loc2 = '\0';
6493 s = rmesc;
6494 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006495 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006496
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006497 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006498 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006499 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006500 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006501 loc++;
6502 loc++;
6503 loc2++;
6504 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006505 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006506}
6507
6508static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006509scanright(char *startp, char *rmesc, char *rmescend,
6510 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006511{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006512#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6513 int try2optimize = match_at_start;
6514#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006515 int esc = 0;
6516 char *loc;
6517 char *loc2;
6518
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006519 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6520 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6521 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6522 * Logic:
6523 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6524 * and on each iteration they go back two/one char until they reach the beginning.
6525 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6526 */
6527 /* TODO: document in what other circumstances we are called. */
6528
6529 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006530 int match;
6531 char c = *loc2;
6532 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006533 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006534 *loc2 = '\0';
6535 s = rmesc;
6536 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006537 match = pmatch(pattern, s);
6538 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006539 *loc2 = c;
6540 if (match)
6541 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006542#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6543 if (try2optimize) {
6544 /* Maybe we can optimize this:
6545 * if pattern ends with unescaped *, we can avoid checking
Denys Vlasenko10ad6222017-04-17 16:13:32 +02006546 * shorter strings: if "foo*" doesn't match "raw_value_of_v",
6547 * it won't match truncated "raw_value_of_" strings too.
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006548 */
6549 unsigned plen = strlen(pattern);
6550 /* Does it end with "*"? */
6551 if (plen != 0 && pattern[--plen] == '*') {
6552 /* "xxxx*" is not escaped */
6553 /* "xxx\*" is escaped */
6554 /* "xx\\*" is not escaped */
6555 /* "x\\\*" is escaped */
6556 int slashes = 0;
6557 while (plen != 0 && pattern[--plen] == '\\')
6558 slashes++;
6559 if (!(slashes & 1))
6560 break; /* ends with unescaped "*" */
6561 }
6562 try2optimize = 0;
6563 }
6564#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006565 loc--;
6566 if (quotes) {
6567 if (--esc < 0) {
6568 esc = esclen(startp, loc);
6569 }
6570 if (esc % 2) {
6571 esc--;
6572 loc--;
6573 }
6574 }
6575 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006576 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006577}
6578
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006579static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006580static void
6581varunset(const char *end, const char *var, const char *umsg, int varflags)
6582{
6583 const char *msg;
6584 const char *tail;
6585
6586 tail = nullstr;
6587 msg = "parameter not set";
6588 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006589 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006590 if (varflags & VSNUL)
6591 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006592 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006593 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006594 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006595 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006596 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006597}
6598
6599static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006600subevalvar(char *p, char *varname, int strloc, int subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006601 int startloc, int varflags, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006602{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006603 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006604 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006605 char *startp;
6606 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006607 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006608 char *str;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006609 IF_BASH_SUBSTR(int pos, len, orig_len;)
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006610 int amount, resetloc;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006611 IF_BASH_PATTERN_SUBST(int workloc;)
6612 IF_BASH_PATTERN_SUBST(char *repl = NULL;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006613 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006614 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006615
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006616 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6617 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006618
Ron Yorstoneb6b48b2015-05-18 09:51:35 +02006619 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
Ron Yorston549deab2015-05-18 09:57:51 +02006620 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6621 var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006622 STPUTC('\0', expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006623 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006624 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006625
6626 switch (subtype) {
6627 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006628 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006629 amount = startp - expdest;
6630 STADJUST(amount, expdest);
6631 return startp;
6632
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006633 case VSQUESTION:
6634 varunset(p, varname, startp, varflags);
6635 /* NOTREACHED */
6636
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006637#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006638 case VSSUBSTR:
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +02006639//TODO: support more general format ${v:EXPR:EXPR},
6640// where EXPR follows $(()) rules
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006641 loc = str = stackblock() + strloc;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006642 /* Read POS in ${var:POS:LEN} */
6643 pos = atoi(loc); /* number(loc) errors out on "1:4" */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006644 len = str - startp - 1;
6645
6646 /* *loc != '\0', guaranteed by parser */
6647 if (quotes) {
6648 char *ptr;
6649
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006650 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006651 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006652 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006653 len--;
6654 ptr++;
6655 }
6656 }
6657 }
6658 orig_len = len;
6659
6660 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006661 /* ${var::LEN} */
6662 len = number(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006663 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006664 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006665 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006666 while (*loc && *loc != ':') {
6667 /* TODO?
6668 * bash complains on: var=qwe; echo ${var:1a:123}
6669 if (!isdigit(*loc))
6670 ash_msg_and_raise_error(msg_illnum, str);
6671 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006672 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006673 }
6674 if (*loc++ == ':') {
6675 len = number(loc);
6676 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006677 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006678 if (pos < 0) {
6679 /* ${VAR:$((-n)):l} starts n chars from the end */
6680 pos = orig_len + pos;
6681 }
6682 if ((unsigned)pos >= orig_len) {
6683 /* apart from obvious ${VAR:999999:l},
6684 * covers ${VAR:$((-9999999)):l} - result is ""
6685 * (bash-compat)
6686 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006687 pos = 0;
6688 len = 0;
6689 }
6690 if (len > (orig_len - pos))
6691 len = orig_len - pos;
6692
6693 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006694 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006695 str++;
6696 }
6697 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006698 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006699 *loc++ = *str++;
6700 *loc++ = *str++;
6701 }
6702 *loc = '\0';
6703 amount = loc - expdest;
6704 STADJUST(amount, expdest);
6705 return loc;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006706#endif /* BASH_SUBSTR */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006707 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006708
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006709 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006710
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006711#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006712 /* We'll comeback here if we grow the stack while handling
6713 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6714 * stack will need rebasing, and we'll need to remove our work
6715 * areas each time
6716 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006717 restart:
6718#endif
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006719
6720 amount = expdest - ((char *)stackblock() + resetloc);
6721 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006722 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006723
6724 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006725 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006726 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006727 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006728 if (rmesc != startp) {
6729 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006730 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006731 }
6732 }
6733 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006734 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02006735 /*
6736 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6737 * The result is a_\_z_c (not a\_\_z_c)!
6738 *
6739 * The search pattern and replace string treat backslashes differently!
6740 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6741 * and string. It's only used on the first call.
6742 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006743 preglob(str, IF_BASH_PATTERN_SUBST(
Ron Yorston417622c2015-05-18 09:59:14 +02006744 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006745 RMESCAPE_SLASH : ) 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006746
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006747#if BASH_PATTERN_SUBST
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006748 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006749 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006750 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006751
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006752 if (!repl) {
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006753 repl = strchr(str, CTLESC);
6754 if (repl)
Ron Yorston417622c2015-05-18 09:59:14 +02006755 *repl++ = '\0';
6756 else
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006757 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006758 }
Ron Yorston417622c2015-05-18 09:59:14 +02006759 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006760
6761 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006762 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006763 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006764
6765 len = 0;
6766 idx = startp;
6767 end = str - 1;
6768 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006769 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006770 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006771 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006772 if (!loc) {
6773 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006774 char *restart_detect = stackblock();
6775 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006776 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006777 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006778 idx++;
6779 len++;
6780 STPUTC(*idx, expdest);
6781 }
6782 if (stackblock() != restart_detect)
6783 goto restart;
6784 idx++;
6785 len++;
6786 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006787 /* continue; - prone to quadratic behavior, smarter code: */
6788 if (idx >= end)
6789 break;
6790 if (str[0] == '*') {
6791 /* Pattern is "*foo". If "*foo" does not match "long_string",
6792 * it would never match "ong_string" etc, no point in trying.
6793 */
6794 goto skip_matching;
6795 }
6796 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006797 }
6798
6799 if (subtype == VSREPLACEALL) {
6800 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006801 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006802 idx++;
6803 idx++;
6804 rmesc++;
6805 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006806 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006807 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006808 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006809
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006810 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006811 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006812 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006813 if (quotes && *loc == '\\') {
6814 STPUTC(CTLESC, expdest);
6815 len++;
6816 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006817 STPUTC(*loc, expdest);
6818 if (stackblock() != restart_detect)
6819 goto restart;
6820 len++;
6821 }
6822
6823 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006824 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006825 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006826 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006827 STPUTC(*idx, expdest);
6828 if (stackblock() != restart_detect)
6829 goto restart;
6830 len++;
6831 idx++;
6832 }
6833 break;
6834 }
6835 }
6836
6837 /* We've put the replaced text into a buffer at workloc, now
6838 * move it to the right place and adjust the stack.
6839 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006840 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006841 startp = (char *)stackblock() + startloc;
6842 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006843 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006844 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006845 STADJUST(-amount, expdest);
6846 return startp;
6847 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006848#endif /* BASH_PATTERN_SUBST */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006849
6850 subtype -= VSTRIMRIGHT;
6851#if DEBUG
6852 if (subtype < 0 || subtype > 7)
6853 abort();
6854#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006855 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006856 zero = subtype >> 1;
6857 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6858 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6859
6860 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6861 if (loc) {
6862 if (zero) {
6863 memmove(startp, loc, str - loc);
6864 loc = startp + (str - loc) - 1;
6865 }
6866 *loc = '\0';
6867 amount = loc - expdest;
6868 STADJUST(amount, expdest);
6869 }
6870 return loc;
6871}
6872
6873/*
6874 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006875 * name parameter (examples):
6876 * ash -c 'echo $1' name:'1='
6877 * ash -c 'echo $qwe' name:'qwe='
6878 * ash -c 'echo $$' name:'$='
6879 * ash -c 'echo ${$}' name:'$='
6880 * ash -c 'echo ${$##q}' name:'$=q'
6881 * ash -c 'echo ${#$}' name:'$='
6882 * note: examples with bad shell syntax:
6883 * ash -c 'echo ${#$1}' name:'$=1'
6884 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006885 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02006886static NOINLINE ssize_t
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006887varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int *quotedp)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006888{
Mike Frysinger98c52642009-04-02 10:02:37 +00006889 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006890 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006891 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006892 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006893 int sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006894 int quoted = *quotedp;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006895 int subtype = varflags & VSTYPE;
6896 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6897 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006898 int syntax;
6899
6900 sep = (flags & EXP_FULL) << CHAR_BIT;
6901 syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006902
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006903 switch (*name) {
6904 case '$':
6905 num = rootpid;
6906 goto numvar;
6907 case '?':
6908 num = exitstatus;
6909 goto numvar;
6910 case '#':
6911 num = shellparam.nparam;
6912 goto numvar;
6913 case '!':
6914 num = backgndpid;
6915 if (num == 0)
6916 return -1;
6917 numvar:
6918 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006919 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006920 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00006921 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006922 for (i = NOPTS - 1; i >= 0; i--) {
6923 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00006924 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006925 len++;
6926 }
6927 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006928 check_1char_name:
6929#if 0
6930 /* handles cases similar to ${#$1} */
6931 if (name[2] != '\0')
6932 raise_error_syntax("bad substitution");
6933#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006934 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006935 case '@':
6936 if (quoted && sep)
6937 goto param;
6938 /* fall through */
6939 case '*': {
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006940 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006941 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006942
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006943 if (quoted)
6944 sep = 0;
6945 sep |= ifsset() ? ifsval()[0] : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006946 param:
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006947 sepc = sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006948 *quotedp = !sepc;
6949 ap = shellparam.p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006950 if (!ap)
6951 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006952 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006953 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006954
6955 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006956 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006957 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006958 }
6959 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006960 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006961 } /* case '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006962 case '0':
6963 case '1':
6964 case '2':
6965 case '3':
6966 case '4':
6967 case '5':
6968 case '6':
6969 case '7':
6970 case '8':
6971 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02006972 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006973 if (num < 0 || num > shellparam.nparam)
6974 return -1;
6975 p = num ? shellparam.p[num - 1] : arg0;
6976 goto value;
6977 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006978 /* NB: name has form "VAR=..." */
6979
6980 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6981 * which should be considered before we check variables. */
6982 if (var_str_list) {
6983 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6984 p = NULL;
6985 do {
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00006986 char *str, *eq;
6987 str = var_str_list->text;
6988 eq = strchr(str, '=');
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006989 if (!eq) /* stop at first non-assignment */
6990 break;
6991 eq++;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00006992 if (name_len == (unsigned)(eq - str)
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006993 && strncmp(str, name, name_len) == 0
6994 ) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006995 p = eq;
6996 /* goto value; - WRONG! */
6997 /* think "A=1 A=2 B=$A" */
6998 }
6999 var_str_list = var_str_list->next;
7000 } while (var_str_list);
7001 if (p)
7002 goto value;
7003 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007004 p = lookupvar(name);
7005 value:
7006 if (!p)
7007 return -1;
7008
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007009 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007010#if ENABLE_UNICODE_SUPPORT
7011 if (subtype == VSLENGTH && len > 0) {
7012 reinit_unicode_for_ash();
7013 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00007014 STADJUST(-len, expdest);
7015 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007016 len = unicode_strlen(p);
7017 }
7018 }
7019#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007020 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007021 }
7022
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007023 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007024 STADJUST(-len, expdest);
7025 return len;
7026}
7027
7028/*
7029 * Expand a variable, and return a pointer to the next character in the
7030 * input string.
7031 */
7032static char *
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007033evalvar(char *p, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007034{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007035 char varflags;
7036 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02007037 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007038 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007039 char *var;
7040 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007041 int startloc;
7042 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007043
Denys Vlasenkob0d63382009-09-16 16:18:32 +02007044 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007045 subtype = varflags & VSTYPE;
Denys Vlasenko88e15702016-10-26 01:55:56 +02007046
7047 if (!subtype)
7048 raise_error_syntax("bad substitution");
7049
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007050 quoted = flag & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007051 var = p;
7052 easy = (!quoted || (*var == '@' && shellparam.nparam));
7053 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02007054 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007055
7056 again:
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007057 varlen = varvalue(var, varflags, flag, var_str_list, &quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007058 if (varflags & VSNUL)
7059 varlen--;
7060
7061 if (subtype == VSPLUS) {
7062 varlen = -1 - varlen;
7063 goto vsplus;
7064 }
7065
7066 if (subtype == VSMINUS) {
7067 vsplus:
7068 if (varlen < 0) {
7069 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02007070 p,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007071 flag | EXP_TILDE | EXP_WORD,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007072 var_str_list
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007073 );
7074 goto end;
7075 }
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007076 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007077 }
7078
7079 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007080 if (varlen >= 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007081 goto record;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007082
7083 subevalvar(p, var, 0, subtype, startloc, varflags,
7084 flag & ~QUOTES_ESC, var_str_list);
7085 varflags &= ~VSNUL;
7086 /*
7087 * Remove any recorded regions beyond
7088 * start of variable
7089 */
7090 removerecordregions(startloc);
7091 goto again;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007092 }
7093
7094 if (varlen < 0 && uflag)
7095 varunset(p, var, 0, 0);
7096
7097 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007098 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007099 goto record;
7100 }
7101
7102 if (subtype == VSNORMAL) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007103 record:
7104 if (!easy)
7105 goto end;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007106 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007107 goto end;
7108 }
7109
7110#if DEBUG
7111 switch (subtype) {
7112 case VSTRIMLEFT:
7113 case VSTRIMLEFTMAX:
7114 case VSTRIMRIGHT:
7115 case VSTRIMRIGHTMAX:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007116#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007117 case VSSUBSTR:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007118#endif
7119#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007120 case VSREPLACE:
7121 case VSREPLACEALL:
7122#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007123 break;
7124 default:
7125 abort();
7126 }
7127#endif
7128
7129 if (varlen >= 0) {
7130 /*
7131 * Terminate the string and start recording the pattern
7132 * right after it
7133 */
7134 STPUTC('\0', expdest);
7135 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007136 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007137 startloc, varflags, flag, var_str_list)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007138 int amount = expdest - (
7139 (char *)stackblock() + patloc - 1
7140 );
7141 STADJUST(-amount, expdest);
7142 }
7143 /* Remove any recorded regions beyond start of variable */
7144 removerecordregions(startloc);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007145 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007146 }
7147
7148 end:
7149 if (subtype != VSNORMAL) { /* skip to end of alternative */
7150 int nesting = 1;
7151 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007152 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007153 if (c == CTLESC)
7154 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02007155 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007156 if (varlen >= 0)
7157 argbackq = argbackq->next;
7158 } else if (c == CTLVAR) {
7159 if ((*p++ & VSTYPE) != VSNORMAL)
7160 nesting++;
7161 } else if (c == CTLENDVAR) {
7162 if (--nesting == 0)
7163 break;
7164 }
7165 }
7166 }
7167 return p;
7168}
7169
7170/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007171 * Add a file name to the list.
7172 */
7173static void
7174addfname(const char *name)
7175{
7176 struct strlist *sp;
7177
Denis Vlasenko597906c2008-02-20 16:38:54 +00007178 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02007179 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007180 *exparg.lastp = sp;
7181 exparg.lastp = &sp->next;
7182}
7183
Felix Fietkaub5b21122017-01-31 21:58:55 +01007184/* Avoid glob() (and thus, stat() et al) for words like "echo" */
7185static int
7186hasmeta(const char *p)
7187{
7188 static const char chars[] ALIGN1 = {
7189 '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
7190 };
7191
7192 for (;;) {
7193 p = strpbrk(p, chars);
7194 if (!p)
7195 break;
7196 switch ((unsigned char) *p) {
7197 case CTLQUOTEMARK:
7198 for (;;) {
7199 p++;
7200 if (*p == CTLQUOTEMARK)
7201 break;
7202 if (*p == CTLESC)
7203 p++;
7204 if (*p == '\0') /* huh? */
7205 return 0;
7206 }
7207 break;
7208 case '\\':
7209 case CTLESC:
7210 p++;
7211 if (*p == '\0')
7212 return 0;
7213 break;
7214 case '[':
7215 if (!strchr(p + 1, ']')) {
7216 /* It's not a properly closed [] pattern,
7217 * but other metas may follow. Continue checking.
7218 * my[file* _is_ globbed by bash
7219 * and matches filenames like "my[file1".
7220 */
7221 break;
7222 }
7223 /* fallthrough */
7224 default:
7225 /* case '*': */
7226 /* case '?': */
7227 return 1;
7228 }
7229 p++;
7230 }
7231
7232 return 0;
7233}
7234
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007235/* If we want to use glob() from libc... */
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007236#if !ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007237
7238/* Add the result of glob() to the list */
7239static void
7240addglob(const glob_t *pglob)
7241{
7242 char **p = pglob->gl_pathv;
7243
7244 do {
7245 addfname(*p);
7246 } while (*++p);
7247}
7248static void
7249expandmeta(struct strlist *str /*, int flag*/)
7250{
7251 /* TODO - EXP_REDIR */
7252
7253 while (str) {
7254 char *p;
7255 glob_t pglob;
7256 int i;
7257
7258 if (fflag)
7259 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007260
Felix Fietkaub5b21122017-01-31 21:58:55 +01007261 if (!hasmeta(str->text))
7262 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007263
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007264 INT_OFF;
7265 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007266// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7267// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7268//
7269// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7270// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7271// Which means you need to unescape the string, right? Not so fast:
7272// if there _is_ a file named "file\?" (with backslash), it is returned
7273// as "file\?" too (whichever pattern you used to find it, say, "file*").
Denys Vlasenko10ad6222017-04-17 16:13:32 +02007274// You DON'T KNOW by looking at the result whether you need to unescape it.
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007275//
7276// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7277// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7278// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7279// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7280// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7281// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7282 i = glob(p, 0, NULL, &pglob);
7283 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007284 if (p != str->text)
7285 free(p);
7286 switch (i) {
7287 case 0:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007288#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007289 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7290 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7291 goto nometa2;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007292#endif
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007293 addglob(&pglob);
7294 globfree(&pglob);
7295 INT_ON;
7296 break;
7297 case GLOB_NOMATCH:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007298 //nometa2:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007299 globfree(&pglob);
7300 INT_ON;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007301 nometa:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007302 *exparg.lastp = str;
7303 rmescapes(str->text, 0);
7304 exparg.lastp = &str->next;
7305 break;
7306 default: /* GLOB_NOSPACE */
7307 globfree(&pglob);
7308 INT_ON;
7309 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7310 }
7311 str = str->next;
7312 }
7313}
7314
7315#else
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007316/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007317
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007318/*
7319 * Do metacharacter (i.e. *, ?, [...]) expansion.
7320 */
7321static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007322expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007323{
7324 char *p;
7325 const char *cp;
7326 char *start;
7327 char *endname;
7328 int metaflag;
7329 struct stat statb;
7330 DIR *dirp;
7331 struct dirent *dp;
7332 int atend;
7333 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007334 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007335
7336 metaflag = 0;
7337 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007338 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007339 if (*p == '*' || *p == '?')
7340 metaflag = 1;
7341 else if (*p == '[') {
7342 char *q = p + 1;
7343 if (*q == '!')
7344 q++;
7345 for (;;) {
7346 if (*q == '\\')
7347 q++;
7348 if (*q == '/' || *q == '\0')
7349 break;
7350 if (*++q == ']') {
7351 metaflag = 1;
7352 break;
7353 }
7354 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007355 } else {
7356 if (*p == '\\')
7357 esc++;
7358 if (p[esc] == '/') {
7359 if (metaflag)
7360 break;
7361 start = p + esc + 1;
7362 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007363 }
7364 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007365 if (metaflag == 0) { /* we've reached the end of the file name */
7366 if (enddir != expdir)
7367 metaflag++;
7368 p = name;
7369 do {
7370 if (*p == '\\')
7371 p++;
7372 *enddir++ = *p;
7373 } while (*p++);
7374 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7375 addfname(expdir);
7376 return;
7377 }
7378 endname = p;
7379 if (name < start) {
7380 p = name;
7381 do {
7382 if (*p == '\\')
7383 p++;
7384 *enddir++ = *p++;
7385 } while (p < start);
7386 }
7387 if (enddir == expdir) {
7388 cp = ".";
7389 } else if (enddir == expdir + 1 && *expdir == '/') {
7390 cp = "/";
7391 } else {
7392 cp = expdir;
7393 enddir[-1] = '\0';
7394 }
7395 dirp = opendir(cp);
7396 if (dirp == NULL)
7397 return;
7398 if (enddir != expdir)
7399 enddir[-1] = '/';
7400 if (*endname == 0) {
7401 atend = 1;
7402 } else {
7403 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007404 *endname = '\0';
7405 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007406 }
7407 matchdot = 0;
7408 p = start;
7409 if (*p == '\\')
7410 p++;
7411 if (*p == '.')
7412 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007413 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007414 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007415 continue;
7416 if (pmatch(start, dp->d_name)) {
7417 if (atend) {
7418 strcpy(enddir, dp->d_name);
7419 addfname(expdir);
7420 } else {
7421 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7422 continue;
7423 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007424 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007425 }
7426 }
7427 }
7428 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007429 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007430 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007431}
7432
7433static struct strlist *
7434msort(struct strlist *list, int len)
7435{
7436 struct strlist *p, *q = NULL;
7437 struct strlist **lpp;
7438 int half;
7439 int n;
7440
7441 if (len <= 1)
7442 return list;
7443 half = len >> 1;
7444 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007445 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007446 q = p;
7447 p = p->next;
7448 }
7449 q->next = NULL; /* terminate first half of list */
7450 q = msort(list, half); /* sort first half of list */
7451 p = msort(p, len - half); /* sort second half */
7452 lpp = &list;
7453 for (;;) {
7454#if ENABLE_LOCALE_SUPPORT
7455 if (strcoll(p->text, q->text) < 0)
7456#else
7457 if (strcmp(p->text, q->text) < 0)
7458#endif
7459 {
7460 *lpp = p;
7461 lpp = &p->next;
7462 p = *lpp;
7463 if (p == NULL) {
7464 *lpp = q;
7465 break;
7466 }
7467 } else {
7468 *lpp = q;
7469 lpp = &q->next;
7470 q = *lpp;
7471 if (q == NULL) {
7472 *lpp = p;
7473 break;
7474 }
7475 }
7476 }
7477 return list;
7478}
7479
7480/*
7481 * Sort the results of file name expansion. It calculates the number of
7482 * strings to sort and then calls msort (short for merge sort) to do the
7483 * work.
7484 */
7485static struct strlist *
7486expsort(struct strlist *str)
7487{
7488 int len;
7489 struct strlist *sp;
7490
7491 len = 0;
7492 for (sp = str; sp; sp = sp->next)
7493 len++;
7494 return msort(str, len);
7495}
7496
7497static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007498expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007499{
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007500 /* TODO - EXP_REDIR */
7501
7502 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007503 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007504 struct strlist **savelastp;
7505 struct strlist *sp;
7506 char *p;
7507
7508 if (fflag)
7509 goto nometa;
Felix Fietkaub5b21122017-01-31 21:58:55 +01007510 if (!hasmeta(str->text))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007511 goto nometa;
7512 savelastp = exparg.lastp;
7513
7514 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007515 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007516 {
7517 int i = strlen(str->text);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007518//BUGGY estimation of how long expanded name can be
7519 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007520 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007521 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007522 free(expdir);
7523 if (p != str->text)
7524 free(p);
7525 INT_ON;
7526 if (exparg.lastp == savelastp) {
7527 /*
7528 * no matches
7529 */
7530 nometa:
7531 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007532 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007533 exparg.lastp = &str->next;
7534 } else {
7535 *exparg.lastp = NULL;
7536 *savelastp = sp = expsort(*savelastp);
7537 while (sp->next != NULL)
7538 sp = sp->next;
7539 exparg.lastp = &sp->next;
7540 }
7541 str = str->next;
7542 }
7543}
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007544#endif /* ENABLE_ASH_INTERNAL_GLOB */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007545
7546/*
7547 * Perform variable substitution and command substitution on an argument,
7548 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7549 * perform splitting and file name expansion. When arglist is NULL, perform
7550 * here document expansion.
7551 */
7552static void
7553expandarg(union node *arg, struct arglist *arglist, int flag)
7554{
7555 struct strlist *sp;
7556 char *p;
7557
7558 argbackq = arg->narg.backquote;
7559 STARTSTACKSTR(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007560 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007561 argstr(arg->narg.text, flag,
7562 /* var_str_list: */ arglist ? arglist->list : NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007563 p = _STPUTC('\0', expdest);
7564 expdest = p - 1;
7565 if (arglist == NULL) {
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007566 /* here document expanded */
7567 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007568 }
7569 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007570 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007571 exparg.lastp = &exparg.list;
7572 /*
7573 * TODO - EXP_REDIR
7574 */
7575 if (flag & EXP_FULL) {
7576 ifsbreakup(p, &exparg);
7577 *exparg.lastp = NULL;
7578 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007579 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007580 } else {
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007581 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007582 rmescapes(p, 0);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007583 TRACE(("expandarg: rmescapes:'%s'\n", p));
7584 }
Denis Vlasenko597906c2008-02-20 16:38:54 +00007585 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007586 sp->text = p;
7587 *exparg.lastp = sp;
7588 exparg.lastp = &sp->next;
7589 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007590 *exparg.lastp = NULL;
7591 if (exparg.list) {
7592 *arglist->lastp = exparg.list;
7593 arglist->lastp = exparg.lastp;
7594 }
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007595
7596 out:
7597 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007598}
7599
7600/*
7601 * Expand shell variables and backquotes inside a here document.
7602 */
7603static void
7604expandhere(union node *arg, int fd)
7605{
Ron Yorston549deab2015-05-18 09:57:51 +02007606 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007607 full_write(fd, stackblock(), expdest - (char *)stackblock());
7608}
7609
7610/*
7611 * Returns true if the pattern matches the string.
7612 */
7613static int
7614patmatch(char *pattern, const char *string)
7615{
Denys Vlasenkobd43c672017-07-05 23:12:15 +02007616 char *p = preglob(pattern, 0);
7617 //bb_error_msg("fnmatch(pattern:'%s',str:'%s')", p, string);
7618 return pmatch(p, string);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007619}
7620
7621/*
7622 * See if a pattern matches in a case statement.
7623 */
7624static int
7625casematch(union node *pattern, char *val)
7626{
7627 struct stackmark smark;
7628 int result;
7629
7630 setstackmark(&smark);
7631 argbackq = pattern->narg.backquote;
7632 STARTSTACKSTR(expdest);
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007633 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7634 /* var_str_list: */ NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007635 STACKSTRNUL(expdest);
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007636 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007637 result = patmatch(stackblock(), val);
7638 popstackmark(&smark);
7639 return result;
7640}
7641
7642
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007643/* ============ find_command */
7644
7645struct builtincmd {
7646 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007647 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007648 /* unsigned flags; */
7649};
7650#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007651/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007652 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007653#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007654#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007655
7656struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007657 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007658 union param {
7659 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007660 /* index >= 0 for commands without path (slashes) */
7661 /* (TODO: what exactly does the value mean? PATH position?) */
7662 /* index == -1 for commands with slashes */
7663 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007664 const struct builtincmd *cmd;
7665 struct funcnode *func;
7666 } u;
7667};
7668/* values of cmdtype */
7669#define CMDUNKNOWN -1 /* no entry in table for command */
7670#define CMDNORMAL 0 /* command is an executable program */
7671#define CMDFUNCTION 1 /* command is a shell function */
7672#define CMDBUILTIN 2 /* command is a shell builtin */
7673
7674/* action to find_command() */
7675#define DO_ERR 0x01 /* prints errors */
7676#define DO_ABS 0x02 /* checks absolute paths */
7677#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7678#define DO_ALTPATH 0x08 /* using alternate path */
7679#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7680
7681static void find_command(char *, struct cmdentry *, int, const char *);
7682
7683
7684/* ============ Hashing commands */
7685
7686/*
7687 * When commands are first encountered, they are entered in a hash table.
7688 * This ensures that a full path search will not have to be done for them
7689 * on each invocation.
7690 *
7691 * We should investigate converting to a linear search, even though that
7692 * would make the command name "hash" a misnomer.
7693 */
7694
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007695struct tblentry {
7696 struct tblentry *next; /* next entry in hash chain */
7697 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007698 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007699 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007700 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007701};
7702
Denis Vlasenko01631112007-12-16 17:20:38 +00007703static struct tblentry **cmdtable;
7704#define INIT_G_cmdtable() do { \
7705 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7706} while (0)
7707
7708static int builtinloc = -1; /* index in path of %builtin, or -1 */
7709
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007710
7711static void
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007712tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007713{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007714#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007715 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007716 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007717 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007718 while (*envp)
7719 putenv(*envp++);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007720 run_applet_no_and_exit(applet_no, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007721 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007722 /* re-exec ourselves with the new arguments */
7723 execve(bb_busybox_exec_path, argv, envp);
7724 /* If they called chroot or otherwise made the binary no longer
7725 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007726 }
7727#endif
7728
7729 repeat:
7730#ifdef SYSV
7731 do {
7732 execve(cmd, argv, envp);
7733 } while (errno == EINTR);
7734#else
7735 execve(cmd, argv, envp);
7736#endif
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007737 if (cmd != (char*) bb_busybox_exec_path && errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007738 /* Run "cmd" as a shell script:
7739 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7740 * "If the execve() function fails with ENOEXEC, the shell
7741 * shall execute a command equivalent to having a shell invoked
7742 * with the command name as its first operand,
7743 * with any remaining arguments passed to the new shell"
7744 *
7745 * That is, do not use $SHELL, user's shell, or /bin/sh;
7746 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007747 *
7748 * Note that bash reads ~80 chars of the file, and if it sees
7749 * a zero byte before it sees newline, it doesn't try to
7750 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007751 * message and exit code 126. For one, this prevents attempts
7752 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007753 */
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007754 argv[0] = cmd;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007755 cmd = (char*) bb_busybox_exec_path;
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007756 /* NB: this is only possible because all callers of shellexec()
7757 * ensure that the argv[-1] slot exists!
7758 */
7759 argv--;
7760 argv[0] = (char*) "ash";
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007761 goto repeat;
7762 }
7763}
7764
7765/*
7766 * Exec a program. Never returns. If you change this routine, you may
7767 * have to change the find_command routine as well.
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007768 * argv[-1] must exist and be writable! See tryexec() for why.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007769 */
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007770static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN;
7771static void shellexec(char *prog, char **argv, const char *path, int idx)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007772{
7773 char *cmdname;
7774 int e;
7775 char **envp;
7776 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007777 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007778
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007779 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007780 if (strchr(prog, '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007781#if ENABLE_FEATURE_SH_STANDALONE
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007782 || (applet_no = find_applet_by_name(prog)) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007783#endif
7784 ) {
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007785 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007786 if (applet_no >= 0) {
7787 /* We tried execing ourself, but it didn't work.
7788 * Maybe /proc/self/exe doesn't exist?
7789 * Try $PATH search.
7790 */
7791 goto try_PATH;
7792 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007793 e = errno;
7794 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007795 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007796 e = ENOENT;
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007797 while ((cmdname = path_advance(&path, prog)) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007798 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007799 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007800 if (errno != ENOENT && errno != ENOTDIR)
7801 e = errno;
7802 }
7803 stunalloc(cmdname);
7804 }
7805 }
7806
7807 /* Map to POSIX errors */
7808 switch (e) {
7809 case EACCES:
7810 exerrno = 126;
7811 break;
7812 case ENOENT:
7813 exerrno = 127;
7814 break;
7815 default:
7816 exerrno = 2;
7817 break;
7818 }
7819 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007820 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007821 prog, e, suppress_int));
7822 ash_msg_and_raise(EXEXIT, "%s: %s", prog, errmsg(e, "not found"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007823 /* NOTREACHED */
7824}
7825
7826static void
7827printentry(struct tblentry *cmdp)
7828{
7829 int idx;
7830 const char *path;
7831 char *name;
7832
7833 idx = cmdp->param.index;
7834 path = pathval();
7835 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007836 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007837 stunalloc(name);
7838 } while (--idx >= 0);
7839 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7840}
7841
7842/*
7843 * Clear out command entries. The argument specifies the first entry in
7844 * PATH which has changed.
7845 */
7846static void
7847clearcmdentry(int firstchange)
7848{
7849 struct tblentry **tblp;
7850 struct tblentry **pp;
7851 struct tblentry *cmdp;
7852
7853 INT_OFF;
7854 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7855 pp = tblp;
7856 while ((cmdp = *pp) != NULL) {
7857 if ((cmdp->cmdtype == CMDNORMAL &&
7858 cmdp->param.index >= firstchange)
7859 || (cmdp->cmdtype == CMDBUILTIN &&
7860 builtinloc >= firstchange)
7861 ) {
7862 *pp = cmdp->next;
7863 free(cmdp);
7864 } else {
7865 pp = &cmdp->next;
7866 }
7867 }
7868 }
7869 INT_ON;
7870}
7871
7872/*
7873 * Locate a command in the command hash table. If "add" is nonzero,
7874 * add the command to the table if it is not already present. The
7875 * variable "lastcmdentry" is set to point to the address of the link
7876 * pointing to the entry, so that delete_cmd_entry can delete the
7877 * entry.
7878 *
7879 * Interrupts must be off if called with add != 0.
7880 */
7881static struct tblentry **lastcmdentry;
7882
7883static struct tblentry *
7884cmdlookup(const char *name, int add)
7885{
7886 unsigned int hashval;
7887 const char *p;
7888 struct tblentry *cmdp;
7889 struct tblentry **pp;
7890
7891 p = name;
7892 hashval = (unsigned char)*p << 4;
7893 while (*p)
7894 hashval += (unsigned char)*p++;
7895 hashval &= 0x7FFF;
7896 pp = &cmdtable[hashval % CMDTABLESIZE];
7897 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7898 if (strcmp(cmdp->cmdname, name) == 0)
7899 break;
7900 pp = &cmdp->next;
7901 }
7902 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007903 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7904 + strlen(name)
7905 /* + 1 - already done because
7906 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007907 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007908 cmdp->cmdtype = CMDUNKNOWN;
7909 strcpy(cmdp->cmdname, name);
7910 }
7911 lastcmdentry = pp;
7912 return cmdp;
7913}
7914
7915/*
7916 * Delete the command entry returned on the last lookup.
7917 */
7918static void
7919delete_cmd_entry(void)
7920{
7921 struct tblentry *cmdp;
7922
7923 INT_OFF;
7924 cmdp = *lastcmdentry;
7925 *lastcmdentry = cmdp->next;
7926 if (cmdp->cmdtype == CMDFUNCTION)
7927 freefunc(cmdp->param.func);
7928 free(cmdp);
7929 INT_ON;
7930}
7931
7932/*
7933 * Add a new command entry, replacing any existing command entry for
7934 * the same name - except special builtins.
7935 */
7936static void
7937addcmdentry(char *name, struct cmdentry *entry)
7938{
7939 struct tblentry *cmdp;
7940
7941 cmdp = cmdlookup(name, 1);
7942 if (cmdp->cmdtype == CMDFUNCTION) {
7943 freefunc(cmdp->param.func);
7944 }
7945 cmdp->cmdtype = entry->cmdtype;
7946 cmdp->param = entry->u;
7947 cmdp->rehash = 0;
7948}
7949
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007950static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007951hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007952{
7953 struct tblentry **pp;
7954 struct tblentry *cmdp;
7955 int c;
7956 struct cmdentry entry;
7957 char *name;
7958
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007959 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007960 clearcmdentry(0);
7961 return 0;
7962 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007963
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007964 if (*argptr == NULL) {
7965 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7966 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7967 if (cmdp->cmdtype == CMDNORMAL)
7968 printentry(cmdp);
7969 }
7970 }
7971 return 0;
7972 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007973
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007974 c = 0;
7975 while ((name = *argptr) != NULL) {
7976 cmdp = cmdlookup(name, 0);
7977 if (cmdp != NULL
7978 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007979 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7980 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007981 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007982 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007983 find_command(name, &entry, DO_ERR, pathval());
7984 if (entry.cmdtype == CMDUNKNOWN)
7985 c = 1;
7986 argptr++;
7987 }
7988 return c;
7989}
7990
7991/*
7992 * Called when a cd is done. Marks all commands so the next time they
7993 * are executed they will be rehashed.
7994 */
7995static void
7996hashcd(void)
7997{
7998 struct tblentry **pp;
7999 struct tblentry *cmdp;
8000
8001 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8002 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008003 if (cmdp->cmdtype == CMDNORMAL
8004 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02008005 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008006 && builtinloc > 0)
8007 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008008 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008009 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008010 }
8011 }
8012}
8013
8014/*
8015 * Fix command hash table when PATH changed.
8016 * Called before PATH is changed. The argument is the new value of PATH;
8017 * pathval() still returns the old value at this point.
8018 * Called with interrupts off.
8019 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008020static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008021changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008022{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008023 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008024 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008025 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008026 int idx_bltin;
8027
8028 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008029 firstchange = 9999; /* assume no change */
8030 idx = 0;
8031 idx_bltin = -1;
8032 for (;;) {
8033 if (*old != *new) {
8034 firstchange = idx;
8035 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008036 || (*old == ':' && *new == '\0')
8037 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008038 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008039 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008040 old = new; /* ignore subsequent differences */
8041 }
8042 if (*new == '\0')
8043 break;
8044 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
8045 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008046 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008047 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008048 new++;
8049 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008050 }
8051 if (builtinloc < 0 && idx_bltin >= 0)
8052 builtinloc = idx_bltin; /* zap builtins */
8053 if (builtinloc >= 0 && idx_bltin < 0)
8054 firstchange = 0;
8055 clearcmdentry(firstchange);
8056 builtinloc = idx_bltin;
8057}
Ron Yorston95ebcf72015-11-03 09:42:23 +00008058enum {
8059 TEOF,
8060 TNL,
8061 TREDIR,
8062 TWORD,
8063 TSEMI,
8064 TBACKGND,
8065 TAND,
8066 TOR,
8067 TPIPE,
8068 TLP,
8069 TRP,
8070 TENDCASE,
8071 TENDBQUOTE,
8072 TNOT,
8073 TCASE,
8074 TDO,
8075 TDONE,
8076 TELIF,
8077 TELSE,
8078 TESAC,
8079 TFI,
8080 TFOR,
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008081#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +00008082 TFUNCTION,
8083#endif
8084 TIF,
8085 TIN,
8086 TTHEN,
8087 TUNTIL,
8088 TWHILE,
8089 TBEGIN,
8090 TEND
8091};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008092typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008093
Denys Vlasenko888527c2016-10-02 16:54:17 +02008094/* Nth bit indicates if token marks the end of a list */
8095enum {
8096 tokendlist = 0
8097 /* 0 */ | (1u << TEOF)
8098 /* 1 */ | (0u << TNL)
8099 /* 2 */ | (0u << TREDIR)
8100 /* 3 */ | (0u << TWORD)
8101 /* 4 */ | (0u << TSEMI)
8102 /* 5 */ | (0u << TBACKGND)
8103 /* 6 */ | (0u << TAND)
8104 /* 7 */ | (0u << TOR)
8105 /* 8 */ | (0u << TPIPE)
8106 /* 9 */ | (0u << TLP)
8107 /* 10 */ | (1u << TRP)
8108 /* 11 */ | (1u << TENDCASE)
8109 /* 12 */ | (1u << TENDBQUOTE)
8110 /* 13 */ | (0u << TNOT)
8111 /* 14 */ | (0u << TCASE)
8112 /* 15 */ | (1u << TDO)
8113 /* 16 */ | (1u << TDONE)
8114 /* 17 */ | (1u << TELIF)
8115 /* 18 */ | (1u << TELSE)
8116 /* 19 */ | (1u << TESAC)
8117 /* 20 */ | (1u << TFI)
8118 /* 21 */ | (0u << TFOR)
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008119#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008120 /* 22 */ | (0u << TFUNCTION)
Denys Vlasenko80729a42016-10-02 22:33:15 +02008121#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008122 /* 23 */ | (0u << TIF)
8123 /* 24 */ | (0u << TIN)
8124 /* 25 */ | (1u << TTHEN)
8125 /* 26 */ | (0u << TUNTIL)
8126 /* 27 */ | (0u << TWHILE)
8127 /* 28 */ | (0u << TBEGIN)
8128 /* 29 */ | (1u << TEND)
8129 , /* thus far 29 bits used */
8130};
8131
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008132static const char *const tokname_array[] = {
Denys Vlasenko888527c2016-10-02 16:54:17 +02008133 "end of file",
8134 "newline",
8135 "redirection",
8136 "word",
8137 ";",
8138 "&",
8139 "&&",
8140 "||",
8141 "|",
8142 "(",
8143 ")",
8144 ";;",
8145 "`",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008146#define KWDOFFSET 13
8147 /* the following are keywords */
Denys Vlasenko888527c2016-10-02 16:54:17 +02008148 "!",
8149 "case",
8150 "do",
8151 "done",
8152 "elif",
8153 "else",
8154 "esac",
8155 "fi",
8156 "for",
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008157#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008158 "function",
Ron Yorston95ebcf72015-11-03 09:42:23 +00008159#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008160 "if",
8161 "in",
8162 "then",
8163 "until",
8164 "while",
8165 "{",
8166 "}",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008167};
8168
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008169/* Wrapper around strcmp for qsort/bsearch/... */
8170static int
8171pstrcmp(const void *a, const void *b)
8172{
Denys Vlasenko888527c2016-10-02 16:54:17 +02008173 return strcmp((char*)a, *(char**)b);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008174}
8175
8176static const char *const *
8177findkwd(const char *s)
8178{
8179 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00008180 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8181 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008182}
8183
8184/*
8185 * Locate and print what a word is...
8186 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008187static int
Ron Yorston3f221112015-08-03 13:47:33 +01008188describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008189{
8190 struct cmdentry entry;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008191#if ENABLE_ASH_ALIAS
8192 const struct alias *ap;
8193#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008194
8195 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008196
8197 if (describe_command_verbose) {
8198 out1str(command);
8199 }
8200
8201 /* First look at the keywords */
8202 if (findkwd(command)) {
8203 out1str(describe_command_verbose ? " is a shell keyword" : command);
8204 goto out;
8205 }
8206
8207#if ENABLE_ASH_ALIAS
8208 /* Then look at the aliases */
8209 ap = lookupalias(command, 0);
8210 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008211 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008212 out1str("alias ");
8213 printalias(ap);
8214 return 0;
8215 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00008216 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008217 goto out;
8218 }
8219#endif
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008220 /* Brute force */
8221 find_command(command, &entry, DO_ABS, path);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008222
8223 switch (entry.cmdtype) {
8224 case CMDNORMAL: {
8225 int j = entry.u.index;
8226 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008227 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008228 p = command;
8229 } else {
8230 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008231 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008232 stunalloc(p);
8233 } while (--j >= 0);
8234 }
8235 if (describe_command_verbose) {
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008236 out1fmt(" is %s", p);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008237 } else {
8238 out1str(p);
8239 }
8240 break;
8241 }
8242
8243 case CMDFUNCTION:
8244 if (describe_command_verbose) {
8245 out1str(" is a shell function");
8246 } else {
8247 out1str(command);
8248 }
8249 break;
8250
8251 case CMDBUILTIN:
8252 if (describe_command_verbose) {
8253 out1fmt(" is a %sshell builtin",
8254 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8255 "special " : nullstr
8256 );
8257 } else {
8258 out1str(command);
8259 }
8260 break;
8261
8262 default:
8263 if (describe_command_verbose) {
8264 out1str(": not found\n");
8265 }
8266 return 127;
8267 }
8268 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008269 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008270 return 0;
8271}
8272
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008273static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008274typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008275{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008276 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008277 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008278 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008279
Denis Vlasenko46846e22007-05-20 13:08:31 +00008280 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008281 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008282 i++;
8283 verbose = 0;
8284 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008285 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008286 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008287 }
8288 return err;
8289}
8290
8291#if ENABLE_ASH_CMDCMD
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008292/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8293static char **
8294parse_command_args(char **argv, const char **path)
8295{
8296 char *cp, c;
8297
8298 for (;;) {
8299 cp = *++argv;
8300 if (!cp)
8301 return NULL;
8302 if (*cp++ != '-')
8303 break;
8304 c = *cp++;
8305 if (!c)
8306 break;
8307 if (c == '-' && !*cp) {
8308 if (!*++argv)
8309 return NULL;
8310 break;
8311 }
8312 do {
8313 switch (c) {
8314 case 'p':
8315 *path = bb_default_path;
8316 break;
8317 default:
8318 /* run 'typecmd' for other options */
8319 return NULL;
8320 }
8321 c = *cp++;
8322 } while (c);
8323 }
8324 return argv;
8325}
8326
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008327static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008328commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008329{
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008330 char *cmd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008331 int c;
8332 enum {
8333 VERIFY_BRIEF = 1,
8334 VERIFY_VERBOSE = 2,
8335 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008336 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008337
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008338 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8339 * never reaches this function.
8340 */
8341
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008342 while ((c = nextopt("pvV")) != '\0')
8343 if (c == 'V')
8344 verify |= VERIFY_VERBOSE;
8345 else if (c == 'v')
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008346 /*verify |= VERIFY_BRIEF*/;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008347#if DEBUG
8348 else if (c != 'p')
8349 abort();
8350#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008351 else
8352 path = bb_default_path;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008353
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008354 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008355 cmd = *argptr;
8356 if (/*verify && */ cmd)
8357 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008358
8359 return 0;
8360}
8361#endif
8362
8363
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008364/*static int funcblocksize; // size of structures in function */
8365/*static int funcstringsize; // size of strings in node */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008366static void *funcblock; /* block to allocate function from */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008367static char *funcstring_end; /* end of block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008368
Eric Andersencb57d552001-06-28 07:25:16 +00008369/* flags in argument to evaltree */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008370#define EV_EXIT 01 /* exit after evaluating tree */
8371#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Eric Andersencb57d552001-06-28 07:25:16 +00008372
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008373static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008374 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8375 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8376 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8377 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8378 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8379 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8380 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8381 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8382 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8383 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8384 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8385 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8386 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8387 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8388 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8389 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8390 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008391#if BASH_REDIR_OUTPUT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008392 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008393#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008394 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8395 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8396 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8397 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8398 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8399 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8400 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8401 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8402 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008403};
8404
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008405static int calcsize(int funcblocksize, union node *n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008406
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008407static int
8408sizenodelist(int funcblocksize, struct nodelist *lp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008409{
8410 while (lp) {
8411 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008412 funcblocksize = calcsize(funcblocksize, lp->n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008413 lp = lp->next;
8414 }
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008415 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008416}
8417
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008418static int
8419calcsize(int funcblocksize, union node *n)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008420{
8421 if (n == NULL)
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008422 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008423 funcblocksize += nodesize[n->type];
8424 switch (n->type) {
8425 case NCMD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008426 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8427 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8428 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008429 break;
8430 case NPIPE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008431 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008432 break;
8433 case NREDIR:
8434 case NBACKGND:
8435 case NSUBSHELL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008436 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8437 funcblocksize = calcsize(funcblocksize, n->nredir.n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008438 break;
8439 case NAND:
8440 case NOR:
8441 case NSEMI:
8442 case NWHILE:
8443 case NUNTIL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008444 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8445 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008446 break;
8447 case NIF:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008448 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8449 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8450 funcblocksize = calcsize(funcblocksize, n->nif.test);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008451 break;
8452 case NFOR:
Denys Vlasenko561639a2016-10-07 04:28:33 +02008453 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008454 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8455 funcblocksize = calcsize(funcblocksize, n->nfor.args);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008456 break;
8457 case NCASE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008458 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8459 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008460 break;
8461 case NCLIST:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008462 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8463 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8464 funcblocksize = calcsize(funcblocksize, n->nclist.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008465 break;
8466 case NDEFUN:
8467 case NARG:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008468 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
Denys Vlasenko561639a2016-10-07 04:28:33 +02008469 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008470 funcblocksize = calcsize(funcblocksize, n->narg.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008471 break;
8472 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008473#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008474 case NTO2:
8475#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008476 case NCLOBBER:
8477 case NFROM:
8478 case NFROMTO:
8479 case NAPPEND:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008480 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8481 funcblocksize = calcsize(funcblocksize, n->nfile.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008482 break;
8483 case NTOFD:
8484 case NFROMFD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008485 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8486 funcblocksize = calcsize(funcblocksize, n->ndup.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008487 break;
8488 case NHERE:
8489 case NXHERE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008490 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8491 funcblocksize = calcsize(funcblocksize, n->nhere.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008492 break;
8493 case NNOT:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008494 funcblocksize = calcsize(funcblocksize, n->nnot.com);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008495 break;
8496 };
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008497 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008498}
8499
8500static char *
8501nodeckstrdup(char *s)
8502{
Denys Vlasenko561639a2016-10-07 04:28:33 +02008503 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008504 return strcpy(funcstring_end, s);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008505}
8506
8507static union node *copynode(union node *);
8508
8509static struct nodelist *
8510copynodelist(struct nodelist *lp)
8511{
8512 struct nodelist *start;
8513 struct nodelist **lpp;
8514
8515 lpp = &start;
8516 while (lp) {
8517 *lpp = funcblock;
8518 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8519 (*lpp)->n = copynode(lp->n);
8520 lp = lp->next;
8521 lpp = &(*lpp)->next;
8522 }
8523 *lpp = NULL;
8524 return start;
8525}
8526
8527static union node *
8528copynode(union node *n)
8529{
8530 union node *new;
8531
8532 if (n == NULL)
8533 return NULL;
8534 new = funcblock;
8535 funcblock = (char *) funcblock + nodesize[n->type];
8536
8537 switch (n->type) {
8538 case NCMD:
8539 new->ncmd.redirect = copynode(n->ncmd.redirect);
8540 new->ncmd.args = copynode(n->ncmd.args);
8541 new->ncmd.assign = copynode(n->ncmd.assign);
8542 break;
8543 case NPIPE:
8544 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008545 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008546 break;
8547 case NREDIR:
8548 case NBACKGND:
8549 case NSUBSHELL:
8550 new->nredir.redirect = copynode(n->nredir.redirect);
8551 new->nredir.n = copynode(n->nredir.n);
8552 break;
8553 case NAND:
8554 case NOR:
8555 case NSEMI:
8556 case NWHILE:
8557 case NUNTIL:
8558 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8559 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8560 break;
8561 case NIF:
8562 new->nif.elsepart = copynode(n->nif.elsepart);
8563 new->nif.ifpart = copynode(n->nif.ifpart);
8564 new->nif.test = copynode(n->nif.test);
8565 break;
8566 case NFOR:
8567 new->nfor.var = nodeckstrdup(n->nfor.var);
8568 new->nfor.body = copynode(n->nfor.body);
8569 new->nfor.args = copynode(n->nfor.args);
8570 break;
8571 case NCASE:
8572 new->ncase.cases = copynode(n->ncase.cases);
8573 new->ncase.expr = copynode(n->ncase.expr);
8574 break;
8575 case NCLIST:
8576 new->nclist.body = copynode(n->nclist.body);
8577 new->nclist.pattern = copynode(n->nclist.pattern);
8578 new->nclist.next = copynode(n->nclist.next);
8579 break;
8580 case NDEFUN:
8581 case NARG:
8582 new->narg.backquote = copynodelist(n->narg.backquote);
8583 new->narg.text = nodeckstrdup(n->narg.text);
8584 new->narg.next = copynode(n->narg.next);
8585 break;
8586 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008587#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008588 case NTO2:
8589#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008590 case NCLOBBER:
8591 case NFROM:
8592 case NFROMTO:
8593 case NAPPEND:
8594 new->nfile.fname = copynode(n->nfile.fname);
8595 new->nfile.fd = n->nfile.fd;
8596 new->nfile.next = copynode(n->nfile.next);
8597 break;
8598 case NTOFD:
8599 case NFROMFD:
8600 new->ndup.vname = copynode(n->ndup.vname);
8601 new->ndup.dupfd = n->ndup.dupfd;
8602 new->ndup.fd = n->ndup.fd;
8603 new->ndup.next = copynode(n->ndup.next);
8604 break;
8605 case NHERE:
8606 case NXHERE:
8607 new->nhere.doc = copynode(n->nhere.doc);
8608 new->nhere.fd = n->nhere.fd;
8609 new->nhere.next = copynode(n->nhere.next);
8610 break;
8611 case NNOT:
8612 new->nnot.com = copynode(n->nnot.com);
8613 break;
8614 };
8615 new->type = n->type;
8616 return new;
8617}
8618
8619/*
8620 * Make a copy of a parse tree.
8621 */
8622static struct funcnode *
8623copyfunc(union node *n)
8624{
8625 struct funcnode *f;
8626 size_t blocksize;
8627
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008628 /*funcstringsize = 0;*/
8629 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8630 f = ckzalloc(blocksize /* + funcstringsize */);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008631 funcblock = (char *) f + offsetof(struct funcnode, n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008632 funcstring_end = (char *) f + blocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008633 copynode(n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008634 /* f->count = 0; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008635 return f;
8636}
8637
8638/*
8639 * Define a shell function.
8640 */
8641static void
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008642defun(union node *func)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008643{
8644 struct cmdentry entry;
8645
8646 INT_OFF;
8647 entry.cmdtype = CMDFUNCTION;
8648 entry.u.func = copyfunc(func);
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008649 addcmdentry(func->narg.text, &entry);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008650 INT_ON;
8651}
8652
Denis Vlasenko4b875702009-03-19 13:30:04 +00008653/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008654#define SKIPBREAK (1 << 0)
8655#define SKIPCONT (1 << 1)
8656#define SKIPFUNC (1 << 2)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008657static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008658static int skipcount; /* number of levels to skip */
8659static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008660static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008661
Denis Vlasenko4b875702009-03-19 13:30:04 +00008662/* Forward decl way out to parsing code - dotrap needs it */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008663static int evalstring(char *s, int flags);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008664
Denis Vlasenko4b875702009-03-19 13:30:04 +00008665/* Called to execute a trap.
8666 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008667 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008668 *
8669 * Perhaps we should avoid entering new trap handlers
8670 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008671 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008672static void
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008673dotrap(void)
8674{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008675 uint8_t *g;
8676 int sig;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008677 uint8_t last_status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008678
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008679 if (!pending_sig)
8680 return;
8681
8682 last_status = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008683 pending_sig = 0;
Denys Vlasenkode892052016-10-02 01:49:13 +02008684 barrier();
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008685
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008686 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008687 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008688 char *p;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008689
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008690 if (!*g)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008691 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008692
8693 if (evalskip) {
8694 pending_sig = sig;
8695 break;
8696 }
8697
8698 p = trap[sig];
Denis Vlasenko4b875702009-03-19 13:30:04 +00008699 /* non-trapped SIGINT is handled separately by raise_interrupt,
8700 * don't upset it by resetting gotsig[SIGINT-1] */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008701 if (sig == SIGINT && !p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008702 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008703
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008704 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008705 *g = 0;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008706 if (!p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008707 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008708 evalstring(p, 0);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008709 }
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008710 exitstatus = last_status;
8711 TRACE(("dotrap returns\n"));
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008712}
8713
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008714/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008715static int evalloop(union node *, int);
8716static int evalfor(union node *, int);
8717static int evalcase(union node *, int);
8718static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008719static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008720static int evalpipe(union node *, int);
8721static int evalcommand(union node *, int);
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008722static int evalbltin(const struct builtincmd *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008723static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008724
Eric Andersen62483552001-07-10 06:09:16 +00008725/*
Eric Andersenc470f442003-07-28 09:56:35 +00008726 * Evaluate a parse tree. The value is left in the global variable
8727 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008728 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008729static int
Eric Andersenc470f442003-07-28 09:56:35 +00008730evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008731{
Eric Andersenc470f442003-07-28 09:56:35 +00008732 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008733 int (*evalfn)(union node *, int);
8734 int status = 0;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008735
Eric Andersenc470f442003-07-28 09:56:35 +00008736 if (n == NULL) {
8737 TRACE(("evaltree(NULL) called\n"));
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02008738 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00008739 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008740 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008741
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008742 dotrap();
8743
Eric Andersenc470f442003-07-28 09:56:35 +00008744 switch (n->type) {
8745 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008746#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008747 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008748 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008749 break;
8750#endif
8751 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008752 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008753 goto setstatus;
8754 case NREDIR:
8755 expredir(n->nredir.redirect);
8756 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8757 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008758 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008759 }
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02008760 if (n->nredir.redirect)
8761 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
Eric Andersenc470f442003-07-28 09:56:35 +00008762 goto setstatus;
8763 case NCMD:
8764 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008765 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008766 if (eflag && !(flags & EV_TESTED))
8767 checkexit = ~0;
8768 goto calleval;
8769 case NFOR:
8770 evalfn = evalfor;
8771 goto calleval;
8772 case NWHILE:
8773 case NUNTIL:
8774 evalfn = evalloop;
8775 goto calleval;
8776 case NSUBSHELL:
8777 case NBACKGND:
8778 evalfn = evalsubshell;
Denys Vlasenkocf98b0c2016-10-25 18:19:39 +02008779 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00008780 case NPIPE:
8781 evalfn = evalpipe;
8782 goto checkexit;
8783 case NCASE:
8784 evalfn = evalcase;
8785 goto calleval;
8786 case NAND:
8787 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008788 case NSEMI: {
8789
Eric Andersenc470f442003-07-28 09:56:35 +00008790#if NAND + 1 != NOR
8791#error NAND + 1 != NOR
8792#endif
8793#if NOR + 1 != NSEMI
8794#error NOR + 1 != NSEMI
8795#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008796 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008797 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00008798 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008799 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008800 );
Denys Vlasenkobc1a0082016-10-02 15:31:33 +02008801 if ((!status) == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00008802 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008803 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008804 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008805 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008806 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008807 status = evalfn(n, flags);
8808 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008809 }
Eric Andersenc470f442003-07-28 09:56:35 +00008810 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008811 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008812 if (evalskip)
8813 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008814 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00008815 n = n->nif.ifpart;
8816 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008817 }
8818 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008819 n = n->nif.elsepart;
8820 goto evaln;
8821 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008822 status = 0;
8823 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00008824 case NDEFUN:
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008825 defun(n);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008826 /* Not necessary. To test it:
8827 * "false; f() { qwerty; }; echo $?" should print 0.
8828 */
8829 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008830 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00008831 exitstatus = status;
8832 break;
8833 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008834 out:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008835 /* Order of checks below is important:
8836 * signal handlers trigger before exit caused by "set -e".
8837 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008838 dotrap();
8839
8840 if (checkexit & status)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008841 raise_exception(EXEXIT);
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008842 if (flags & EV_EXIT)
8843 raise_exception(EXEXIT);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008844
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008845 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008846 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00008847}
8848
Eric Andersenc470f442003-07-28 09:56:35 +00008849#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8850static
8851#endif
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008852int evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
Eric Andersenc470f442003-07-28 09:56:35 +00008853
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02008854static int
8855skiploop(void)
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008856{
8857 int skip = evalskip;
8858
8859 switch (skip) {
8860 case 0:
8861 break;
8862 case SKIPBREAK:
8863 case SKIPCONT:
8864 if (--skipcount <= 0) {
8865 evalskip = 0;
8866 break;
8867 }
8868 skip = SKIPBREAK;
8869 break;
8870 }
8871 return skip;
8872}
8873
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008874static int
Eric Andersenc470f442003-07-28 09:56:35 +00008875evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008876{
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008877 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00008878 int status;
8879
8880 loopnest++;
8881 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008882 flags &= EV_TESTED;
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008883 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008884 int i;
8885
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008886 i = evaltree(n->nbinary.ch1, EV_TESTED);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008887 skip = skiploop();
8888 if (skip == SKIPFUNC)
8889 status = i;
8890 if (skip)
8891 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00008892 if (n->type != NWHILE)
8893 i = !i;
8894 if (i != 0)
8895 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008896 status = evaltree(n->nbinary.ch2, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008897 skip = skiploop();
8898 } while (!(skip & ~SKIPCONT));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008899 loopnest--;
8900
8901 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008902}
8903
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008904static int
Eric Andersenc470f442003-07-28 09:56:35 +00008905evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008906{
8907 struct arglist arglist;
8908 union node *argp;
8909 struct strlist *sp;
8910 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008911 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008912
8913 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008914 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008915 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008916 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02008917 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersencb57d552001-06-28 07:25:16 +00008918 }
8919 *arglist.lastp = NULL;
8920
Eric Andersencb57d552001-06-28 07:25:16 +00008921 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008922 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008923 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008924 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008925 status = evaltree(n->nfor.body, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008926 if (skiploop() & ~SKIPCONT)
Eric Andersencb57d552001-06-28 07:25:16 +00008927 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008928 }
8929 loopnest--;
Eric Andersencb57d552001-06-28 07:25:16 +00008930 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008931
8932 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008933}
8934
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008935static int
Eric Andersenc470f442003-07-28 09:56:35 +00008936evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008937{
8938 union node *cp;
8939 union node *patp;
8940 struct arglist arglist;
8941 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008942 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008943
8944 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008945 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008946 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00008947 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008948 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8949 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008950 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008951 /* Ensure body is non-empty as otherwise
8952 * EV_EXIT may prevent us from setting the
8953 * exit status.
8954 */
8955 if (evalskip == 0 && cp->nclist.body) {
8956 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008957 }
8958 goto out;
8959 }
8960 }
8961 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008962 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008963 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008964
8965 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008966}
8967
Eric Andersenc470f442003-07-28 09:56:35 +00008968/*
8969 * Kick off a subshell to evaluate a tree.
8970 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008971static int
Eric Andersenc470f442003-07-28 09:56:35 +00008972evalsubshell(union node *n, int flags)
8973{
8974 struct job *jp;
Denys Vlasenko098b7132017-01-11 19:59:03 +01008975 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
Eric Andersenc470f442003-07-28 09:56:35 +00008976 int status;
8977
8978 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02008979 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00008980 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008981 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01008982 if (backgnd == FORK_FG)
8983 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00008984 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008985 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02008986 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008987 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008988 flags |= EV_EXIT;
8989 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02008990 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00008991 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00008992 redirect(n->nredir.redirect, 0);
8993 evaltreenr(n->nredir.n, flags);
8994 /* never returns */
8995 }
Denys Vlasenko70392332016-10-27 02:31:55 +02008996 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00008997 status = 0;
Denys Vlasenko098b7132017-01-11 19:59:03 +01008998 if (backgnd == FORK_FG)
Eric Andersenc470f442003-07-28 09:56:35 +00008999 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009000 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009001 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009002}
9003
Eric Andersenc470f442003-07-28 09:56:35 +00009004/*
9005 * Compute the names of the files in a redirection list.
9006 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009007static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00009008static void
9009expredir(union node *n)
9010{
9011 union node *redir;
9012
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009013 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009014 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009015
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009016 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009017 fn.lastp = &fn.list;
9018 switch (redir->type) {
9019 case NFROMTO:
9020 case NFROM:
9021 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009022#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009023 case NTO2:
9024#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009025 case NCLOBBER:
9026 case NAPPEND:
9027 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02009028 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009029#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009030 store_expfname:
9031#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009032#if 0
9033// By the design of stack allocator, the loop of this kind:
9034// while true; do while true; do break; done </dev/null; done
9035// will look like a memory leak: ash plans to free expfname's
9036// of "/dev/null" as soon as it finishes running the loop
9037// (in this case, never).
9038// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01009039 if (redir->nfile.expfname)
9040 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009041// It results in corrupted state of stacked allocations.
9042#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009043 redir->nfile.expfname = fn.list->text;
9044 break;
9045 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00009046 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00009047 if (redir->ndup.vname) {
9048 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009049 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009050 ash_msg_and_raise_error("redir error");
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009051#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009052//FIXME: we used expandarg with different args!
9053 if (!isdigit_str9(fn.list->text)) {
9054 /* >&file, not >&fd */
9055 if (redir->nfile.fd != 1) /* 123>&file - BAD */
9056 ash_msg_and_raise_error("redir error");
9057 redir->type = NTO2;
9058 goto store_expfname;
9059 }
9060#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009061 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009062 }
9063 break;
9064 }
9065 }
9066}
9067
Eric Andersencb57d552001-06-28 07:25:16 +00009068/*
Eric Andersencb57d552001-06-28 07:25:16 +00009069 * Evaluate a pipeline. All the processes in the pipeline are children
9070 * of the process creating the pipeline. (This differs from some versions
9071 * of the shell, which make the last process in a pipeline the parent
9072 * of all the rest.)
9073 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009074static int
Eric Andersenc470f442003-07-28 09:56:35 +00009075evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009076{
9077 struct job *jp;
9078 struct nodelist *lp;
9079 int pipelen;
9080 int prevfd;
9081 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009082 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009083
Eric Andersenc470f442003-07-28 09:56:35 +00009084 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00009085 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009086 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00009087 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009088 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009089 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009090 if (n->npipe.pipe_backgnd == 0)
9091 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009092 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00009093 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009094 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009095 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00009096 pip[1] = -1;
9097 if (lp->next) {
9098 if (pipe(pip) < 0) {
9099 close(prevfd);
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00009100 ash_msg_and_raise_error("pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00009101 }
9102 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009103 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02009104 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009105 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00009106 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009107 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00009108 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009109 if (prevfd > 0) {
9110 dup2(prevfd, 0);
9111 close(prevfd);
9112 }
9113 if (pip[1] > 1) {
9114 dup2(pip[1], 1);
9115 close(pip[1]);
9116 }
Eric Andersenc470f442003-07-28 09:56:35 +00009117 evaltreenr(lp->n, flags);
9118 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00009119 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009120 /* parent */
Eric Andersencb57d552001-06-28 07:25:16 +00009121 if (prevfd >= 0)
9122 close(prevfd);
9123 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00009124 /* Don't want to trigger debugging */
9125 if (pip[1] != -1)
9126 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009127 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009128 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009129 status = waitforjob(jp);
9130 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00009131 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009132 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009133
9134 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009135}
9136
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009137/*
9138 * Controls whether the shell is interactive or not.
9139 */
9140static void
9141setinteractive(int on)
9142{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009143 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009144
9145 if (++on == is_interactive)
9146 return;
9147 is_interactive = on;
9148 setsignal(SIGINT);
9149 setsignal(SIGQUIT);
9150 setsignal(SIGTERM);
9151#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9152 if (is_interactive > 1) {
9153 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009154 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009155
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009156 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009157 /* note: ash and hush share this string */
9158 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009159 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9160 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009161 bb_banner,
9162 "built-in shell (ash)"
9163 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009164 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009165 }
9166 }
9167#endif
9168}
9169
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009170static void
9171optschanged(void)
9172{
9173#if DEBUG
9174 opentrace();
9175#endif
9176 setinteractive(iflag);
9177 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009178#if ENABLE_FEATURE_EDITING_VI
9179 if (viflag)
9180 line_input_state->flags |= VI_MODE;
9181 else
9182 line_input_state->flags &= ~VI_MODE;
9183#else
9184 viflag = 0; /* forcibly keep the option off */
9185#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009186}
9187
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009188static struct localvar *localvars;
9189
9190/*
9191 * Called after a function returns.
9192 * Interrupts must be off.
9193 */
9194static void
9195poplocalvars(void)
9196{
9197 struct localvar *lvp;
9198 struct var *vp;
9199
9200 while ((lvp = localvars) != NULL) {
9201 localvars = lvp->next;
9202 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02009203 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009204 if (vp == NULL) { /* $- saved */
9205 memcpy(optlist, lvp->text, sizeof(optlist));
9206 free((char*)lvp->text);
9207 optschanged();
9208 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009209 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009210 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009211 if (vp->var_func)
9212 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009213 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009214 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009215 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009216 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009217 }
9218 free(lvp);
9219 }
9220}
9221
9222static int
9223evalfun(struct funcnode *func, int argc, char **argv, int flags)
9224{
9225 volatile struct shparam saveparam;
9226 struct localvar *volatile savelocalvars;
9227 struct jmploc *volatile savehandler;
9228 struct jmploc jmploc;
9229 int e;
9230
9231 saveparam = shellparam;
9232 savelocalvars = localvars;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009233 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009234 e = setjmp(jmploc.loc);
9235 if (e) {
9236 goto funcdone;
9237 }
9238 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009239 exception_handler = &jmploc;
9240 localvars = NULL;
Denis Vlasenko01631112007-12-16 17:20:38 +00009241 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009242 func->count++;
9243 funcnest++;
9244 INT_ON;
9245 shellparam.nparam = argc - 1;
9246 shellparam.p = argv + 1;
9247#if ENABLE_ASH_GETOPTS
9248 shellparam.optind = 1;
9249 shellparam.optoff = -1;
9250#endif
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009251 evaltree(func->n.narg.next, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00009252 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009253 INT_OFF;
9254 funcnest--;
9255 freefunc(func);
9256 poplocalvars();
9257 localvars = savelocalvars;
9258 freeparam(&shellparam);
9259 shellparam = saveparam;
9260 exception_handler = savehandler;
9261 INT_ON;
9262 evalskip &= ~SKIPFUNC;
9263 return e;
9264}
9265
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009266/*
9267 * Make a variable a local variable. When a variable is made local, it's
9268 * value and flags are saved in a localvar structure. The saved values
9269 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009270 * "-" as a special case: it makes changes to "set +-options" local
9271 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009272 */
9273static void
9274mklocal(char *name)
9275{
9276 struct localvar *lvp;
9277 struct var **vpp;
9278 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009279 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009280
9281 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009282 /* Cater for duplicate "local". Examples:
9283 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9284 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9285 */
9286 lvp = localvars;
9287 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009288 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009289 if (eq)
9290 setvareq(name, 0);
9291 /* else:
9292 * it's a duplicate "local VAR" declaration, do nothing
9293 */
Denys Vlasenko06b11492016-11-04 16:43:18 +01009294 goto ret;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009295 }
9296 lvp = lvp->next;
9297 }
9298
9299 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009300 if (LONE_DASH(name)) {
9301 char *p;
9302 p = ckmalloc(sizeof(optlist));
9303 lvp->text = memcpy(p, optlist, sizeof(optlist));
9304 vp = NULL;
9305 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009306 vpp = hashvar(name);
9307 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009308 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009309 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009310 if (eq)
9311 setvareq(name, VSTRFIXED);
9312 else
9313 setvar(name, NULL, VSTRFIXED);
9314 vp = *vpp; /* the new variable */
9315 lvp->flags = VUNSET;
9316 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009317 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009318 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009319 /* make sure neither "struct var" nor string gets freed
9320 * during (un)setting:
9321 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009322 vp->flags |= VSTRFIXED|VTEXTFIXED;
9323 if (eq)
9324 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009325 else
9326 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009327 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009328 }
9329 }
9330 lvp->vp = vp;
9331 lvp->next = localvars;
9332 localvars = lvp;
Denys Vlasenko06b11492016-11-04 16:43:18 +01009333 ret:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009334 INT_ON;
9335}
9336
9337/*
9338 * The "local" command.
9339 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009340static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009341localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009342{
9343 char *name;
9344
Ron Yorstonef2386b2015-10-29 16:19:14 +00009345 if (!funcnest)
9346 ash_msg_and_raise_error("not in a function");
9347
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009348 argv = argptr;
9349 while ((name = *argv++) != NULL) {
9350 mklocal(name);
9351 }
9352 return 0;
9353}
9354
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009355static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009356falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009357{
9358 return 1;
9359}
9360
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009361static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009362truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009363{
9364 return 0;
9365}
9366
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009367static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009368execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009369{
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009370 optionarg = NULL;
9371 while (nextopt("a:") != '\0')
9372 /* nextopt() sets optionarg to "-a ARGV0" */;
9373
9374 argv = argptr;
9375 if (argv[0]) {
9376 char *prog;
9377
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009378 iflag = 0; /* exit on error */
9379 mflag = 0;
9380 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009381 /* We should set up signals for "exec CMD"
9382 * the same way as for "CMD" without "exec".
9383 * But optschanged->setinteractive->setsignal
9384 * still thought we are a root shell. Therefore, for example,
9385 * SIGQUIT is still set to IGN. Fix it:
9386 */
9387 shlvl++;
9388 setsignal(SIGQUIT);
9389 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9390 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9391 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9392
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009393 prog = argv[0];
9394 if (optionarg)
9395 argv[0] = optionarg;
9396 shellexec(prog, argv, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009397 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009398 }
9399 return 0;
9400}
9401
9402/*
9403 * The return command.
9404 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009405static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009406returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009407{
9408 /*
9409 * If called outside a function, do what ksh does;
9410 * skip the rest of the file.
9411 */
Denys Vlasenko6a0710e2016-09-30 14:18:34 +02009412 evalskip = SKIPFUNC;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009413 return argv[1] ? number(argv[1]) : exitstatus;
9414}
9415
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009416/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009417static int breakcmd(int, char **) FAST_FUNC;
9418static int dotcmd(int, char **) FAST_FUNC;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009419static int evalcmd(int, char **, int) FAST_FUNC;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009420static int exitcmd(int, char **) FAST_FUNC;
9421static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009422#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009423static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009424#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009425#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009426static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009427#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009428#if MAX_HISTORY
9429static int historycmd(int, char **) FAST_FUNC;
9430#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009431#if ENABLE_FEATURE_SH_MATH
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009432static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009433#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009434static int readcmd(int, char **) FAST_FUNC;
9435static int setcmd(int, char **) FAST_FUNC;
9436static int shiftcmd(int, char **) FAST_FUNC;
9437static int timescmd(int, char **) FAST_FUNC;
9438static int trapcmd(int, char **) FAST_FUNC;
9439static int umaskcmd(int, char **) FAST_FUNC;
9440static int unsetcmd(int, char **) FAST_FUNC;
9441static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009442
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009443#define BUILTIN_NOSPEC "0"
9444#define BUILTIN_SPECIAL "1"
9445#define BUILTIN_REGULAR "2"
9446#define BUILTIN_SPEC_REG "3"
9447#define BUILTIN_ASSIGN "4"
9448#define BUILTIN_SPEC_ASSG "5"
9449#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009450#define BUILTIN_SPEC_REG_ASSG "7"
9451
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009452/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko265062d2017-01-10 15:13:30 +01009453#if ENABLE_ASH_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009454static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009455#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009456#if ENABLE_ASH_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009457static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009458#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009459#if ENABLE_ASH_TEST || BASH_TEST2
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009460static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009461#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009462
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009463/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009464static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009465 { BUILTIN_SPEC_REG "." , dotcmd },
9466 { BUILTIN_SPEC_REG ":" , truecmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009467#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009468 { BUILTIN_REGULAR "[" , testcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009469#endif
9470#if BASH_TEST2
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009471 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009472#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009473#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009474 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009475#endif
9476#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009477 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009478#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009479 { BUILTIN_SPEC_REG "break" , breakcmd },
9480 { BUILTIN_REGULAR "cd" , cdcmd },
9481 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009482#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009483 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009484#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009485 { BUILTIN_SPEC_REG "continue", breakcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009486#if ENABLE_ASH_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009487 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009488#endif
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009489 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009490 { BUILTIN_SPEC_REG "exec" , execcmd },
9491 { BUILTIN_SPEC_REG "exit" , exitcmd },
9492 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9493 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009494#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009495 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009496#endif
9497#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009498 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009499#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009500 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009501#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009502 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009503#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009504#if MAX_HISTORY
9505 { BUILTIN_NOSPEC "history" , historycmd },
9506#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009507#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009508 { BUILTIN_REGULAR "jobs" , jobscmd },
9509 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009510#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009511#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009512 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009513#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009514 { BUILTIN_ASSIGN "local" , localcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009515#if ENABLE_ASH_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009516 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009517#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009518 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9519 { BUILTIN_REGULAR "read" , readcmd },
9520 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9521 { BUILTIN_SPEC_REG "return" , returncmd },
9522 { BUILTIN_SPEC_REG "set" , setcmd },
9523 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009524#if BASH_SOURCE
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009525 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009526#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009527#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009528 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009529#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009530 { BUILTIN_SPEC_REG "times" , timescmd },
9531 { BUILTIN_SPEC_REG "trap" , trapcmd },
9532 { BUILTIN_REGULAR "true" , truecmd },
9533 { BUILTIN_NOSPEC "type" , typecmd },
9534 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9535 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009536#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009537 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009538#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009539 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9540 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009541};
9542
Denis Vlasenko80591b02008-03-25 07:49:43 +00009543/* Should match the above table! */
9544#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009545 /* . : */ 2 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009546 /* [ */ 1 * ENABLE_ASH_TEST + \
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009547 /* [[ */ 1 * BASH_TEST2 + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009548 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9549 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9550 /* break cd cddir */ 3)
9551#define EVALCMD (COMMANDCMD + \
9552 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9553 /* continue */ 1 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009554 /* echo */ 1 * ENABLE_ASH_ECHO + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009555 0)
9556#define EXECCMD (EVALCMD + \
9557 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009558
9559/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009560 * Search the table of builtin commands.
9561 */
Denys Vlasenko888527c2016-10-02 16:54:17 +02009562static int
9563pstrcmp1(const void *a, const void *b)
9564{
9565 return strcmp((char*)a, *(char**)b + 1);
9566}
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009567static struct builtincmd *
9568find_builtin(const char *name)
9569{
9570 struct builtincmd *bp;
9571
9572 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009573 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denys Vlasenko888527c2016-10-02 16:54:17 +02009574 pstrcmp1
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009575 );
9576 return bp;
9577}
9578
9579/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009580 * Execute a simple command.
9581 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009582static int
9583isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009584{
9585 const char *q = endofname(p);
9586 if (p == q)
9587 return 0;
9588 return *q == '=';
9589}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009590static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009591bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009592{
9593 /* Preserve exitstatus of a previous possible redirection
9594 * as POSIX mandates */
9595 return back_exitstatus;
9596}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009597static int
Eric Andersenc470f442003-07-28 09:56:35 +00009598evalcommand(union node *cmd, int flags)
9599{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009600 static const struct builtincmd null_bltin = {
9601 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009602 };
Eric Andersenc470f442003-07-28 09:56:35 +00009603 struct stackmark smark;
9604 union node *argp;
9605 struct arglist arglist;
9606 struct arglist varlist;
9607 char **argv;
9608 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009609 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009610 struct cmdentry cmdentry;
9611 struct job *jp;
9612 char *lastarg;
9613 const char *path;
9614 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009615 int status;
9616 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00009617 struct builtincmd *bcmd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009618 smallint cmd_is_exec;
9619 smallint pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009620
9621 /* First expand the arguments. */
9622 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9623 setstackmark(&smark);
9624 back_exitstatus = 0;
9625
9626 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009627 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009628 varlist.lastp = &varlist.list;
9629 *varlist.lastp = NULL;
9630 arglist.lastp = &arglist.list;
9631 *arglist.lastp = NULL;
9632
9633 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009634 if (cmd->ncmd.args) {
Paul Foxc3850c82005-07-20 18:23:39 +00009635 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9636 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9637 }
9638
Eric Andersenc470f442003-07-28 09:56:35 +00009639 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9640 struct strlist **spp;
9641
9642 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00009643 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00009644 expandarg(argp, &arglist, EXP_VARTILDE);
9645 else
9646 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9647
Eric Andersenc470f442003-07-28 09:56:35 +00009648 for (sp = *spp; sp; sp = sp->next)
9649 argc++;
9650 }
9651
Denys Vlasenko65a8b852016-10-26 22:29:11 +02009652 /* Reserve one extra spot at the front for shellexec. */
9653 nargv = stalloc(sizeof(char *) * (argc + 2));
9654 argv = ++nargv;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009655 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009656 TRACE(("evalcommand arg: %s\n", sp->text));
9657 *nargv++ = sp->text;
9658 }
9659 *nargv = NULL;
9660
9661 lastarg = NULL;
9662 if (iflag && funcnest == 0 && argc > 0)
9663 lastarg = nargv[-1];
9664
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009665 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009666 expredir(cmd->ncmd.redirect);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009667 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009668
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009669 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009670 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9671 struct strlist **spp;
9672 char *p;
9673
9674 spp = varlist.lastp;
9675 expandarg(argp, &varlist, EXP_VARTILDE);
9676
9677 /*
9678 * Modify the command lookup path, if a PATH= assignment
9679 * is present
9680 */
9681 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009682 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009683 path = p;
9684 }
9685
9686 /* Print the command if xflag is set. */
9687 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009688 int n;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009689 const char *p = " %s" + 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009690
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009691 fdprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009692 sp = varlist.list;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009693 for (n = 0; n < 2; n++) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009694 while (sp) {
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009695 fdprintf(preverrout_fd, p, sp->text);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009696 sp = sp->next;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009697 p = " %s";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009698 }
9699 sp = arglist.list;
9700 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009701 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009702 }
9703
9704 cmd_is_exec = 0;
9705 spclbltin = -1;
9706
9707 /* Now locate the command. */
9708 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009709 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02009710#if ENABLE_ASH_CMDCMD
9711 const char *oldpath = path + 5;
9712#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009713 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009714 for (;;) {
9715 find_command(argv[0], &cmdentry, cmd_flag, path);
9716 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009717 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009718 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009719 goto bail;
9720 }
9721
9722 /* implement bltin and command here */
9723 if (cmdentry.cmdtype != CMDBUILTIN)
9724 break;
9725 if (spclbltin < 0)
9726 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9727 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009728 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009729#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009730 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009731 path = oldpath;
9732 nargv = parse_command_args(argv, &path);
9733 if (!nargv)
9734 break;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02009735 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
9736 * nargv => "PROG". path is updated if -p.
9737 */
Eric Andersenc470f442003-07-28 09:56:35 +00009738 argc -= nargv - argv;
9739 argv = nargv;
9740 cmd_flag |= DO_NOFUNC;
9741 } else
9742#endif
9743 break;
9744 }
9745 }
9746
9747 if (status) {
Ron Yorstonea7d2f62017-01-03 11:18:23 +01009748 bail:
9749 exitstatus = status;
9750
Eric Andersenc470f442003-07-28 09:56:35 +00009751 /* We have a redirection error. */
9752 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009753 raise_exception(EXERROR);
Ron Yorstonea7d2f62017-01-03 11:18:23 +01009754
Eric Andersenc470f442003-07-28 09:56:35 +00009755 goto out;
9756 }
9757
9758 /* Execute the command. */
9759 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009760 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009761
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009762#if ENABLE_FEATURE_SH_NOFORK
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009763/* (1) BUG: if variables are set, we need to fork, or save/restore them
9764 * around run_nofork_applet() call.
9765 * (2) Should this check also be done in forkshell()?
9766 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9767 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009768 /* find_command() encodes applet_no as (-2 - applet_no) */
9769 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009770 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009771 listsetvar(varlist.list, VEXPORT|VSTACK);
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009772 /* run <applet>_main() */
Ron Yorston5ccb0e92016-10-20 12:24:02 +01009773 status = run_nofork_applet(applet_no, argv);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009774 break;
9775 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009776#endif
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009777 /* Can we avoid forking off? For example, very last command
9778 * in a script or a subshell does not need forking,
9779 * we can just exec it.
9780 */
Denys Vlasenko238bf182010-05-18 15:49:07 +02009781 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009782 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009783 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009784 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009785 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009786 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009787 /* parent */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009788 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009789 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009790 TRACE(("forked child exited with %d\n", status));
Eric Andersenc470f442003-07-28 09:56:35 +00009791 break;
9792 }
Denys Vlasenko238bf182010-05-18 15:49:07 +02009793 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009794 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +02009795 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +00009796 }
9797 listsetvar(varlist.list, VEXPORT|VSTACK);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02009798 shellexec(argv[0], argv, path, cmdentry.u.index);
Eric Andersenc470f442003-07-28 09:56:35 +00009799 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009800 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +00009801 case CMDBUILTIN:
9802 cmdenviron = varlist.list;
9803 if (cmdenviron) {
9804 struct strlist *list = cmdenviron;
9805 int i = VNOSET;
9806 if (spclbltin > 0 || argc == 0) {
9807 i = 0;
9808 if (cmd_is_exec && argc > 1)
9809 i = VEXPORT;
9810 }
9811 listsetvar(list, i);
9812 }
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009813 /* Tight loop with builtins only:
9814 * "while kill -0 $child; do true; done"
9815 * will never exit even if $child died, unless we do this
9816 * to reap the zombie and make kill detect that it's gone: */
9817 dowait(DOWAIT_NONBLOCK, NULL);
9818
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009819 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009820 if (exception_type == EXERROR && spclbltin <= 0) {
9821 FORCE_INT_ON;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02009822 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009823 }
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009824 raise:
9825 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009826 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009827 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009828
9829 case CMDFUNCTION:
9830 listsetvar(varlist.list, 0);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009831 /* See above for the rationale */
9832 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009833 if (evalfun(cmdentry.u.func, argc, argv, flags))
9834 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009835 readstatus:
9836 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009837 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009838 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +00009839
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009840 out:
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02009841 if (cmd->ncmd.redirect)
9842 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009843 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +00009844 /* dsl: I think this is intended to be used to support
9845 * '_' in 'vi' command mode during line editing...
9846 * However I implemented that within libedit itself.
9847 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009848 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009849 }
Eric Andersenc470f442003-07-28 09:56:35 +00009850 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009851
9852 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009853}
9854
9855static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009856evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009857{
Eric Andersenc470f442003-07-28 09:56:35 +00009858 char *volatile savecmdname;
9859 struct jmploc *volatile savehandler;
9860 struct jmploc jmploc;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009861 int status;
Eric Andersenc470f442003-07-28 09:56:35 +00009862 int i;
9863
9864 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009865 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009866 i = setjmp(jmploc.loc);
9867 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +00009868 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009869 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00009870 commandname = argv[0];
9871 argptr = argv + 1;
9872 optptr = NULL; /* initialize nextopt */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009873 if (cmd == EVALCMD)
9874 status = evalcmd(argc, argv, flags);
9875 else
9876 status = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009877 flush_stdout_stderr();
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009878 status |= ferror(stdout);
9879 exitstatus = status;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009880 cmddone:
Rob Landleyf296f0b2006-07-06 01:09:21 +00009881 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009882 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009883 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +00009884
9885 return i;
9886}
9887
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009888static int
9889goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009890{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02009891 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009892}
9893
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009894
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009895/*
9896 * Search for a command. This is called before we fork so that the
9897 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009898 * the child. The check for "goodname" is an overly conservative
9899 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009900 */
Eric Andersenc470f442003-07-28 09:56:35 +00009901static void
9902prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009903{
9904 struct cmdentry entry;
9905
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009906 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9907 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009908}
9909
Eric Andersencb57d552001-06-28 07:25:16 +00009910
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009911/* ============ Builtin commands
9912 *
9913 * Builtin commands whose functions are closely tied to evaluation
9914 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +00009915 */
9916
9917/*
Eric Andersencb57d552001-06-28 07:25:16 +00009918 * Handle break and continue commands. Break, continue, and return are
9919 * all handled by setting the evalskip flag. The evaluation routines
9920 * above all check this flag, and if it is set they start skipping
9921 * commands rather than executing them. The variable skipcount is
9922 * the number of loops to break/continue, or the number of function
9923 * levels to return. (The latter is always 1.) It should probably
9924 * be an error to break out of more loops than exist, but it isn't
9925 * in the standard shell so we don't make it one here.
9926 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009927static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009928breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009929{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009930 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009931
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00009932 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009933 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009934 if (n > loopnest)
9935 n = loopnest;
9936 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009937 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00009938 skipcount = n;
9939 }
9940 return 0;
9941}
9942
Eric Andersenc470f442003-07-28 09:56:35 +00009943
Denys Vlasenko70392332016-10-27 02:31:55 +02009944/*
Eric Andersen90898442003-08-06 11:20:52 +00009945 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00009946 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009947
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009948enum {
9949 INPUT_PUSH_FILE = 1,
9950 INPUT_NOFILE_OK = 2,
9951};
Eric Andersencb57d552001-06-28 07:25:16 +00009952
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009953static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009954/* values of checkkwd variable */
9955#define CHKALIAS 0x1
9956#define CHKKWD 0x2
9957#define CHKNL 0x4
9958
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009959/*
9960 * Push a string back onto the input at this current parsefile level.
9961 * We handle aliases this way.
9962 */
9963#if !ENABLE_ASH_ALIAS
9964#define pushstring(s, ap) pushstring(s)
9965#endif
9966static void
9967pushstring(char *s, struct alias *ap)
9968{
9969 struct strpush *sp;
9970 int len;
9971
9972 len = strlen(s);
9973 INT_OFF;
9974 if (g_parsefile->strpush) {
9975 sp = ckzalloc(sizeof(*sp));
9976 sp->prev = g_parsefile->strpush;
9977 } else {
9978 sp = &(g_parsefile->basestrpush);
9979 }
9980 g_parsefile->strpush = sp;
9981 sp->prev_string = g_parsefile->next_to_pgetc;
9982 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009983 sp->unget = g_parsefile->unget;
9984 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009985#if ENABLE_ASH_ALIAS
9986 sp->ap = ap;
9987 if (ap) {
9988 ap->flag |= ALIASINUSE;
9989 sp->string = s;
9990 }
9991#endif
9992 g_parsefile->next_to_pgetc = s;
9993 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009994 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009995 INT_ON;
9996}
9997
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009998static void
9999popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010000{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010001 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +000010002
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010003 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010004#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010005 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010006 if (g_parsefile->next_to_pgetc[-1] == ' '
10007 || g_parsefile->next_to_pgetc[-1] == '\t'
10008 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010009 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010010 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010011 if (sp->string != sp->ap->val) {
10012 free(sp->string);
10013 }
10014 sp->ap->flag &= ~ALIASINUSE;
10015 if (sp->ap->flag & ALIASDEAD) {
10016 unalias(sp->ap->name);
10017 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010018 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010019#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010020 g_parsefile->next_to_pgetc = sp->prev_string;
10021 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010022 g_parsefile->unget = sp->unget;
10023 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010024 g_parsefile->strpush = sp->prev;
10025 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010026 free(sp);
10027 INT_ON;
10028}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010029
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010030static int
10031preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010032{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010033 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +000010034 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010035
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010036 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +000010037#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +000010038 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010039 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +010010040 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010041 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010042 int timeout = -1;
10043# if ENABLE_ASH_IDLE_TIMEOUT
10044 if (iflag) {
10045 const char *tmout_var = lookupvar("TMOUT");
10046 if (tmout_var) {
10047 timeout = atoi(tmout_var) * 1000;
10048 if (timeout <= 0)
10049 timeout = -1;
10050 }
10051 }
10052# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010053# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010054 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010055# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +020010056 reinit_unicode_for_ash();
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010057 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010058 if (nr == 0) {
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010059 /* ^C pressed, "convert" to SIGINT */
10060 write(STDOUT_FILENO, "^C", 2);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010061 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010062 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010063 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010064 raise(SIGINT);
10065 return 1;
10066 }
Denys Vlasenko8660aeb2016-11-24 17:44:02 +010010067 exitstatus = 128 + SIGINT;
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010068 bb_putchar('\n');
Eric Andersenc470f442003-07-28 09:56:35 +000010069 goto retry;
10070 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010071 if (nr < 0) {
10072 if (errno == 0) {
10073 /* Ctrl+D pressed */
10074 nr = 0;
10075 }
10076# if ENABLE_ASH_IDLE_TIMEOUT
10077 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +020010078 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010079 exitshell();
10080 }
10081# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010082 }
Eric Andersencb57d552001-06-28 07:25:16 +000010083 }
10084#else
Ron Yorston61d6ae22015-04-19 10:50:25 +010010085 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +000010086#endif
10087
Denys Vlasenko80c5b682011-05-08 21:21:10 +020010088#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +000010089 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010090 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +000010091 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +000010092 if (flags >= 0 && (flags & O_NONBLOCK)) {
10093 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +000010094 if (fcntl(0, F_SETFL, flags) >= 0) {
10095 out2str("sh: turning off NDELAY mode\n");
10096 goto retry;
10097 }
10098 }
10099 }
10100 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +000010101#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010102 return nr;
10103}
10104
10105/*
10106 * Refill the input buffer and return the next input character:
10107 *
10108 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010109 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
10110 * or we are reading from a string so we can't refill the buffer,
10111 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +020010112 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +000010113 * 4) Process input up to the next newline, deleting nul characters.
10114 */
Denis Vlasenko727752d2008-11-28 03:41:47 +000010115//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
10116#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010117static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010118static int
Eric Andersenc470f442003-07-28 09:56:35 +000010119preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010120{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010121 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010122 int more;
Eric Andersencb57d552001-06-28 07:25:16 +000010123
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010124 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000010125#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010126 if (g_parsefile->left_in_line == -1
10127 && g_parsefile->strpush->ap
10128 && g_parsefile->next_to_pgetc[-1] != ' '
10129 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +000010130 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010131 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +000010132 return PEOA;
10133 }
Eric Andersen2870d962001-07-02 17:27:21 +000010134#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010135 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010136 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010137 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010138 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010139 * "pgetc" needs refilling.
10140 */
10141
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010142 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010143 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010144 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010145 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010146 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010147 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010148 /* even in failure keep left_in_line and next_to_pgetc
10149 * in lock step, for correct multi-layer pungetc.
10150 * left_in_line was decremented before preadbuffer(),
10151 * must inc next_to_pgetc: */
10152 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010153 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010154 }
Eric Andersencb57d552001-06-28 07:25:16 +000010155
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010156 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010157 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010158 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010159 again:
10160 more = preadfd();
10161 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010162 /* don't try reading again */
10163 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010164 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010165 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010166 return PEOF;
10167 }
10168 }
10169
Denis Vlasenko727752d2008-11-28 03:41:47 +000010170 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010171 * Set g_parsefile->left_in_line
10172 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010173 * NUL chars are deleted.
10174 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010175 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010176 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010177 char c;
Eric Andersencb57d552001-06-28 07:25:16 +000010178
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010179 more--;
Eric Andersenc470f442003-07-28 09:56:35 +000010180
Denis Vlasenko727752d2008-11-28 03:41:47 +000010181 c = *q;
10182 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010183 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010184 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010185 q++;
10186 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010187 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010188 break;
10189 }
Eric Andersencb57d552001-06-28 07:25:16 +000010190 }
10191
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010192 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010193 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10194 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010195 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010196 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010197 }
10198 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010199 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +000010200
Eric Andersencb57d552001-06-28 07:25:16 +000010201 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010202 char save = *q;
10203 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010204 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010205 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +000010206 }
10207
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010208 pgetc_debug("preadbuffer at %d:%p'%s'",
10209 g_parsefile->left_in_line,
10210 g_parsefile->next_to_pgetc,
10211 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +010010212 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010213}
10214
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010215static void
10216nlprompt(void)
10217{
10218 g_parsefile->linno++;
10219 setprompt_if(doprompt, 2);
10220}
10221static void
10222nlnoprompt(void)
10223{
10224 g_parsefile->linno++;
10225 needprompt = doprompt;
10226}
10227
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010228static int
10229pgetc(void)
10230{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010231 int c;
10232
10233 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010234 g_parsefile->left_in_line,
10235 g_parsefile->next_to_pgetc,
10236 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010237 if (g_parsefile->unget)
10238 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010239
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010240 if (--g_parsefile->left_in_line >= 0)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +010010241 c = (unsigned char)*g_parsefile->next_to_pgetc++;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010242 else
10243 c = preadbuffer();
10244
10245 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10246 g_parsefile->lastc[0] = c;
10247
10248 return c;
10249}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010250
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010251#if ENABLE_ASH_ALIAS
10252static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010253pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010254{
10255 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010256 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010257 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010258 g_parsefile->left_in_line,
10259 g_parsefile->next_to_pgetc,
10260 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010261 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010262 } while (c == PEOA);
10263 return c;
10264}
10265#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010266# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010267#endif
10268
10269/*
10270 * Read a line from the script.
10271 */
10272static char *
10273pfgets(char *line, int len)
10274{
10275 char *p = line;
10276 int nleft = len;
10277 int c;
10278
10279 while (--nleft > 0) {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010280 c = pgetc_without_PEOA();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010281 if (c == PEOF) {
10282 if (p == line)
10283 return NULL;
10284 break;
10285 }
10286 *p++ = c;
10287 if (c == '\n')
10288 break;
10289 }
10290 *p = '\0';
10291 return line;
10292}
10293
Eric Andersenc470f442003-07-28 09:56:35 +000010294/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010295 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010296 * PEOF may be pushed back.
10297 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010298static void
Eric Andersenc470f442003-07-28 09:56:35 +000010299pungetc(void)
10300{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010301 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010302}
10303
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010304/* This one eats backslash+newline */
10305static int
10306pgetc_eatbnl(void)
10307{
10308 int c;
10309
10310 while ((c = pgetc()) == '\\') {
10311 if (pgetc() != '\n') {
10312 pungetc();
10313 break;
10314 }
10315
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010316 nlprompt();
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010317 }
10318
10319 return c;
10320}
10321
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010322/*
10323 * To handle the "." command, a stack of input files is used. Pushfile
10324 * adds a new entry to the stack and popfile restores the previous level.
10325 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010326static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010327pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010328{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010329 struct parsefile *pf;
10330
Denis Vlasenko597906c2008-02-20 16:38:54 +000010331 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010332 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010333 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010334 /*pf->strpush = NULL; - ckzalloc did it */
10335 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010336 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010337 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010338}
10339
10340static void
10341popfile(void)
10342{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010343 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010344
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010010345 if (pf == &basepf)
10346 return;
10347
Denis Vlasenkob012b102007-02-19 22:43:01 +000010348 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010349 if (pf->pf_fd >= 0)
10350 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010351 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010352 while (pf->strpush)
10353 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010354 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010355 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010356 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010357}
10358
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010359/*
10360 * Return to top level.
10361 */
10362static void
10363popallfiles(void)
10364{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010365 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010366 popfile();
10367}
10368
10369/*
10370 * Close the file(s) that the shell is reading commands from. Called
10371 * after a fork is done.
10372 */
10373static void
10374closescript(void)
10375{
10376 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010377 if (g_parsefile->pf_fd > 0) {
10378 close(g_parsefile->pf_fd);
10379 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010380 }
10381}
10382
10383/*
10384 * Like setinputfile, but takes an open file descriptor. Call this with
10385 * interrupts off.
10386 */
10387static void
10388setinputfd(int fd, int push)
10389{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010390 if (push) {
10391 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010392 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010393 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010394 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010395 if (g_parsefile->buf == NULL)
10396 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010397 g_parsefile->left_in_buffer = 0;
10398 g_parsefile->left_in_line = 0;
10399 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010400}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010401
Eric Andersenc470f442003-07-28 09:56:35 +000010402/*
10403 * Set the input to take input from a file. If push is set, push the
10404 * old input onto the stack first.
10405 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010406static int
10407setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010408{
10409 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010410
Denis Vlasenkob012b102007-02-19 22:43:01 +000010411 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010412 fd = open(fname, O_RDONLY);
10413 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010414 if (flags & INPUT_NOFILE_OK)
10415 goto out;
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010416 exitstatus = 127;
Denis Vlasenko9604e1b2009-03-03 18:47:56 +000010417 ash_msg_and_raise_error("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010418 }
Denys Vlasenko64774602016-10-26 15:24:30 +020010419 if (fd < 10)
10420 fd = savefd(fd);
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020010421 else
10422 close_on_exec_on(fd);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010423 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010424 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010425 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010426 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010427}
10428
Eric Andersencb57d552001-06-28 07:25:16 +000010429/*
10430 * Like setinputfile, but takes input from a string.
10431 */
Eric Andersenc470f442003-07-28 09:56:35 +000010432static void
10433setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010434{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010435 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010436 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010437 g_parsefile->next_to_pgetc = string;
10438 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010439 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010440 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010441 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010442}
10443
10444
Denys Vlasenko70392332016-10-27 02:31:55 +020010445/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010446 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010447 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010448
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010449#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010450
Denys Vlasenko23841622015-10-09 15:52:03 +020010451/* Hash of mtimes of mailboxes */
10452static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010453/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010454static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010455
Eric Andersencb57d552001-06-28 07:25:16 +000010456/*
Eric Andersenc470f442003-07-28 09:56:35 +000010457 * Print appropriate message(s) if mail has arrived.
10458 * If mail_var_path_changed is set,
10459 * then the value of MAIL has mail_var_path_changed,
10460 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010461 */
Eric Andersenc470f442003-07-28 09:56:35 +000010462static void
10463chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010464{
Eric Andersencb57d552001-06-28 07:25:16 +000010465 const char *mpath;
10466 char *p;
10467 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010468 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010469 struct stackmark smark;
10470 struct stat statb;
10471
Eric Andersencb57d552001-06-28 07:25:16 +000010472 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010473 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010474 new_hash = 0;
10475 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010476 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010477 if (p == NULL)
10478 break;
10479 if (*p == '\0')
10480 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010481 for (q = p; *q; q++)
10482 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010483#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010484 if (q[-1] != '/')
10485 abort();
10486#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010487 q[-1] = '\0'; /* delete trailing '/' */
10488 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010489 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010490 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010491 /* Very simplistic "hash": just a sum of all mtimes */
10492 new_hash += (unsigned)statb.st_mtime;
10493 }
10494 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010495 if (mailtime_hash != 0)
10496 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010497 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010498 }
Eric Andersenc470f442003-07-28 09:56:35 +000010499 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010500 popstackmark(&smark);
10501}
Eric Andersencb57d552001-06-28 07:25:16 +000010502
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010503static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010504changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010505{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010506 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010507}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010508
Denis Vlasenko131ae172007-02-18 13:00:19 +000010509#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010510
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010511
10512/* ============ ??? */
10513
Eric Andersencb57d552001-06-28 07:25:16 +000010514/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010515 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010516 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010517static void
10518setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010519{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010520 char **newparam;
10521 char **ap;
10522 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010523
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010524 for (nparam = 0; argv[nparam]; nparam++)
10525 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010526 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10527 while (*argv) {
10528 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010529 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010530 *ap = NULL;
10531 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010532 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010533 shellparam.nparam = nparam;
10534 shellparam.p = newparam;
10535#if ENABLE_ASH_GETOPTS
10536 shellparam.optind = 1;
10537 shellparam.optoff = -1;
10538#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010539}
10540
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010541/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010542 * Process shell options. The global variable argptr contains a pointer
10543 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010544 *
10545 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10546 * For a non-interactive shell, an error condition encountered
10547 * by a special built-in ... shall cause the shell to write a diagnostic message
10548 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010549 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010550 * ...
10551 * Utility syntax error (option or operand error) Shall exit
10552 * ...
10553 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10554 * we see that bash does not do that (set "finishes" with error code 1 instead,
10555 * and shell continues), and people rely on this behavior!
10556 * Testcase:
10557 * set -o barfoo 2>/dev/null
10558 * echo $?
10559 *
10560 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010561 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010562static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010563plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010564{
10565 int i;
10566
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010567 if (name) {
10568 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010569 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010570 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010571 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010572 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010573 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010574 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010575 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010576 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010577 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010578 if (val) {
10579 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10580 } else {
10581 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10582 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010583 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010584 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010585}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010586static void
10587setoption(int flag, int val)
10588{
10589 int i;
10590
10591 for (i = 0; i < NOPTS; i++) {
10592 if (optletters(i) == flag) {
10593 optlist[i] = val;
10594 return;
10595 }
10596 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010597 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010598 /* NOTREACHED */
10599}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010600static int
Eric Andersenc470f442003-07-28 09:56:35 +000010601options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +000010602{
10603 char *p;
10604 int val;
10605 int c;
10606
10607 if (cmdline)
10608 minusc = NULL;
10609 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010610 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010611 if (c != '-' && c != '+')
10612 break;
10613 argptr++;
10614 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010615 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010616 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010617 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010618 if (!cmdline) {
10619 /* "-" means turn off -x and -v */
10620 if (p[0] == '\0')
10621 xflag = vflag = 0;
10622 /* "--" means reset params */
10623 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010624 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010625 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010626 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010627 }
Eric Andersencb57d552001-06-28 07:25:16 +000010628 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010629 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010630 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010631 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010632 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010633 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010634 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010635 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010636 /* it already printed err message */
10637 return 1; /* error */
10638 }
Eric Andersencb57d552001-06-28 07:25:16 +000010639 if (*argptr)
10640 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010641 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10642 isloginsh = 1;
10643 /* bash does not accept +-login, we also won't */
10644 } else if (cmdline && val && (c == '-')) { /* long options */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010645 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +000010646 isloginsh = 1;
10647 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010648 } else {
10649 setoption(c, val);
10650 }
10651 }
10652 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010653 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010654}
10655
Eric Andersencb57d552001-06-28 07:25:16 +000010656/*
Eric Andersencb57d552001-06-28 07:25:16 +000010657 * The shift builtin command.
10658 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010659static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010660shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010661{
10662 int n;
10663 char **ap1, **ap2;
10664
10665 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010666 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010667 n = number(argv[1]);
10668 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010669 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010670 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010671 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010672 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010673 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010674 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010675 }
10676 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010677 while ((*ap2++ = *ap1++) != NULL)
10678 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010679#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010680 shellparam.optind = 1;
10681 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010682#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010683 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010684 return 0;
10685}
10686
Eric Andersencb57d552001-06-28 07:25:16 +000010687/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010688 * POSIX requires that 'set' (but not export or readonly) output the
10689 * variables in lexicographic order - by the locale's collating order (sigh).
10690 * Maybe we could keep them in an ordered balanced binary tree
10691 * instead of hashed lists.
10692 * For now just roll 'em through qsort for printing...
10693 */
10694static int
10695showvars(const char *sep_prefix, int on, int off)
10696{
10697 const char *sep;
10698 char **ep, **epend;
10699
10700 ep = listvars(on, off, &epend);
10701 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10702
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010703 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010704
10705 for (; ep < epend; ep++) {
10706 const char *p;
10707 const char *q;
10708
10709 p = strchrnul(*ep, '=');
10710 q = nullstr;
10711 if (*p)
10712 q = single_quote(++p);
10713 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10714 }
10715 return 0;
10716}
10717
10718/*
Eric Andersencb57d552001-06-28 07:25:16 +000010719 * The set command builtin.
10720 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010721static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010722setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010723{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010724 int retval;
10725
Denis Vlasenko68404f12008-03-17 09:00:54 +000010726 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010727 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010728
Denis Vlasenkob012b102007-02-19 22:43:01 +000010729 INT_OFF;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010730 retval = options(/*cmdline:*/ 0);
10731 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010732 optschanged();
10733 if (*argptr != NULL) {
10734 setparam(argptr);
10735 }
Eric Andersencb57d552001-06-28 07:25:16 +000010736 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010737 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010738 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010739}
10740
Denis Vlasenko131ae172007-02-18 13:00:19 +000010741#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010742static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010743change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010744{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010745 uint32_t t;
10746
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010747 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010748 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010749 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010750 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010751 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010752 vrandom.flags &= ~VNOFUNC;
10753 } else {
10754 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010755 t = strtoul(value, NULL, 10);
10756 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010757 }
Eric Andersenef02f822004-03-11 13:34:24 +000010758}
Eric Andersen16767e22004-03-16 05:14:10 +000010759#endif
10760
Denis Vlasenko131ae172007-02-18 13:00:19 +000010761#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010762static int
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010763getopts(char *optstr, char *optvar, char **optfirst)
Eric Andersencb57d552001-06-28 07:25:16 +000010764{
10765 char *p, *q;
10766 char c = '?';
10767 int done = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010768 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000010769 char **optnext;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010770 int ind = shellparam.optind;
10771 int off = shellparam.optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010772
Denys Vlasenko9c541002015-10-07 15:44:36 +020010773 sbuf[1] = '\0';
10774
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010775 shellparam.optind = -1;
10776 optnext = optfirst + ind - 1;
Eric Andersena48b0a32003-10-22 10:56:47 +000010777
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010778 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
Eric Andersencb57d552001-06-28 07:25:16 +000010779 p = NULL;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010780 else
10781 p = optnext[-1] + off;
Eric Andersencb57d552001-06-28 07:25:16 +000010782 if (p == NULL || *p == '\0') {
10783 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010784 p = *optnext;
10785 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010786 atend:
Eric Andersencb57d552001-06-28 07:25:16 +000010787 p = NULL;
10788 done = 1;
10789 goto out;
10790 }
10791 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010792 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010793 goto atend;
10794 }
10795
10796 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010797 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010798 if (*q == '\0') {
10799 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010800 sbuf[0] = c;
10801 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010802 setvar0("OPTARG", sbuf);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010803 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010804 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010805 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010806 }
10807 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010808 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010809 }
10810 if (*++q == ':')
10811 q++;
10812 }
10813
10814 if (*++q == ':') {
10815 if (*p == '\0' && (p = *optnext) == NULL) {
10816 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010817 sbuf[0] = c;
10818 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010819 setvar0("OPTARG", sbuf);
Eric Andersencb57d552001-06-28 07:25:16 +000010820 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010821 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010822 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010823 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010824 c = '?';
10825 }
Eric Andersenc470f442003-07-28 09:56:35 +000010826 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010827 }
10828
10829 if (p == *optnext)
10830 optnext++;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010831 setvar0("OPTARG", p);
Eric Andersencb57d552001-06-28 07:25:16 +000010832 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010833 } else
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010834 setvar0("OPTARG", nullstr);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010835 out:
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010836 ind = optnext - optfirst + 1;
10837 setvar("OPTIND", itoa(ind), VNOFUNC);
Denys Vlasenko9c541002015-10-07 15:44:36 +020010838 sbuf[0] = c;
10839 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010840 setvar0(optvar, sbuf);
10841
10842 shellparam.optoff = p ? p - *(optnext - 1) : -1;
10843 shellparam.optind = ind;
10844
Eric Andersencb57d552001-06-28 07:25:16 +000010845 return done;
10846}
Eric Andersenc470f442003-07-28 09:56:35 +000010847
10848/*
10849 * The getopts builtin. Shellparam.optnext points to the next argument
10850 * to be processed. Shellparam.optptr points to the next character to
10851 * be processed in the current argument. If shellparam.optnext is NULL,
10852 * then it's the first time getopts has been called.
10853 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010854static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000010855getoptscmd(int argc, char **argv)
10856{
10857 char **optbase;
10858
10859 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010860 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010861 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000010862 optbase = shellparam.p;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010863 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
Eric Andersenc470f442003-07-28 09:56:35 +000010864 shellparam.optind = 1;
10865 shellparam.optoff = -1;
10866 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010867 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010868 optbase = &argv[3];
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010869 if ((unsigned)shellparam.optind > argc - 2) {
Eric Andersenc470f442003-07-28 09:56:35 +000010870 shellparam.optind = 1;
10871 shellparam.optoff = -1;
10872 }
10873 }
10874
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010875 return getopts(argv[1], argv[2], optbase);
Eric Andersenc470f442003-07-28 09:56:35 +000010876}
Denis Vlasenko131ae172007-02-18 13:00:19 +000010877#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000010878
Eric Andersencb57d552001-06-28 07:25:16 +000010879
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010880/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000010881
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010882struct heredoc {
10883 struct heredoc *next; /* next here document in list */
10884 union node *here; /* redirection node */
10885 char *eofmark; /* string indicating end of input */
10886 smallint striptabs; /* if set, strip leading tabs */
10887};
10888
10889static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010890static smallint quoteflag; /* set if (part of) last token was quoted */
10891static token_id_t lasttoken; /* last token read (integer id Txxx) */
10892static struct heredoc *heredoclist; /* list of here documents to read */
10893static char *wordtext; /* text of last word returned by readtoken */
10894static struct nodelist *backquotelist;
10895static union node *redirnode;
10896static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010897
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010898static const char *
10899tokname(char *buf, int tok)
10900{
10901 if (tok < TSEMI)
Denys Vlasenko888527c2016-10-02 16:54:17 +020010902 return tokname_array[tok];
10903 sprintf(buf, "\"%s\"", tokname_array[tok]);
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010904 return buf;
10905}
10906
10907/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010908 * Called when an unexpected token is read during the parse. The argument
10909 * is the token that is expected, or -1 if more than one type of token can
10910 * occur at this point.
10911 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010912static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010913static void
10914raise_error_unexpected_syntax(int token)
10915{
10916 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010917 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010918 int l;
10919
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010920 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010921 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010922 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010923 raise_error_syntax(msg);
10924 /* NOTREACHED */
10925}
Eric Andersencb57d552001-06-28 07:25:16 +000010926
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010927#define EOFMARKLEN 79
Eric Andersencb57d552001-06-28 07:25:16 +000010928
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010929/* parsing is heavily cross-recursive, need these forward decls */
10930static union node *andor(void);
10931static union node *pipeline(void);
10932static union node *parse_command(void);
10933static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000010934static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010935static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000010936
Eric Andersenc470f442003-07-28 09:56:35 +000010937static union node *
10938list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000010939{
10940 union node *n1, *n2, *n3;
10941 int tok;
10942
Eric Andersencb57d552001-06-28 07:25:16 +000010943 n1 = NULL;
10944 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010945 switch (peektoken()) {
10946 case TNL:
10947 if (!(nlflag & 1))
10948 break;
10949 parseheredoc();
10950 return n1;
10951
10952 case TEOF:
10953 if (!n1 && (nlflag & 1))
10954 n1 = NODE_EOF;
10955 parseheredoc();
10956 return n1;
10957 }
10958
10959 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko888527c2016-10-02 16:54:17 +020010960 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
Ron Yorstonc0e00762015-10-29 11:30:55 +000010961 return n1;
10962 nlflag |= 2;
10963
Eric Andersencb57d552001-06-28 07:25:16 +000010964 n2 = andor();
10965 tok = readtoken();
10966 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000010967 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010968 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010969 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010970 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010971 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000010972 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010973 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010974 n2 = n3;
10975 }
10976 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000010977 }
10978 }
10979 if (n1 == NULL) {
10980 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010981 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010982 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010983 n3->type = NSEMI;
10984 n3->nbinary.ch1 = n1;
10985 n3->nbinary.ch2 = n2;
10986 n1 = n3;
10987 }
10988 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010989 case TNL:
10990 case TEOF:
10991 tokpushback = 1;
10992 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000010993 case TBACKGND:
10994 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000010995 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010996 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000010997 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010998 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010999 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011000 return n1;
11001 }
11002 }
11003}
11004
Eric Andersenc470f442003-07-28 09:56:35 +000011005static union node *
11006andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011007{
Eric Andersencb57d552001-06-28 07:25:16 +000011008 union node *n1, *n2, *n3;
11009 int t;
11010
Eric Andersencb57d552001-06-28 07:25:16 +000011011 n1 = pipeline();
11012 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011013 t = readtoken();
11014 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000011015 t = NAND;
11016 } else if (t == TOR) {
11017 t = NOR;
11018 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011019 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011020 return n1;
11021 }
Eric Andersenc470f442003-07-28 09:56:35 +000011022 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011023 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011024 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011025 n3->type = t;
11026 n3->nbinary.ch1 = n1;
11027 n3->nbinary.ch2 = n2;
11028 n1 = n3;
11029 }
11030}
11031
Eric Andersenc470f442003-07-28 09:56:35 +000011032static union node *
11033pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011034{
Eric Andersencb57d552001-06-28 07:25:16 +000011035 union node *n1, *n2, *pipenode;
11036 struct nodelist *lp, *prev;
11037 int negate;
11038
11039 negate = 0;
11040 TRACE(("pipeline: entered\n"));
11041 if (readtoken() == TNOT) {
11042 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000011043 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011044 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011045 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011046 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011047 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011048 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000011049 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011050 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011051 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000011052 pipenode->npipe.cmdlist = lp;
11053 lp->n = n1;
11054 do {
11055 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011056 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000011057 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011058 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011059 prev->next = lp;
11060 } while (readtoken() == TPIPE);
11061 lp->next = NULL;
11062 n1 = pipenode;
11063 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011064 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011065 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011066 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000011067 n2->type = NNOT;
11068 n2->nnot.com = n1;
11069 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011070 }
11071 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000011072}
11073
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011074static union node *
11075makename(void)
11076{
11077 union node *n;
11078
Denis Vlasenko597906c2008-02-20 16:38:54 +000011079 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011080 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011081 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011082 n->narg.text = wordtext;
11083 n->narg.backquote = backquotelist;
11084 return n;
11085}
11086
11087static void
11088fixredir(union node *n, const char *text, int err)
11089{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011090 int fd;
11091
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011092 TRACE(("Fix redir %s %d\n", text, err));
11093 if (!err)
11094 n->ndup.vname = NULL;
11095
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011096 fd = bb_strtou(text, NULL, 10);
11097 if (!errno && fd >= 0)
11098 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011099 else if (LONE_DASH(text))
11100 n->ndup.dupfd = -1;
11101 else {
11102 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011103 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011104 n->ndup.vname = makename();
11105 }
11106}
11107
11108/*
11109 * Returns true if the text contains nothing to expand (no dollar signs
11110 * or backquotes).
11111 */
11112static int
Denis Vlasenko68819d12008-12-15 11:26:36 +000011113noexpand(const char *text)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011114{
Denys Vlasenkocd716832009-11-28 22:14:02 +010011115 unsigned char c;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011116
Denys Vlasenkocd716832009-11-28 22:14:02 +010011117 while ((c = *text++) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011118 if (c == CTLQUOTEMARK)
11119 continue;
11120 if (c == CTLESC)
Denys Vlasenkocd716832009-11-28 22:14:02 +010011121 text++;
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011122 else if (SIT(c, BASESYNTAX) == CCTL)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011123 return 0;
11124 }
11125 return 1;
11126}
11127
11128static void
11129parsefname(void)
11130{
11131 union node *n = redirnode;
11132
11133 if (readtoken() != TWORD)
11134 raise_error_unexpected_syntax(-1);
11135 if (n->type == NHERE) {
11136 struct heredoc *here = heredoc;
11137 struct heredoc *p;
11138 int i;
11139
11140 if (quoteflag == 0)
11141 n->type = NXHERE;
11142 TRACE(("Here document %d\n", n->type));
11143 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011144 raise_error_syntax("illegal eof marker for << redirection");
Denys Vlasenkob6c84342009-08-29 20:23:20 +020011145 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011146 here->eofmark = wordtext;
11147 here->next = NULL;
11148 if (heredoclist == NULL)
11149 heredoclist = here;
11150 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011151 for (p = heredoclist; p->next; p = p->next)
11152 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011153 p->next = here;
11154 }
11155 } else if (n->type == NTOFD || n->type == NFROMFD) {
11156 fixredir(n, wordtext, 0);
11157 } else {
11158 n->nfile.fname = makename();
11159 }
11160}
Eric Andersencb57d552001-06-28 07:25:16 +000011161
Eric Andersenc470f442003-07-28 09:56:35 +000011162static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011163simplecmd(void)
11164{
11165 union node *args, **app;
11166 union node *n = NULL;
11167 union node *vars, **vpp;
11168 union node **rpp, *redir;
11169 int savecheckkwd;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011170#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011171 smallint double_brackets_flag = 0;
11172#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011173 IF_BASH_FUNCTION(smallint function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011174
11175 args = NULL;
11176 app = &args;
11177 vars = NULL;
11178 vpp = &vars;
11179 redir = NULL;
11180 rpp = &redir;
11181
11182 savecheckkwd = CHKALIAS;
11183 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000011184 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011185 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011186 t = readtoken();
11187 switch (t) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011188#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011189 case TFUNCTION:
11190 if (peektoken() != TWORD)
11191 raise_error_unexpected_syntax(TWORD);
11192 function_flag = 1;
11193 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011194#endif
11195#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011196 case TAND: /* "&&" */
11197 case TOR: /* "||" */
11198 if (!double_brackets_flag) {
11199 tokpushback = 1;
11200 goto out;
11201 }
11202 wordtext = (char *) (t == TAND ? "-a" : "-o");
11203#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011204 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011205 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011206 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011207 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011208 n->narg.text = wordtext;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011209#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011210 if (strcmp("[[", wordtext) == 0)
11211 double_brackets_flag = 1;
11212 else if (strcmp("]]", wordtext) == 0)
11213 double_brackets_flag = 0;
11214#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011215 n->narg.backquote = backquotelist;
11216 if (savecheckkwd && isassignment(wordtext)) {
11217 *vpp = n;
11218 vpp = &n->narg.next;
11219 } else {
11220 *app = n;
11221 app = &n->narg.next;
11222 savecheckkwd = 0;
11223 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011224#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011225 if (function_flag) {
11226 checkkwd = CHKNL | CHKKWD;
11227 switch (peektoken()) {
11228 case TBEGIN:
11229 case TIF:
11230 case TCASE:
11231 case TUNTIL:
11232 case TWHILE:
11233 case TFOR:
11234 goto do_func;
11235 case TLP:
11236 function_flag = 0;
11237 break;
11238 case TWORD:
11239 if (strcmp("[[", wordtext) == 0)
11240 goto do_func;
11241 /* fall through */
11242 default:
11243 raise_error_unexpected_syntax(-1);
11244 }
11245 }
11246#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011247 break;
11248 case TREDIR:
11249 *rpp = n = redirnode;
11250 rpp = &n->nfile.next;
11251 parsefname(); /* read name of redirection file */
11252 break;
11253 case TLP:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011254 IF_BASH_FUNCTION(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011255 if (args && app == &args->narg.next
11256 && !vars && !redir
11257 ) {
11258 struct builtincmd *bcmd;
11259 const char *name;
11260
11261 /* We have a function */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011262 if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011263 raise_error_unexpected_syntax(TRP);
11264 name = n->narg.text;
11265 if (!goodname(name)
11266 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11267 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011268 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011269 }
11270 n->type = NDEFUN;
11271 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11272 n->narg.next = parse_command();
11273 return n;
11274 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011275 IF_BASH_FUNCTION(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011276 /* fall through */
11277 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011278 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011279 goto out;
11280 }
11281 }
11282 out:
11283 *app = NULL;
11284 *vpp = NULL;
11285 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011286 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011287 n->type = NCMD;
11288 n->ncmd.args = args;
11289 n->ncmd.assign = vars;
11290 n->ncmd.redirect = redir;
11291 return n;
11292}
11293
11294static union node *
11295parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011296{
Eric Andersencb57d552001-06-28 07:25:16 +000011297 union node *n1, *n2;
11298 union node *ap, **app;
11299 union node *cp, **cpp;
11300 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011301 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011302 int t;
11303
11304 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011305 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011306
Eric Andersencb57d552001-06-28 07:25:16 +000011307 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011308 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011309 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011310 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011311 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011312 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011313 n1->type = NIF;
11314 n1->nif.test = list(0);
11315 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011316 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011317 n1->nif.ifpart = list(0);
11318 n2 = n1;
11319 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011320 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011321 n2 = n2->nif.elsepart;
11322 n2->type = NIF;
11323 n2->nif.test = list(0);
11324 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011325 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011326 n2->nif.ifpart = list(0);
11327 }
11328 if (lasttoken == TELSE)
11329 n2->nif.elsepart = list(0);
11330 else {
11331 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011332 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011333 }
Eric Andersenc470f442003-07-28 09:56:35 +000011334 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011335 break;
11336 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011337 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011338 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011339 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011340 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011341 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011342 got = readtoken();
11343 if (got != TDO) {
Denys Vlasenko888527c2016-10-02 16:54:17 +020011344 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
Denis Vlasenko131ae172007-02-18 13:00:19 +000011345 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011346 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011347 }
11348 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011349 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011350 break;
11351 }
11352 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011353 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011354 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011355 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011356 n1->type = NFOR;
11357 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011358 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011359 if (readtoken() == TIN) {
11360 app = &ap;
11361 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011362 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011363 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011364 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011365 n2->narg.text = wordtext;
11366 n2->narg.backquote = backquotelist;
11367 *app = n2;
11368 app = &n2->narg.next;
11369 }
11370 *app = NULL;
11371 n1->nfor.args = ap;
11372 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011373 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011374 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011375 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011376 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011377 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011378 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011379 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011380 n1->nfor.args = n2;
11381 /*
11382 * Newline or semicolon here is optional (but note
11383 * that the original Bourne shell only allowed NL).
11384 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011385 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011386 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011387 }
Eric Andersenc470f442003-07-28 09:56:35 +000011388 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011389 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011390 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011391 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011392 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011393 break;
11394 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011395 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011396 n1->type = NCASE;
11397 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011398 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011399 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011400 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011401 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011402 n2->narg.text = wordtext;
11403 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011404 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11405 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011406 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011407 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011408 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011409 checkkwd = CHKNL | CHKKWD;
11410 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011411 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011412 if (lasttoken == TLP)
11413 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011414 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011415 cp->type = NCLIST;
11416 app = &cp->nclist.pattern;
11417 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011418 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011419 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011420 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011421 ap->narg.text = wordtext;
11422 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011423 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011424 break;
11425 app = &ap->narg.next;
11426 readtoken();
11427 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011428 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011429 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011430 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011431 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011432
Eric Andersenc470f442003-07-28 09:56:35 +000011433 cpp = &cp->nclist.next;
11434
11435 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011436 t = readtoken();
11437 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011438 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011439 raise_error_unexpected_syntax(TENDCASE);
11440 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011441 }
Eric Andersenc470f442003-07-28 09:56:35 +000011442 }
Eric Andersencb57d552001-06-28 07:25:16 +000011443 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011444 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011445 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011446 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011447 n1->type = NSUBSHELL;
11448 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011449 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011450 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011451 break;
11452 case TBEGIN:
11453 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011454 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011455 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011456 IF_BASH_FUNCTION(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011457 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011458 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011459 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011460 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011461 }
11462
Eric Andersenc470f442003-07-28 09:56:35 +000011463 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011464 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011465
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011466 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011467 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011468 checkkwd = CHKKWD | CHKALIAS;
11469 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011470 while (readtoken() == TREDIR) {
11471 *rpp = n2 = redirnode;
11472 rpp = &n2->nfile.next;
11473 parsefname();
11474 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011475 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011476 *rpp = NULL;
11477 if (redir) {
11478 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011479 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011480 n2->type = NREDIR;
11481 n2->nredir.n = n1;
11482 n1 = n2;
11483 }
11484 n1->nredir.redirect = redir;
11485 }
Eric Andersencb57d552001-06-28 07:25:16 +000011486 return n1;
11487}
11488
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011489#if BASH_DOLLAR_SQUOTE
Denys Vlasenko37dc08b2016-10-02 04:38:07 +020011490static int
11491decode_dollar_squote(void)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011492{
11493 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11494 int c, cnt;
11495 char *p;
11496 char buf[4];
11497
11498 c = pgetc();
11499 p = strchr(C_escapes, c);
11500 if (p) {
11501 buf[0] = c;
11502 p = buf;
11503 cnt = 3;
11504 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11505 do {
11506 c = pgetc();
11507 *++p = c;
11508 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11509 pungetc();
11510 } else if (c == 'x') { /* \xHH */
11511 do {
11512 c = pgetc();
11513 *++p = c;
11514 } while (isxdigit(c) && --cnt);
11515 pungetc();
11516 if (cnt == 3) { /* \x but next char is "bad" */
11517 c = 'x';
11518 goto unrecognized;
11519 }
11520 } else { /* simple seq like \\ or \t */
11521 p++;
11522 }
11523 *p = '\0';
11524 p = buf;
11525 c = bb_process_escape_sequence((void*)&p);
11526 } else { /* unrecognized "\z": print both chars unless ' or " */
11527 if (c != '\'' && c != '"') {
11528 unrecognized:
11529 c |= 0x100; /* "please encode \, then me" */
11530 }
11531 }
11532 return c;
11533}
11534#endif
11535
Eric Andersencb57d552001-06-28 07:25:16 +000011536/*
11537 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11538 * is not NULL, read a here document. In the latter case, eofmark is the
11539 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011540 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011541 * is the first character of the input token or document.
11542 *
11543 * Because C does not have internal subroutines, I have simulated them
11544 * using goto's to implement the subroutine linkage. The following macros
11545 * will run code that appears at the end of readtoken1.
11546 */
Eric Andersen2870d962001-07-02 17:27:21 +000011547#define CHECKEND() {goto checkend; checkend_return:;}
11548#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11549#define PARSESUB() {goto parsesub; parsesub_return:;}
11550#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11551#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11552#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011553static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011554readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011555{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011556 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011557 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011558 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020011559 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +000011560 char line[EOFMARKLEN + 1];
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011561 struct nodelist *bqlist;
11562 smallint quotef;
11563 smallint dblquote;
11564 smallint oldstyle;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011565 IF_FEATURE_SH_MATH(smallint prevsyntax;) /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011566 smallint pssyntax; /* we are expanding a prompt string */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011567 int varnest; /* levels of variables expansion */
Denys Vlasenko0b883582016-12-23 16:49:07 +010011568 IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */
11569 IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011570 int dqvarnest; /* levels of variables expansion within double quotes */
11571
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011572 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011573
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011574 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011575 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011576 quotef = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011577 IF_FEATURE_SH_MATH(prevsyntax = 0;)
Denis Vlasenko46a53062007-09-24 18:30:02 +000011578 pssyntax = (syntax == PSSYNTAX);
11579 if (pssyntax)
11580 syntax = DQSYNTAX;
Denis Vlasenko46a53062007-09-24 18:30:02 +000011581 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011582 varnest = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011583 IF_FEATURE_SH_MATH(arinest = 0;)
11584 IF_FEATURE_SH_MATH(parenlevel = 0;)
Eric Andersencb57d552001-06-28 07:25:16 +000011585 dqvarnest = 0;
11586
11587 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011588 loop:
11589 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011590 CHECKEND(); /* set c to PEOF if at end of here document */
11591 for (;;) { /* until end of line or end of word */
11592 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11593 switch (SIT(c, syntax)) {
11594 case CNL: /* '\n' */
11595 if (syntax == BASESYNTAX)
11596 goto endword; /* exit outer loop */
11597 USTPUTC(c, out);
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011598 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011599 c = pgetc();
11600 goto loop; /* continue outer loop */
11601 case CWORD:
11602 USTPUTC(c, out);
11603 break;
11604 case CCTL:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011605#if BASH_DOLLAR_SQUOTE
Denys Vlasenko958581a2010-09-12 15:04:27 +020011606 if (c == '\\' && bash_dollar_squote) {
11607 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020011608 if (c == '\0') {
11609 /* skip $'\000', $'\x00' (like bash) */
11610 break;
11611 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011612 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020011613 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011614 c = (unsigned char)c;
Denys Vlasenko13f20912016-09-25 20:54:25 +020011615 if (eofmark == NULL || dblquote)
11616 USTPUTC(CTLESC, out);
11617 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011618 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011619 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011620#endif
Denys Vlasenko13f20912016-09-25 20:54:25 +020011621 if (eofmark == NULL || dblquote)
11622 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011623 USTPUTC(c, out);
11624 break;
11625 case CBACK: /* backslash */
11626 c = pgetc_without_PEOA();
11627 if (c == PEOF) {
11628 USTPUTC(CTLESC, out);
11629 USTPUTC('\\', out);
11630 pungetc();
11631 } else if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011632 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011633 } else {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011634 if (c == '$' && pssyntax) {
Eric Andersenc470f442003-07-28 09:56:35 +000011635 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011636 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011637 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011638 /* Backslash is retained if we are in "str" and next char isn't special */
11639 if (dblquote
11640 && c != '\\'
11641 && c != '`'
11642 && c != '$'
11643 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011644 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011645 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011646 }
Ron Yorston549deab2015-05-18 09:57:51 +020011647 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011648 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011649 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011650 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011651 break;
11652 case CSQUOTE:
11653 syntax = SQSYNTAX;
11654 quotemark:
11655 if (eofmark == NULL) {
11656 USTPUTC(CTLQUOTEMARK, out);
11657 }
11658 break;
11659 case CDQUOTE:
11660 syntax = DQSYNTAX;
11661 dblquote = 1;
11662 goto quotemark;
11663 case CENDQUOTE:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011664 IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020011665 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011666 USTPUTC(c, out);
11667 } else {
11668 if (dqvarnest == 0) {
11669 syntax = BASESYNTAX;
11670 dblquote = 0;
11671 }
11672 quotef = 1;
11673 goto quotemark;
11674 }
11675 break;
11676 case CVAR: /* '$' */
11677 PARSESUB(); /* parse substitution */
11678 break;
11679 case CENDVAR: /* '}' */
11680 if (varnest > 0) {
11681 varnest--;
11682 if (dqvarnest > 0) {
11683 dqvarnest--;
11684 }
11685 c = CTLENDVAR;
11686 }
11687 USTPUTC(c, out);
11688 break;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011689#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko958581a2010-09-12 15:04:27 +020011690 case CLP: /* '(' in arithmetic */
11691 parenlevel++;
11692 USTPUTC(c, out);
11693 break;
11694 case CRP: /* ')' in arithmetic */
11695 if (parenlevel > 0) {
11696 parenlevel--;
11697 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011698 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020011699 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011700 if (--arinest == 0) {
11701 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011702 }
11703 } else {
11704 /*
11705 * unbalanced parens
11706 * (don't 2nd guess - no error)
11707 */
11708 pungetc();
11709 }
11710 }
11711 USTPUTC(c, out);
11712 break;
11713#endif
11714 case CBQUOTE: /* '`' */
11715 PARSEBACKQOLD();
11716 break;
11717 case CENDFILE:
11718 goto endword; /* exit outer loop */
11719 case CIGN:
11720 break;
11721 default:
11722 if (varnest == 0) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011723#if BASH_REDIR_OUTPUT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011724 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011725//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020011726 if (pgetc() == '>')
11727 c = 0x100 + '>'; /* flag &> */
11728 pungetc();
11729 }
11730#endif
11731 goto endword; /* exit outer loop */
11732 }
11733 IF_ASH_ALIAS(if (c != PEOA))
11734 USTPUTC(c, out);
11735 }
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020011736 c = pgetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011737 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011738 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011739
Denys Vlasenko0b883582016-12-23 16:49:07 +010011740#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000011741 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011742 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011743#endif
Ron Yorston0e056f72015-07-01 16:45:40 +010011744 if (syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011745 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011746 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011747 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011748 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011749 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011750 }
11751 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011752 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011753 out = stackblock();
11754 if (eofmark == NULL) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011755 if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011756 && quotef == 0
11757 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011758 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011759 PARSEREDIR(); /* passed as params: out, c */
11760 lasttoken = TREDIR;
11761 return lasttoken;
11762 }
11763 /* else: non-number X seen, interpret it
11764 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011765 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011766 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011767 }
11768 quoteflag = quotef;
11769 backquotelist = bqlist;
11770 grabstackblock(len);
11771 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011772 lasttoken = TWORD;
11773 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011774/* end of readtoken routine */
11775
Eric Andersencb57d552001-06-28 07:25:16 +000011776/*
11777 * Check to see whether we are at the end of the here document. When this
11778 * is called, c is set to the first character of the next input line. If
11779 * we are at the end of the here document, this routine sets the c to PEOF.
11780 */
Eric Andersenc470f442003-07-28 09:56:35 +000011781checkend: {
11782 if (eofmark) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000011783#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011784 if (c == PEOA)
11785 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011786#endif
11787 if (striptabs) {
11788 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011789 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011790 }
Eric Andersenc470f442003-07-28 09:56:35 +000011791 }
11792 if (c == *eofmark) {
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011793 if (pfgets(line, sizeof(line)) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000011794 char *p, *q;
Denys Vlasenko350e6862016-10-26 16:26:45 +020011795 int cc;
Eric Andersencb57d552001-06-28 07:25:16 +000011796
Eric Andersenc470f442003-07-28 09:56:35 +000011797 p = line;
Denys Vlasenko350e6862016-10-26 16:26:45 +020011798 for (q = eofmark + 1;; p++, q++) {
11799 cc = *p;
11800 if (cc == '\n')
11801 cc = 0;
11802 if (!*q || cc != *q)
11803 break;
11804 }
11805 if (cc == *q) {
Eric Andersenc470f442003-07-28 09:56:35 +000011806 c = PEOF;
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011807 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011808 } else {
11809 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011810 }
11811 }
11812 }
11813 }
Eric Andersenc470f442003-07-28 09:56:35 +000011814 goto checkend_return;
11815}
Eric Andersencb57d552001-06-28 07:25:16 +000011816
Eric Andersencb57d552001-06-28 07:25:16 +000011817/*
11818 * Parse a redirection operator. The variable "out" points to a string
11819 * specifying the fd to be redirected. The variable "c" contains the
11820 * first character of the redirection operator.
11821 */
Eric Andersenc470f442003-07-28 09:56:35 +000011822parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011823 /* out is already checked to be a valid number or "" */
11824 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000011825 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000011826
Denis Vlasenko597906c2008-02-20 16:38:54 +000011827 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000011828 if (c == '>') {
11829 np->nfile.fd = 1;
11830 c = pgetc();
11831 if (c == '>')
11832 np->type = NAPPEND;
11833 else if (c == '|')
11834 np->type = NCLOBBER;
11835 else if (c == '&')
11836 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011837 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000011838 else {
11839 np->type = NTO;
11840 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011841 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000011842 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011843#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000011844 else if (c == 0x100 + '>') { /* this flags &> redirection */
11845 np->nfile.fd = 1;
11846 pgetc(); /* this is '>', no need to check */
11847 np->type = NTO2;
11848 }
11849#endif
11850 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000011851 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011852 c = pgetc();
11853 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000011854 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011855 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011856 np = stzalloc(sizeof(struct nhere));
11857 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011858 }
11859 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011860 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000011861 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011862 c = pgetc();
11863 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000011864 heredoc->striptabs = 1;
11865 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011866 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011867 pungetc();
11868 }
11869 break;
11870
11871 case '&':
11872 np->type = NFROMFD;
11873 break;
11874
11875 case '>':
11876 np->type = NFROMTO;
11877 break;
11878
11879 default:
11880 np->type = NFROM;
11881 pungetc();
11882 break;
11883 }
Eric Andersencb57d552001-06-28 07:25:16 +000011884 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011885 if (fd >= 0)
11886 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011887 redirnode = np;
11888 goto parseredir_return;
11889}
Eric Andersencb57d552001-06-28 07:25:16 +000011890
Eric Andersencb57d552001-06-28 07:25:16 +000011891/*
11892 * Parse a substitution. At this point, we have read the dollar sign
11893 * and nothing else.
11894 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000011895
11896/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11897 * (assuming ascii char codes, as the original implementation did) */
11898#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011899 (((unsigned)(c) - 33 < 32) \
11900 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000011901parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010011902 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011903 int typeloc;
Eric Andersencb57d552001-06-28 07:25:16 +000011904
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011905 c = pgetc_eatbnl();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011906 if (c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011907 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000011908 ) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011909#if BASH_DOLLAR_SQUOTE
Ron Yorston84ba50c2016-04-03 22:43:14 +010011910 if (syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011911 bash_dollar_squote = 1;
11912 else
11913#endif
11914 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011915 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011916 } else if (c == '(') {
11917 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011918 if (pgetc_eatbnl() == '(') {
Denys Vlasenko0b883582016-12-23 16:49:07 +010011919#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000011920 PARSEARITH();
11921#else
Mike Frysinger98a6f562008-06-09 09:38:45 +000011922 raise_error_syntax("you disabled math support for $((arith)) syntax");
Eric Andersenc470f442003-07-28 09:56:35 +000011923#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011924 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011925 pungetc();
11926 PARSEBACKQNEW();
11927 }
11928 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011929 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000011930 USTPUTC(CTLVAR, out);
11931 typeloc = out - (char *)stackblock();
Denys Vlasenko3df14102016-10-26 16:41:13 +020011932 STADJUST(1, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011933 subtype = VSNORMAL;
11934 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011935 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011936 subtype = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011937 }
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011938 varname:
Denys Vlasenko3df14102016-10-26 16:41:13 +020011939 if (is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011940 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011941 do {
11942 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011943 c = pgetc_eatbnl();
Denys Vlasenko3df14102016-10-26 16:41:13 +020011944 } while (is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011945 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011946 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011947 do {
11948 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011949 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011950 } while (isdigit(c));
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011951 } else if (is_special(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011952 /* $[{[#]]<specialchar>[}] */
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011953 int cc = c;
11954
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011955 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011956 if (!subtype && cc == '#') {
11957 subtype = VSLENGTH;
11958 if (c == '_' || isalnum(c))
11959 goto varname;
11960 cc = c;
11961 c = pgetc_eatbnl();
11962 if (cc == '}' || c != '}') {
11963 pungetc();
11964 subtype = 0;
11965 c = cc;
11966 cc = '#';
11967 }
11968 }
11969 USTPUTC(cc, out);
Denis Vlasenko559691a2008-10-05 18:39:31 +000011970 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020011971 goto badsub;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011972 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011973 if (c != '}' && subtype == VSLENGTH) {
11974 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020011975 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011976 }
Eric Andersencb57d552001-06-28 07:25:16 +000011977
Eric Andersenc470f442003-07-28 09:56:35 +000011978 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011979 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011980 /* ${VAR...} but not $VAR or ${#VAR} */
11981 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000011982 switch (c) {
11983 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011984 c = pgetc_eatbnl();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011985#if BASH_SUBSTR
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011986 /* This check is only needed to not misinterpret
11987 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
11988 * constructs.
11989 */
11990 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011991 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011992 pungetc();
Denys Vlasenko88e15702016-10-26 01:55:56 +020011993 break; /* "goto badsub" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011994 }
11995#endif
Denys Vlasenko3df14102016-10-26 16:41:13 +020011996 subtype = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000011997 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011998 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011999 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000012000 if (p == NULL)
Denys Vlasenko88e15702016-10-26 01:55:56 +020012001 break;
Denys Vlasenko3df14102016-10-26 16:41:13 +020012002 subtype |= p - types + VSNORMAL;
Eric Andersenc470f442003-07-28 09:56:35 +000012003 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012004 }
Eric Andersenc470f442003-07-28 09:56:35 +000012005 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012006 case '#': {
12007 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012008 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012009 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012010 if (c != cc)
Denys Vlasenko88e15702016-10-26 01:55:56 +020012011 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012012 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012013 break;
12014 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012015#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012016 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020012017 /* ${v/[/]pattern/repl} */
12018//TODO: encode pattern and repl separately.
12019// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012020 subtype = VSREPLACE;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012021 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012022 if (c != '/')
Denys Vlasenko88e15702016-10-26 01:55:56 +020012023 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012024 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012025 break;
12026#endif
Eric Andersencb57d552001-06-28 07:25:16 +000012027 }
Eric Andersenc470f442003-07-28 09:56:35 +000012028 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020012029 badsub:
Eric Andersenc470f442003-07-28 09:56:35 +000012030 pungetc();
12031 }
Denys Vlasenko3df14102016-10-26 16:41:13 +020012032 ((unsigned char *)stackblock())[typeloc] = subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012033 if (subtype != VSNORMAL) {
12034 varnest++;
Denys Vlasenko3df14102016-10-26 16:41:13 +020012035 if (dblquote)
Eric Andersenc470f442003-07-28 09:56:35 +000012036 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000012037 }
Denys Vlasenko88e15702016-10-26 01:55:56 +020012038 STPUTC('=', out);
Eric Andersencb57d552001-06-28 07:25:16 +000012039 }
Eric Andersenc470f442003-07-28 09:56:35 +000012040 goto parsesub_return;
12041}
Eric Andersencb57d552001-06-28 07:25:16 +000012042
Eric Andersencb57d552001-06-28 07:25:16 +000012043/*
12044 * Called to parse command substitutions. Newstyle is set if the command
12045 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
12046 * list of commands (passed by reference), and savelen is the number of
12047 * characters on the top of the stack which must be preserved.
12048 */
Eric Andersenc470f442003-07-28 09:56:35 +000012049parsebackq: {
12050 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012051 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010012052 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000012053 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012054 smallint saveprompt = 0;
12055
Eric Andersenc470f442003-07-28 09:56:35 +000012056 str = NULL;
12057 savelen = out - (char *)stackblock();
12058 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012059 /*
12060 * FIXME: this can allocate very large block on stack and SEGV.
12061 * Example:
12062 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020012063 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012064 * a hundred command substitutions stack overflows.
12065 * With larger prepended string, SEGV happens sooner.
12066 */
Ron Yorston072fc602015-07-01 16:46:18 +010012067 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000012068 memcpy(str, stackblock(), savelen);
12069 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012070
Eric Andersenc470f442003-07-28 09:56:35 +000012071 if (oldstyle) {
12072 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010012073 * treatment to some slashes, and then push the string and
12074 * reread it as input, interpreting it normally.
12075 */
Eric Andersenc470f442003-07-28 09:56:35 +000012076 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000012077 size_t psavelen;
12078 char *pstr;
12079
Eric Andersenc470f442003-07-28 09:56:35 +000012080 STARTSTACKSTR(pout);
12081 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012082 int pc;
12083
12084 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012085 pc = pgetc();
12086 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000012087 case '`':
12088 goto done;
12089
12090 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012091 pc = pgetc();
12092 if (pc == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012093 nlprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012094 /*
12095 * If eating a newline, avoid putting
12096 * the newline into the new character
12097 * stream (via the STPUTC after the
12098 * switch).
12099 */
12100 continue;
12101 }
12102 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012103 && (!dblquote || pc != '"')
12104 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000012105 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012106 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010012107 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000012108 break;
12109 }
12110 /* fall through */
12111
12112 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012113 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012114 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012115 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000012116
12117 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012118 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012119 break;
12120
12121 default:
12122 break;
12123 }
12124 STPUTC(pc, pout);
12125 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012126 done:
Eric Andersenc470f442003-07-28 09:56:35 +000012127 STPUTC('\0', pout);
12128 psavelen = pout - (char *)stackblock();
12129 if (psavelen > 0) {
12130 pstr = grabstackstr(pout);
12131 setinputstring(pstr);
12132 }
12133 }
12134 nlpp = &bqlist;
12135 while (*nlpp)
12136 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012137 *nlpp = stzalloc(sizeof(**nlpp));
12138 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012139
12140 if (oldstyle) {
12141 saveprompt = doprompt;
12142 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012143 }
12144
Eric Andersenc470f442003-07-28 09:56:35 +000012145 n = list(2);
12146
12147 if (oldstyle)
12148 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012149 else if (readtoken() != TRP)
12150 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000012151
12152 (*nlpp)->n = n;
12153 if (oldstyle) {
12154 /*
12155 * Start reading from old file again, ignoring any pushed back
12156 * tokens left from the backquote parsing
12157 */
12158 popfile();
12159 tokpushback = 0;
12160 }
12161 while (stackblocksize() <= savelen)
12162 growstackblock();
12163 STARTSTACKSTR(out);
12164 if (str) {
12165 memcpy(out, str, savelen);
12166 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012167 }
Ron Yorston549deab2015-05-18 09:57:51 +020012168 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012169 if (oldstyle)
12170 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012171 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000012172}
12173
Denys Vlasenko0b883582016-12-23 16:49:07 +010012174#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000012175/*
12176 * Parse an arithmetic expansion (indicate start of one and set state)
12177 */
Eric Andersenc470f442003-07-28 09:56:35 +000012178parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000012179 if (++arinest == 1) {
12180 prevsyntax = syntax;
12181 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000012182 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020012183 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012184 goto parsearith_return;
12185}
12186#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012187} /* end of readtoken */
12188
Eric Andersencb57d552001-06-28 07:25:16 +000012189/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012190 * Read the next input token.
12191 * If the token is a word, we set backquotelist to the list of cmds in
12192 * backquotes. We set quoteflag to true if any part of the word was
12193 * quoted.
12194 * If the token is TREDIR, then we set redirnode to a structure containing
12195 * the redirection.
12196 * In all cases, the variable startlinno is set to the number of the line
12197 * on which the token starts.
12198 *
12199 * [Change comment: here documents and internal procedures]
12200 * [Readtoken shouldn't have any arguments. Perhaps we should make the
12201 * word parsing code into a separate routine. In this case, readtoken
12202 * doesn't need to have any internal procedures, but parseword does.
12203 * We could also make parseoperator in essence the main routine, and
12204 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000012205 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012206#define NEW_xxreadtoken
12207#ifdef NEW_xxreadtoken
12208/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012209static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000012210 '\n', '(', ')', /* singles */
12211 '&', '|', ';', /* doubles */
12212 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012213};
Eric Andersencb57d552001-06-28 07:25:16 +000012214
Denis Vlasenko834dee72008-10-07 09:18:30 +000012215#define xxreadtoken_singles 3
12216#define xxreadtoken_doubles 3
12217
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012218static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012219 TNL, TLP, TRP, /* only single occurrence allowed */
12220 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12221 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012222 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012223};
12224
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012225static int
12226xxreadtoken(void)
12227{
12228 int c;
12229
12230 if (tokpushback) {
12231 tokpushback = 0;
12232 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012233 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012234 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012235 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012236 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012237 c = pgetc();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000012238 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012239 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012240
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012241 if (c == '#') {
12242 while ((c = pgetc()) != '\n' && c != PEOF)
12243 continue;
12244 pungetc();
12245 } else if (c == '\\') {
12246 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012247 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012248 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012249 }
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012250 nlprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012251 } else {
12252 const char *p;
12253
12254 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12255 if (c != PEOF) {
12256 if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012257 nlnoprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012258 }
12259
12260 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000012261 if (p == NULL)
12262 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012263
Denis Vlasenko834dee72008-10-07 09:18:30 +000012264 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12265 int cc = pgetc();
12266 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012267 p += xxreadtoken_doubles + 1;
12268 } else {
12269 pungetc();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012270#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012271 if (c == '&' && cc == '>') /* &> */
12272 break; /* return readtoken1(...) */
12273#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012274 }
12275 }
12276 }
12277 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12278 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012279 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012280 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012281
12282 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012283}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012284#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012285#define RETURN(token) return lasttoken = token
12286static int
12287xxreadtoken(void)
12288{
12289 int c;
12290
12291 if (tokpushback) {
12292 tokpushback = 0;
12293 return lasttoken;
12294 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012295 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012296 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012297 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012298 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012299 switch (c) {
12300 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012301 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012302 continue;
12303 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012304 while ((c = pgetc()) != '\n' && c != PEOF)
12305 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012306 pungetc();
12307 continue;
12308 case '\\':
12309 if (pgetc() == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012310 nlprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012311 continue;
12312 }
12313 pungetc();
12314 goto breakloop;
12315 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012316 nlnoprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012317 RETURN(TNL);
12318 case PEOF:
12319 RETURN(TEOF);
12320 case '&':
12321 if (pgetc() == '&')
12322 RETURN(TAND);
12323 pungetc();
12324 RETURN(TBACKGND);
12325 case '|':
12326 if (pgetc() == '|')
12327 RETURN(TOR);
12328 pungetc();
12329 RETURN(TPIPE);
12330 case ';':
12331 if (pgetc() == ';')
12332 RETURN(TENDCASE);
12333 pungetc();
12334 RETURN(TSEMI);
12335 case '(':
12336 RETURN(TLP);
12337 case ')':
12338 RETURN(TRP);
12339 default:
12340 goto breakloop;
12341 }
12342 }
12343 breakloop:
12344 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12345#undef RETURN
12346}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012347#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012348
12349static int
12350readtoken(void)
12351{
12352 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012353 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012354#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012355 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012356#endif
12357
12358#if ENABLE_ASH_ALIAS
12359 top:
12360#endif
12361
12362 t = xxreadtoken();
12363
12364 /*
12365 * eat newlines
12366 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012367 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012368 while (t == TNL) {
12369 parseheredoc();
12370 t = xxreadtoken();
12371 }
12372 }
12373
12374 if (t != TWORD || quoteflag) {
12375 goto out;
12376 }
12377
12378 /*
12379 * check for keywords
12380 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012381 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012382 const char *const *pp;
12383
12384 pp = findkwd(wordtext);
12385 if (pp) {
12386 lasttoken = t = pp - tokname_array;
Denys Vlasenko888527c2016-10-02 16:54:17 +020012387 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012388 goto out;
12389 }
12390 }
12391
12392 if (checkkwd & CHKALIAS) {
12393#if ENABLE_ASH_ALIAS
12394 struct alias *ap;
12395 ap = lookupalias(wordtext, 1);
12396 if (ap != NULL) {
12397 if (*ap->val) {
12398 pushstring(ap->val, ap);
12399 }
12400 goto top;
12401 }
12402#endif
12403 }
12404 out:
12405 checkkwd = 0;
12406#if DEBUG
12407 if (!alreadyseen)
Denys Vlasenko888527c2016-10-02 16:54:17 +020012408 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012409 else
Denys Vlasenko888527c2016-10-02 16:54:17 +020012410 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012411#endif
12412 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012413}
12414
Ron Yorstonc0e00762015-10-29 11:30:55 +000012415static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012416peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012417{
12418 int t;
12419
12420 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012421 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012422 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012423}
Eric Andersencb57d552001-06-28 07:25:16 +000012424
12425/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012426 * Read and parse a command. Returns NODE_EOF on end of file.
12427 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012428 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012429static union node *
12430parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012431{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012432 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012433 checkkwd = 0;
12434 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012435 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012436 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012437 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012438 return list(1);
12439}
12440
12441/*
12442 * Input any here documents.
12443 */
12444static void
12445parseheredoc(void)
12446{
12447 struct heredoc *here;
12448 union node *n;
12449
12450 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012451 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012452
12453 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012454 setprompt_if(needprompt, 2);
12455 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012456 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012457 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012458 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012459 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012460 n->narg.text = wordtext;
12461 n->narg.backquote = backquotelist;
12462 here->here->nhere.doc = n;
12463 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012464 }
Eric Andersencb57d552001-06-28 07:25:16 +000012465}
12466
12467
12468/*
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012469 * called by editline -- any expansions to the prompt should be added here.
Eric Andersencb57d552001-06-28 07:25:16 +000012470 */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012471static const char *
12472expandstr(const char *ps)
12473{
12474 union node n;
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012475 int saveprompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012476
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000012477 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12478 * and token processing _can_ alter it (delete NULs etc). */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012479 setinputstring((char *)ps);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012480
12481 saveprompt = doprompt;
12482 doprompt = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000012483 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012484 doprompt = saveprompt;
12485
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012486 popfile();
12487
12488 n.narg.type = NARG;
12489 n.narg.next = NULL;
12490 n.narg.text = wordtext;
12491 n.narg.backquote = backquotelist;
12492
Ron Yorston549deab2015-05-18 09:57:51 +020012493 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012494 return stackblock();
12495}
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012496
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012497/*
12498 * Execute a command or commands contained in a string.
12499 */
12500static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012501evalstring(char *s, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000012502{
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012503 struct jmploc *volatile savehandler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012504 struct jmploc jmploc;
12505 int ex;
12506
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012507 union node *n;
12508 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012509 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012510
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012511 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012512 setinputstring(s);
12513 setstackmark(&smark);
12514
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012515 status = 0;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012516 /* On exception inside execution loop, we must popfile().
12517 * Try interactively:
12518 * readonly a=a
12519 * command eval "a=b" # throws "is read only" error
12520 * "command BLTIN" is not supposed to abort (even in non-interactive use).
12521 * But if we skip popfile(), we hit EOF in eval's string, and exit.
12522 */
12523 savehandler = exception_handler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012524 ex = setjmp(jmploc.loc);
12525 if (ex)
12526 goto out;
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012527 exception_handler = &jmploc;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012528
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012529 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012530 int i;
12531
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012532 i = evaltree(n, flags);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012533 if (n)
12534 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012535 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012536 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012537 break;
12538 }
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012539 out:
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012540 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012541 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012542 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012543
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012544 exception_handler = savehandler;
12545 if (ex)
12546 longjmp(exception_handler->loc, ex);
12547
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012548 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000012549}
12550
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012551/*
12552 * The eval command.
12553 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012554static int FAST_FUNC
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012555evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012556{
12557 char *p;
12558 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012559
Denis Vlasenko68404f12008-03-17 09:00:54 +000012560 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012561 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012562 argv += 2;
12563 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012564 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012565 for (;;) {
12566 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012567 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012568 if (p == NULL)
12569 break;
12570 STPUTC(' ', concat);
12571 }
12572 STPUTC('\0', concat);
12573 p = grabstackstr(concat);
12574 }
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012575 return evalstring(p, flags & EV_TESTED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012576 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012577 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012578}
12579
12580/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012581 * Read and execute commands.
12582 * "Top" is nonzero for the top level command loop;
12583 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012584 */
12585static int
12586cmdloop(int top)
12587{
12588 union node *n;
12589 struct stackmark smark;
12590 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012591 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012592 int numeof = 0;
12593
12594 TRACE(("cmdloop(%d) called\n", top));
12595 for (;;) {
12596 int skip;
12597
12598 setstackmark(&smark);
12599#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012600 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020012601 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012602#endif
12603 inter = 0;
12604 if (iflag && top) {
12605 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012606 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012607 }
12608 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012609#if DEBUG
12610 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012611 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012612#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012613 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012614 if (!top || numeof >= 50)
12615 break;
12616 if (!stoppedjobs()) {
12617 if (!Iflag)
12618 break;
12619 out2str("\nUse \"exit\" to leave shell.\n");
12620 }
12621 numeof++;
12622 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012623 int i;
12624
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012625 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12626 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012627 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012628 i = evaltree(n, 0);
12629 if (n)
12630 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012631 }
12632 popstackmark(&smark);
12633 skip = evalskip;
12634
12635 if (skip) {
Denys Vlasenko6a0710e2016-09-30 14:18:34 +020012636 evalskip &= ~SKIPFUNC;
Denys Vlasenko0840c912016-10-01 15:27:44 +020012637 break;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012638 }
12639 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012640 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012641}
12642
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012643/*
12644 * Take commands from a file. To be compatible we should do a path
12645 * search for the file, which is necessary to find sub-commands.
12646 */
12647static char *
12648find_dot_file(char *name)
12649{
12650 char *fullname;
12651 const char *path = pathval();
12652 struct stat statb;
12653
12654 /* don't try this for absolute or relative paths */
12655 if (strchr(name, '/'))
12656 return name;
12657
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012658 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012659 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12660 /*
12661 * Don't bother freeing here, since it will
12662 * be freed by the caller.
12663 */
12664 return fullname;
12665 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012666 if (fullname != name)
12667 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012668 }
12669
12670 /* not found in the PATH */
12671 ash_msg_and_raise_error("%s: not found", name);
12672 /* NOTREACHED */
12673}
12674
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012675static int FAST_FUNC
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012676dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012677{
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012678 /* "false; . empty_file; echo $?" should print 0, not 1: */
12679 int status = 0;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012680 char *fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012681 char **argv;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012682 char *args_need_save;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012683 struct strlist *sp;
12684 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012685
12686 for (sp = cmdenviron; sp; sp = sp->next)
Denis Vlasenko4222ae42007-02-25 02:37:49 +000012687 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012688
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012689 nextopt(nullstr); /* handle possible "--" */
12690 argv = argptr;
12691
12692 if (!argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012693 /* bash says: "bash: .: filename argument required" */
12694 return 2; /* bash compat */
12695 }
12696
Denys Vlasenko091f8312013-03-17 14:25:22 +010012697 /* This aborts if file isn't found, which is POSIXly correct.
12698 * bash returns exitcode 1 instead.
12699 */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012700 fullname = find_dot_file(argv[0]);
12701 argv++;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012702 args_need_save = argv[0];
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010012703 if (args_need_save) { /* ". FILE ARGS", and ARGS are not empty */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012704 int argc;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012705 saveparam = shellparam;
12706 shellparam.malloced = 0;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012707 argc = 1;
12708 while (argv[argc])
12709 argc++;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012710 shellparam.nparam = argc;
12711 shellparam.p = argv;
12712 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012713
Denys Vlasenko091f8312013-03-17 14:25:22 +010012714 /* This aborts if file can't be opened, which is POSIXly correct.
12715 * bash returns exitcode 1 instead.
12716 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012717 setinputfile(fullname, INPUT_PUSH_FILE);
12718 commandname = fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012719 status = cmdloop(0);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012720 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012721
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012722 if (args_need_save) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012723 freeparam(&shellparam);
12724 shellparam = saveparam;
12725 };
12726
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012727 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012728}
12729
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012730static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012731exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012732{
12733 if (stoppedjobs())
12734 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012735 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012736 exitstatus = number(argv[1]);
12737 raise_exception(EXEXIT);
12738 /* NOTREACHED */
12739}
12740
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012741/*
12742 * Read a file containing shell functions.
12743 */
12744static void
12745readcmdfile(char *name)
12746{
12747 setinputfile(name, INPUT_PUSH_FILE);
12748 cmdloop(0);
12749 popfile();
12750}
12751
12752
Denis Vlasenkocc571512007-02-23 21:10:35 +000012753/* ============ find_command inplementation */
12754
12755/*
12756 * Resolve a command name. If you change this routine, you may have to
12757 * change the shellexec routine as well.
12758 */
12759static void
12760find_command(char *name, struct cmdentry *entry, int act, const char *path)
12761{
12762 struct tblentry *cmdp;
12763 int idx;
12764 int prev;
12765 char *fullname;
12766 struct stat statb;
12767 int e;
12768 int updatetbl;
12769 struct builtincmd *bcmd;
12770
12771 /* If name contains a slash, don't use PATH or hash table */
12772 if (strchr(name, '/') != NULL) {
12773 entry->u.index = -1;
12774 if (act & DO_ABS) {
12775 while (stat(name, &statb) < 0) {
12776#ifdef SYSV
12777 if (errno == EINTR)
12778 continue;
12779#endif
12780 entry->cmdtype = CMDUNKNOWN;
12781 return;
12782 }
12783 }
12784 entry->cmdtype = CMDNORMAL;
12785 return;
12786 }
12787
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012788/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012789
12790 updatetbl = (path == pathval());
12791 if (!updatetbl) {
12792 act |= DO_ALTPATH;
12793 if (strstr(path, "%builtin") != NULL)
12794 act |= DO_ALTBLTIN;
12795 }
12796
12797 /* If name is in the table, check answer will be ok */
12798 cmdp = cmdlookup(name, 0);
12799 if (cmdp != NULL) {
12800 int bit;
12801
12802 switch (cmdp->cmdtype) {
12803 default:
12804#if DEBUG
12805 abort();
12806#endif
12807 case CMDNORMAL:
12808 bit = DO_ALTPATH;
12809 break;
12810 case CMDFUNCTION:
12811 bit = DO_NOFUNC;
12812 break;
12813 case CMDBUILTIN:
12814 bit = DO_ALTBLTIN;
12815 break;
12816 }
12817 if (act & bit) {
12818 updatetbl = 0;
12819 cmdp = NULL;
12820 } else if (cmdp->rehash == 0)
12821 /* if not invalidated by cd, we're done */
12822 goto success;
12823 }
12824
12825 /* If %builtin not in path, check for builtin next */
12826 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012827 if (bcmd) {
12828 if (IS_BUILTIN_REGULAR(bcmd))
12829 goto builtin_success;
12830 if (act & DO_ALTPATH) {
12831 if (!(act & DO_ALTBLTIN))
12832 goto builtin_success;
12833 } else if (builtinloc <= 0) {
12834 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000012835 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012836 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000012837
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012838#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000012839 {
12840 int applet_no = find_applet_by_name(name);
12841 if (applet_no >= 0) {
12842 entry->cmdtype = CMDNORMAL;
12843 entry->u.index = -2 - applet_no;
12844 return;
12845 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012846 }
12847#endif
12848
Denis Vlasenkocc571512007-02-23 21:10:35 +000012849 /* We have to search path. */
12850 prev = -1; /* where to start */
12851 if (cmdp && cmdp->rehash) { /* doing a rehash */
12852 if (cmdp->cmdtype == CMDBUILTIN)
12853 prev = builtinloc;
12854 else
12855 prev = cmdp->param.index;
12856 }
12857
12858 e = ENOENT;
12859 idx = -1;
12860 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012861 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000012862 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012863 /* NB: code below will still use fullname
12864 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012865 idx++;
12866 if (pathopt) {
12867 if (prefix(pathopt, "builtin")) {
12868 if (bcmd)
12869 goto builtin_success;
12870 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000012871 }
12872 if ((act & DO_NOFUNC)
12873 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020012874 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012875 continue;
12876 }
12877 }
12878 /* if rehash, don't redo absolute path names */
12879 if (fullname[0] == '/' && idx <= prev) {
12880 if (idx < prev)
12881 continue;
12882 TRACE(("searchexec \"%s\": no change\n", name));
12883 goto success;
12884 }
12885 while (stat(fullname, &statb) < 0) {
12886#ifdef SYSV
12887 if (errno == EINTR)
12888 continue;
12889#endif
12890 if (errno != ENOENT && errno != ENOTDIR)
12891 e = errno;
12892 goto loop;
12893 }
12894 e = EACCES; /* if we fail, this will be the error */
12895 if (!S_ISREG(statb.st_mode))
12896 continue;
12897 if (pathopt) { /* this is a %func directory */
12898 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012899 /* NB: stalloc will return space pointed by fullname
12900 * (because we don't have any intervening allocations
12901 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012902 readcmdfile(fullname);
12903 cmdp = cmdlookup(name, 0);
12904 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12905 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12906 stunalloc(fullname);
12907 goto success;
12908 }
12909 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12910 if (!updatetbl) {
12911 entry->cmdtype = CMDNORMAL;
12912 entry->u.index = idx;
12913 return;
12914 }
12915 INT_OFF;
12916 cmdp = cmdlookup(name, 1);
12917 cmdp->cmdtype = CMDNORMAL;
12918 cmdp->param.index = idx;
12919 INT_ON;
12920 goto success;
12921 }
12922
12923 /* We failed. If there was an entry for this command, delete it */
12924 if (cmdp && updatetbl)
12925 delete_cmd_entry();
12926 if (act & DO_ERR)
12927 ash_msg("%s: %s", name, errmsg(e, "not found"));
12928 entry->cmdtype = CMDUNKNOWN;
12929 return;
12930
12931 builtin_success:
12932 if (!updatetbl) {
12933 entry->cmdtype = CMDBUILTIN;
12934 entry->u.cmd = bcmd;
12935 return;
12936 }
12937 INT_OFF;
12938 cmdp = cmdlookup(name, 1);
12939 cmdp->cmdtype = CMDBUILTIN;
12940 cmdp->param.cmd = bcmd;
12941 INT_ON;
12942 success:
12943 cmdp->rehash = 0;
12944 entry->cmdtype = cmdp->cmdtype;
12945 entry->u = cmdp->param;
12946}
12947
12948
Eric Andersencb57d552001-06-28 07:25:16 +000012949/*
Eric Andersencb57d552001-06-28 07:25:16 +000012950 * The trap builtin.
12951 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012952static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012953trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012954{
12955 char *action;
12956 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012957 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012958
Eric Andersenc470f442003-07-28 09:56:35 +000012959 nextopt(nullstr);
12960 ap = argptr;
12961 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012962 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012963 char *tr = trap_ptr[signo];
12964 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012965 /* note: bash adds "SIG", but only if invoked
12966 * as "bash". If called as "sh", or if set -o posix,
12967 * then it prints short signal names.
12968 * We are printing short names: */
12969 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012970 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012971 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012972 /* trap_ptr != trap only if we are in special-cased `trap` code.
12973 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012974 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012975 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000012976 }
12977 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012978 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012979 if (trap_ptr != trap) {
12980 free(trap_ptr);
12981 trap_ptr = trap;
12982 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012983 */
Eric Andersencb57d552001-06-28 07:25:16 +000012984 return 0;
12985 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012986
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012987 action = NULL;
12988 if (ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000012989 action = *ap++;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012990 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012991 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012992 signo = get_signum(*ap);
Denys Vlasenkoe9aba3e2017-07-01 21:09:27 +020012993 if (signo < 0 || signo >= NSIG) {
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012994 /* Mimic bash message exactly */
12995 ash_msg("%s: invalid signal specification", *ap);
12996 exitcode = 1;
12997 goto next;
12998 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000012999 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000013000 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000013001 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000013002 action = NULL;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013003 else {
13004 if (action[0]) /* not NULL and not "" and not "-" */
13005 may_have_traps = 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013006 action = ckstrdup(action);
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013007 }
Eric Andersencb57d552001-06-28 07:25:16 +000013008 }
Denis Vlasenko60818682007-09-28 22:07:23 +000013009 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000013010 trap[signo] = action;
13011 if (signo != 0)
13012 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013013 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013014 next:
Eric Andersencb57d552001-06-28 07:25:16 +000013015 ap++;
13016 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013017 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013018}
13019
Eric Andersenc470f442003-07-28 09:56:35 +000013020
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013021/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000013022
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013023#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013024static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013025helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013026{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000013027 unsigned col;
13028 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000013029
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020013030 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000013031 "Built-in commands:\n"
13032 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000013033 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013034 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000013035 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013036 if (col > 60) {
13037 out1fmt("\n");
13038 col = 0;
13039 }
13040 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013041# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000013042 {
13043 const char *a = applet_names;
13044 while (*a) {
13045 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
13046 if (col > 60) {
13047 out1fmt("\n");
13048 col = 0;
13049 }
Ron Yorston2b919582016-04-08 11:57:20 +010013050 while (*a++ != '\0')
13051 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013052 }
13053 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013054# endif
Denys Vlasenkoebedb942016-10-02 18:45:09 +020013055 newline_and_flush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000013056 return EXIT_SUCCESS;
13057}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013058#endif
Eric Andersenc470f442003-07-28 09:56:35 +000013059
Flemming Madsend96ffda2013-04-07 18:47:24 +020013060#if MAX_HISTORY
13061static int FAST_FUNC
13062historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13063{
13064 show_history(line_input_state);
13065 return EXIT_SUCCESS;
13066}
13067#endif
13068
Eric Andersencb57d552001-06-28 07:25:16 +000013069/*
Eric Andersencb57d552001-06-28 07:25:16 +000013070 * The export and readonly commands.
13071 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013072static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013073exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000013074{
13075 struct var *vp;
13076 char *name;
13077 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000013078 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020013079 char opt;
13080 int flag;
13081 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000013082
Denys Vlasenkod5275882012-10-01 13:41:17 +020013083 /* "readonly" in bash accepts, but ignores -n.
13084 * We do the same: it saves a conditional in nextopt's param.
13085 */
13086 flag_off = 0;
13087 while ((opt = nextopt("np")) != '\0') {
13088 if (opt == 'n')
13089 flag_off = VEXPORT;
13090 }
13091 flag = VEXPORT;
13092 if (argv[0][0] == 'r') {
13093 flag = VREADONLY;
13094 flag_off = 0; /* readonly ignores -n */
13095 }
13096 flag_off = ~flag_off;
13097
Denys Vlasenko10ad6222017-04-17 16:13:32 +020013098 /*if (opt_p_not_specified) - bash doesn't check this. Try "export -p NAME" */
Denys Vlasenkod5275882012-10-01 13:41:17 +020013099 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013100 aptr = argptr;
13101 name = *aptr;
13102 if (name) {
13103 do {
13104 p = strchr(name, '=');
13105 if (p != NULL) {
13106 p++;
13107 } else {
13108 vp = *findvar(hashvar(name), name);
13109 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020013110 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013111 continue;
13112 }
Eric Andersencb57d552001-06-28 07:25:16 +000013113 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013114 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013115 } while ((name = *++aptr) != NULL);
13116 return 0;
13117 }
Eric Andersencb57d552001-06-28 07:25:16 +000013118 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013119
13120 /* No arguments. Show the list of exported or readonly vars.
13121 * -n is ignored.
13122 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013123 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000013124 return 0;
13125}
13126
Eric Andersencb57d552001-06-28 07:25:16 +000013127/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013128 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000013129 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013130static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013131unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000013132{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013133 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000013134
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013135 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013136 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013137 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000013138}
13139
Eric Andersencb57d552001-06-28 07:25:16 +000013140/*
Eric Andersencb57d552001-06-28 07:25:16 +000013141 * The unset builtin command. We unset the function before we unset the
13142 * variable to allow a function to be unset when there is a readonly variable
13143 * with the same name.
13144 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013145static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013146unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013147{
13148 char **ap;
13149 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013150 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013151 int ret = 0;
13152
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013153 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000013154 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000013155 }
Eric Andersencb57d552001-06-28 07:25:16 +000013156
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013157 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013158 if (flag != 'f') {
13159 i = unsetvar(*ap);
13160 ret |= i;
13161 if (!(i & 2))
13162 continue;
13163 }
13164 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000013165 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000013166 }
Eric Andersenc470f442003-07-28 09:56:35 +000013167 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000013168}
13169
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000013170static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013171 ' ', offsetof(struct tms, tms_utime),
13172 '\n', offsetof(struct tms, tms_stime),
13173 ' ', offsetof(struct tms, tms_cutime),
13174 '\n', offsetof(struct tms, tms_cstime),
13175 0
13176};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013177static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013178timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013179{
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020013180 unsigned long clk_tck, s, t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013181 const unsigned char *p;
13182 struct tms buf;
13183
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020013184 clk_tck = bb_clk_tck();
Eric Andersencb57d552001-06-28 07:25:16 +000013185 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013186
13187 p = timescmd_str;
13188 do {
13189 t = *(clock_t *)(((char *) &buf) + p[1]);
13190 s = t / clk_tck;
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020013191 t = t % clk_tck;
13192 out1fmt("%lum%lu.%03lus%c",
13193 s / 60, s % 60,
13194 (t * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013195 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013196 p += 2;
13197 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013198
Eric Andersencb57d552001-06-28 07:25:16 +000013199 return 0;
13200}
13201
Denys Vlasenko0b883582016-12-23 16:49:07 +010013202#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000013203/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013204 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013205 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000013206 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013207 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000013208 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013209static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013210letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013211{
Denis Vlasenko68404f12008-03-17 09:00:54 +000013212 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000013213
Denis Vlasenko68404f12008-03-17 09:00:54 +000013214 argv++;
13215 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000013216 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000013217 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013218 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013219 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013220
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000013221 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000013222}
Eric Andersenc470f442003-07-28 09:56:35 +000013223#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013224
Eric Andersenc470f442003-07-28 09:56:35 +000013225/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013226 * The read builtin. Options:
13227 * -r Do not interpret '\' specially
13228 * -s Turn off echo (tty only)
13229 * -n NCHARS Read NCHARS max
13230 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13231 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13232 * -u FD Read from given FD instead of fd 0
Eric Andersenc470f442003-07-28 09:56:35 +000013233 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013234 * TODO: bash also has:
13235 * -a ARRAY Read into array[0],[1],etc
13236 * -d DELIM End on DELIM char, not newline
13237 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000013238 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013239static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013240readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013241{
Denys Vlasenko73067272010-01-12 22:11:24 +010013242 char *opt_n = NULL;
13243 char *opt_p = NULL;
13244 char *opt_t = NULL;
13245 char *opt_u = NULL;
13246 int read_flags = 0;
13247 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000013248 int i;
13249
Denys Vlasenko73067272010-01-12 22:11:24 +010013250 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000013251 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000013252 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010013253 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013254 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013255 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010013256 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013257 break;
13258 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010013259 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000013260 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013261 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010013262 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013263 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013264 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010013265 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000013266 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013267 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010013268 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013269 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013270 default:
13271 break;
13272 }
Eric Andersenc470f442003-07-28 09:56:35 +000013273 }
Paul Fox02eb9342005-09-07 16:56:02 +000013274
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013275 /* "read -s" needs to save/restore termios, can't allow ^C
13276 * to jump out of it.
13277 */
Denys Vlasenkof5470412017-05-22 19:34:45 +020013278 again:
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013279 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013280 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010013281 argptr,
13282 bltinlookup("IFS"), /* can be NULL */
13283 read_flags,
13284 opt_n,
13285 opt_p,
13286 opt_t,
13287 opt_u
13288 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013289 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000013290
Denys Vlasenkof5470412017-05-22 19:34:45 +020013291 if ((uintptr_t)r == 1 && errno == EINTR) {
13292 /* to get SIGCHLD: sleep 1 & read x; echo $x */
13293 if (pending_sig == 0)
13294 goto again;
13295 }
13296
Denys Vlasenko73067272010-01-12 22:11:24 +010013297 if ((uintptr_t)r > 1)
13298 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000013299
Denys Vlasenko73067272010-01-12 22:11:24 +010013300 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000013301}
13302
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013303static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020013304umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013305{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013306 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000013307
Eric Andersenc470f442003-07-28 09:56:35 +000013308 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000013309 int symbolic_mode = 0;
13310
13311 while (nextopt("S") != '\0') {
13312 symbolic_mode = 1;
13313 }
13314
Denis Vlasenkob012b102007-02-19 22:43:01 +000013315 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013316 mask = umask(0);
13317 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013318 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013319
Denys Vlasenko6283f982015-10-07 16:56:20 +020013320 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013321 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013322 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013323 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013324 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013325
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013326 i = 2;
13327 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013328 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013329 *p++ = permuser[i];
13330 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013331 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013332 if (!(mask & 0400)) *p++ = 'r';
13333 if (!(mask & 0200)) *p++ = 'w';
13334 if (!(mask & 0100)) *p++ = 'x';
13335 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013336 if (--i < 0)
13337 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013338 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013339 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013340 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013341 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013342 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013343 }
13344 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013345 char *modestr = *argptr;
13346 /* numeric umasks are taken as-is */
13347 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
13348 if (!isdigit(modestr[0]))
13349 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013350 mask = bb_parse_mode(modestr, mask);
13351 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013352 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013353 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013354 if (!isdigit(modestr[0]))
13355 mask ^= 0777;
13356 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013357 }
13358 return 0;
13359}
13360
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013361static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013362ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013363{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013364 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013365}
13366
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013367/* ============ main() and helpers */
13368
13369/*
13370 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013371 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013372static void
13373exitshell(void)
13374{
13375 struct jmploc loc;
13376 char *p;
13377 int status;
13378
Denys Vlasenkobede2152011-09-04 16:12:33 +020013379#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13380 save_history(line_input_state);
13381#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013382 status = exitstatus;
13383 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13384 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013385 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013386 status = exitstatus;
13387 goto out;
13388 }
13389 exception_handler = &loc;
13390 p = trap[0];
13391 if (p) {
13392 trap[0] = NULL;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013393 evalskip = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013394 evalstring(p, 0);
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013395 /*free(p); - we'll exit soon */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013396 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013397 out:
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013398 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13399 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13400 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013401 setjobctl(0);
Denys Vlasenkocaee80c2016-10-25 20:49:53 +020013402 flush_stdout_stderr();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013403 _exit(status);
13404 /* NOTREACHED */
13405}
13406
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013407static void
13408init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013409{
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013410 /* we will never free this */
13411 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013412
Denys Vlasenko458c1f22016-10-27 23:51:19 +020013413 sigmode[SIGCHLD - 1] = S_DFL;
13414 setsignal(SIGCHLD);
13415
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013416 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13417 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13418 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013419 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013420
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013421 {
13422 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013423 const char *p;
13424 struct stat st1, st2;
13425
13426 initvar();
13427 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenkob6838b52016-09-30 11:33:47 +020013428 p = endofname(*envp);
13429 if (p != *envp && *p == '=') {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013430 setvareq(*envp, VEXPORT|VTEXTFIXED);
13431 }
13432 }
13433
Denys Vlasenkoe627ac92016-09-30 14:36:59 +020013434 setvareq((char*)defoptindvar, VTEXTFIXED);
13435
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013436 setvar0("PPID", utoa(getppid()));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013437#if BASH_SHLVL_VAR
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013438 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013439 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013440#endif
13441#if BASH_HOSTNAME_VAR
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013442 if (!lookupvar("HOSTNAME")) {
13443 struct utsname uts;
13444 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013445 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013446 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013447#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013448 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013449 if (p) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013450 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013451 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13452 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013453 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013454 }
13455 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013456 setpwd(p, 0);
13457 }
13458}
13459
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013460
13461//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013462//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013463//usage:#define ash_full_usage "\n\n"
13464//usage: "Unix shell interpreter"
13465
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013466/*
13467 * Process the shell command line arguments.
13468 */
13469static void
Denis Vlasenko68404f12008-03-17 09:00:54 +000013470procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013471{
13472 int i;
13473 const char *xminusc;
13474 char **xargv;
13475
13476 xargv = argv;
13477 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013478 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013479 xargv++;
13480 for (i = 0; i < NOPTS; i++)
13481 optlist[i] = 2;
13482 argptr = xargv;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013483 if (options(/*cmdline:*/ 1)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013484 /* it already printed err message */
13485 raise_exception(EXERROR);
13486 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013487 xargv = argptr;
13488 xminusc = minusc;
13489 if (*xargv == NULL) {
13490 if (xminusc)
13491 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13492 sflag = 1;
13493 }
13494 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13495 iflag = 1;
13496 if (mflag == 2)
13497 mflag = iflag;
13498 for (i = 0; i < NOPTS; i++)
13499 if (optlist[i] == 2)
13500 optlist[i] = 0;
13501#if DEBUG == 2
13502 debug = 1;
13503#endif
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013504 /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013505 if (xminusc) {
13506 minusc = *xargv++;
13507 if (*xargv)
13508 goto setarg0;
13509 } else if (!sflag) {
13510 setinputfile(*xargv, 0);
13511 setarg0:
13512 arg0 = *xargv++;
13513 commandname = arg0;
13514 }
13515
13516 shellparam.p = xargv;
13517#if ENABLE_ASH_GETOPTS
13518 shellparam.optind = 1;
13519 shellparam.optoff = -1;
13520#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013521 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013522 while (*xargv) {
13523 shellparam.nparam++;
13524 xargv++;
13525 }
13526 optschanged();
13527}
13528
13529/*
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013530 * Read /etc/profile, ~/.profile, $ENV.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013531 */
13532static void
13533read_profile(const char *name)
13534{
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013535 name = expandstr(name);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013536 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13537 return;
Denys Vlasenko0840c912016-10-01 15:27:44 +020013538 cmdloop(0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013539 popfile();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013540}
13541
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013542/*
13543 * This routine is called when an error or an interrupt occurs in an
13544 * interactive shell and control is returned to the main command loop.
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013545 * (In dash, this function is auto-generated by build machinery).
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013546 */
13547static void
13548reset(void)
13549{
13550 /* from eval.c: */
13551 evalskip = 0;
13552 loopnest = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013553
13554 /* from expand.c: */
13555 ifsfree();
13556
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013557 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013558 g_parsefile->left_in_buffer = 0;
13559 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013560 popallfiles();
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013561
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013562 /* from redir.c: */
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020013563 while (redirlist)
13564 popredir(/*drop:*/ 0, /*restore:*/ 0);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013565}
13566
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013567#if PROFILE
13568static short profile_buf[16384];
13569extern int etext();
13570#endif
13571
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013572/*
13573 * Main routine. We initialize things, parse the arguments, execute
13574 * profiles if we're a login shell, and then call cmdloop to execute
13575 * commands. The setjmp call sets up the location to jump to when an
13576 * exception occurs. When an exception occurs the variable "state"
13577 * is used to figure out how far we had gotten.
13578 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013579int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013580int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013581{
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013582 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013583 struct jmploc jmploc;
13584 struct stackmark smark;
13585
Denis Vlasenko01631112007-12-16 17:20:38 +000013586 /* Initialize global data */
13587 INIT_G_misc();
13588 INIT_G_memstack();
13589 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013590#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013591 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013592#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013593 INIT_G_cmdtable();
13594
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013595#if PROFILE
13596 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13597#endif
13598
13599#if ENABLE_FEATURE_EDITING
13600 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13601#endif
13602 state = 0;
13603 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013604 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013605 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013606
13607 reset();
13608
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013609 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013610 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013611 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013612 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013613 }
13614 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020013615 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013616 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013617
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013618 popstackmark(&smark);
13619 FORCE_INT_ON; /* enable interrupts */
13620 if (s == 1)
13621 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013622 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013623 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013624 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013625 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013626 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013627 }
13628 exception_handler = &jmploc;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013629 rootpid = getpid();
13630
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013631 init();
13632 setstackmark(&smark);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013633 procargs(argv);
Denys Vlasenko474ed062016-10-30 18:30:29 +010013634#if DEBUG
13635 TRACE(("Shell args: "));
13636 trace_puts_args(argv);
13637#endif
Denis Vlasenko68404f12008-03-17 09:00:54 +000013638
Denys Vlasenko6088e132010-12-25 23:58:42 +010013639 if (argv[0] && argv[0][0] == '-')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013640 isloginsh = 1;
13641 if (isloginsh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013642 const char *hp;
13643
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013644 state = 1;
13645 read_profile("/etc/profile");
13646 state1:
13647 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013648 hp = lookupvar("HOME");
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013649 if (hp)
13650 read_profile("$HOME/.profile");
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013651 }
13652 state2:
13653 state = 3;
13654 if (
13655#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013656 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013657#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013658 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013659 ) {
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013660 const char *shinit = lookupvar("ENV");
13661 if (shinit != NULL && *shinit != '\0')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013662 read_profile(shinit);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013663 }
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013664 popstackmark(&smark);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013665 state3:
13666 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013667 if (minusc) {
13668 /* evalstring pushes parsefile stack.
13669 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013670 * is one of stacked source fds.
13671 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013672 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013673 // ^^ not necessary since now we special-case fd 0
13674 // in is_hidden_fd() to not be considered "hidden fd"
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013675 evalstring(minusc, 0);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013676 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013677
13678 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020013679#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013680 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013681 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013682 if (!hp) {
13683 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013684 if (hp) {
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013685 INT_OFF;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013686 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013687 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013688 free((char*)hp);
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013689 INT_ON;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013690 hp = lookupvar("HISTFILE");
13691 }
13692 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013693 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013694 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013695# if ENABLE_FEATURE_SH_HISTFILESIZE
13696 hp = lookupvar("HISTFILESIZE");
13697 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13698# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013699 }
13700#endif
13701 state4: /* XXX ??? - why isn't this before the "if" statement */
13702 cmdloop(1);
13703 }
13704#if PROFILE
13705 monitor(0);
13706#endif
13707#ifdef GPROF
13708 {
13709 extern void _mcleanup(void);
13710 _mcleanup();
13711 }
13712#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013713 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013714 exitshell();
13715 /* NOTREACHED */
13716}
13717
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013718
Eric Andersendf82f612001-06-28 07:46:40 +000013719/*-
13720 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013721 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013722 *
13723 * This code is derived from software contributed to Berkeley by
13724 * Kenneth Almquist.
13725 *
13726 * Redistribution and use in source and binary forms, with or without
13727 * modification, are permitted provided that the following conditions
13728 * are met:
13729 * 1. Redistributions of source code must retain the above copyright
13730 * notice, this list of conditions and the following disclaimer.
13731 * 2. Redistributions in binary form must reproduce the above copyright
13732 * notice, this list of conditions and the following disclaimer in the
13733 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013734 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013735 * may be used to endorse or promote products derived from this software
13736 * without specific prior written permission.
13737 *
13738 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13739 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13740 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13741 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13742 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13743 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13744 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13745 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13746 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13747 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13748 * SUCH DAMAGE.
13749 */