blob: 02545f565334fbd7d68df3ac099bad4a3c066846 [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 Vlasenko0b883582016-12-23 16:49:07 +0100139//applet:IF_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
140//applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
Denys Vlasenko20704f02011-03-23 17:59:27 +0100141
142//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
Denys Vlasenko0b883582016-12-23 16:49:07 +0100143//kbuild:lib-$(CONFIG_SH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
144//kbuild:lib-$(CONFIG_BASH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
Denys Vlasenko20704f02011-03-23 17:59:27 +0100145//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
146
Denys Vlasenko67047462016-12-22 15:21:58 +0100147/*
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100148 * DEBUG=1 to compile in debugging ('set -o debug' turns on)
149 * DEBUG=2 to compile in and turn on debugging.
150 * When debugging is on ("set -o debug" was executed, or DEBUG=2),
151 * debugging info is written to ./trace, quit signal generates core dump.
Denys Vlasenko67047462016-12-22 15:21:58 +0100152 */
153#define DEBUG 0
154/* Tweak debug output verbosity here */
155#define DEBUG_TIME 0
156#define DEBUG_PID 1
157#define DEBUG_SIG 1
158#define DEBUG_INTONOFF 0
159
160#define PROFILE 0
161
162#define JOBS ENABLE_ASH_JOB_CONTROL
163
164#include <setjmp.h>
165#include <fnmatch.h>
166#include <sys/times.h>
167#include <sys/utsname.h> /* for setting $HOSTNAME */
Denys Vlasenko67047462016-12-22 15:21:58 +0100168#include "busybox.h" /* for applet_names */
169
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100170/* So far, all bash compat is controlled by one config option */
171/* Separate defines document which part of code implements what */
172/* function keyword */
173#define BASH_FUNCTION ENABLE_ASH_BASH_COMPAT
174#define IF_BASH_FUNCTION IF_ASH_BASH_COMPAT
175/* &>file */
176#define BASH_REDIR_OUTPUT ENABLE_ASH_BASH_COMPAT
177#define IF_BASH_REDIR_OUTPUT IF_ASH_BASH_COMPAT
178/* $'...' */
179#define BASH_DOLLAR_SQUOTE ENABLE_ASH_BASH_COMPAT
180#define IF_BASH_DOLLAR_SQUOTE IF_ASH_BASH_COMPAT
181#define BASH_PATTERN_SUBST ENABLE_ASH_BASH_COMPAT
182#define IF_BASH_PATTERN_SUBST IF_ASH_BASH_COMPAT
183#define BASH_SUBSTR ENABLE_ASH_BASH_COMPAT
184#define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT
185/* [[ EXPR ]] */
186#define BASH_TEST2 (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST)
187#define BASH_SOURCE ENABLE_ASH_BASH_COMPAT
188#define BASH_PIPEFAIL ENABLE_ASH_BASH_COMPAT
189#define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT
190#define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT
191
Denys Vlasenko67047462016-12-22 15:21:58 +0100192#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
193/* Bionic at least up to version 24 has no glob() */
194# undef ENABLE_ASH_INTERNAL_GLOB
195# define ENABLE_ASH_INTERNAL_GLOB 1
196#endif
197
198#if !ENABLE_ASH_INTERNAL_GLOB && defined(__UCLIBC__)
199# error uClibc glob() is buggy, use ASH_INTERNAL_GLOB.
200# error The bug is: for "$PWD"/<pattern> ash will escape e.g. dashes in "$PWD"
201# error with backslash, even ones which do not need to be: "/a-b" -> "/a\-b"
202# error glob() should unbackslash them and match. uClibc does not unbackslash,
203# error fails to match dirname, subsequently not expanding <pattern> in it.
204// Testcase:
205// if (glob("/etc/polkit\\-1", 0, NULL, &pglob)) - this returns 0 on uclibc, no bug
206// if (glob("/etc/polkit\\-1/*", 0, NULL, &pglob)) printf("uclibc bug!\n");
207#endif
208
209#if !ENABLE_ASH_INTERNAL_GLOB
210# include <glob.h>
211#endif
212
213#include "unicode.h"
214#include "shell_common.h"
Denys Vlasenko0b883582016-12-23 16:49:07 +0100215#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko67047462016-12-22 15:21:58 +0100216# include "math.h"
217#endif
218#if ENABLE_ASH_RANDOM_SUPPORT
219# include "random.h"
220#else
221# define CLEAR_RANDOM_T(rnd) ((void)0)
222#endif
223
224#include "NUM_APPLETS.h"
225#if NUM_APPLETS == 1
226/* STANDALONE does not make sense, and won't compile */
227# undef CONFIG_FEATURE_SH_STANDALONE
228# undef ENABLE_FEATURE_SH_STANDALONE
229# undef IF_FEATURE_SH_STANDALONE
230# undef IF_NOT_FEATURE_SH_STANDALONE
231# define ENABLE_FEATURE_SH_STANDALONE 0
232# define IF_FEATURE_SH_STANDALONE(...)
233# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
234#endif
235
236#ifndef PIPE_BUF
237# define PIPE_BUF 4096 /* amount of buffering in a pipe */
238#endif
239
240#if !BB_MMU
241# error "Do not even bother, ash will not run on NOMMU machine"
242#endif
243
Denis Vlasenkob012b102007-02-19 22:43:01 +0000244
Denis Vlasenko01631112007-12-16 17:20:38 +0000245/* ============ Hash table sizes. Configurable. */
246
247#define VTABSIZE 39
248#define ATABSIZE 39
249#define CMDTABLESIZE 31 /* should be prime */
250
251
Denis Vlasenkob012b102007-02-19 22:43:01 +0000252/* ============ Shell options */
253
254static const char *const optletters_optnames[] = {
255 "e" "errexit",
256 "f" "noglob",
257 "I" "ignoreeof",
258 "i" "interactive",
259 "m" "monitor",
260 "n" "noexec",
261 "s" "stdin",
262 "x" "xtrace",
263 "v" "verbose",
264 "C" "noclobber",
265 "a" "allexport",
266 "b" "notify",
267 "u" "nounset",
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100268 "\0" "vi"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100269#if BASH_PIPEFAIL
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100270 ,"\0" "pipefail"
Michael Abbott359da5e2009-12-04 23:03:29 +0100271#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000272#if DEBUG
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000273 ,"\0" "nolog"
274 ,"\0" "debug"
Denis Vlasenkob012b102007-02-19 22:43:01 +0000275#endif
276};
277
Denys Vlasenko285ad152009-12-04 23:02:27 +0100278#define optletters(n) optletters_optnames[n][0]
279#define optnames(n) (optletters_optnames[n] + 1)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000280
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000281enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
Denis Vlasenkob012b102007-02-19 22:43:01 +0000282
Eric Andersenc470f442003-07-28 09:56:35 +0000283
Denis Vlasenkob012b102007-02-19 22:43:01 +0000284/* ============ Misc data */
Eric Andersenc470f442003-07-28 09:56:35 +0000285
Denys Vlasenkoea8b2522010-06-02 12:57:26 +0200286#define msg_illnum "Illegal number: %s"
Denis Vlasenkoaa744452007-02-23 01:04:22 +0000287
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +0000288/*
Eric Andersenc470f442003-07-28 09:56:35 +0000289 * We enclose jmp_buf in a structure so that we can declare pointers to
290 * jump locations. The global variable handler contains the location to
Denis Vlasenkof1733952009-03-19 23:21:55 +0000291 * jump to when an exception occurs, and the global variable exception_type
Eric Andersenaff114c2004-04-14 17:51:38 +0000292 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000293 * exception handlers, the user should save the value of handler on entry
294 * to an inner scope, set handler to point to a jmploc structure for the
295 * inner scope, and restore handler on exit from the scope.
296 */
Eric Andersenc470f442003-07-28 09:56:35 +0000297struct jmploc {
298 jmp_buf loc;
299};
Denis Vlasenko01631112007-12-16 17:20:38 +0000300
301struct globals_misc {
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200302 uint8_t exitstatus; /* exit status of last command */
303 uint8_t back_exitstatus;/* exit status of backquoted command */
304 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
305 int rootpid; /* pid of main shell */
Denis Vlasenko01631112007-12-16 17:20:38 +0000306 /* shell level: 0 for the main shell, 1 for its children, and so on */
307 int shlvl;
308#define rootshell (!shlvl)
309 char *minusc; /* argument to -c option */
310
311 char *curdir; // = nullstr; /* current working directory */
312 char *physdir; // = nullstr; /* physical working directory */
313
314 char *arg0; /* value of $0 */
315
316 struct jmploc *exception_handler;
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000317
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200318 volatile int suppress_int; /* counter */
319 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200320 volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +0200321 volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000322 smallint exception_type; /* kind of exception (0..5) */
Denis Vlasenko01631112007-12-16 17:20:38 +0000323 /* exceptions */
Eric Andersenc470f442003-07-28 09:56:35 +0000324#define EXINT 0 /* SIGINT received */
325#define EXERROR 1 /* a generic error */
Eric Andersenc470f442003-07-28 09:56:35 +0000326#define EXEXIT 4 /* exit the shell */
Eric Andersen2870d962001-07-02 17:27:21 +0000327
Denis Vlasenko01631112007-12-16 17:20:38 +0000328 smallint isloginsh;
Denis Vlasenkob07a4962008-06-22 13:16:23 +0000329 char nullstr[1]; /* zero length string */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000330
331 char optlist[NOPTS];
332#define eflag optlist[0]
333#define fflag optlist[1]
334#define Iflag optlist[2]
335#define iflag optlist[3]
336#define mflag optlist[4]
337#define nflag optlist[5]
338#define sflag optlist[6]
339#define xflag optlist[7]
340#define vflag optlist[8]
341#define Cflag optlist[9]
342#define aflag optlist[10]
343#define bflag optlist[11]
344#define uflag optlist[12]
345#define viflag optlist[13]
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100346#if BASH_PIPEFAIL
Michael Abbott359da5e2009-12-04 23:03:29 +0100347# define pipefail optlist[14]
348#else
349# define pipefail 0
350#endif
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000351#if DEBUG
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100352# define nolog optlist[14 + BASH_PIPEFAIL]
353# define debug optlist[15 + BASH_PIPEFAIL]
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000354#endif
355
356 /* trap handler commands */
Denis Vlasenko01631112007-12-16 17:20:38 +0000357 /*
358 * Sigmode records the current value of the signal handlers for the various
359 * modes. A value of zero means that the current handler is not known.
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000360 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
Denis Vlasenko01631112007-12-16 17:20:38 +0000361 */
362 char sigmode[NSIG - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000363#define S_DFL 1 /* default signal handling (SIG_DFL) */
364#define S_CATCH 2 /* signal is caught */
365#define S_IGN 3 /* signal is ignored (SIG_IGN) */
Denys Vlasenkoe5814a52016-07-16 18:33:55 +0200366#define S_HARD_IGN 4 /* signal is ignored permanently */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000367
Denis Vlasenko01631112007-12-16 17:20:38 +0000368 /* indicates specified signal received */
Denis Vlasenko4b875702009-03-19 13:30:04 +0000369 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
Denys Vlasenko238bf182010-05-18 15:49:07 +0200370 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000371 char *trap[NSIG];
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200372 char **trap_ptr; /* used only by "trap hack" */
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000373
374 /* Rarely referenced stuff */
375#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200376 random_t random_gen;
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000377#endif
378 pid_t backgndpid; /* pid of last background process */
Denis Vlasenko01631112007-12-16 17:20:38 +0000379};
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000380extern struct globals_misc *const ash_ptr_to_globals_misc;
381#define G_misc (*ash_ptr_to_globals_misc)
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200382#define exitstatus (G_misc.exitstatus )
383#define back_exitstatus (G_misc.back_exitstatus )
384#define job_warning (G_misc.job_warning)
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000385#define rootpid (G_misc.rootpid )
386#define shlvl (G_misc.shlvl )
387#define minusc (G_misc.minusc )
388#define curdir (G_misc.curdir )
389#define physdir (G_misc.physdir )
390#define arg0 (G_misc.arg0 )
Denis Vlasenko01631112007-12-16 17:20:38 +0000391#define exception_handler (G_misc.exception_handler)
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000392#define exception_type (G_misc.exception_type )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200393#define suppress_int (G_misc.suppress_int )
394#define pending_int (G_misc.pending_int )
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200395#define got_sigchld (G_misc.got_sigchld )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200396#define pending_sig (G_misc.pending_sig )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000397#define isloginsh (G_misc.isloginsh )
398#define nullstr (G_misc.nullstr )
399#define optlist (G_misc.optlist )
400#define sigmode (G_misc.sigmode )
401#define gotsig (G_misc.gotsig )
Denys Vlasenko238bf182010-05-18 15:49:07 +0200402#define may_have_traps (G_misc.may_have_traps )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000403#define trap (G_misc.trap )
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200404#define trap_ptr (G_misc.trap_ptr )
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200405#define random_gen (G_misc.random_gen )
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000406#define backgndpid (G_misc.backgndpid )
Denis Vlasenko01631112007-12-16 17:20:38 +0000407#define INIT_G_misc() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000408 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
409 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +0000410 curdir = nullstr; \
411 physdir = nullstr; \
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200412 trap_ptr = trap; \
Denis Vlasenko01631112007-12-16 17:20:38 +0000413} while (0)
414
415
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000416/* ============ DEBUG */
417#if DEBUG
418static void trace_printf(const char *fmt, ...);
419static void trace_vprintf(const char *fmt, va_list va);
420# define TRACE(param) trace_printf param
421# define TRACEV(param) trace_vprintf param
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000422# define close(fd) do { \
423 int dfd = (fd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000424 if (close(dfd) < 0) \
Denys Vlasenko883cea42009-07-11 15:31:59 +0200425 bb_error_msg("bug on %d: closing %d(0x%x)", \
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000426 __LINE__, dfd, dfd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000427} while (0)
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000428#else
429# define TRACE(param)
430# define TRACEV(param)
431#endif
432
433
Denis Vlasenko559691a2008-10-05 18:39:31 +0000434/* ============ Utility functions */
Denys Vlasenko1961aea2013-02-26 00:36:53 +0100435#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
436#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
437
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200438static int
439isdigit_str9(const char *str)
Denis Vlasenko559691a2008-10-05 18:39:31 +0000440{
441 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
442 while (--maxlen && isdigit(*str))
443 str++;
444 return (*str == '\0');
445}
Denis Vlasenko01631112007-12-16 17:20:38 +0000446
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200447static const char *
448var_end(const char *var)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +0200449{
450 while (*var)
451 if (*var++ == '=')
452 break;
453 return var;
454}
455
Denis Vlasenko559691a2008-10-05 18:39:31 +0000456
457/* ============ Interrupts / exceptions */
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100458
459static void exitshell(void) NORETURN;
460
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000461/*
Eric Andersen2870d962001-07-02 17:27:21 +0000462 * These macros allow the user to suspend the handling of interrupt signals
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000463 * over a period of time. This is similar to SIGHOLD or to sigblock, but
Eric Andersen2870d962001-07-02 17:27:21 +0000464 * much more efficient and portable. (But hacking the kernel is so much
465 * more fun than worrying about efficiency and portability. :-))
466 */
Denys Vlasenko06b11492016-11-04 16:43:18 +0100467#if DEBUG_INTONOFF
468# define INT_OFF do { \
469 TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200470 suppress_int++; \
Denys Vlasenkode892052016-10-02 01:49:13 +0200471 barrier(); \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000472} while (0)
Denys Vlasenko06b11492016-11-04 16:43:18 +0100473#else
474# define INT_OFF do { \
475 suppress_int++; \
476 barrier(); \
477} while (0)
478#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000479
480/*
481 * Called to raise an exception. Since C doesn't include exceptions, we
482 * just do a longjmp to the exception handler. The type of exception is
Denis Vlasenko4b875702009-03-19 13:30:04 +0000483 * stored in the global variable "exception_type".
Denis Vlasenkob012b102007-02-19 22:43:01 +0000484 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000485static void raise_exception(int) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000486static void
487raise_exception(int e)
488{
489#if DEBUG
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000490 if (exception_handler == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000491 abort();
492#endif
493 INT_OFF;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000494 exception_type = e;
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000495 longjmp(exception_handler->loc, 1);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000496}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000497#if DEBUG
498#define raise_exception(e) do { \
499 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
500 raise_exception(e); \
501} while (0)
502#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000503
504/*
Denys Vlasenkof37e1152016-10-07 03:17:28 +0200505 * Called when a SIGINT is received. (If the user specifies
Denis Vlasenkob012b102007-02-19 22:43:01 +0000506 * that SIGINT is to be trapped or ignored using the trap builtin, then
507 * this routine is not called.) Suppressint is nonzero when interrupts
508 * are held using the INT_OFF macro. (The test for iflag is just
509 * defensive programming.)
510 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000511static void raise_interrupt(void) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000512static void
513raise_interrupt(void)
514{
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200515 pending_int = 0;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000516 /* Signal is not automatically unmasked after it is raised,
517 * do it ourself - unmask all signals */
Denis Vlasenko3f165fa2008-03-17 08:29:08 +0000518 sigprocmask_allsigs(SIG_UNBLOCK);
Denys Vlasenko238bf182010-05-18 15:49:07 +0200519 /* pending_sig = 0; - now done in signal_handler() */
Denis Vlasenko7c139b42007-03-21 20:17:27 +0000520
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200521 if (!(rootshell && iflag)) {
522 /* Kill ourself with SIGINT */
523 signal(SIGINT, SIG_DFL);
524 raise(SIGINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000525 }
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200526 /* bash: ^C even on empty command line sets $? */
527 exitstatus = SIGINT + 128;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200528 raise_exception(EXINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000529 /* NOTREACHED */
530}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000531#if DEBUG
532#define raise_interrupt() do { \
533 TRACE(("raising interrupt on line %d\n", __LINE__)); \
534 raise_interrupt(); \
535} while (0)
536#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000537
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000538static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000539int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000540{
Denys Vlasenkode892052016-10-02 01:49:13 +0200541 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200542 if (--suppress_int == 0 && pending_int) {
Denis Vlasenkob012b102007-02-19 22:43:01 +0000543 raise_interrupt();
544 }
545}
Denys Vlasenko06b11492016-11-04 16:43:18 +0100546#if DEBUG_INTONOFF
547# define INT_ON do { \
548 TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
549 int_on(); \
550} while (0)
551#else
552# define INT_ON int_on()
553#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000554static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000555force_int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000556{
Denys Vlasenkode892052016-10-02 01:49:13 +0200557 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200558 suppress_int = 0;
559 if (pending_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000560 raise_interrupt();
561}
562#define FORCE_INT_ON force_int_on()
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000563
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200564#define SAVE_INT(v) ((v) = suppress_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000565
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000566#define RESTORE_INT(v) do { \
Denys Vlasenkode892052016-10-02 01:49:13 +0200567 barrier(); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200568 suppress_int = (v); \
569 if (suppress_int == 0 && pending_int) \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000570 raise_interrupt(); \
571} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000572
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000573
Denis Vlasenkobc54cff2007-02-23 01:05:52 +0000574/* ============ Stdout/stderr output */
Eric Andersenc470f442003-07-28 09:56:35 +0000575
Eric Andersenc470f442003-07-28 09:56:35 +0000576static void
Denis Vlasenkob012b102007-02-19 22:43:01 +0000577outstr(const char *p, FILE *file)
Denis Vlasenkoe5570da2007-02-19 22:41:55 +0000578{
Denis Vlasenkob012b102007-02-19 22:43:01 +0000579 INT_OFF;
580 fputs(p, file);
581 INT_ON;
582}
583
584static void
585flush_stdout_stderr(void)
586{
587 INT_OFF;
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100588 fflush_all();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000589 INT_ON;
590}
591
Denys Vlasenko9c541002015-10-07 15:44:36 +0200592/* Was called outcslow(c,FILE*), but c was always '\n' */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000593static void
Denys Vlasenko9c541002015-10-07 15:44:36 +0200594newline_and_flush(FILE *dest)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000595{
596 INT_OFF;
Denys Vlasenko9c541002015-10-07 15:44:36 +0200597 putc('\n', dest);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000598 fflush(dest);
599 INT_ON;
600}
601
602static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
603static int
604out1fmt(const char *fmt, ...)
605{
606 va_list ap;
607 int r;
608
609 INT_OFF;
610 va_start(ap, fmt);
611 r = vprintf(fmt, ap);
612 va_end(ap);
613 INT_ON;
614 return r;
615}
616
617static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
618static int
619fmtstr(char *outbuf, size_t length, const char *fmt, ...)
620{
621 va_list ap;
622 int ret;
623
624 va_start(ap, fmt);
625 INT_OFF;
626 ret = vsnprintf(outbuf, length, fmt, ap);
627 va_end(ap);
628 INT_ON;
629 return ret;
630}
631
632static void
633out1str(const char *p)
634{
635 outstr(p, stdout);
636}
637
638static void
639out2str(const char *p)
640{
641 outstr(p, stderr);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100642 flush_stdout_stderr();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000643}
644
645
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000646/* ============ Parser structures */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +0000647
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000648/* control characters in argument strings */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100649#define CTL_FIRST CTLESC
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200650#define CTLESC ((unsigned char)'\201') /* escape next character */
651#define CTLVAR ((unsigned char)'\202') /* variable defn */
652#define CTLENDVAR ((unsigned char)'\203')
653#define CTLBACKQ ((unsigned char)'\204')
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200654#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
655#define CTLENDARI ((unsigned char)'\207')
656#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100657#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000658
659/* variable substitution byte (follows CTLVAR) */
660#define VSTYPE 0x0f /* type of variable substitution */
661#define VSNUL 0x10 /* colon--treat the empty string as unset */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000662
663/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000664#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
665#define VSMINUS 0x2 /* ${var-text} */
666#define VSPLUS 0x3 /* ${var+text} */
667#define VSQUESTION 0x4 /* ${var?message} */
668#define VSASSIGN 0x5 /* ${var=text} */
669#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
670#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
671#define VSTRIMLEFT 0x8 /* ${var#pattern} */
672#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
673#define VSLENGTH 0xa /* ${#var} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100674#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000675#define VSSUBSTR 0xc /* ${var:position:length} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100676#endif
677#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000678#define VSREPLACE 0xd /* ${var/pattern/replacement} */
679#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
680#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000681
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000682static const char dolatstr[] ALIGN1 = {
Ron Yorston549deab2015-05-18 09:57:51 +0200683 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000684};
Ron Yorston549deab2015-05-18 09:57:51 +0200685#define DOLATSTRLEN 6
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000686
Denis Vlasenko559691a2008-10-05 18:39:31 +0000687#define NCMD 0
688#define NPIPE 1
689#define NREDIR 2
690#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000691#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000692#define NAND 5
693#define NOR 6
694#define NSEMI 7
695#define NIF 8
696#define NWHILE 9
697#define NUNTIL 10
698#define NFOR 11
699#define NCASE 12
700#define NCLIST 13
701#define NDEFUN 14
702#define NARG 15
703#define NTO 16
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100704#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +0000705#define NTO2 17
706#endif
707#define NCLOBBER 18
708#define NFROM 19
709#define NFROMTO 20
710#define NAPPEND 21
711#define NTOFD 22
712#define NFROMFD 23
713#define NHERE 24
714#define NXHERE 25
715#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000716#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000717
718union node;
719
720struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000721 smallint type; /* Nxxxx */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000722 union node *assign;
723 union node *args;
724 union node *redirect;
725};
726
727struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000728 smallint type;
729 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000730 struct nodelist *cmdlist;
731};
732
733struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000734 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000735 union node *n;
736 union node *redirect;
737};
738
739struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000740 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000741 union node *ch1;
742 union node *ch2;
743};
744
745struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000746 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000747 union node *test;
748 union node *ifpart;
749 union node *elsepart;
750};
751
752struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000753 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000754 union node *args;
755 union node *body;
756 char *var;
757};
758
759struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000760 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000761 union node *expr;
762 union node *cases;
763};
764
765struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000766 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000767 union node *next;
768 union node *pattern;
769 union node *body;
770};
771
772struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000773 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000774 union node *next;
775 char *text;
776 struct nodelist *backquote;
777};
778
Denis Vlasenko559691a2008-10-05 18:39:31 +0000779/* nfile and ndup layout must match!
780 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
781 * that it is actually NTO2 (>&file), and change its type.
782 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000783struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000784 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000785 union node *next;
786 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000787 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000788 union node *fname;
789 char *expfname;
790};
791
792struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000793 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000794 union node *next;
795 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000796 int dupfd;
797 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000798 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000799};
800
801struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000802 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000803 union node *next;
804 int fd;
805 union node *doc;
806};
807
808struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000809 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000810 union node *com;
811};
812
813union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000814 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000815 struct ncmd ncmd;
816 struct npipe npipe;
817 struct nredir nredir;
818 struct nbinary nbinary;
819 struct nif nif;
820 struct nfor nfor;
821 struct ncase ncase;
822 struct nclist nclist;
823 struct narg narg;
824 struct nfile nfile;
825 struct ndup ndup;
826 struct nhere nhere;
827 struct nnot nnot;
828};
829
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200830/*
831 * NODE_EOF is returned by parsecmd when it encounters an end of file.
832 * It must be distinct from NULL.
833 */
834#define NODE_EOF ((union node *) -1L)
835
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000836struct nodelist {
837 struct nodelist *next;
838 union node *n;
839};
840
841struct funcnode {
842 int count;
843 union node n;
844};
845
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000846/*
847 * Free a parse tree.
848 */
849static void
850freefunc(struct funcnode *f)
851{
852 if (f && --f->count < 0)
853 free(f);
854}
855
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000856
857/* ============ Debugging output */
858
859#if DEBUG
860
861static FILE *tracefile;
862
863static void
864trace_printf(const char *fmt, ...)
865{
866 va_list va;
867
868 if (debug != 1)
869 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000870 if (DEBUG_TIME)
871 fprintf(tracefile, "%u ", (int) time(NULL));
872 if (DEBUG_PID)
873 fprintf(tracefile, "[%u] ", (int) getpid());
874 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200875 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000876 va_start(va, fmt);
877 vfprintf(tracefile, fmt, va);
878 va_end(va);
879}
880
881static void
882trace_vprintf(const char *fmt, va_list va)
883{
884 if (debug != 1)
885 return;
886 vfprintf(tracefile, fmt, va);
Denys Vlasenko474ed062016-10-30 18:30:29 +0100887 fprintf(tracefile, "\n");
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000888}
889
890static void
891trace_puts(const char *s)
892{
893 if (debug != 1)
894 return;
895 fputs(s, tracefile);
896}
897
898static void
899trace_puts_quoted(char *s)
900{
901 char *p;
902 char c;
903
904 if (debug != 1)
905 return;
906 putc('"', tracefile);
907 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100908 switch ((unsigned char)*p) {
909 case '\n': c = 'n'; goto backslash;
910 case '\t': c = 't'; goto backslash;
911 case '\r': c = 'r'; goto backslash;
912 case '\"': c = '\"'; goto backslash;
913 case '\\': c = '\\'; goto backslash;
914 case CTLESC: c = 'e'; goto backslash;
915 case CTLVAR: c = 'v'; goto backslash;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100916 case CTLBACKQ: c = 'q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000917 backslash:
918 putc('\\', tracefile);
919 putc(c, tracefile);
920 break;
921 default:
922 if (*p >= ' ' && *p <= '~')
923 putc(*p, tracefile);
924 else {
925 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +0100926 putc((*p >> 6) & 03, tracefile);
927 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000928 putc(*p & 07, tracefile);
929 }
930 break;
931 }
932 }
933 putc('"', tracefile);
934}
935
936static void
937trace_puts_args(char **ap)
938{
939 if (debug != 1)
940 return;
941 if (!*ap)
942 return;
943 while (1) {
944 trace_puts_quoted(*ap);
945 if (!*++ap) {
946 putc('\n', tracefile);
947 break;
948 }
949 putc(' ', tracefile);
950 }
951}
952
953static void
954opentrace(void)
955{
956 char s[100];
957#ifdef O_APPEND
958 int flags;
959#endif
960
961 if (debug != 1) {
962 if (tracefile)
963 fflush(tracefile);
964 /* leave open because libedit might be using it */
965 return;
966 }
967 strcpy(s, "./trace");
968 if (tracefile) {
969 if (!freopen(s, "a", tracefile)) {
970 fprintf(stderr, "Can't re-open %s\n", s);
971 debug = 0;
972 return;
973 }
974 } else {
975 tracefile = fopen(s, "a");
976 if (tracefile == NULL) {
977 fprintf(stderr, "Can't open %s\n", s);
978 debug = 0;
979 return;
980 }
981 }
982#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000983 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000984 if (flags >= 0)
985 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
986#endif
987 setlinebuf(tracefile);
988 fputs("\nTracing started.\n", tracefile);
989}
990
991static void
992indent(int amount, char *pfx, FILE *fp)
993{
994 int i;
995
996 for (i = 0; i < amount; i++) {
997 if (pfx && i == amount - 1)
998 fputs(pfx, fp);
999 putc('\t', fp);
1000 }
1001}
1002
1003/* little circular references here... */
1004static void shtree(union node *n, int ind, char *pfx, FILE *fp);
1005
1006static void
1007sharg(union node *arg, FILE *fp)
1008{
1009 char *p;
1010 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001011 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001012
1013 if (arg->type != NARG) {
1014 out1fmt("<node type %d>\n", arg->type);
1015 abort();
1016 }
1017 bqlist = arg->narg.backquote;
1018 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01001019 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001020 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -07001021 p++;
1022 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001023 break;
1024 case CTLVAR:
1025 putc('$', fp);
1026 putc('{', fp);
1027 subtype = *++p;
1028 if (subtype == VSLENGTH)
1029 putc('#', fp);
1030
Dan Fandrich77d48722010-09-07 23:38:28 -07001031 while (*p != '=') {
1032 putc(*p, fp);
1033 p++;
1034 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001035
1036 if (subtype & VSNUL)
1037 putc(':', fp);
1038
1039 switch (subtype & VSTYPE) {
1040 case VSNORMAL:
1041 putc('}', fp);
1042 break;
1043 case VSMINUS:
1044 putc('-', fp);
1045 break;
1046 case VSPLUS:
1047 putc('+', fp);
1048 break;
1049 case VSQUESTION:
1050 putc('?', fp);
1051 break;
1052 case VSASSIGN:
1053 putc('=', fp);
1054 break;
1055 case VSTRIMLEFT:
1056 putc('#', fp);
1057 break;
1058 case VSTRIMLEFTMAX:
1059 putc('#', fp);
1060 putc('#', fp);
1061 break;
1062 case VSTRIMRIGHT:
1063 putc('%', fp);
1064 break;
1065 case VSTRIMRIGHTMAX:
1066 putc('%', fp);
1067 putc('%', fp);
1068 break;
1069 case VSLENGTH:
1070 break;
1071 default:
1072 out1fmt("<subtype %d>", subtype);
1073 }
1074 break;
1075 case CTLENDVAR:
1076 putc('}', fp);
1077 break;
1078 case CTLBACKQ:
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001079 putc('$', fp);
1080 putc('(', fp);
1081 shtree(bqlist->n, -1, NULL, fp);
1082 putc(')', fp);
1083 break;
1084 default:
1085 putc(*p, fp);
1086 break;
1087 }
1088 }
1089}
1090
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001091static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001092shcmd(union node *cmd, FILE *fp)
1093{
1094 union node *np;
1095 int first;
1096 const char *s;
1097 int dftfd;
1098
1099 first = 1;
1100 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001101 if (!first)
1102 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001103 sharg(np, fp);
1104 first = 0;
1105 }
1106 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001107 if (!first)
1108 putc(' ', fp);
1109 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001110 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001111 case NTO: s = ">>"+1; dftfd = 1; break;
1112 case NCLOBBER: s = ">|"; dftfd = 1; break;
1113 case NAPPEND: s = ">>"; dftfd = 1; break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01001114#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00001115 case NTO2:
1116#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001117 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001118 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001119 case NFROMFD: s = "<&"; break;
1120 case NFROMTO: s = "<>"; break;
1121 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001122 }
1123 if (np->nfile.fd != dftfd)
1124 fprintf(fp, "%d", np->nfile.fd);
1125 fputs(s, fp);
1126 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1127 fprintf(fp, "%d", np->ndup.dupfd);
1128 } else {
1129 sharg(np->nfile.fname, fp);
1130 }
1131 first = 0;
1132 }
1133}
1134
1135static void
1136shtree(union node *n, int ind, char *pfx, FILE *fp)
1137{
1138 struct nodelist *lp;
1139 const char *s;
1140
1141 if (n == NULL)
1142 return;
1143
1144 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001145
1146 if (n == NODE_EOF) {
1147 fputs("<EOF>", fp);
1148 return;
1149 }
1150
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001151 switch (n->type) {
1152 case NSEMI:
1153 s = "; ";
1154 goto binop;
1155 case NAND:
1156 s = " && ";
1157 goto binop;
1158 case NOR:
1159 s = " || ";
1160 binop:
1161 shtree(n->nbinary.ch1, ind, NULL, fp);
1162 /* if (ind < 0) */
1163 fputs(s, fp);
1164 shtree(n->nbinary.ch2, ind, NULL, fp);
1165 break;
1166 case NCMD:
1167 shcmd(n, fp);
1168 if (ind >= 0)
1169 putc('\n', fp);
1170 break;
1171 case NPIPE:
1172 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001173 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001174 if (lp->next)
1175 fputs(" | ", fp);
1176 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001177 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001178 fputs(" &", fp);
1179 if (ind >= 0)
1180 putc('\n', fp);
1181 break;
1182 default:
1183 fprintf(fp, "<node type %d>", n->type);
1184 if (ind >= 0)
1185 putc('\n', fp);
1186 break;
1187 }
1188}
1189
1190static void
1191showtree(union node *n)
1192{
1193 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001194 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001195}
1196
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001197#endif /* DEBUG */
1198
1199
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001200/* ============ Parser data */
1201
1202/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001203 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1204 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001205struct strlist {
1206 struct strlist *next;
1207 char *text;
1208};
1209
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001210struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001211
Denis Vlasenkob012b102007-02-19 22:43:01 +00001212struct strpush {
1213 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001214 char *prev_string;
1215 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001216#if ENABLE_ASH_ALIAS
1217 struct alias *ap; /* if push was associated with an alias */
1218#endif
1219 char *string; /* remember the string since it may change */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001220
1221 /* Remember last two characters for pungetc. */
1222 int lastc[2];
1223
1224 /* Number of outstanding calls to pungetc. */
1225 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001226};
1227
1228struct parsefile {
1229 struct parsefile *prev; /* preceding file on stack */
1230 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001231 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001232 int left_in_line; /* number of chars left in this line */
1233 int left_in_buffer; /* number of chars left in this buffer past the line */
1234 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001235 char *buf; /* input buffer */
1236 struct strpush *strpush; /* for pushing strings at this level */
1237 struct strpush basestrpush; /* so pushing one is fast */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001238
1239 /* Remember last two characters for pungetc. */
1240 int lastc[2];
1241
1242 /* Number of outstanding calls to pungetc. */
1243 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001244};
1245
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001246static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001247static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001248static int startlinno; /* line # where last token started */
1249static char *commandname; /* currently executing command */
1250static struct strlist *cmdenviron; /* environment for builtin command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001251
1252
1253/* ============ Message printing */
1254
1255static void
1256ash_vmsg(const char *msg, va_list ap)
1257{
1258 fprintf(stderr, "%s: ", arg0);
1259 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001260 if (strcmp(arg0, commandname))
1261 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001262 if (!iflag || g_parsefile->pf_fd > 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001263 fprintf(stderr, "line %d: ", startlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001264 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001265 vfprintf(stderr, msg, ap);
Denys Vlasenko9c541002015-10-07 15:44:36 +02001266 newline_and_flush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001267}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001268
1269/*
1270 * Exverror is called to raise the error exception. If the second argument
1271 * is not NULL then error prints an error message using printf style
1272 * formatting. It then raises the error exception.
1273 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001274static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001275static void
1276ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001277{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001278#if DEBUG
1279 if (msg) {
Denys Vlasenko474ed062016-10-30 18:30:29 +01001280 TRACE(("ash_vmsg_and_raise(%d):", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001281 TRACEV((msg, ap));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001282 } else
Denys Vlasenko474ed062016-10-30 18:30:29 +01001283 TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001284 if (msg)
1285#endif
1286 ash_vmsg(msg, ap);
1287
1288 flush_stdout_stderr();
1289 raise_exception(cond);
1290 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001291}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001292
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001293static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001294static void
1295ash_msg_and_raise_error(const char *msg, ...)
1296{
1297 va_list ap;
1298
Ron Yorstonea7d2f62017-01-03 11:18:23 +01001299 exitstatus = 2;
1300
Denis Vlasenkob012b102007-02-19 22:43:01 +00001301 va_start(ap, msg);
1302 ash_vmsg_and_raise(EXERROR, msg, ap);
1303 /* NOTREACHED */
1304 va_end(ap);
1305}
1306
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001307static void raise_error_syntax(const char *) NORETURN;
1308static void
1309raise_error_syntax(const char *msg)
1310{
1311 ash_msg_and_raise_error("syntax error: %s", msg);
1312 /* NOTREACHED */
1313}
1314
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001315static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001316static void
1317ash_msg_and_raise(int cond, const char *msg, ...)
1318{
1319 va_list ap;
1320
1321 va_start(ap, msg);
1322 ash_vmsg_and_raise(cond, msg, ap);
1323 /* NOTREACHED */
1324 va_end(ap);
1325}
1326
1327/*
1328 * error/warning routines for external builtins
1329 */
1330static void
1331ash_msg(const char *fmt, ...)
1332{
1333 va_list ap;
1334
1335 va_start(ap, fmt);
1336 ash_vmsg(fmt, ap);
1337 va_end(ap);
1338}
1339
1340/*
1341 * Return a string describing an error. The returned string may be a
1342 * pointer to a static buffer that will be overwritten on the next call.
1343 * Action describes the operation that got the error.
1344 */
1345static const char *
1346errmsg(int e, const char *em)
1347{
1348 if (e == ENOENT || e == ENOTDIR) {
1349 return em;
1350 }
1351 return strerror(e);
1352}
1353
1354
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001355/* ============ Memory allocation */
1356
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001357#if 0
1358/* I consider these wrappers nearly useless:
1359 * ok, they return you to nearest exception handler, but
1360 * how much memory do you leak in the process, making
1361 * memory starvation worse?
1362 */
1363static void *
1364ckrealloc(void * p, size_t nbytes)
1365{
1366 p = realloc(p, nbytes);
1367 if (!p)
1368 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1369 return p;
1370}
1371
1372static void *
1373ckmalloc(size_t nbytes)
1374{
1375 return ckrealloc(NULL, nbytes);
1376}
1377
1378static void *
1379ckzalloc(size_t nbytes)
1380{
1381 return memset(ckmalloc(nbytes), 0, nbytes);
1382}
1383
1384static char *
1385ckstrdup(const char *s)
1386{
1387 char *p = strdup(s);
1388 if (!p)
1389 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1390 return p;
1391}
1392#else
1393/* Using bbox equivalents. They exit if out of memory */
1394# define ckrealloc xrealloc
1395# define ckmalloc xmalloc
1396# define ckzalloc xzalloc
1397# define ckstrdup xstrdup
1398#endif
1399
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001400/*
1401 * It appears that grabstackstr() will barf with such alignments
1402 * because stalloc() will return a string allocated in a new stackblock.
1403 */
1404#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1405enum {
1406 /* Most machines require the value returned from malloc to be aligned
1407 * in some way. The following macro will get this right
1408 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001409 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001410 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001411 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001412};
1413
1414struct stack_block {
1415 struct stack_block *prev;
1416 char space[MINSIZE];
1417};
1418
1419struct stackmark {
1420 struct stack_block *stackp;
1421 char *stacknxt;
1422 size_t stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001423};
1424
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001425
Denis Vlasenko01631112007-12-16 17:20:38 +00001426struct globals_memstack {
1427 struct stack_block *g_stackp; // = &stackbase;
Denis Vlasenko01631112007-12-16 17:20:38 +00001428 char *g_stacknxt; // = stackbase.space;
1429 char *sstrend; // = stackbase.space + MINSIZE;
1430 size_t g_stacknleft; // = MINSIZE;
Denis Vlasenko01631112007-12-16 17:20:38 +00001431 struct stack_block stackbase;
1432};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001433extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1434#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001435#define g_stackp (G_memstack.g_stackp )
Denis Vlasenko01631112007-12-16 17:20:38 +00001436#define g_stacknxt (G_memstack.g_stacknxt )
1437#define sstrend (G_memstack.sstrend )
1438#define g_stacknleft (G_memstack.g_stacknleft)
Denis Vlasenko01631112007-12-16 17:20:38 +00001439#define stackbase (G_memstack.stackbase )
1440#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001441 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1442 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001443 g_stackp = &stackbase; \
1444 g_stacknxt = stackbase.space; \
1445 g_stacknleft = MINSIZE; \
1446 sstrend = stackbase.space + MINSIZE; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001447} while (0)
1448
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001449
Denis Vlasenko01631112007-12-16 17:20:38 +00001450#define stackblock() ((void *)g_stacknxt)
1451#define stackblocksize() g_stacknleft
1452
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001453/*
1454 * Parse trees for commands are allocated in lifo order, so we use a stack
1455 * to make this more efficient, and also to avoid all sorts of exception
1456 * handling code to handle interrupts in the middle of a parse.
1457 *
1458 * The size 504 was chosen because the Ultrix malloc handles that size
1459 * well.
1460 */
1461static void *
1462stalloc(size_t nbytes)
1463{
1464 char *p;
1465 size_t aligned;
1466
1467 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001468 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001469 size_t len;
1470 size_t blocksize;
1471 struct stack_block *sp;
1472
1473 blocksize = aligned;
1474 if (blocksize < MINSIZE)
1475 blocksize = MINSIZE;
1476 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1477 if (len < blocksize)
1478 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1479 INT_OFF;
1480 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001481 sp->prev = g_stackp;
1482 g_stacknxt = sp->space;
1483 g_stacknleft = blocksize;
1484 sstrend = g_stacknxt + blocksize;
1485 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001486 INT_ON;
1487 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001488 p = g_stacknxt;
1489 g_stacknxt += aligned;
1490 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001491 return p;
1492}
1493
Denis Vlasenko597906c2008-02-20 16:38:54 +00001494static void *
1495stzalloc(size_t nbytes)
1496{
1497 return memset(stalloc(nbytes), 0, nbytes);
1498}
1499
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001500static void
1501stunalloc(void *p)
1502{
1503#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001504 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001505 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001506 abort();
1507 }
1508#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001509 g_stacknleft += g_stacknxt - (char *)p;
1510 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001511}
1512
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001513/*
1514 * Like strdup but works with the ash stack.
1515 */
1516static char *
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02001517sstrdup(const char *p)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001518{
1519 size_t len = strlen(p) + 1;
1520 return memcpy(stalloc(len), p, len);
1521}
1522
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001523static inline void
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001524grabstackblock(size_t len)
1525{
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001526 stalloc(len);
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001527}
1528
1529static void
1530pushstackmark(struct stackmark *mark, size_t len)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001531{
Denis Vlasenko01631112007-12-16 17:20:38 +00001532 mark->stackp = g_stackp;
1533 mark->stacknxt = g_stacknxt;
1534 mark->stacknleft = g_stacknleft;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001535 grabstackblock(len);
1536}
1537
1538static void
1539setstackmark(struct stackmark *mark)
1540{
1541 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001542}
1543
1544static void
1545popstackmark(struct stackmark *mark)
1546{
1547 struct stack_block *sp;
1548
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001549 if (!mark->stackp)
1550 return;
1551
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001552 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001553 while (g_stackp != mark->stackp) {
1554 sp = g_stackp;
1555 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001556 free(sp);
1557 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001558 g_stacknxt = mark->stacknxt;
1559 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001560 sstrend = mark->stacknxt + mark->stacknleft;
1561 INT_ON;
1562}
1563
1564/*
1565 * When the parser reads in a string, it wants to stick the string on the
1566 * stack and only adjust the stack pointer when it knows how big the
1567 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1568 * of space on top of the stack and stackblocklen returns the length of
1569 * this block. Growstackblock will grow this space by at least one byte,
1570 * possibly moving it (like realloc). Grabstackblock actually allocates the
1571 * part of the block that has been used.
1572 */
1573static void
1574growstackblock(void)
1575{
1576 size_t newlen;
1577
Denis Vlasenko01631112007-12-16 17:20:38 +00001578 newlen = g_stacknleft * 2;
1579 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001580 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1581 if (newlen < 128)
1582 newlen += 128;
1583
Denis Vlasenko01631112007-12-16 17:20:38 +00001584 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001585 struct stack_block *sp;
1586 struct stack_block *prevstackp;
1587 size_t grosslen;
1588
1589 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001590 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001591 prevstackp = sp->prev;
1592 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1593 sp = ckrealloc(sp, grosslen);
1594 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001595 g_stackp = sp;
1596 g_stacknxt = sp->space;
1597 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001598 sstrend = sp->space + newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001599 INT_ON;
1600 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001601 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001602 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001603 char *p = stalloc(newlen);
1604
1605 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001606 g_stacknxt = memcpy(p, oldspace, oldlen);
1607 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001608 }
1609}
1610
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001611/*
1612 * The following routines are somewhat easier to use than the above.
1613 * The user declares a variable of type STACKSTR, which may be declared
1614 * to be a register. The macro STARTSTACKSTR initializes things. Then
1615 * the user uses the macro STPUTC to add characters to the string. In
1616 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1617 * grown as necessary. When the user is done, she can just leave the
1618 * string there and refer to it using stackblock(). Or she can allocate
1619 * the space for it using grabstackstr(). If it is necessary to allow
1620 * someone else to use the stack temporarily and then continue to grow
1621 * the string, the user should use grabstack to allocate the space, and
1622 * then call ungrabstr(p) to return to the previous mode of operation.
1623 *
1624 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1625 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1626 * is space for at least one character.
1627 */
1628static void *
1629growstackstr(void)
1630{
1631 size_t len = stackblocksize();
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001632 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001633 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001634}
1635
1636/*
1637 * Called from CHECKSTRSPACE.
1638 */
1639static char *
1640makestrspace(size_t newlen, char *p)
1641{
Denis Vlasenko01631112007-12-16 17:20:38 +00001642 size_t len = p - g_stacknxt;
Denys Vlasenko53d6e032016-09-30 11:24:12 +02001643 size_t size;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001644
1645 for (;;) {
1646 size_t nleft;
1647
1648 size = stackblocksize();
1649 nleft = size - len;
1650 if (nleft >= newlen)
1651 break;
1652 growstackblock();
1653 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001654 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001655}
1656
1657static char *
1658stack_nputstr(const char *s, size_t n, char *p)
1659{
1660 p = makestrspace(n, p);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001661 p = (char *)memcpy(p, s, n) + n;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001662 return p;
1663}
1664
1665static char *
1666stack_putstr(const char *s, char *p)
1667{
1668 return stack_nputstr(s, strlen(s), p);
1669}
1670
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001671static char *
1672_STPUTC(int c, char *p)
1673{
1674 if (p == sstrend)
1675 p = growstackstr();
1676 *p++ = c;
1677 return p;
1678}
1679
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001680#define STARTSTACKSTR(p) ((p) = stackblock())
1681#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001682#define CHECKSTRSPACE(n, p) do { \
1683 char *q = (p); \
1684 size_t l = (n); \
1685 size_t m = sstrend - q; \
1686 if (l > m) \
1687 (p) = makestrspace(l, q); \
1688} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001689#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001690#define STACKSTRNUL(p) do { \
1691 if ((p) == sstrend) \
1692 (p) = growstackstr(); \
1693 *(p) = '\0'; \
1694} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001695#define STUNPUTC(p) (--(p))
1696#define STTOPC(p) ((p)[-1])
1697#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001698
1699#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001700#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001701#define stackstrend() ((void *)sstrend)
1702
1703
1704/* ============ String helpers */
1705
1706/*
1707 * prefix -- see if pfx is a prefix of string.
1708 */
1709static char *
1710prefix(const char *string, const char *pfx)
1711{
1712 while (*pfx) {
1713 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001714 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001715 }
1716 return (char *) string;
1717}
1718
1719/*
1720 * Check for a valid number. This should be elsewhere.
1721 */
1722static int
1723is_number(const char *p)
1724{
1725 do {
1726 if (!isdigit(*p))
1727 return 0;
1728 } while (*++p != '\0');
1729 return 1;
1730}
1731
1732/*
1733 * Convert a string of digits to an integer, printing an error message on
1734 * failure.
1735 */
1736static int
1737number(const char *s)
1738{
1739 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001740 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001741 return atoi(s);
1742}
1743
1744/*
1745 * Produce a possibly single quoted string suitable as input to the shell.
1746 * The return string is allocated on the stack.
1747 */
1748static char *
1749single_quote(const char *s)
1750{
1751 char *p;
1752
1753 STARTSTACKSTR(p);
1754
1755 do {
1756 char *q;
1757 size_t len;
1758
1759 len = strchrnul(s, '\'') - s;
1760
1761 q = p = makestrspace(len + 3, p);
1762
1763 *q++ = '\'';
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001764 q = (char *)memcpy(q, s, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001765 *q++ = '\'';
1766 s += len;
1767
1768 STADJUST(q - p, p);
1769
Denys Vlasenkocd716832009-11-28 22:14:02 +01001770 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001771 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001772 len = 0;
1773 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001774
1775 q = p = makestrspace(len + 3, p);
1776
1777 *q++ = '"';
Denys Vlasenkocd716832009-11-28 22:14:02 +01001778 q = (char *)memcpy(q, s - len, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001779 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001780
1781 STADJUST(q - p, p);
1782 } while (*s);
1783
Denys Vlasenkocd716832009-11-28 22:14:02 +01001784 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001785
1786 return stackblock();
1787}
1788
1789
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001790/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001791
1792static char **argptr; /* argument list for builtin commands */
1793static char *optionarg; /* set by nextopt (like getopt) */
1794static char *optptr; /* used by nextopt */
1795
1796/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001797 * XXX - should get rid of. Have all builtins use getopt(3).
1798 * The library getopt must have the BSD extension static variable
1799 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001800 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001801 * Standard option processing (a la getopt) for builtin routines.
1802 * The only argument that is passed to nextopt is the option string;
1803 * the other arguments are unnecessary. It returns the character,
1804 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001805 */
1806static int
1807nextopt(const char *optstring)
1808{
1809 char *p;
1810 const char *q;
1811 char c;
1812
1813 p = optptr;
1814 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001815 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001816 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001817 if (p == NULL)
1818 return '\0';
1819 if (*p != '-')
1820 return '\0';
1821 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001822 return '\0';
1823 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001824 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001825 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001826 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001827 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001828 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001829 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001830 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001831 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001832 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001833 if (*++q == ':')
1834 q++;
1835 }
1836 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001837 if (*p == '\0') {
1838 p = *argptr++;
1839 if (p == NULL)
1840 ash_msg_and_raise_error("no arg for -%c option", c);
1841 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001842 optionarg = p;
1843 p = NULL;
1844 }
1845 optptr = p;
1846 return c;
1847}
1848
1849
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001850/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001851
Denis Vlasenko01631112007-12-16 17:20:38 +00001852/*
1853 * The parsefile structure pointed to by the global variable parsefile
1854 * contains information about the current file being read.
1855 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001856struct shparam {
1857 int nparam; /* # of positional parameters (without $0) */
1858#if ENABLE_ASH_GETOPTS
1859 int optind; /* next parameter to be processed by getopts */
1860 int optoff; /* used by getopts */
1861#endif
1862 unsigned char malloced; /* if parameter list dynamically allocated */
1863 char **p; /* parameter list */
1864};
1865
1866/*
1867 * Free the list of positional parameters.
1868 */
1869static void
1870freeparam(volatile struct shparam *param)
1871{
Denis Vlasenko01631112007-12-16 17:20:38 +00001872 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001873 char **ap, **ap1;
1874 ap = ap1 = param->p;
1875 while (*ap)
1876 free(*ap++);
1877 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001878 }
1879}
1880
1881#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001882static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001883#endif
1884
1885struct var {
1886 struct var *next; /* next entry in hash list */
1887 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001888 const char *var_text; /* name=value */
1889 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001890 /* the variable gets set/unset */
1891};
1892
1893struct localvar {
1894 struct localvar *next; /* next local variable in list */
1895 struct var *vp; /* the variable that was made local */
1896 int flags; /* saved flags */
1897 const char *text; /* saved text */
1898};
1899
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001900/* flags */
1901#define VEXPORT 0x01 /* variable is exported */
1902#define VREADONLY 0x02 /* variable cannot be modified */
1903#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1904#define VTEXTFIXED 0x08 /* text is statically allocated */
1905#define VSTACK 0x10 /* text is allocated on the stack */
1906#define VUNSET 0x20 /* the variable is not set */
1907#define VNOFUNC 0x40 /* don't call the callback function */
1908#define VNOSET 0x80 /* do not set variable - just readonly test */
1909#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001910#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001911# define VDYNAMIC 0x200 /* dynamic variable */
1912#else
1913# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001914#endif
1915
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001916
Denis Vlasenko01631112007-12-16 17:20:38 +00001917/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001918#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001919static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001920change_lc_all(const char *value)
1921{
1922 if (value && *value != '\0')
1923 setlocale(LC_ALL, value);
1924}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001925static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001926change_lc_ctype(const char *value)
1927{
1928 if (value && *value != '\0')
1929 setlocale(LC_CTYPE, value);
1930}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001931#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001932#if ENABLE_ASH_MAIL
1933static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01001934static void changemail(const char *var_value) FAST_FUNC;
1935#else
1936# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001937#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001938static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001939#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001940static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001941#endif
1942
Denis Vlasenko01631112007-12-16 17:20:38 +00001943static const struct {
1944 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001945 const char *var_text;
1946 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00001947} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02001948 /*
1949 * Note: VEXPORT would not work correctly here for NOFORK applets:
1950 * some environment strings may be constant.
1951 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001952 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001953#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001954 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
1955 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001956#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001957 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1958 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1959 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1960 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001961#if ENABLE_ASH_GETOPTS
Denys Vlasenkoe627ac92016-09-30 14:36:59 +02001962 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001963#endif
1964#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001965 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001966#endif
1967#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001968 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
1969 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001970#endif
1971#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001972 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001973#endif
1974};
1975
Denis Vlasenko0b769642008-07-24 07:54:57 +00001976struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00001977
1978struct globals_var {
1979 struct shparam shellparam; /* $@ current positional parameters */
1980 struct redirtab *redirlist;
Denis Vlasenko01631112007-12-16 17:20:38 +00001981 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1982 struct var *vartab[VTABSIZE];
1983 struct var varinit[ARRAY_SIZE(varinit_data)];
1984};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001985extern struct globals_var *const ash_ptr_to_globals_var;
1986#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00001987#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00001988//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00001989#define preverrout_fd (G_var.preverrout_fd)
1990#define vartab (G_var.vartab )
1991#define varinit (G_var.varinit )
1992#define INIT_G_var() do { \
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00001993 unsigned i; \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001994 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1995 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001996 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001997 varinit[i].flags = varinit_data[i].flags; \
1998 varinit[i].var_text = varinit_data[i].var_text; \
1999 varinit[i].var_func = varinit_data[i].var_func; \
Denis Vlasenko01631112007-12-16 17:20:38 +00002000 } \
2001} while (0)
2002
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002003#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002004#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002005# define vmail (&vifs)[1]
2006# define vmpath (&vmail)[1]
2007# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002008#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002009# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002010#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002011#define vps1 (&vpath)[1]
2012#define vps2 (&vps1)[1]
2013#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002014#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002015# define voptind (&vps4)[1]
2016# if ENABLE_ASH_RANDOM_SUPPORT
2017# define vrandom (&voptind)[1]
2018# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002019#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002020# if ENABLE_ASH_RANDOM_SUPPORT
2021# define vrandom (&vps4)[1]
2022# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002023#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002024
2025/*
2026 * The following macros access the values of the above variables.
2027 * They have to skip over the name. They return the null string
2028 * for unset variables.
2029 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002030#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002031#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002032#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002033# define mailval() (vmail.var_text + 5)
2034# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002035# define mpathset() ((vmpath.flags & VUNSET) == 0)
2036#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002037#define pathval() (vpath.var_text + 5)
2038#define ps1val() (vps1.var_text + 4)
2039#define ps2val() (vps2.var_text + 4)
2040#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002041#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002042# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002043#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002044
Denis Vlasenko01631112007-12-16 17:20:38 +00002045#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002046static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002047getoptsreset(const char *value)
2048{
Denys Vlasenkoa513bf32016-10-26 02:03:37 +02002049 shellparam.optind = number(value) ?: 1;
Denis Vlasenko01631112007-12-16 17:20:38 +00002050 shellparam.optoff = -1;
2051}
2052#endif
2053
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002054/*
2055 * Compares two strings up to the first = or '\0'. The first
2056 * string must be terminated by '='; the second may be terminated by
2057 * either '=' or '\0'.
2058 */
2059static int
2060varcmp(const char *p, const char *q)
2061{
2062 int c, d;
2063
2064 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002065 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002066 goto out;
2067 p++;
2068 q++;
2069 }
2070 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002071 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002072 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002073 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002074 out:
2075 return c - d;
2076}
2077
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002078/*
2079 * Find the appropriate entry in the hash table from the name.
2080 */
2081static struct var **
2082hashvar(const char *p)
2083{
2084 unsigned hashval;
2085
2086 hashval = ((unsigned char) *p) << 4;
2087 while (*p && *p != '=')
2088 hashval += (unsigned char) *p++;
2089 return &vartab[hashval % VTABSIZE];
2090}
2091
2092static int
2093vpcmp(const void *a, const void *b)
2094{
2095 return varcmp(*(const char **)a, *(const char **)b);
2096}
2097
2098/*
2099 * This routine initializes the builtin variables.
2100 */
2101static void
2102initvar(void)
2103{
2104 struct var *vp;
2105 struct var *end;
2106 struct var **vpp;
2107
2108 /*
2109 * PS1 depends on uid
2110 */
2111#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002112 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002113#else
2114 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002115 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002116#endif
2117 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002118 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002119 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002120 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002121 vp->next = *vpp;
2122 *vpp = vp;
2123 } while (++vp < end);
2124}
2125
2126static struct var **
2127findvar(struct var **vpp, const char *name)
2128{
2129 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002130 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002131 break;
2132 }
2133 }
2134 return vpp;
2135}
2136
2137/*
2138 * Find the value of a variable. Returns NULL if not set.
2139 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002140static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002141lookupvar(const char *name)
2142{
2143 struct var *v;
2144
2145 v = *findvar(hashvar(name), name);
2146 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002147#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002148 /*
2149 * Dynamic variables are implemented roughly the same way they are
2150 * in bash. Namely, they're "special" so long as they aren't unset.
2151 * As soon as they're unset, they're no longer dynamic, and dynamic
2152 * lookup will no longer happen at that point. -- PFM.
2153 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002154 if (v->flags & VDYNAMIC)
2155 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002156#endif
2157 if (!(v->flags & VUNSET))
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002158 return var_end(v->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002159 }
2160 return NULL;
2161}
2162
Denys Vlasenko0b883582016-12-23 16:49:07 +01002163#if ENABLE_UNICODE_SUPPORT
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02002164static void
2165reinit_unicode_for_ash(void)
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002166{
2167 /* Unicode support should be activated even if LANG is set
2168 * _during_ shell execution, not only if it was set when
2169 * shell was started. Therefore, re-check LANG every time:
2170 */
2171 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2172 || ENABLE_UNICODE_USING_LOCALE
2173 ) {
2174 const char *s = lookupvar("LC_ALL");
2175 if (!s) s = lookupvar("LC_CTYPE");
2176 if (!s) s = lookupvar("LANG");
2177 reinit_unicode(s);
2178 }
2179}
Denys Vlasenko0b883582016-12-23 16:49:07 +01002180#else
2181# define reinit_unicode_for_ash() ((void)0)
2182#endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002183
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002184/*
2185 * Search the environment of a builtin command.
2186 */
Mike Frysinger98c52642009-04-02 10:02:37 +00002187static const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002188bltinlookup(const char *name)
2189{
2190 struct strlist *sp;
2191
2192 for (sp = cmdenviron; sp; sp = sp->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002193 if (varcmp(sp->text, name) == 0)
2194 return var_end(sp->text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002195 }
2196 return lookupvar(name);
2197}
2198
2199/*
2200 * Same as setvar except that the variable and value are passed in
2201 * the first argument as name=value. Since the first argument will
2202 * be actually stored in the table, it should not be a string that
2203 * will go away.
2204 * Called with interrupts off.
2205 */
2206static void
2207setvareq(char *s, int flags)
2208{
2209 struct var *vp, **vpp;
2210
2211 vpp = hashvar(s);
2212 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2213 vp = *findvar(vpp, s);
2214 if (vp) {
2215 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2216 const char *n;
2217
2218 if (flags & VNOSAVE)
2219 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002220 n = vp->var_text;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02002221 exitstatus = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002222 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2223 }
2224
2225 if (flags & VNOSET)
2226 return;
2227
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002228 if (vp->var_func && !(flags & VNOFUNC))
2229 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002230
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002231 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2232 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002233
2234 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2235 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002236 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002237 if (flags & VNOSET)
2238 return;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002239 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002240 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002241 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002242 *vpp = vp;
2243 }
2244 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2245 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002246 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002247 vp->flags = flags;
2248}
2249
2250/*
2251 * Set the value of a variable. The flags argument is ored with the
2252 * flags of the variable. If val is NULL, the variable is unset.
2253 */
2254static void
2255setvar(const char *name, const char *val, int flags)
2256{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002257 const char *q;
2258 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002259 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002260 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002261 size_t vallen;
2262
2263 q = endofname(name);
2264 p = strchrnul(q, '=');
2265 namelen = p - name;
2266 if (!namelen || p != q)
2267 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2268 vallen = 0;
2269 if (val == NULL) {
2270 flags |= VUNSET;
2271 } else {
2272 vallen = strlen(val);
2273 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002274
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002275 INT_OFF;
2276 nameeq = ckmalloc(namelen + vallen + 2);
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002277 p = memcpy(nameeq, name, namelen) + namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002278 if (val) {
2279 *p++ = '=';
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002280 p = memcpy(p, val, vallen) + vallen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002281 }
2282 *p = '\0';
2283 setvareq(nameeq, flags | VNOSAVE);
2284 INT_ON;
2285}
2286
Denys Vlasenko03dad222010-01-12 23:29:57 +01002287static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002288setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002289{
2290 setvar(name, val, 0);
2291}
2292
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002293/*
2294 * Unset the specified variable.
2295 */
2296static int
2297unsetvar(const char *s)
2298{
2299 struct var **vpp;
2300 struct var *vp;
2301 int retval;
2302
2303 vpp = findvar(hashvar(s), s);
2304 vp = *vpp;
2305 retval = 2;
2306 if (vp) {
2307 int flags = vp->flags;
2308
2309 retval = 1;
2310 if (flags & VREADONLY)
2311 goto out;
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002312#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002313 vp->flags &= ~VDYNAMIC;
2314#endif
2315 if (flags & VUNSET)
2316 goto ok;
2317 if ((flags & VSTRFIXED) == 0) {
2318 INT_OFF;
2319 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002320 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002321 *vpp = vp->next;
2322 free(vp);
2323 INT_ON;
2324 } else {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002325 setvar0(s, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002326 vp->flags &= ~VEXPORT;
2327 }
2328 ok:
2329 retval = 0;
2330 }
2331 out:
2332 return retval;
2333}
2334
2335/*
2336 * Process a linked list of variable assignments.
2337 */
2338static void
2339listsetvar(struct strlist *list_set_var, int flags)
2340{
2341 struct strlist *lp = list_set_var;
2342
2343 if (!lp)
2344 return;
2345 INT_OFF;
2346 do {
2347 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002348 lp = lp->next;
2349 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002350 INT_ON;
2351}
2352
2353/*
2354 * Generate a list of variables satisfying the given conditions.
2355 */
2356static char **
2357listvars(int on, int off, char ***end)
2358{
2359 struct var **vpp;
2360 struct var *vp;
2361 char **ep;
2362 int mask;
2363
2364 STARTSTACKSTR(ep);
2365 vpp = vartab;
2366 mask = on | off;
2367 do {
2368 for (vp = *vpp; vp; vp = vp->next) {
2369 if ((vp->flags & mask) == on) {
2370 if (ep == stackstrend())
2371 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002372 *ep++ = (char*)vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002373 }
2374 }
2375 } while (++vpp < vartab + VTABSIZE);
2376 if (ep == stackstrend())
2377 ep = growstackstr();
2378 if (end)
2379 *end = ep;
2380 *ep++ = NULL;
2381 return grabstackstr(ep);
2382}
2383
2384
2385/* ============ Path search helper
2386 *
2387 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002388 * of the path before the first call; path_advance will update
2389 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002390 * the possible path expansions in sequence. If an option (indicated by
2391 * a percent sign) appears in the path entry then the global variable
2392 * pathopt will be set to point to it; otherwise pathopt will be set to
2393 * NULL.
2394 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002395static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002396
2397static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002398path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002399{
2400 const char *p;
2401 char *q;
2402 const char *start;
2403 size_t len;
2404
2405 if (*path == NULL)
2406 return NULL;
2407 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002408 for (p = start; *p && *p != ':' && *p != '%'; p++)
2409 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002410 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2411 while (stackblocksize() < len)
2412 growstackblock();
2413 q = stackblock();
2414 if (p != start) {
2415 memcpy(q, start, p - start);
2416 q += p - start;
2417 *q++ = '/';
2418 }
2419 strcpy(q, name);
2420 pathopt = NULL;
2421 if (*p == '%') {
2422 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002423 while (*p && *p != ':')
2424 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002425 }
2426 if (*p == ':')
2427 *path = p + 1;
2428 else
2429 *path = NULL;
2430 return stalloc(len);
2431}
2432
2433
2434/* ============ Prompt */
2435
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002436static smallint doprompt; /* if set, prompt the user */
2437static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002438
2439#if ENABLE_FEATURE_EDITING
2440static line_input_t *line_input_state;
2441static const char *cmdedit_prompt;
2442static void
2443putprompt(const char *s)
2444{
2445 if (ENABLE_ASH_EXPAND_PRMT) {
2446 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002447 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002448 return;
2449 }
2450 cmdedit_prompt = s;
2451}
2452#else
2453static void
2454putprompt(const char *s)
2455{
2456 out2str(s);
2457}
2458#endif
2459
2460#if ENABLE_ASH_EXPAND_PRMT
2461/* expandstr() needs parsing machinery, so it is far away ahead... */
2462static const char *expandstr(const char *ps);
2463#else
2464#define expandstr(s) s
2465#endif
2466
2467static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002468setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002469{
2470 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002471 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2472
2473 if (!do_set)
2474 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002475
2476 needprompt = 0;
2477
2478 switch (whichprompt) {
2479 case 1:
2480 prompt = ps1val();
2481 break;
2482 case 2:
2483 prompt = ps2val();
2484 break;
2485 default: /* 0 */
2486 prompt = nullstr;
2487 }
2488#if ENABLE_ASH_EXPAND_PRMT
Denys Vlasenko60ca8342016-09-30 11:21:21 +02002489 pushstackmark(&smark, stackblocksize());
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002490#endif
2491 putprompt(expandstr(prompt));
2492#if ENABLE_ASH_EXPAND_PRMT
2493 popstackmark(&smark);
2494#endif
2495}
2496
2497
2498/* ============ The cd and pwd commands */
2499
2500#define CD_PHYSICAL 1
2501#define CD_PRINT 2
2502
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002503static int
2504cdopt(void)
2505{
2506 int flags = 0;
2507 int i, j;
2508
2509 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002510 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002511 if (i != j) {
2512 flags ^= CD_PHYSICAL;
2513 j = i;
2514 }
2515 }
2516
2517 return flags;
2518}
2519
2520/*
2521 * Update curdir (the name of the current directory) in response to a
2522 * cd command.
2523 */
2524static const char *
2525updatepwd(const char *dir)
2526{
2527 char *new;
2528 char *p;
2529 char *cdcomppath;
2530 const char *lim;
2531
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02002532 cdcomppath = sstrdup(dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002533 STARTSTACKSTR(new);
2534 if (*dir != '/') {
2535 if (curdir == nullstr)
2536 return 0;
2537 new = stack_putstr(curdir, new);
2538 }
2539 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002540 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002541 if (*dir != '/') {
2542 if (new[-1] != '/')
2543 USTPUTC('/', new);
2544 if (new > lim && *lim == '/')
2545 lim++;
2546 } else {
2547 USTPUTC('/', new);
2548 cdcomppath++;
2549 if (dir[1] == '/' && dir[2] != '/') {
2550 USTPUTC('/', new);
2551 cdcomppath++;
2552 lim++;
2553 }
2554 }
2555 p = strtok(cdcomppath, "/");
2556 while (p) {
2557 switch (*p) {
2558 case '.':
2559 if (p[1] == '.' && p[2] == '\0') {
2560 while (new > lim) {
2561 STUNPUTC(new);
2562 if (new[-1] == '/')
2563 break;
2564 }
2565 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002566 }
2567 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002568 break;
2569 /* fall through */
2570 default:
2571 new = stack_putstr(p, new);
2572 USTPUTC('/', new);
2573 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002574 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002575 }
2576 if (new > lim)
2577 STUNPUTC(new);
2578 *new = 0;
2579 return stackblock();
2580}
2581
2582/*
2583 * Find out what the current directory is. If we already know the current
2584 * directory, this routine returns immediately.
2585 */
2586static char *
2587getpwd(void)
2588{
Denis Vlasenko01631112007-12-16 17:20:38 +00002589 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002590 return dir ? dir : nullstr;
2591}
2592
2593static void
2594setpwd(const char *val, int setold)
2595{
2596 char *oldcur, *dir;
2597
2598 oldcur = dir = curdir;
2599
2600 if (setold) {
2601 setvar("OLDPWD", oldcur, VEXPORT);
2602 }
2603 INT_OFF;
2604 if (physdir != nullstr) {
2605 if (physdir != oldcur)
2606 free(physdir);
2607 physdir = nullstr;
2608 }
2609 if (oldcur == val || !val) {
2610 char *s = getpwd();
2611 physdir = s;
2612 if (!val)
2613 dir = s;
2614 } else
2615 dir = ckstrdup(val);
2616 if (oldcur != dir && oldcur != nullstr) {
2617 free(oldcur);
2618 }
2619 curdir = dir;
2620 INT_ON;
2621 setvar("PWD", dir, VEXPORT);
2622}
2623
2624static void hashcd(void);
2625
2626/*
Denys Vlasenko70392332016-10-27 02:31:55 +02002627 * Actually do the chdir. We also call hashcd to let other routines
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002628 * know that the current directory has changed.
2629 */
2630static int
2631docd(const char *dest, int flags)
2632{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002633 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002634 int err;
2635
2636 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2637
2638 INT_OFF;
2639 if (!(flags & CD_PHYSICAL)) {
2640 dir = updatepwd(dest);
2641 if (dir)
2642 dest = dir;
2643 }
2644 err = chdir(dest);
2645 if (err)
2646 goto out;
2647 setpwd(dir, 1);
2648 hashcd();
2649 out:
2650 INT_ON;
2651 return err;
2652}
2653
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002654static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002655cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002656{
2657 const char *dest;
2658 const char *path;
2659 const char *p;
2660 char c;
2661 struct stat statb;
2662 int flags;
2663
2664 flags = cdopt();
2665 dest = *argptr;
2666 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002667 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002668 else if (LONE_DASH(dest)) {
2669 dest = bltinlookup("OLDPWD");
2670 flags |= CD_PRINT;
2671 }
2672 if (!dest)
2673 dest = nullstr;
2674 if (*dest == '/')
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002675 goto step6;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002676 if (*dest == '.') {
2677 c = dest[1];
2678 dotdot:
2679 switch (c) {
2680 case '\0':
2681 case '/':
2682 goto step6;
2683 case '.':
2684 c = dest[2];
2685 if (c != '.')
2686 goto dotdot;
2687 }
2688 }
2689 if (!*dest)
2690 dest = ".";
2691 path = bltinlookup("CDPATH");
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002692 while (path) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002693 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002694 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002695 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2696 if (c && c != ':')
2697 flags |= CD_PRINT;
2698 docd:
2699 if (!docd(p, flags))
2700 goto out;
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002701 goto err;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002702 }
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002703 }
2704
2705 step6:
2706 p = dest;
2707 goto docd;
2708
2709 err:
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002710 ash_msg_and_raise_error("can't cd to %s", dest);
2711 /* NOTREACHED */
2712 out:
2713 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002714 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002715 return 0;
2716}
2717
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002718static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002719pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002720{
2721 int flags;
2722 const char *dir = curdir;
2723
2724 flags = cdopt();
2725 if (flags) {
2726 if (physdir == nullstr)
2727 setpwd(dir, 0);
2728 dir = physdir;
2729 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002730 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002731 return 0;
2732}
2733
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002734
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002735/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002736
Denis Vlasenko834dee72008-10-07 09:18:30 +00002737
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002738#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002739
Eric Andersenc470f442003-07-28 09:56:35 +00002740/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002741#define CWORD 0 /* character is nothing special */
2742#define CNL 1 /* newline character */
2743#define CBACK 2 /* a backslash character */
2744#define CSQUOTE 3 /* single quote */
2745#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002746#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002747#define CBQUOTE 6 /* backwards single quote */
2748#define CVAR 7 /* a dollar sign */
2749#define CENDVAR 8 /* a '}' character */
2750#define CLP 9 /* a left paren in arithmetic */
2751#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002752#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002753#define CCTL 12 /* like CWORD, except it must be escaped */
2754#define CSPCL 13 /* these terminate a word */
2755#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002756
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002757#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002758#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002759# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002760#endif
2761
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002762#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002763
Denys Vlasenko0b883582016-12-23 16:49:07 +01002764#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002765# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002766#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002767# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002768#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002769static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002770#if ENABLE_ASH_ALIAS
2771 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2772#endif
2773 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2774 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2775 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2776 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2777 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2778 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2779 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2780 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2781 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2782 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2783 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002784#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002785 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2786 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2787 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2788#endif
2789#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002790};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002791/* Constants below must match table above */
2792enum {
2793#if ENABLE_ASH_ALIAS
2794 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2795#endif
2796 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2797 CNL_CNL_CNL_CNL , /* 2 */
2798 CWORD_CCTL_CCTL_CWORD , /* 3 */
2799 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2800 CVAR_CVAR_CWORD_CVAR , /* 5 */
2801 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2802 CSPCL_CWORD_CWORD_CLP , /* 7 */
2803 CSPCL_CWORD_CWORD_CRP , /* 8 */
2804 CBACK_CBACK_CCTL_CBACK , /* 9 */
2805 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2806 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2807 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2808 CWORD_CWORD_CWORD_CWORD , /* 13 */
2809 CCTL_CCTL_CCTL_CCTL , /* 14 */
2810};
Eric Andersen2870d962001-07-02 17:27:21 +00002811
Denys Vlasenkocd716832009-11-28 22:14:02 +01002812/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2813 * caller must ensure proper cast on it if c is *char_ptr!
2814 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002815/* Values for syntax param */
2816#define BASESYNTAX 0 /* not in quotes */
2817#define DQSYNTAX 1 /* in double quotes */
2818#define SQSYNTAX 2 /* in single quotes */
2819#define ARISYNTAX 3 /* in arithmetic */
2820#define PSSYNTAX 4 /* prompt. never passed to SIT() */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002821
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002822#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002823
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002824static int
2825SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002826{
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002827 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2828 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2829 /*
2830 * This causes '/' to be prepended with CTLESC in dquoted string,
2831 * making "./file"* treated incorrectly because we feed
2832 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2833 * The "homegrown" glob implementation is okay with that,
2834 * but glibc one isn't. With '/' always treated as CWORD,
2835 * both work fine.
2836 */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002837# if ENABLE_ASH_ALIAS
2838 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002839 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002840 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002841 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2842 11, 3 /* "}~" */
2843 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002844# else
2845 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002846 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002847 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002848 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2849 10, 2 /* "}~" */
2850 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002851# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002852 const char *s;
2853 int indx;
2854
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002855 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002856 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002857# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002858 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002859 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002860 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002861# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002862 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002863 /* Cast is purely for paranoia here,
2864 * just in case someone passed signed char to us */
2865 if ((unsigned char)c >= CTL_FIRST
2866 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002867 ) {
2868 return CCTL;
2869 }
2870 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002871 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002872 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002873 indx = syntax_index_table[s - spec_symbls];
2874 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002875 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002876}
2877
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002878#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002879
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002880static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002881 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002882 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2889 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2890 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2891 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2892 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2893 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2894 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2895 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2896 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2897 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2898 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2899 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2900 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2901 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2902 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2903 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2904 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2905 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2906 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2907 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2908 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2909 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2910 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2911 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2912 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2913 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2914 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2915 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2916 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2917 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2918 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2919 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2920 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2921 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2922 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2923 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2924 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2925 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2926 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2927 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2928 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002929/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
2930 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkocd716832009-11-28 22:14:02 +01002931 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2942 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2943 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2944 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2945 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2946 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2947 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2975 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2976 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2977 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2980 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2983 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2986 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2987 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2988 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2989 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2990 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2991 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2992 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2993 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2994 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2995 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2996 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2997 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2998 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2999 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
3000 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
3001 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
3002 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
3003 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
3004 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
3005 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
3006 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
3007 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
3008 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3009 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
3010 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
3011 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
3012 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
3013 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
3014 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
3015 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
3016 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
3017 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
3018 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
3019 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3020 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3021 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3029 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3042 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3047 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3112 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3113 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3114 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3115 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3116 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3117 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3118 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3119 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3120 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3121 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3122 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3123 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3124 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3125 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3126 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3127 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3128 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3129 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3130 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3131 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3132 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3133 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3134 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3135 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3136 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3137 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3138 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003139 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003140# if ENABLE_ASH_ALIAS
3141 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3142# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003143};
3144
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003145#if 1
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003146# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003147#else /* debug version, caught one signed char bug */
3148# define SIT(c, syntax) \
3149 ({ \
3150 if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3151 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
Denys Vlasenko0b883582016-12-23 16:49:07 +01003152 if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003153 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3154 ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3155 })
3156#endif
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003157
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003158#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003159
Eric Andersen2870d962001-07-02 17:27:21 +00003160
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003161/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003162
Denis Vlasenko131ae172007-02-18 13:00:19 +00003163#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003164
3165#define ALIASINUSE 1
3166#define ALIASDEAD 2
3167
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003168struct alias {
3169 struct alias *next;
3170 char *name;
3171 char *val;
3172 int flag;
3173};
3174
Denis Vlasenko01631112007-12-16 17:20:38 +00003175
3176static struct alias **atab; // [ATABSIZE];
3177#define INIT_G_alias() do { \
3178 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3179} while (0)
3180
Eric Andersen2870d962001-07-02 17:27:21 +00003181
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003182static struct alias **
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02003183__lookupalias(const char *name)
3184{
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003185 unsigned int hashval;
3186 struct alias **app;
3187 const char *p;
3188 unsigned int ch;
3189
3190 p = name;
3191
3192 ch = (unsigned char)*p;
3193 hashval = ch << 4;
3194 while (ch) {
3195 hashval += ch;
3196 ch = (unsigned char)*++p;
3197 }
3198 app = &atab[hashval % ATABSIZE];
3199
3200 for (; *app; app = &(*app)->next) {
3201 if (strcmp(name, (*app)->name) == 0) {
3202 break;
3203 }
3204 }
3205
3206 return app;
3207}
3208
3209static struct alias *
3210lookupalias(const char *name, int check)
3211{
3212 struct alias *ap = *__lookupalias(name);
3213
3214 if (check && ap && (ap->flag & ALIASINUSE))
3215 return NULL;
3216 return ap;
3217}
3218
3219static struct alias *
3220freealias(struct alias *ap)
3221{
3222 struct alias *next;
3223
3224 if (ap->flag & ALIASINUSE) {
3225 ap->flag |= ALIASDEAD;
3226 return ap;
3227 }
3228
3229 next = ap->next;
3230 free(ap->name);
3231 free(ap->val);
3232 free(ap);
3233 return next;
3234}
Eric Andersencb57d552001-06-28 07:25:16 +00003235
Eric Andersenc470f442003-07-28 09:56:35 +00003236static void
3237setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003238{
3239 struct alias *ap, **app;
3240
3241 app = __lookupalias(name);
3242 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003243 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003244 if (ap) {
3245 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003246 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003247 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003248 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003249 ap->flag &= ~ALIASDEAD;
3250 } else {
3251 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003252 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003253 ap->name = ckstrdup(name);
3254 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003255 /*ap->flag = 0; - ckzalloc did it */
3256 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003257 *app = ap;
3258 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003259 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003260}
3261
Eric Andersenc470f442003-07-28 09:56:35 +00003262static int
3263unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003264{
Eric Andersencb57d552001-06-28 07:25:16 +00003265 struct alias **app;
3266
3267 app = __lookupalias(name);
3268
3269 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003270 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003271 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003272 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003273 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003274 }
3275
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003276 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003277}
3278
Eric Andersenc470f442003-07-28 09:56:35 +00003279static void
3280rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003281{
Eric Andersencb57d552001-06-28 07:25:16 +00003282 struct alias *ap, **app;
3283 int i;
3284
Denis Vlasenkob012b102007-02-19 22:43:01 +00003285 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003286 for (i = 0; i < ATABSIZE; i++) {
3287 app = &atab[i];
3288 for (ap = *app; ap; ap = *app) {
3289 *app = freealias(*app);
3290 if (ap == *app) {
3291 app = &ap->next;
3292 }
3293 }
3294 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003295 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003296}
3297
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003298static void
3299printalias(const struct alias *ap)
3300{
3301 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3302}
3303
Eric Andersencb57d552001-06-28 07:25:16 +00003304/*
3305 * TODO - sort output
3306 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003307static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003308aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003309{
3310 char *n, *v;
3311 int ret = 0;
3312 struct alias *ap;
3313
Denis Vlasenko68404f12008-03-17 09:00:54 +00003314 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003315 int i;
3316
Denis Vlasenko68404f12008-03-17 09:00:54 +00003317 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003318 for (ap = atab[i]; ap; ap = ap->next) {
3319 printalias(ap);
3320 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003321 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003322 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003323 }
3324 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003325 v = strchr(n+1, '=');
3326 if (v == NULL) { /* n+1: funny ksh stuff */
3327 ap = *__lookupalias(n);
3328 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003329 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003330 ret = 1;
3331 } else
3332 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003333 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003334 *v++ = '\0';
3335 setalias(n, v);
3336 }
3337 }
3338
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003339 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003340}
3341
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003342static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003343unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003344{
3345 int i;
3346
3347 while ((i = nextopt("a")) != '\0') {
3348 if (i == 'a') {
3349 rmaliases();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003350 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003351 }
3352 }
3353 for (i = 0; *argptr; argptr++) {
3354 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003355 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003356 i = 1;
3357 }
3358 }
3359
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003360 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003361}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003362
Denis Vlasenko131ae172007-02-18 13:00:19 +00003363#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003364
Eric Andersenc470f442003-07-28 09:56:35 +00003365
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003366/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003367#define FORK_FG 0
3368#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003369#define FORK_NOJOB 2
3370
3371/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003372#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3373#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3374#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003375#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003376
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003377/*
3378 * A job structure contains information about a job. A job is either a
3379 * single process or a set of processes contained in a pipeline. In the
3380 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3381 * array of pids.
3382 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003383struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003384 pid_t ps_pid; /* process id */
3385 int ps_status; /* last process status from wait() */
3386 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003387};
3388
3389struct job {
3390 struct procstat ps0; /* status of process */
3391 struct procstat *ps; /* status or processes when more than one */
3392#if JOBS
3393 int stopstatus; /* status of a stopped job */
3394#endif
3395 uint32_t
3396 nprocs: 16, /* number of processes */
3397 state: 8,
3398#define JOBRUNNING 0 /* at least one proc running */
3399#define JOBSTOPPED 1 /* all procs are stopped */
3400#define JOBDONE 2 /* all procs are completed */
3401#if JOBS
3402 sigint: 1, /* job was killed by SIGINT */
3403 jobctl: 1, /* job running under job control */
3404#endif
3405 waited: 1, /* true if this entry has been waited for */
3406 used: 1, /* true if this entry is in used */
3407 changed: 1; /* true if status has changed */
3408 struct job *prev_job; /* previous job */
3409};
3410
Denis Vlasenko68404f12008-03-17 09:00:54 +00003411static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003412static int forkshell(struct job *, union node *, int);
3413static int waitforjob(struct job *);
3414
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003415#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003416enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003417#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003418#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003419static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003420static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003421#endif
3422
3423/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003424 * Ignore a signal.
3425 */
3426static void
3427ignoresig(int signo)
3428{
3429 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3430 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3431 /* No, need to do it */
3432 signal(signo, SIG_IGN);
3433 }
3434 sigmode[signo - 1] = S_HARD_IGN;
3435}
3436
3437/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003438 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003439 */
3440static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003441signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003442{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003443 if (signo == SIGCHLD) {
3444 got_sigchld = 1;
3445 if (!trap[SIGCHLD])
3446 return;
3447 }
3448
Denis Vlasenko4b875702009-03-19 13:30:04 +00003449 gotsig[signo - 1] = 1;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003450 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003451
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003452 if (signo == SIGINT && !trap[SIGINT]) {
3453 if (!suppress_int) {
3454 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003455 raise_interrupt(); /* does not return */
3456 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003457 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003458 }
3459}
3460
3461/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003462 * Set the signal handler for the specified signal. The routine figures
3463 * out what it should be set to.
3464 */
3465static void
3466setsignal(int signo)
3467{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003468 char *t;
3469 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003470 struct sigaction act;
3471
3472 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003473 new_act = S_DFL;
3474 if (t != NULL) { /* trap for this sig is set */
3475 new_act = S_CATCH;
3476 if (t[0] == '\0') /* trap is "": ignore this sig */
3477 new_act = S_IGN;
3478 }
3479
3480 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003481 switch (signo) {
3482 case SIGINT:
3483 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003484 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003485 break;
3486 case SIGQUIT:
3487#if DEBUG
3488 if (debug)
3489 break;
3490#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003491 /* man bash:
3492 * "In all cases, bash ignores SIGQUIT. Non-builtin
3493 * commands run by bash have signal handlers
3494 * set to the values inherited by the shell
3495 * from its parent". */
3496 new_act = S_IGN;
3497 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003498 case SIGTERM:
3499 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003500 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003501 break;
3502#if JOBS
3503 case SIGTSTP:
3504 case SIGTTOU:
3505 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003506 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003507 break;
3508#endif
3509 }
3510 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003511//TODO: if !rootshell, we reset SIGQUIT to DFL,
3512//whereas we have to restore it to what shell got on entry
3513//from the parent. See comment above
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003514
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003515 if (signo == SIGCHLD)
3516 new_act = S_CATCH;
3517
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003518 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003519 cur_act = *t;
3520 if (cur_act == 0) {
3521 /* current setting is not yet known */
3522 if (sigaction(signo, NULL, &act)) {
3523 /* pretend it worked; maybe we should give a warning,
3524 * but other shells don't. We don't alter sigmode,
3525 * so we retry every time.
3526 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003527 return;
3528 }
3529 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003530 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003531 if (mflag
3532 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3533 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003534 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003535 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003536 }
3537 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003538 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003539 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003540
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003541 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003542 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003543 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003544 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003545 break;
3546 case S_IGN:
3547 act.sa_handler = SIG_IGN;
3548 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003549 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003550
3551 /* flags and mask matter only if !DFL and !IGN, but we do it
3552 * for all cases for more deterministic behavior:
3553 */
3554 act.sa_flags = 0;
3555 sigfillset(&act.sa_mask);
3556
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003557 sigaction_set(signo, &act);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003558
3559 *t = new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003560}
3561
3562/* mode flags for set_curjob */
3563#define CUR_DELETE 2
3564#define CUR_RUNNING 1
3565#define CUR_STOPPED 0
3566
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003567#if JOBS
3568/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003569static int initialpgrp; //references:2
3570static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003571#endif
3572/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003573static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003574/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003575static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003576/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003577static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003578/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003579static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003580
3581static void
3582set_curjob(struct job *jp, unsigned mode)
3583{
3584 struct job *jp1;
3585 struct job **jpp, **curp;
3586
3587 /* first remove from list */
3588 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003589 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003590 jp1 = *jpp;
3591 if (jp1 == jp)
3592 break;
3593 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003594 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003595 *jpp = jp1->prev_job;
3596
3597 /* Then re-insert in correct position */
3598 jpp = curp;
3599 switch (mode) {
3600 default:
3601#if DEBUG
3602 abort();
3603#endif
3604 case CUR_DELETE:
3605 /* job being deleted */
3606 break;
3607 case CUR_RUNNING:
3608 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003609 * put after all stopped jobs.
3610 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003611 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003612 jp1 = *jpp;
3613#if JOBS
3614 if (!jp1 || jp1->state != JOBSTOPPED)
3615#endif
3616 break;
3617 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003618 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003619 /* FALLTHROUGH */
3620#if JOBS
3621 case CUR_STOPPED:
3622#endif
3623 /* newly stopped job - becomes curjob */
3624 jp->prev_job = *jpp;
3625 *jpp = jp;
3626 break;
3627 }
3628}
3629
3630#if JOBS || DEBUG
3631static int
3632jobno(const struct job *jp)
3633{
3634 return jp - jobtab + 1;
3635}
3636#endif
3637
3638/*
3639 * Convert a job name to a job structure.
3640 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003641#if !JOBS
3642#define getjob(name, getctl) getjob(name)
3643#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003644static struct job *
3645getjob(const char *name, int getctl)
3646{
3647 struct job *jp;
3648 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003649 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003650 unsigned num;
3651 int c;
3652 const char *p;
3653 char *(*match)(const char *, const char *);
3654
3655 jp = curjob;
3656 p = name;
3657 if (!p)
3658 goto currentjob;
3659
3660 if (*p != '%')
3661 goto err;
3662
3663 c = *++p;
3664 if (!c)
3665 goto currentjob;
3666
3667 if (!p[1]) {
3668 if (c == '+' || c == '%') {
3669 currentjob:
3670 err_msg = "No current job";
3671 goto check;
3672 }
3673 if (c == '-') {
3674 if (jp)
3675 jp = jp->prev_job;
3676 err_msg = "No previous job";
3677 check:
3678 if (!jp)
3679 goto err;
3680 goto gotit;
3681 }
3682 }
3683
3684 if (is_number(p)) {
3685 num = atoi(p);
Denys Vlasenko46a45ce2016-09-29 01:10:08 +02003686 if (num > 0 && num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003687 jp = jobtab + num - 1;
3688 if (jp->used)
3689 goto gotit;
3690 goto err;
3691 }
3692 }
3693
3694 match = prefix;
3695 if (*p == '?') {
3696 match = strstr;
3697 p++;
3698 }
3699
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003700 found = NULL;
3701 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003702 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003703 if (found)
3704 goto err;
3705 found = jp;
3706 err_msg = "%s: ambiguous";
3707 }
3708 jp = jp->prev_job;
3709 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003710 if (!found)
3711 goto err;
3712 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003713
3714 gotit:
3715#if JOBS
3716 err_msg = "job %s not created under job control";
3717 if (getctl && jp->jobctl == 0)
3718 goto err;
3719#endif
3720 return jp;
3721 err:
3722 ash_msg_and_raise_error(err_msg, name);
3723}
3724
3725/*
3726 * Mark a job structure as unused.
3727 */
3728static void
3729freejob(struct job *jp)
3730{
3731 struct procstat *ps;
3732 int i;
3733
3734 INT_OFF;
3735 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003736 if (ps->ps_cmd != nullstr)
3737 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003738 }
3739 if (jp->ps != &jp->ps0)
3740 free(jp->ps);
3741 jp->used = 0;
3742 set_curjob(jp, CUR_DELETE);
3743 INT_ON;
3744}
3745
3746#if JOBS
3747static void
3748xtcsetpgrp(int fd, pid_t pgrp)
3749{
3750 if (tcsetpgrp(fd, pgrp))
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003751 ash_msg_and_raise_error("can't set tty process group (%m)");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003752}
3753
3754/*
3755 * Turn job control on and off.
3756 *
3757 * Note: This code assumes that the third arg to ioctl is a character
3758 * pointer, which is true on Berkeley systems but not System V. Since
3759 * System V doesn't have job control yet, this isn't a problem now.
3760 *
3761 * Called with interrupts off.
3762 */
3763static void
3764setjobctl(int on)
3765{
3766 int fd;
3767 int pgrp;
3768
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003769 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003770 return;
3771 if (on) {
3772 int ofd;
3773 ofd = fd = open(_PATH_TTY, O_RDWR);
3774 if (fd < 0) {
3775 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3776 * That sometimes helps to acquire controlling tty.
3777 * Obviously, a workaround for bugs when someone
3778 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003779 fd = 2;
3780 while (!isatty(fd))
3781 if (--fd < 0)
3782 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003783 }
Denys Vlasenko64774602016-10-26 15:24:30 +02003784 /* fd is a tty at this point */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003785 fd = fcntl(fd, F_DUPFD, 10);
Denys Vlasenko64774602016-10-26 15:24:30 +02003786 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, dont */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003787 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003788 if (fd < 0)
Denys Vlasenko64774602016-10-26 15:24:30 +02003789 goto out; /* F_DUPFD failed */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003790 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003791 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003792 pgrp = tcgetpgrp(fd);
3793 if (pgrp < 0) {
3794 out:
3795 ash_msg("can't access tty; job control turned off");
3796 mflag = on = 0;
3797 goto close;
3798 }
3799 if (pgrp == getpgrp())
3800 break;
3801 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003802 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003803 initialpgrp = pgrp;
3804
3805 setsignal(SIGTSTP);
3806 setsignal(SIGTTOU);
3807 setsignal(SIGTTIN);
3808 pgrp = rootpid;
3809 setpgid(0, pgrp);
3810 xtcsetpgrp(fd, pgrp);
3811 } else {
3812 /* turning job control off */
3813 fd = ttyfd;
3814 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003815 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003816 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003817 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003818 setpgid(0, pgrp);
3819 setsignal(SIGTSTP);
3820 setsignal(SIGTTOU);
3821 setsignal(SIGTTIN);
3822 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003823 if (fd >= 0)
3824 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003825 fd = -1;
3826 }
3827 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003828 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003829}
3830
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003831static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003832killcmd(int argc, char **argv)
3833{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003834 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003835 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003836 do {
3837 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003838 /*
3839 * "kill %N" - job kill
3840 * Converting to pgrp / pid kill
3841 */
3842 struct job *jp;
3843 char *dst;
3844 int j, n;
3845
3846 jp = getjob(argv[i], 0);
3847 /*
3848 * In jobs started under job control, we signal
3849 * entire process group by kill -PGRP_ID.
3850 * This happens, f.e., in interactive shell.
3851 *
3852 * Otherwise, we signal each child via
3853 * kill PID1 PID2 PID3.
3854 * Testcases:
3855 * sh -c 'sleep 1|sleep 1 & kill %1'
3856 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3857 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3858 */
3859 n = jp->nprocs; /* can't be 0 (I hope) */
3860 if (jp->jobctl)
3861 n = 1;
3862 dst = alloca(n * sizeof(int)*4);
3863 argv[i] = dst;
3864 for (j = 0; j < n; j++) {
3865 struct procstat *ps = &jp->ps[j];
3866 /* Skip non-running and not-stopped members
3867 * (i.e. dead members) of the job
3868 */
3869 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3870 continue;
3871 /*
3872 * kill_main has matching code to expect
3873 * leading space. Needed to not confuse
3874 * negative pids with "kill -SIGNAL_NO" syntax
3875 */
3876 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3877 }
3878 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003879 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003880 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003881 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003882 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003883}
3884
3885static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01003886showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003887{
Denys Vlasenko285ad152009-12-04 23:02:27 +01003888 struct procstat *ps;
3889 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003890
Denys Vlasenko285ad152009-12-04 23:02:27 +01003891 psend = jp->ps + jp->nprocs;
3892 for (ps = jp->ps + 1; ps < psend; ps++)
3893 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003894 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003895 flush_stdout_stderr();
3896}
3897
3898
3899static int
3900restartjob(struct job *jp, int mode)
3901{
3902 struct procstat *ps;
3903 int i;
3904 int status;
3905 pid_t pgid;
3906
3907 INT_OFF;
3908 if (jp->state == JOBDONE)
3909 goto out;
3910 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003911 pgid = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003912 if (mode == FORK_FG)
3913 xtcsetpgrp(ttyfd, pgid);
3914 killpg(pgid, SIGCONT);
3915 ps = jp->ps;
3916 i = jp->nprocs;
3917 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003918 if (WIFSTOPPED(ps->ps_status)) {
3919 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003920 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003921 ps++;
3922 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003923 out:
3924 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3925 INT_ON;
3926 return status;
3927}
3928
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003929static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003930fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003931{
3932 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003933 int mode;
3934 int retval;
3935
3936 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3937 nextopt(nullstr);
3938 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003939 do {
3940 jp = getjob(*argv, 1);
3941 if (mode == FORK_BG) {
3942 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01003943 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003944 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003945 out1str(jp->ps[0].ps_cmd);
3946 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003947 retval = restartjob(jp, mode);
3948 } while (*argv && *++argv);
3949 return retval;
3950}
3951#endif
3952
3953static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02003954sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003955{
3956 int col;
3957 int st;
3958
3959 col = 0;
3960 if (!WIFEXITED(status)) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003961 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003962 st = WSTOPSIG(status);
3963 else
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003964 st = WTERMSIG(status);
3965 if (sigonly) {
3966 if (st == SIGINT || st == SIGPIPE)
3967 goto out;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003968 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003969 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003970 }
3971 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01003972//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003973 col = fmtstr(s, 32, strsignal(st));
3974 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02003975 strcpy(s + col, " (core dumped)");
3976 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003977 }
3978 } else if (!sigonly) {
3979 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003980 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003981 }
3982 out:
3983 return col;
3984}
3985
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003986static int
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003987wait_block_or_sig(int *status)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003988{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003989 int pid;
3990
3991 do {
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01003992 sigset_t mask;
3993
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003994 /* Poll all children for changes in their state */
3995 got_sigchld = 0;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003996 /* if job control is active, accept stopped processes too */
3997 pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003998 if (pid != 0)
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003999 break; /* Error (e.g. EINTR, ECHILD) or pid */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004000
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004001 /* Children exist, but none are ready. Sleep until interesting signal */
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004002#if 1
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004003 sigfillset(&mask);
4004 sigprocmask(SIG_SETMASK, &mask, &mask);
4005 while (!got_sigchld && !pending_sig)
4006 sigsuspend(&mask);
4007 sigprocmask(SIG_SETMASK, &mask, NULL);
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004008#else /* unsafe: a signal can set pending_sig after check, but before pause() */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004009 while (!got_sigchld && !pending_sig)
4010 pause();
4011#endif
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004012
4013 /* If it was SIGCHLD, poll children again */
4014 } while (got_sigchld);
4015
4016 return pid;
4017}
4018
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004019#define DOWAIT_NONBLOCK 0
4020#define DOWAIT_BLOCK 1
4021#define DOWAIT_BLOCK_OR_SIG 2
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004022
4023static int
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004024dowait(int block, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004025{
4026 int pid;
4027 int status;
4028 struct job *jp;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004029 struct job *thisjob = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004030
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004031 TRACE(("dowait(0x%x) called\n", block));
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00004032
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004033 /* It's wrong to call waitpid() outside of INT_OFF region:
4034 * signal can arrive just after syscall return and handler can
4035 * longjmp away, losing stop/exit notification processing.
4036 * Thus, for "jobs" builtin, and for waiting for a fg job,
4037 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4038 *
4039 * However, for "wait" builtin it is wrong to simply call waitpid()
4040 * in INT_OFF region: "wait" needs to wait for any running job
4041 * to change state, but should exit on any trap too.
4042 * In INT_OFF region, a signal just before syscall entry can set
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004043 * pending_sig variables, but we can't check them, and we would
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004044 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004045 *
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004046 * Because of this, we run inside INT_OFF, but use a special routine
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004047 * which combines waitpid() and sigsuspend().
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004048 * This is the reason why we need to have a handler for SIGCHLD:
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004049 * SIG_DFL handler does not wake sigsuspend().
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004050 */
4051 INT_OFF;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004052 if (block == DOWAIT_BLOCK_OR_SIG) {
4053 pid = wait_block_or_sig(&status);
4054 } else {
4055 int wait_flags = 0;
4056 if (block == DOWAIT_NONBLOCK)
4057 wait_flags = WNOHANG;
4058 /* if job control is active, accept stopped processes too */
4059 if (doing_jobctl)
4060 wait_flags |= WUNTRACED;
4061 /* NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004062 pid = waitpid(-1, &status, wait_flags);
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004063 }
Denis Vlasenkob21f3792009-03-19 23:09:58 +00004064 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4065 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004066 if (pid <= 0)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004067 goto out;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004068
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004069 thisjob = NULL;
4070 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004071 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004072 struct procstat *ps;
4073 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004074 if (jp->state == JOBDONE)
4075 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004076 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004077 ps = jp->ps;
4078 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004079 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004080 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004081 TRACE(("Job %d: changing status of proc %d "
4082 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01004083 jobno(jp), pid, ps->ps_status, status));
4084 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004085 thisjob = jp;
4086 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004087 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004088 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004089#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004090 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004091 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004092 if (WIFSTOPPED(ps->ps_status)) {
4093 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004094 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004095 }
4096#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004097 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004098 if (!thisjob)
4099 continue;
4100
4101 /* Found the job where one of its processes changed its state.
4102 * Is there at least one live and running process in this job? */
4103 if (jobstate != JOBRUNNING) {
4104 /* No. All live processes in the job are stopped
4105 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4106 */
4107 thisjob->changed = 1;
4108 if (thisjob->state != jobstate) {
4109 TRACE(("Job %d: changing state from %d to %d\n",
4110 jobno(thisjob), thisjob->state, jobstate));
4111 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004112#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004113 if (jobstate == JOBSTOPPED)
4114 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004115#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004116 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004117 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004118 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004119 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004120 /* The process wasn't found in job list */
4121 if (JOBS && !WIFSTOPPED(status))
4122 jobless--;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004123 out:
4124 INT_ON;
4125
4126 if (thisjob && thisjob == job) {
4127 char s[48 + 1];
4128 int len;
4129
Denys Vlasenko9c541002015-10-07 15:44:36 +02004130 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004131 if (len) {
4132 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004133 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004134 out2str(s);
4135 }
4136 }
4137 return pid;
4138}
4139
4140#if JOBS
4141static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004142showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004143{
4144 struct procstat *ps;
4145 struct procstat *psend;
4146 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004147 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004148 char s[16 + 16 + 48];
4149 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004150
4151 ps = jp->ps;
4152
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004153 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004154 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004155 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004156 return;
4157 }
4158
4159 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004160 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004161
4162 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004163 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004164 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004165 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004166
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004167 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004168 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004169
4170 psend = ps + jp->nprocs;
4171
4172 if (jp->state == JOBRUNNING) {
4173 strcpy(s + col, "Running");
4174 col += sizeof("Running") - 1;
4175 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004176 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004177 if (jp->state == JOBSTOPPED)
4178 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004179 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004180 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004181 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004182
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004183 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4184 * or prints several "PID | <cmdN>" lines,
4185 * depending on SHOW_PIDS bit.
4186 * We do not print status of individual processes
4187 * between PID and <cmdN>. bash does it, but not very well:
4188 * first line shows overall job status, not process status,
4189 * making it impossible to know 1st process status.
4190 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004191 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004192 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004193 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004194 s[0] = '\0';
4195 col = 33;
4196 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004197 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004198 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004199 fprintf(out, "%s%*c%s%s",
4200 s,
4201 33 - col >= 0 ? 33 - col : 0, ' ',
4202 ps == jp->ps ? "" : "| ",
4203 ps->ps_cmd
4204 );
4205 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004206 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004207
4208 jp->changed = 0;
4209
4210 if (jp->state == JOBDONE) {
4211 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4212 freejob(jp);
4213 }
4214}
4215
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004216/*
4217 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4218 * statuses have changed since the last call to showjobs.
4219 */
4220static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004221showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004222{
4223 struct job *jp;
4224
Denys Vlasenko883cea42009-07-11 15:31:59 +02004225 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004226
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004227 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004228 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004229 continue;
4230
4231 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004232 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004233 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004234 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004235 }
4236}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004237
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004238static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004239jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004240{
4241 int mode, m;
4242
4243 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004244 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004245 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004246 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004247 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004248 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004249 }
4250
4251 argv = argptr;
4252 if (*argv) {
4253 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004254 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004255 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004256 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004257 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004258 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004259
4260 return 0;
4261}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004262#endif /* JOBS */
4263
Michael Abbott359da5e2009-12-04 23:03:29 +01004264/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004265static int
4266getstatus(struct job *job)
4267{
4268 int status;
4269 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004270 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004271
Michael Abbott359da5e2009-12-04 23:03:29 +01004272 /* Fetch last member's status */
4273 ps = job->ps + job->nprocs - 1;
4274 status = ps->ps_status;
4275 if (pipefail) {
4276 /* "set -o pipefail" mode: use last _nonzero_ status */
4277 while (status == 0 && --ps >= job->ps)
4278 status = ps->ps_status;
4279 }
4280
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004281 retval = WEXITSTATUS(status);
4282 if (!WIFEXITED(status)) {
4283#if JOBS
4284 retval = WSTOPSIG(status);
4285 if (!WIFSTOPPED(status))
4286#endif
4287 {
4288 /* XXX: limits number of signals */
4289 retval = WTERMSIG(status);
4290#if JOBS
4291 if (retval == SIGINT)
4292 job->sigint = 1;
4293#endif
4294 }
4295 retval += 128;
4296 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004297 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004298 jobno(job), job->nprocs, status, retval));
4299 return retval;
4300}
4301
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004302static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004303waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004304{
4305 struct job *job;
4306 int retval;
4307 struct job *jp;
4308
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004309 nextopt(nullstr);
4310 retval = 0;
4311
4312 argv = argptr;
4313 if (!*argv) {
4314 /* wait for all jobs */
4315 for (;;) {
4316 jp = curjob;
4317 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004318 if (!jp) /* no running procs */
4319 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004320 if (jp->state == JOBRUNNING)
4321 break;
4322 jp->waited = 1;
4323 jp = jp->prev_job;
4324 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004325 /* man bash:
4326 * "When bash is waiting for an asynchronous command via
4327 * the wait builtin, the reception of a signal for which a trap
4328 * has been set will cause the wait builtin to return immediately
4329 * with an exit status greater than 128, immediately after which
4330 * the trap is executed."
Denys Vlasenko69188112016-10-27 20:18:18 +02004331 */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004332 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004333 /* if child sends us a signal *and immediately exits*,
4334 * dowait() returns pid > 0. Check this case,
4335 * not "if (dowait() < 0)"!
4336 */
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004337 if (pending_sig)
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004338 goto sigout;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004339 }
4340 }
4341
4342 retval = 127;
4343 do {
4344 if (**argv != '%') {
4345 pid_t pid = number(*argv);
4346 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004347 while (1) {
4348 if (!job)
4349 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004350 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004351 break;
4352 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004353 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004354 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004355 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004356 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004357 /* loop until process terminated or stopped */
Denys Vlasenko69188112016-10-27 20:18:18 +02004358 while (job->state == JOBRUNNING) {
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004359 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004360 if (pending_sig)
4361 goto sigout;
Denys Vlasenko69188112016-10-27 20:18:18 +02004362 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004363 job->waited = 1;
4364 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004365 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004366 } while (*++argv);
4367
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004368 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004369 return retval;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004370 sigout:
4371 retval = 128 + pending_sig;
4372 return retval;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004373}
4374
4375static struct job *
4376growjobtab(void)
4377{
4378 size_t len;
4379 ptrdiff_t offset;
4380 struct job *jp, *jq;
4381
4382 len = njobs * sizeof(*jp);
4383 jq = jobtab;
4384 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4385
4386 offset = (char *)jp - (char *)jq;
4387 if (offset) {
4388 /* Relocate pointers */
4389 size_t l = len;
4390
4391 jq = (struct job *)((char *)jq + l);
4392 while (l) {
4393 l -= sizeof(*jp);
4394 jq--;
4395#define joff(p) ((struct job *)((char *)(p) + l))
4396#define jmove(p) (p) = (void *)((char *)(p) + offset)
4397 if (joff(jp)->ps == &jq->ps0)
4398 jmove(joff(jp)->ps);
4399 if (joff(jp)->prev_job)
4400 jmove(joff(jp)->prev_job);
4401 }
4402 if (curjob)
4403 jmove(curjob);
4404#undef joff
4405#undef jmove
4406 }
4407
4408 njobs += 4;
4409 jobtab = jp;
4410 jp = (struct job *)((char *)jp + len);
4411 jq = jp + 3;
4412 do {
4413 jq->used = 0;
4414 } while (--jq >= jp);
4415 return jp;
4416}
4417
4418/*
4419 * Return a new job structure.
4420 * Called with interrupts off.
4421 */
4422static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004423makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004424{
4425 int i;
4426 struct job *jp;
4427
4428 for (i = njobs, jp = jobtab; ; jp++) {
4429 if (--i < 0) {
4430 jp = growjobtab();
4431 break;
4432 }
4433 if (jp->used == 0)
4434 break;
4435 if (jp->state != JOBDONE || !jp->waited)
4436 continue;
4437#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004438 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004439 continue;
4440#endif
4441 freejob(jp);
4442 break;
4443 }
4444 memset(jp, 0, sizeof(*jp));
4445#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004446 /* jp->jobctl is a bitfield.
4447 * "jp->jobctl |= jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004448 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004449 jp->jobctl = 1;
4450#endif
4451 jp->prev_job = curjob;
4452 curjob = jp;
4453 jp->used = 1;
4454 jp->ps = &jp->ps0;
4455 if (nprocs > 1) {
4456 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4457 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004458 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004459 jobno(jp)));
4460 return jp;
4461}
4462
4463#if JOBS
4464/*
4465 * Return a string identifying a command (to be printed by the
4466 * jobs command).
4467 */
4468static char *cmdnextc;
4469
4470static void
4471cmdputs(const char *s)
4472{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004473 static const char vstype[VSTYPE + 1][3] = {
4474 "", "}", "-", "+", "?", "=",
4475 "%", "%%", "#", "##"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004476 IF_BASH_SUBSTR(, ":")
4477 IF_BASH_PATTERN_SUBST(, "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004478 };
4479
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004480 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004481 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004482 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004483 unsigned char c;
4484 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004485 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004486
Denys Vlasenko46a14772009-12-10 21:27:13 +01004487 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004488 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4489 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004490 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004491 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004492 switch (c) {
4493 case CTLESC:
4494 c = *p++;
4495 break;
4496 case CTLVAR:
4497 subtype = *p++;
4498 if ((subtype & VSTYPE) == VSLENGTH)
4499 str = "${#";
4500 else
4501 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004502 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004503 case CTLENDVAR:
4504 str = "\"}" + !(quoted & 1);
4505 quoted >>= 1;
4506 subtype = 0;
4507 goto dostr;
4508 case CTLBACKQ:
4509 str = "$(...)";
4510 goto dostr;
Denys Vlasenko0b883582016-12-23 16:49:07 +01004511#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004512 case CTLARI:
4513 str = "$((";
4514 goto dostr;
4515 case CTLENDARI:
4516 str = "))";
4517 goto dostr;
4518#endif
4519 case CTLQUOTEMARK:
4520 quoted ^= 1;
4521 c = '"';
4522 break;
4523 case '=':
4524 if (subtype == 0)
4525 break;
4526 if ((subtype & VSTYPE) != VSNORMAL)
4527 quoted <<= 1;
4528 str = vstype[subtype & VSTYPE];
4529 if (subtype & VSNUL)
4530 c = ':';
4531 else
4532 goto checkstr;
4533 break;
4534 case '\'':
4535 case '\\':
4536 case '"':
4537 case '$':
4538 /* These can only happen inside quotes */
4539 cc[0] = c;
4540 str = cc;
4541 c = '\\';
4542 break;
4543 default:
4544 break;
4545 }
4546 USTPUTC(c, nextc);
4547 checkstr:
4548 if (!str)
4549 continue;
4550 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004551 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004552 USTPUTC(c, nextc);
4553 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004554 } /* while *p++ not NUL */
4555
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004556 if (quoted & 1) {
4557 USTPUTC('"', nextc);
4558 }
4559 *nextc = 0;
4560 cmdnextc = nextc;
4561}
4562
4563/* cmdtxt() and cmdlist() call each other */
4564static void cmdtxt(union node *n);
4565
4566static void
4567cmdlist(union node *np, int sep)
4568{
4569 for (; np; np = np->narg.next) {
4570 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004571 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004572 cmdtxt(np);
4573 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004574 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004575 }
4576}
4577
4578static void
4579cmdtxt(union node *n)
4580{
4581 union node *np;
4582 struct nodelist *lp;
4583 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004584
4585 if (!n)
4586 return;
4587 switch (n->type) {
4588 default:
4589#if DEBUG
4590 abort();
4591#endif
4592 case NPIPE:
4593 lp = n->npipe.cmdlist;
4594 for (;;) {
4595 cmdtxt(lp->n);
4596 lp = lp->next;
4597 if (!lp)
4598 break;
4599 cmdputs(" | ");
4600 }
4601 break;
4602 case NSEMI:
4603 p = "; ";
4604 goto binop;
4605 case NAND:
4606 p = " && ";
4607 goto binop;
4608 case NOR:
4609 p = " || ";
4610 binop:
4611 cmdtxt(n->nbinary.ch1);
4612 cmdputs(p);
4613 n = n->nbinary.ch2;
4614 goto donode;
4615 case NREDIR:
4616 case NBACKGND:
4617 n = n->nredir.n;
4618 goto donode;
4619 case NNOT:
4620 cmdputs("!");
4621 n = n->nnot.com;
4622 donode:
4623 cmdtxt(n);
4624 break;
4625 case NIF:
4626 cmdputs("if ");
4627 cmdtxt(n->nif.test);
4628 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004629 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004630 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004631 cmdputs("; else ");
4632 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004633 } else {
4634 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004635 }
4636 p = "; fi";
4637 goto dotail;
4638 case NSUBSHELL:
4639 cmdputs("(");
4640 n = n->nredir.n;
4641 p = ")";
4642 goto dotail;
4643 case NWHILE:
4644 p = "while ";
4645 goto until;
4646 case NUNTIL:
4647 p = "until ";
4648 until:
4649 cmdputs(p);
4650 cmdtxt(n->nbinary.ch1);
4651 n = n->nbinary.ch2;
4652 p = "; done";
4653 dodo:
4654 cmdputs("; do ");
4655 dotail:
4656 cmdtxt(n);
4657 goto dotail2;
4658 case NFOR:
4659 cmdputs("for ");
4660 cmdputs(n->nfor.var);
4661 cmdputs(" in ");
4662 cmdlist(n->nfor.args, 1);
4663 n = n->nfor.body;
4664 p = "; done";
4665 goto dodo;
4666 case NDEFUN:
4667 cmdputs(n->narg.text);
4668 p = "() { ... }";
4669 goto dotail2;
4670 case NCMD:
4671 cmdlist(n->ncmd.args, 1);
4672 cmdlist(n->ncmd.redirect, 0);
4673 break;
4674 case NARG:
4675 p = n->narg.text;
4676 dotail2:
4677 cmdputs(p);
4678 break;
4679 case NHERE:
4680 case NXHERE:
4681 p = "<<...";
4682 goto dotail2;
4683 case NCASE:
4684 cmdputs("case ");
4685 cmdputs(n->ncase.expr->narg.text);
4686 cmdputs(" in ");
4687 for (np = n->ncase.cases; np; np = np->nclist.next) {
4688 cmdtxt(np->nclist.pattern);
4689 cmdputs(") ");
4690 cmdtxt(np->nclist.body);
4691 cmdputs(";; ");
4692 }
4693 p = "esac";
4694 goto dotail2;
4695 case NTO:
4696 p = ">";
4697 goto redir;
4698 case NCLOBBER:
4699 p = ">|";
4700 goto redir;
4701 case NAPPEND:
4702 p = ">>";
4703 goto redir;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004704#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00004705 case NTO2:
4706#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004707 case NTOFD:
4708 p = ">&";
4709 goto redir;
4710 case NFROM:
4711 p = "<";
4712 goto redir;
4713 case NFROMFD:
4714 p = "<&";
4715 goto redir;
4716 case NFROMTO:
4717 p = "<>";
4718 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004719 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004720 cmdputs(p);
4721 if (n->type == NTOFD || n->type == NFROMFD) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004722 cmdputs(utoa(n->ndup.dupfd));
4723 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004724 }
4725 n = n->nfile.fname;
4726 goto donode;
4727 }
4728}
4729
4730static char *
4731commandtext(union node *n)
4732{
4733 char *name;
4734
4735 STARTSTACKSTR(cmdnextc);
4736 cmdtxt(n);
4737 name = stackblock();
Denys Vlasenko6a94cee2016-10-25 17:40:25 +02004738 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004739 return ckstrdup(name);
4740}
4741#endif /* JOBS */
4742
4743/*
4744 * Fork off a subshell. If we are doing job control, give the subshell its
4745 * own process group. Jp is a job structure that the job is to be added to.
4746 * N is the command that will be evaluated by the child. Both jp and n may
4747 * be NULL. The mode parameter can be one of the following:
4748 * FORK_FG - Fork off a foreground process.
4749 * FORK_BG - Fork off a background process.
4750 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4751 * process group even if job control is on.
4752 *
4753 * When job control is turned off, background processes have their standard
4754 * input redirected to /dev/null (except for the second and later processes
4755 * in a pipeline).
4756 *
4757 * Called with interrupts off.
4758 */
4759/*
4760 * Clear traps on a fork.
4761 */
4762static void
4763clear_traps(void)
4764{
4765 char **tp;
4766
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004767 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004768 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004769 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004770 if (trap_ptr == trap)
4771 free(*tp);
4772 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004773 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004774 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004775 setsignal(tp - trap);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004776 }
4777 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004778 may_have_traps = 0;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004779 INT_ON;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004780}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004781
4782/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004783static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004784
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004785/* Called after fork(), in child */
Denys Vlasenko70392332016-10-27 02:31:55 +02004786/* jp and n are NULL when called by openhere() for heredoc support */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004787static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004788forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004789{
4790 int oldlvl;
4791
4792 TRACE(("Child shell %d\n", getpid()));
4793 oldlvl = shlvl;
4794 shlvl++;
4795
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004796 /* man bash: "Non-builtin commands run by bash have signal handlers
4797 * set to the values inherited by the shell from its parent".
4798 * Do we do it correctly? */
4799
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004800 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004801
4802 if (mode == FORK_NOJOB /* is it `xxx` ? */
4803 && n && n->type == NCMD /* is it single cmd? */
4804 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004805 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004806 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4807 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4808 ) {
4809 TRACE(("Trap hack\n"));
4810 /* Awful hack for `trap` or $(trap).
4811 *
4812 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4813 * contains an example where "trap" is executed in a subshell:
4814 *
4815 * save_traps=$(trap)
4816 * ...
4817 * eval "$save_traps"
4818 *
4819 * Standard does not say that "trap" in subshell shall print
4820 * parent shell's traps. It only says that its output
4821 * must have suitable form, but then, in the above example
4822 * (which is not supposed to be normative), it implies that.
4823 *
4824 * bash (and probably other shell) does implement it
4825 * (traps are reset to defaults, but "trap" still shows them),
4826 * but as a result, "trap" logic is hopelessly messed up:
4827 *
4828 * # trap
4829 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4830 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4831 * # true | trap <--- trap is in subshell - no output (ditto)
4832 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4833 * trap -- 'echo Ho' SIGWINCH
4834 * # echo `(trap)` <--- in subshell in subshell - output
4835 * trap -- 'echo Ho' SIGWINCH
4836 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4837 * trap -- 'echo Ho' SIGWINCH
4838 *
4839 * The rules when to forget and when to not forget traps
4840 * get really complex and nonsensical.
4841 *
4842 * Our solution: ONLY bare $(trap) or `trap` is special.
4843 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004844 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02004845 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004846 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004847 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004848 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004849#if JOBS
4850 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004851 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004852 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004853 pid_t pgrp;
4854
4855 if (jp->nprocs == 0)
4856 pgrp = getpid();
4857 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004858 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004859 /* this can fail because we are doing it in the parent also */
4860 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004861 if (mode == FORK_FG)
4862 xtcsetpgrp(ttyfd, pgrp);
4863 setsignal(SIGTSTP);
4864 setsignal(SIGTTOU);
4865 } else
4866#endif
4867 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004868 /* man bash: "When job control is not in effect,
4869 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004870 ignoresig(SIGINT);
4871 ignoresig(SIGQUIT);
4872 if (jp->nprocs == 0) {
4873 close(0);
4874 if (open(bb_dev_null, O_RDONLY) != 0)
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00004875 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004876 }
4877 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004878 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004879 if (iflag) { /* why if iflag only? */
4880 setsignal(SIGINT);
4881 setsignal(SIGTERM);
4882 }
4883 /* man bash:
4884 * "In all cases, bash ignores SIGQUIT. Non-builtin
4885 * commands run by bash have signal handlers
4886 * set to the values inherited by the shell
4887 * from its parent".
4888 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004889 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004890 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004891#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02004892 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01004893 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004894 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004895 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02004896 /* "jobs": we do not want to clear job list for it,
4897 * instead we remove only _its_ own_ job from job list.
4898 * This makes "jobs .... | cat" more useful.
4899 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004900 freejob(curjob);
4901 return;
4902 }
4903#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004904 for (jp = curjob; jp; jp = jp->prev_job)
4905 freejob(jp);
4906 jobless = 0;
4907}
4908
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004909/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00004910#if !JOBS
4911#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4912#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004913static void
4914forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4915{
4916 TRACE(("In parent shell: child = %d\n", pid));
4917 if (!jp) {
Denys Vlasenko70392332016-10-27 02:31:55 +02004918 /* jp is NULL when called by openhere() for heredoc support */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004919 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4920 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004921 jobless++;
4922 return;
4923 }
4924#if JOBS
4925 if (mode != FORK_NOJOB && jp->jobctl) {
4926 int pgrp;
4927
4928 if (jp->nprocs == 0)
4929 pgrp = pid;
4930 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004931 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004932 /* This can fail because we are doing it in the child also */
4933 setpgid(pid, pgrp);
4934 }
4935#endif
4936 if (mode == FORK_BG) {
4937 backgndpid = pid; /* set $! */
4938 set_curjob(jp, CUR_RUNNING);
4939 }
4940 if (jp) {
4941 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01004942 ps->ps_pid = pid;
4943 ps->ps_status = -1;
4944 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004945#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004946 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004947 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004948#endif
4949 }
4950}
4951
Denys Vlasenko70392332016-10-27 02:31:55 +02004952/* jp and n are NULL when called by openhere() for heredoc support */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004953static int
4954forkshell(struct job *jp, union node *n, int mode)
4955{
4956 int pid;
4957
4958 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4959 pid = fork();
4960 if (pid < 0) {
4961 TRACE(("Fork failed, errno=%d", errno));
4962 if (jp)
4963 freejob(jp);
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +00004964 ash_msg_and_raise_error("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004965 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02004966 if (pid == 0) {
4967 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004968 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004969 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004970 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004971 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004972 return pid;
4973}
4974
4975/*
4976 * Wait for job to finish.
4977 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004978 * Under job control we have the problem that while a child process
4979 * is running interrupts generated by the user are sent to the child
4980 * but not to the shell. This means that an infinite loop started by
4981 * an interactive user may be hard to kill. With job control turned off,
4982 * an interactive user may place an interactive program inside a loop.
4983 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004984 * these interrupts to also abort the loop. The approach we take here
4985 * is to have the shell ignore interrupt signals while waiting for a
4986 * foreground process to terminate, and then send itself an interrupt
4987 * signal if the child process was terminated by an interrupt signal.
4988 * Unfortunately, some programs want to do a bit of cleanup and then
4989 * exit on interrupt; unless these processes terminate themselves by
4990 * sending a signal to themselves (instead of calling exit) they will
4991 * confuse this approach.
4992 *
4993 * Called with interrupts off.
4994 */
4995static int
4996waitforjob(struct job *jp)
4997{
4998 int st;
4999
5000 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005001
5002 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005003 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005004 /* In non-interactive shells, we _can_ get
5005 * a keyboard signal here and be EINTRed,
5006 * but we just loop back, waiting for command to complete.
5007 *
5008 * man bash:
5009 * "If bash is waiting for a command to complete and receives
5010 * a signal for which a trap has been set, the trap
5011 * will not be executed until the command completes."
5012 *
5013 * Reality is that even if trap is not set, bash
5014 * will not act on the signal until command completes.
5015 * Try this. sleep5intoff.c:
5016 * #include <signal.h>
5017 * #include <unistd.h>
5018 * int main() {
5019 * sigset_t set;
5020 * sigemptyset(&set);
5021 * sigaddset(&set, SIGINT);
5022 * sigaddset(&set, SIGQUIT);
5023 * sigprocmask(SIG_BLOCK, &set, NULL);
5024 * sleep(5);
5025 * return 0;
5026 * }
5027 * $ bash -c './sleep5intoff; echo hi'
5028 * ^C^C^C^C <--- pressing ^C once a second
5029 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005030 * $ bash -c './sleep5intoff; echo hi'
5031 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5032 * $ _
5033 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005034 dowait(DOWAIT_BLOCK, jp);
5035 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005036 INT_ON;
5037
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005038 st = getstatus(jp);
5039#if JOBS
5040 if (jp->jobctl) {
5041 xtcsetpgrp(ttyfd, rootpid);
5042 /*
5043 * This is truly gross.
5044 * If we're doing job control, then we did a TIOCSPGRP which
5045 * caused us (the shell) to no longer be in the controlling
5046 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
5047 * intuit from the subprocess exit status whether a SIGINT
5048 * occurred, and if so interrupt ourselves. Yuck. - mycroft
5049 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00005050 if (jp->sigint) /* TODO: do the same with all signals */
5051 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005052 }
5053 if (jp->state == JOBDONE)
5054#endif
5055 freejob(jp);
5056 return st;
5057}
5058
5059/*
5060 * return 1 if there are stopped jobs, otherwise 0
5061 */
5062static int
5063stoppedjobs(void)
5064{
5065 struct job *jp;
5066 int retval;
5067
5068 retval = 0;
5069 if (job_warning)
5070 goto out;
5071 jp = curjob;
5072 if (jp && jp->state == JOBSTOPPED) {
5073 out2str("You have stopped jobs.\n");
5074 job_warning = 2;
5075 retval++;
5076 }
5077 out:
5078 return retval;
5079}
5080
5081
Denys Vlasenko70392332016-10-27 02:31:55 +02005082/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005083 * Code for dealing with input/output redirection.
5084 */
5085
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005086#undef EMPTY
5087#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005088#define EMPTY -2 /* marks an unused slot in redirtab */
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005089#define CLOSED -3 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005090
5091/*
5092 * Open a file in noclobber mode.
5093 * The code was copied from bash.
5094 */
5095static int
5096noclobberopen(const char *fname)
5097{
5098 int r, fd;
5099 struct stat finfo, finfo2;
5100
5101 /*
5102 * If the file exists and is a regular file, return an error
5103 * immediately.
5104 */
5105 r = stat(fname, &finfo);
5106 if (r == 0 && S_ISREG(finfo.st_mode)) {
5107 errno = EEXIST;
5108 return -1;
5109 }
5110
5111 /*
5112 * If the file was not present (r != 0), make sure we open it
5113 * exclusively so that if it is created before we open it, our open
5114 * will fail. Make sure that we do not truncate an existing file.
5115 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5116 * file was not a regular file, we leave O_EXCL off.
5117 */
5118 if (r != 0)
5119 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5120 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5121
5122 /* If the open failed, return the file descriptor right away. */
5123 if (fd < 0)
5124 return fd;
5125
5126 /*
5127 * OK, the open succeeded, but the file may have been changed from a
5128 * non-regular file to a regular file between the stat and the open.
5129 * We are assuming that the O_EXCL open handles the case where FILENAME
5130 * did not exist and is symlinked to an existing file between the stat
5131 * and open.
5132 */
5133
5134 /*
5135 * If we can open it and fstat the file descriptor, and neither check
5136 * revealed that it was a regular file, and the file has not been
5137 * replaced, return the file descriptor.
5138 */
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005139 if (fstat(fd, &finfo2) == 0
5140 && !S_ISREG(finfo2.st_mode)
5141 && finfo.st_dev == finfo2.st_dev
5142 && finfo.st_ino == finfo2.st_ino
5143 ) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005144 return fd;
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005145 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005146
5147 /* The file has been replaced. badness. */
5148 close(fd);
5149 errno = EEXIST;
5150 return -1;
5151}
5152
5153/*
5154 * Handle here documents. Normally we fork off a process to write the
5155 * data to a pipe. If the document is short, we can stuff the data in
5156 * the pipe without forking.
5157 */
5158/* openhere needs this forward reference */
5159static void expandhere(union node *arg, int fd);
5160static int
5161openhere(union node *redir)
5162{
5163 int pip[2];
5164 size_t len = 0;
5165
5166 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005167 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005168 if (redir->type == NHERE) {
5169 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005170 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005171 full_write(pip[1], redir->nhere.doc->narg.text, len);
5172 goto out;
5173 }
5174 }
5175 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005176 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005177 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005178 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5179 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5180 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5181 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005182 signal(SIGPIPE, SIG_DFL);
5183 if (redir->type == NHERE)
5184 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005185 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005186 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005187 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005188 }
5189 out:
5190 close(pip[1]);
5191 return pip[0];
5192}
5193
5194static int
5195openredirect(union node *redir)
5196{
5197 char *fname;
5198 int f;
5199
5200 switch (redir->nfile.type) {
Denys Vlasenko557482c2016-09-25 21:24:04 +02005201/* Can't happen, our single caller does this itself */
5202// case NTOFD:
5203// case NFROMFD:
5204// return -1;
5205 case NHERE:
5206 case NXHERE:
5207 return openhere(redir);
5208 }
5209
5210 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5211 * allocated space. Do it only when we know it is safe.
5212 */
5213 fname = redir->nfile.expfname;
5214
5215 switch (redir->nfile.type) {
5216 default:
5217#if DEBUG
5218 abort();
5219#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005220 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005221 f = open(fname, O_RDONLY);
5222 if (f < 0)
5223 goto eopen;
5224 break;
5225 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005226 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005227 if (f < 0)
5228 goto ecreate;
5229 break;
5230 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005231#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005232 case NTO2:
5233#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005234 /* Take care of noclobber mode. */
5235 if (Cflag) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005236 f = noclobberopen(fname);
5237 if (f < 0)
5238 goto ecreate;
5239 break;
5240 }
5241 /* FALLTHROUGH */
5242 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005243 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5244 if (f < 0)
5245 goto ecreate;
5246 break;
5247 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005248 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5249 if (f < 0)
5250 goto ecreate;
5251 break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005252 }
5253
5254 return f;
5255 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005256 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005257 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005258 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005259}
5260
5261/*
Denys Vlasenko64774602016-10-26 15:24:30 +02005262 * Copy a file descriptor to be >= 10. Throws exception on error.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005263 */
5264static int
Denys Vlasenko64774602016-10-26 15:24:30 +02005265savefd(int from)
5266{
5267 int newfd;
5268 int err;
5269
5270 newfd = fcntl(from, F_DUPFD, 10);
5271 err = newfd < 0 ? errno : 0;
5272 if (err != EBADF) {
5273 if (err)
5274 ash_msg_and_raise_error("%d: %m", from);
5275 close(from);
5276 fcntl(newfd, F_SETFD, FD_CLOEXEC);
5277 }
5278
5279 return newfd;
5280}
5281static int
5282dup2_or_raise(int from, int to)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005283{
5284 int newfd;
5285
Denys Vlasenko64774602016-10-26 15:24:30 +02005286 newfd = (from != to) ? dup2(from, to) : to;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005287 if (newfd < 0) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005288 /* Happens when source fd is not open: try "echo >&99" */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005289 ash_msg_and_raise_error("%d: %m", from);
5290 }
5291 return newfd;
5292}
5293
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005294/* Struct def and variable are moved down to the first usage site */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005295struct two_fd_t {
5296 int orig, copy;
5297};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005298struct redirtab {
5299 struct redirtab *next;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005300 int pair_count;
Denys Vlasenko606291b2009-09-23 23:15:43 +02005301 struct two_fd_t two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005302};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005303#define redirlist (G_var.redirlist)
Denys Vlasenko64774602016-10-26 15:24:30 +02005304enum {
5305 COPYFD_RESTORE = (int)~(INT_MAX),
5306};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005307
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005308static int
5309need_to_remember(struct redirtab *rp, int fd)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005310{
5311 int i;
5312
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005313 if (!rp) /* remembering was not requested */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005314 return 0;
5315
5316 for (i = 0; i < rp->pair_count; i++) {
5317 if (rp->two_fd[i].orig == fd) {
5318 /* already remembered */
5319 return 0;
5320 }
5321 }
5322 return 1;
5323}
5324
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005325/* "hidden" fd is a fd used to read scripts, or a copy of such */
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005326static int
5327is_hidden_fd(struct redirtab *rp, int fd)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005328{
5329 int i;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005330 struct parsefile *pf;
5331
5332 if (fd == -1)
5333 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005334 /* Check open scripts' fds */
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005335 pf = g_parsefile;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005336 while (pf) {
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005337 /* We skip pf_fd == 0 case because of the following case:
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005338 * $ ash # running ash interactively
5339 * $ . ./script.sh
5340 * and in script.sh: "exec 9>&0".
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005341 * Even though top-level pf_fd _is_ 0,
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005342 * it's still ok to use it: "read" builtin uses it,
5343 * why should we cripple "exec" builtin?
5344 */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005345 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005346 return 1;
5347 }
5348 pf = pf->prev;
5349 }
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005350
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005351 if (!rp)
5352 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005353 /* Check saved fds of redirects */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005354 fd |= COPYFD_RESTORE;
5355 for (i = 0; i < rp->pair_count; i++) {
5356 if (rp->two_fd[i].copy == fd) {
5357 return 1;
5358 }
5359 }
5360 return 0;
5361}
5362
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005363/*
5364 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5365 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005366 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005367 */
5368/* flags passed to redirect */
5369#define REDIR_PUSH 01 /* save previous values of file descriptors */
5370#define REDIR_SAVEFD2 03 /* set preverrout */
5371static void
5372redirect(union node *redir, int flags)
5373{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005374 struct redirtab *sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005375 int sv_pos;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005376 int i;
5377 int fd;
5378 int newfd;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005379 int copied_fd2 = -1;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005380
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005381 if (!redir) {
5382 return;
5383 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005384
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005385 sv = NULL;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005386 sv_pos = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005387 INT_OFF;
5388 if (flags & REDIR_PUSH) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005389 union node *tmp = redir;
5390 do {
5391 sv_pos++;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005392#if BASH_REDIR_OUTPUT
Chris Metcalfc3c1fb62010-01-08 13:18:06 +01005393 if (tmp->nfile.type == NTO2)
Denis Vlasenko559691a2008-10-05 18:39:31 +00005394 sv_pos++;
5395#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005396 tmp = tmp->nfile.next;
5397 } while (tmp);
5398 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005399 sv->next = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005400 sv->pair_count = sv_pos;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005401 redirlist = sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005402 while (sv_pos > 0) {
5403 sv_pos--;
5404 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5405 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005406 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005407
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005408 do {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005409 int right_fd = -1;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005410 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005411 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005412 right_fd = redir->ndup.dupfd;
5413 //bb_error_msg("doing %d > %d", fd, right_fd);
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005414 /* redirect from/to same file descriptor? */
5415 if (right_fd == fd)
5416 continue;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005417 /* "echo >&10" and 10 is a fd opened to a sh script? */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005418 if (is_hidden_fd(sv, right_fd)) {
5419 errno = EBADF; /* as if it is closed */
5420 ash_msg_and_raise_error("%d: %m", right_fd);
5421 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005422 newfd = -1;
5423 } else {
5424 newfd = openredirect(redir); /* always >= 0 */
5425 if (fd == newfd) {
5426 /* Descriptor wasn't open before redirect.
5427 * Mark it for close in the future */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005428 if (need_to_remember(sv, fd)) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005429 goto remember_to_close;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005430 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005431 continue;
5432 }
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005433 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005434#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005435 redirect_more:
5436#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005437 if (need_to_remember(sv, fd)) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005438 /* Copy old descriptor */
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005439 /* Careful to not accidentally "save"
5440 * to the same fd as right side fd in N>&M */
5441 int minfd = right_fd < 10 ? 10 : right_fd + 1;
Denys Vlasenko86584e12017-01-07 10:15:01 +01005442#if defined(F_DUPFD_CLOEXEC)
5443 i = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
5444#else
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005445 i = fcntl(fd, F_DUPFD, minfd);
Denys Vlasenko86584e12017-01-07 10:15:01 +01005446#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005447 if (i == -1) {
5448 i = errno;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005449 if (i != EBADF) {
5450 /* Strange error (e.g. "too many files" EMFILE?) */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005451 if (newfd >= 0)
5452 close(newfd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005453 errno = i;
5454 ash_msg_and_raise_error("%d: %m", fd);
5455 /* NOTREACHED */
5456 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005457 /* EBADF: it is not open - good, remember to close it */
5458 remember_to_close:
5459 i = CLOSED;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005460 } else { /* fd is open, save its copy */
Denys Vlasenko86584e12017-01-07 10:15:01 +01005461#if !defined(F_DUPFD_CLOEXEC)
5462 fcntl(i, F_SETFD, FD_CLOEXEC);
5463#endif
Denis Vlasenko22f74142008-07-24 22:34:43 +00005464 /* "exec fd>&-" should not close fds
5465 * which point to script file(s).
5466 * Force them to be restored afterwards */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005467 if (is_hidden_fd(sv, fd))
5468 i |= COPYFD_RESTORE;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005469 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005470 if (fd == 2)
5471 copied_fd2 = i;
5472 sv->two_fd[sv_pos].orig = fd;
5473 sv->two_fd[sv_pos].copy = i;
5474 sv_pos++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005475 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005476 if (newfd < 0) {
5477 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005478 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005479 /* Don't want to trigger debugging */
5480 if (fd != -1)
5481 close(fd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005482 } else {
Denys Vlasenko64774602016-10-26 15:24:30 +02005483 dup2_or_raise(redir->ndup.dupfd, fd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005484 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005485 } else if (fd != newfd) { /* move newfd to fd */
Denys Vlasenko64774602016-10-26 15:24:30 +02005486 dup2_or_raise(newfd, fd);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005487#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005488 if (!(redir->nfile.type == NTO2 && fd == 2))
5489#endif
5490 close(newfd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005491 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005492#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005493 if (redir->nfile.type == NTO2 && fd == 1) {
5494 /* We already redirected it to fd 1, now copy it to 2 */
5495 newfd = 1;
5496 fd = 2;
5497 goto redirect_more;
5498 }
5499#endif
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005500 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005501
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005502 INT_ON;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005503 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5504 preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005505}
5506
5507/*
5508 * Undo the effects of the last redirection.
5509 */
5510static void
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005511popredir(int drop, int restore)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005512{
5513 struct redirtab *rp;
5514 int i;
5515
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02005516 if (redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005517 return;
5518 INT_OFF;
5519 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005520 for (i = 0; i < rp->pair_count; i++) {
5521 int fd = rp->two_fd[i].orig;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005522 int copy = rp->two_fd[i].copy;
5523 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005524 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005525 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005526 continue;
5527 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005528 if (copy != EMPTY) {
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005529 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
Denis Vlasenko22f74142008-07-24 22:34:43 +00005530 copy &= ~COPYFD_RESTORE;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005531 /*close(fd);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02005532 dup2_or_raise(copy, fd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005533 }
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005534 close(copy & ~COPYFD_RESTORE);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005535 }
5536 }
5537 redirlist = rp->next;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005538 free(rp);
5539 INT_ON;
5540}
5541
5542/*
5543 * Undo all redirections. Called on error or interrupt.
5544 */
5545
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005546static int
5547redirectsafe(union node *redir, int flags)
5548{
5549 int err;
5550 volatile int saveint;
5551 struct jmploc *volatile savehandler = exception_handler;
5552 struct jmploc jmploc;
5553
5554 SAVE_INT(saveint);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005555 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5556 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005557 if (!err) {
5558 exception_handler = &jmploc;
5559 redirect(redir, flags);
5560 }
5561 exception_handler = savehandler;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00005562 if (err && exception_type != EXERROR)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005563 longjmp(exception_handler->loc, 1);
5564 RESTORE_INT(saveint);
5565 return err;
5566}
5567
5568
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005569/* ============ Routines to expand arguments to commands
5570 *
5571 * We have to deal with backquotes, shell variables, and file metacharacters.
5572 */
5573
Denys Vlasenko0b883582016-12-23 16:49:07 +01005574#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005575static arith_t
5576ash_arith(const char *s)
5577{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005578 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005579 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005580
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005581 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005582 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005583 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005584
5585 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005586 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005587 if (math_state.errmsg)
5588 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005589 INT_ON;
5590
5591 return result;
5592}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005593#endif
5594
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005595/*
5596 * expandarg flags
5597 */
5598#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5599#define EXP_TILDE 0x2 /* do normal tilde expansion */
5600#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5601#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
Denys Vlasenkodb74c6c2016-10-24 21:12:33 +02005602/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5603 * POSIX says for this case:
5604 * Pathname expansion shall not be performed on the word by a
5605 * non-interactive shell; an interactive shell may perform it, but shall
5606 * do so only when the expansion would result in one word.
5607 * Currently, our code complies to the above rule by never globbing
5608 * redirection filenames.
5609 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5610 * (this means that on a typical Linux distro, bash almost always
5611 * performs globbing, and thus diverges from what we do).
5612 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005613#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Ron Yorston549deab2015-05-18 09:57:51 +02005614#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005615#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5616#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005617#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005618/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005619 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005620 */
5621#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5622#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005623#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5624#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Ron Yorston417622c2015-05-18 09:59:14 +02005625#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005626
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005627/* Add CTLESC when necessary. */
Ron Yorston549deab2015-05-18 09:57:51 +02005628#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005629/* Do not skip NUL characters. */
5630#define QUOTES_KEEPNUL EXP_TILDE
5631
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005632/*
5633 * Structure specifying which parts of the string should be searched
5634 * for IFS characters.
5635 */
5636struct ifsregion {
5637 struct ifsregion *next; /* next region in list */
5638 int begoff; /* offset of start of region */
5639 int endoff; /* offset of end of region */
5640 int nulonly; /* search for nul bytes only */
5641};
5642
5643struct arglist {
5644 struct strlist *list;
5645 struct strlist **lastp;
5646};
5647
5648/* output of current string */
5649static char *expdest;
5650/* list of back quote expressions */
5651static struct nodelist *argbackq;
5652/* first struct in list of ifs regions */
5653static struct ifsregion ifsfirst;
5654/* last struct in list */
5655static struct ifsregion *ifslastp;
5656/* holds expanded arg list */
5657static struct arglist exparg;
5658
5659/*
5660 * Our own itoa().
5661 */
Denys Vlasenko0b883582016-12-23 16:49:07 +01005662#if !ENABLE_FEATURE_SH_MATH
Denys Vlasenko26777aa2010-11-22 23:49:10 +01005663/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5664typedef long arith_t;
5665# define ARITH_FMT "%ld"
5666#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005667static int
5668cvtnum(arith_t num)
5669{
5670 int len;
5671
Denys Vlasenko9c541002015-10-07 15:44:36 +02005672 expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest);
5673 len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005674 STADJUST(len, expdest);
5675 return len;
5676}
5677
Denys Vlasenko455e4222016-10-27 14:45:13 +02005678/*
5679 * Break the argument string into pieces based upon IFS and add the
5680 * strings to the argument list. The regions of the string to be
5681 * searched for IFS characters have been stored by recordregion.
5682 */
5683static void
5684ifsbreakup(char *string, struct arglist *arglist)
5685{
5686 struct ifsregion *ifsp;
5687 struct strlist *sp;
5688 char *start;
5689 char *p;
5690 char *q;
5691 const char *ifs, *realifs;
5692 int ifsspc;
5693 int nulonly;
5694
5695 start = string;
5696 if (ifslastp != NULL) {
5697 ifsspc = 0;
5698 nulonly = 0;
5699 realifs = ifsset() ? ifsval() : defifs;
5700 ifsp = &ifsfirst;
5701 do {
5702 p = string + ifsp->begoff;
5703 nulonly = ifsp->nulonly;
5704 ifs = nulonly ? nullstr : realifs;
5705 ifsspc = 0;
5706 while (p < string + ifsp->endoff) {
5707 q = p;
5708 if ((unsigned char)*p == CTLESC)
5709 p++;
5710 if (!strchr(ifs, *p)) {
5711 p++;
5712 continue;
5713 }
5714 if (!nulonly)
5715 ifsspc = (strchr(defifs, *p) != NULL);
5716 /* Ignore IFS whitespace at start */
5717 if (q == start && ifsspc) {
5718 p++;
5719 start = p;
5720 continue;
5721 }
5722 *q = '\0';
5723 sp = stzalloc(sizeof(*sp));
5724 sp->text = start;
5725 *arglist->lastp = sp;
5726 arglist->lastp = &sp->next;
5727 p++;
5728 if (!nulonly) {
5729 for (;;) {
5730 if (p >= string + ifsp->endoff) {
5731 break;
5732 }
5733 q = p;
5734 if ((unsigned char)*p == CTLESC)
5735 p++;
5736 if (strchr(ifs, *p) == NULL) {
5737 p = q;
5738 break;
5739 }
5740 if (strchr(defifs, *p) == NULL) {
5741 if (ifsspc) {
5742 p++;
5743 ifsspc = 0;
5744 } else {
5745 p = q;
5746 break;
5747 }
5748 } else
5749 p++;
5750 }
5751 }
5752 start = p;
5753 } /* while */
5754 ifsp = ifsp->next;
5755 } while (ifsp != NULL);
5756 if (nulonly)
5757 goto add;
5758 }
5759
5760 if (!*start)
5761 return;
5762
5763 add:
5764 sp = stzalloc(sizeof(*sp));
5765 sp->text = start;
5766 *arglist->lastp = sp;
5767 arglist->lastp = &sp->next;
5768}
5769
5770static void
5771ifsfree(void)
5772{
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005773 struct ifsregion *p = ifsfirst.next;
5774
5775 if (!p)
5776 goto out;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005777
5778 INT_OFF;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005779 do {
5780 struct ifsregion *ifsp;
5781 ifsp = p->next;
5782 free(p);
5783 p = ifsp;
5784 } while (p);
Denys Vlasenko455e4222016-10-27 14:45:13 +02005785 ifsfirst.next = NULL;
5786 INT_ON;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005787 out:
5788 ifslastp = NULL;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005789}
5790
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005791static size_t
5792esclen(const char *start, const char *p)
5793{
5794 size_t esc = 0;
5795
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005796 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005797 esc++;
5798 }
5799 return esc;
5800}
5801
5802/*
5803 * Remove any CTLESC characters from a string.
5804 */
5805static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005806rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005807{
Ron Yorston417622c2015-05-18 09:59:14 +02005808 static const char qchars[] ALIGN1 = {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005809 IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005810
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005811 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005812 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005813 unsigned protect_against_glob;
5814 unsigned globbing;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005815 IF_BASH_PATTERN_SUBST(unsigned slash = flag & RMESCAPE_SLASH;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005816
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005817 p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005818 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005819 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005820
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005821 q = p;
5822 r = str;
5823 if (flag & RMESCAPE_ALLOC) {
5824 size_t len = p - str;
5825 size_t fulllen = len + strlen(p) + 1;
5826
5827 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005828 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005829 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005830 /* p and str may be invalidated by makestrspace */
5831 str = (char *)stackblock() + strloc;
5832 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005833 } else if (flag & RMESCAPE_HEAP) {
5834 r = ckmalloc(fulllen);
5835 } else {
5836 r = stalloc(fulllen);
5837 }
5838 q = r;
5839 if (len > 0) {
Denis Vlasenko29eb3592008-05-18 14:06:08 +00005840 q = (char *)memcpy(q, str, len) + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005841 }
5842 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005843
Ron Yorston549deab2015-05-18 09:57:51 +02005844 inquotes = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005845 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005846 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005847 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005848 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005849// Note: both inquotes and protect_against_glob only affect whether
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005850 inquotes = ~inquotes;
5851 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005852 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005853 continue;
5854 }
Ron Yorston549deab2015-05-18 09:57:51 +02005855 if ((unsigned char)*p == CTLESC) {
5856 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02005857#if DEBUG
5858 if (*p == '\0')
5859 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
5860#endif
Ron Yorston549deab2015-05-18 09:57:51 +02005861 if (protect_against_glob) {
5862 *q++ = '\\';
5863 }
5864 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005865 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005866 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005867 goto copy;
5868 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005869#if BASH_PATTERN_SUBST
Ron Yorston417622c2015-05-18 09:59:14 +02005870 else if (*p == '/' && slash) {
5871 /* stop handling globbing and mark location of slash */
5872 globbing = slash = 0;
5873 *p = CTLESC;
5874 }
5875#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005876 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005877 copy:
5878 *q++ = *p++;
5879 }
5880 *q = '\0';
5881 if (flag & RMESCAPE_GROW) {
5882 expdest = r;
5883 STADJUST(q - r + 1, expdest);
5884 }
5885 return r;
5886}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005887#define pmatch(a, b) !fnmatch((a), (b), 0)
5888
5889/*
5890 * Prepare a pattern for a expmeta (internal glob(3)) call.
5891 *
5892 * Returns an stalloced string.
5893 */
5894static char *
Ron Yorston549deab2015-05-18 09:57:51 +02005895preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005896{
Ron Yorston549deab2015-05-18 09:57:51 +02005897 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005898}
5899
5900/*
5901 * Put a string on the stack.
5902 */
5903static void
5904memtodest(const char *p, size_t len, int syntax, int quotes)
5905{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005906 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005907
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005908 if (!len)
5909 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005910
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005911 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
5912
5913 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005914 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005915 if (c) {
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01005916 if (quotes & QUOTES_ESC) {
5917 int n = SIT(c, syntax);
5918 if (n == CCTL
5919 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
5920 && n == CBACK
5921 )
5922 ) {
5923 USTPUTC(CTLESC, q);
5924 }
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02005925 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005926 } else if (!(quotes & QUOTES_KEEPNUL))
5927 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005928 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005929 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005930
5931 expdest = q;
5932}
5933
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005934static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005935strtodest(const char *p, int syntax, int quotes)
5936{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005937 size_t len = strlen(p);
5938 memtodest(p, len, syntax, quotes);
5939 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005940}
5941
5942/*
5943 * Record the fact that we have to scan this region of the
5944 * string for IFS characters.
5945 */
5946static void
5947recordregion(int start, int end, int nulonly)
5948{
5949 struct ifsregion *ifsp;
5950
5951 if (ifslastp == NULL) {
5952 ifsp = &ifsfirst;
5953 } else {
5954 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00005955 ifsp = ckzalloc(sizeof(*ifsp));
5956 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005957 ifslastp->next = ifsp;
5958 INT_ON;
5959 }
5960 ifslastp = ifsp;
5961 ifslastp->begoff = start;
5962 ifslastp->endoff = end;
5963 ifslastp->nulonly = nulonly;
5964}
5965
5966static void
5967removerecordregions(int endoff)
5968{
5969 if (ifslastp == NULL)
5970 return;
5971
5972 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005973 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005974 struct ifsregion *ifsp;
5975 INT_OFF;
5976 ifsp = ifsfirst.next->next;
5977 free(ifsfirst.next);
5978 ifsfirst.next = ifsp;
5979 INT_ON;
5980 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005981 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005982 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005983 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005984 ifslastp = &ifsfirst;
5985 ifsfirst.endoff = endoff;
5986 }
5987 return;
5988 }
5989
5990 ifslastp = &ifsfirst;
5991 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005992 ifslastp = ifslastp->next;
5993 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005994 struct ifsregion *ifsp;
5995 INT_OFF;
5996 ifsp = ifslastp->next->next;
5997 free(ifslastp->next);
5998 ifslastp->next = ifsp;
5999 INT_ON;
6000 }
6001 if (ifslastp->endoff > endoff)
6002 ifslastp->endoff = endoff;
6003}
6004
6005static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006006exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006007{
Denys Vlasenkocd716832009-11-28 22:14:02 +01006008 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006009 char *name;
6010 struct passwd *pw;
6011 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006012 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006013
6014 name = p + 1;
6015
6016 while ((c = *++p) != '\0') {
6017 switch (c) {
6018 case CTLESC:
6019 return startp;
6020 case CTLQUOTEMARK:
6021 return startp;
6022 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006023 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006024 goto done;
6025 break;
6026 case '/':
6027 case CTLENDVAR:
6028 goto done;
6029 }
6030 }
6031 done:
6032 *p = '\0';
6033 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02006034 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006035 } else {
6036 pw = getpwnam(name);
6037 if (pw == NULL)
6038 goto lose;
6039 home = pw->pw_dir;
6040 }
6041 if (!home || !*home)
6042 goto lose;
6043 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006044 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006045 return p;
6046 lose:
6047 *p = c;
6048 return startp;
6049}
6050
6051/*
6052 * Execute a command inside back quotes. If it's a builtin command, we
6053 * want to save its output in a block obtained from malloc. Otherwise
6054 * we fork off a subprocess and get the output of the command via a pipe.
6055 * Should be called with interrupts off.
6056 */
6057struct backcmd { /* result of evalbackcmd */
6058 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006059 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00006060 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006061 struct job *jp; /* job structure for command */
6062};
6063
6064/* These forward decls are needed to use "eval" code for backticks handling: */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006065#define EV_EXIT 01 /* exit after evaluating tree */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02006066static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006067
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02006068static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006069evalbackcmd(union node *n, struct backcmd *result)
6070{
Denys Vlasenko579ad102016-10-25 21:10:20 +02006071 int pip[2];
6072 struct job *jp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006073
6074 result->fd = -1;
6075 result->buf = NULL;
6076 result->nleft = 0;
6077 result->jp = NULL;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006078 if (n == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006079 goto out;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006080 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006081
Denys Vlasenko579ad102016-10-25 21:10:20 +02006082 if (pipe(pip) < 0)
6083 ash_msg_and_raise_error("pipe call failed");
6084 jp = makejob(/*n,*/ 1);
6085 if (forkshell(jp, n, FORK_NOJOB) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02006086 /* child */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006087 FORCE_INT_ON;
6088 close(pip[0]);
6089 if (pip[1] != 1) {
6090 /*close(1);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02006091 dup2_or_raise(pip[1], 1);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006092 close(pip[1]);
6093 }
Denys Vlasenko960ca382016-10-25 18:12:15 +02006094/* TODO: eflag clearing makes the following not abort:
6095 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6096 * which is what bash does (unless it is in POSIX mode).
6097 * dash deleted "eflag = 0" line in the commit
6098 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6099 * [EVAL] Don't clear eflag in evalbackcmd
6100 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6101 */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006102 eflag = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006103 ifsfree();
Denys Vlasenko579ad102016-10-25 21:10:20 +02006104 evaltree(n, EV_EXIT); /* actually evaltreenr... */
6105 /* NOTREACHED */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006106 }
Denys Vlasenko70392332016-10-27 02:31:55 +02006107 /* parent */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006108 close(pip[1]);
6109 result->fd = pip[0];
6110 result->jp = jp;
6111
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006112 out:
6113 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6114 result->fd, result->buf, result->nleft, result->jp));
6115}
6116
6117/*
6118 * Expand stuff in backwards quotes.
6119 */
6120static void
Ron Yorston549deab2015-05-18 09:57:51 +02006121expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006122{
6123 struct backcmd in;
6124 int i;
6125 char buf[128];
6126 char *p;
6127 char *dest;
6128 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02006129 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006130 struct stackmark smark;
6131
6132 INT_OFF;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02006133 startloc = expdest - (char *)stackblock();
6134 pushstackmark(&smark, startloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006135 evalbackcmd(cmd, &in);
6136 popstackmark(&smark);
6137
6138 p = in.buf;
6139 i = in.nleft;
6140 if (i == 0)
6141 goto read;
6142 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02006143 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006144 read:
6145 if (in.fd < 0)
6146 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01006147 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006148 TRACE(("expbackq: read returns %d\n", i));
6149 if (i <= 0)
6150 break;
6151 p = buf;
6152 }
6153
Denis Vlasenko60818682007-09-28 22:07:23 +00006154 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006155 if (in.fd >= 0) {
6156 close(in.fd);
6157 back_exitstatus = waitforjob(in.jp);
6158 }
6159 INT_ON;
6160
6161 /* Eat all trailing newlines */
6162 dest = expdest;
6163 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6164 STUNPUTC(dest);
6165 expdest = dest;
6166
Ron Yorston549deab2015-05-18 09:57:51 +02006167 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006168 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006169 TRACE(("evalbackq: size:%d:'%.*s'\n",
6170 (int)((dest - (char *)stackblock()) - startloc),
6171 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006172 stackblock() + startloc));
6173}
6174
Denys Vlasenko0b883582016-12-23 16:49:07 +01006175#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006176/*
6177 * Expand arithmetic expression. Backup to start of expression,
6178 * evaluate, place result in (backed up) result, adjust string position.
6179 */
6180static void
Ron Yorston549deab2015-05-18 09:57:51 +02006181expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006182{
6183 char *p, *start;
6184 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006185 int len;
6186
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006187 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006188
6189 /*
6190 * This routine is slightly over-complicated for
6191 * efficiency. Next we scan backwards looking for the
6192 * start of arithmetic.
6193 */
6194 start = stackblock();
6195 p = expdest - 1;
6196 *p = '\0';
6197 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006198 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006199 int esc;
6200
Denys Vlasenkocd716832009-11-28 22:14:02 +01006201 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006202 p--;
6203#if DEBUG
6204 if (p < start) {
6205 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6206 }
6207#endif
6208 }
6209
6210 esc = esclen(start, p);
6211 if (!(esc % 2)) {
6212 break;
6213 }
6214
6215 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006216 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006217
6218 begoff = p - start;
6219
6220 removerecordregions(begoff);
6221
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006222 expdest = p;
6223
Ron Yorston549deab2015-05-18 09:57:51 +02006224 if (flag & QUOTES_ESC)
6225 rmescapes(p + 1, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006226
Ron Yorston549deab2015-05-18 09:57:51 +02006227 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006228
Ron Yorston549deab2015-05-18 09:57:51 +02006229 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006230 recordregion(begoff, begoff + len, 0);
6231}
6232#endif
6233
6234/* argstr needs it */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006235static char *evalvar(char *p, int flags, struct strlist *var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006236
6237/*
6238 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6239 * characters to allow for further processing. Otherwise treat
6240 * $@ like $* since no splitting will be performed.
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006241 *
6242 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
6243 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
6244 * for correct expansion of "B=$A" word.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006245 */
6246static void
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006247argstr(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006248{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006249 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006250 '=',
6251 ':',
6252 CTLQUOTEMARK,
6253 CTLENDVAR,
6254 CTLESC,
6255 CTLVAR,
6256 CTLBACKQ,
Denys Vlasenko0b883582016-12-23 16:49:07 +01006257#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006258 CTLENDARI,
6259#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006260 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006261 };
6262 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006263 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006264 int inquotes;
6265 size_t length;
6266 int startloc;
6267
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006268 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006269 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006270 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006271 reject++;
6272 }
6273 inquotes = 0;
6274 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006275 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006276 char *q;
6277
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006278 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006279 tilde:
6280 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006281 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006282 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006283 }
6284 start:
6285 startloc = expdest - (char *)stackblock();
6286 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006287 unsigned char c;
6288
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006289 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006290 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006291 if (c) {
6292 if (!(c & 0x80)
Denys Vlasenko0b883582016-12-23 16:49:07 +01006293 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006294 ) {
6295 /* c == '=' || c == ':' || c == CTLENDARI */
6296 length++;
6297 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006298 }
6299 if (length > 0) {
6300 int newloc;
6301 expdest = stack_nputstr(p, length, expdest);
6302 newloc = expdest - (char *)stackblock();
6303 if (breakall && !inquotes && newloc > startloc) {
6304 recordregion(startloc, newloc, 0);
6305 }
6306 startloc = newloc;
6307 }
6308 p += length + 1;
6309 length = 0;
6310
6311 switch (c) {
6312 case '\0':
6313 goto breakloop;
6314 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006315 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006316 p--;
6317 continue;
6318 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006319 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006320 reject++;
6321 /* fall through */
6322 case ':':
6323 /*
6324 * sort of a hack - expand tildes in variable
6325 * assignments (after the first '=' and after ':'s).
6326 */
6327 if (*--p == '~') {
6328 goto tilde;
6329 }
6330 continue;
6331 }
6332
6333 switch (c) {
6334 case CTLENDVAR: /* ??? */
6335 goto breakloop;
6336 case CTLQUOTEMARK:
Ron Yorston549deab2015-05-18 09:57:51 +02006337 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006338 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006339 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6340 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006341 goto start;
6342 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006343 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006344 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006345 p--;
6346 length++;
6347 startloc++;
6348 }
6349 break;
6350 case CTLESC:
6351 startloc++;
6352 length++;
Ron Yorston549deab2015-05-18 09:57:51 +02006353
6354 /*
6355 * Quoted parameter expansion pattern: remove quote
6356 * unless inside inner quotes or we have a literal
6357 * backslash.
6358 */
6359 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6360 EXP_QPAT && *p != '\\')
6361 break;
6362
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006363 goto addquote;
6364 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006365 TRACE(("argstr: evalvar('%s')\n", p));
Ron Yorston549deab2015-05-18 09:57:51 +02006366 p = evalvar(p, flags | inquotes, var_str_list);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006367 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006368 goto start;
6369 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006370 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006371 argbackq = argbackq->next;
6372 goto start;
Denys Vlasenko0b883582016-12-23 16:49:07 +01006373#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006374 case CTLENDARI:
6375 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006376 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006377 goto start;
6378#endif
6379 }
6380 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006381 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006382}
6383
6384static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006385scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6386 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006387{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006388 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006389 char c;
6390
6391 loc = startp;
6392 loc2 = rmesc;
6393 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006394 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006395 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006396
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006397 c = *loc2;
6398 if (zero) {
6399 *loc2 = '\0';
6400 s = rmesc;
6401 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006402 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006403
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006404 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006405 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006406 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006407 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006408 loc++;
6409 loc++;
6410 loc2++;
6411 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006412 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006413}
6414
6415static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006416scanright(char *startp, char *rmesc, char *rmescend,
6417 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006418{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006419#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6420 int try2optimize = match_at_start;
6421#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006422 int esc = 0;
6423 char *loc;
6424 char *loc2;
6425
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006426 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6427 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6428 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6429 * Logic:
6430 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6431 * and on each iteration they go back two/one char until they reach the beginning.
6432 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6433 */
6434 /* TODO: document in what other circumstances we are called. */
6435
6436 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006437 int match;
6438 char c = *loc2;
6439 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006440 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006441 *loc2 = '\0';
6442 s = rmesc;
6443 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006444 match = pmatch(pattern, s);
6445 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006446 *loc2 = c;
6447 if (match)
6448 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006449#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6450 if (try2optimize) {
6451 /* Maybe we can optimize this:
6452 * if pattern ends with unescaped *, we can avoid checking
6453 * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6454 * it wont match truncated "raw_value_of_" strings too.
6455 */
6456 unsigned plen = strlen(pattern);
6457 /* Does it end with "*"? */
6458 if (plen != 0 && pattern[--plen] == '*') {
6459 /* "xxxx*" is not escaped */
6460 /* "xxx\*" is escaped */
6461 /* "xx\\*" is not escaped */
6462 /* "x\\\*" is escaped */
6463 int slashes = 0;
6464 while (plen != 0 && pattern[--plen] == '\\')
6465 slashes++;
6466 if (!(slashes & 1))
6467 break; /* ends with unescaped "*" */
6468 }
6469 try2optimize = 0;
6470 }
6471#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006472 loc--;
6473 if (quotes) {
6474 if (--esc < 0) {
6475 esc = esclen(startp, loc);
6476 }
6477 if (esc % 2) {
6478 esc--;
6479 loc--;
6480 }
6481 }
6482 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006483 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006484}
6485
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006486static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006487static void
6488varunset(const char *end, const char *var, const char *umsg, int varflags)
6489{
6490 const char *msg;
6491 const char *tail;
6492
6493 tail = nullstr;
6494 msg = "parameter not set";
6495 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006496 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006497 if (varflags & VSNUL)
6498 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006499 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006500 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006501 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006502 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006503 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006504}
6505
6506static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006507subevalvar(char *p, char *varname, int strloc, int subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006508 int startloc, int varflags, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006509{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006510 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006511 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006512 char *startp;
6513 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006514 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006515 char *str;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006516 IF_BASH_SUBSTR(int pos, len, orig_len;)
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006517 int amount, resetloc;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006518 IF_BASH_PATTERN_SUBST(int workloc;)
6519 IF_BASH_PATTERN_SUBST(char *repl = NULL;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006520 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006521 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006522
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006523 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6524 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006525
Ron Yorstoneb6b48b2015-05-18 09:51:35 +02006526 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
Ron Yorston549deab2015-05-18 09:57:51 +02006527 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6528 var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006529 STPUTC('\0', expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006530 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006531 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006532
6533 switch (subtype) {
6534 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006535 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006536 amount = startp - expdest;
6537 STADJUST(amount, expdest);
6538 return startp;
6539
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006540 case VSQUESTION:
6541 varunset(p, varname, startp, varflags);
6542 /* NOTREACHED */
6543
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006544#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006545 case VSSUBSTR:
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +02006546//TODO: support more general format ${v:EXPR:EXPR},
6547// where EXPR follows $(()) rules
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006548 loc = str = stackblock() + strloc;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006549 /* Read POS in ${var:POS:LEN} */
6550 pos = atoi(loc); /* number(loc) errors out on "1:4" */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006551 len = str - startp - 1;
6552
6553 /* *loc != '\0', guaranteed by parser */
6554 if (quotes) {
6555 char *ptr;
6556
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006557 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006558 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006559 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006560 len--;
6561 ptr++;
6562 }
6563 }
6564 }
6565 orig_len = len;
6566
6567 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006568 /* ${var::LEN} */
6569 len = number(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006570 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006571 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006572 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006573 while (*loc && *loc != ':') {
6574 /* TODO?
6575 * bash complains on: var=qwe; echo ${var:1a:123}
6576 if (!isdigit(*loc))
6577 ash_msg_and_raise_error(msg_illnum, str);
6578 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006579 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006580 }
6581 if (*loc++ == ':') {
6582 len = number(loc);
6583 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006584 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006585 if (pos < 0) {
6586 /* ${VAR:$((-n)):l} starts n chars from the end */
6587 pos = orig_len + pos;
6588 }
6589 if ((unsigned)pos >= orig_len) {
6590 /* apart from obvious ${VAR:999999:l},
6591 * covers ${VAR:$((-9999999)):l} - result is ""
6592 * (bash-compat)
6593 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006594 pos = 0;
6595 len = 0;
6596 }
6597 if (len > (orig_len - pos))
6598 len = orig_len - pos;
6599
6600 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006601 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006602 str++;
6603 }
6604 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006605 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006606 *loc++ = *str++;
6607 *loc++ = *str++;
6608 }
6609 *loc = '\0';
6610 amount = loc - expdest;
6611 STADJUST(amount, expdest);
6612 return loc;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006613#endif /* BASH_SUBSTR */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006614 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006615
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006616 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006617
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006618#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006619 /* We'll comeback here if we grow the stack while handling
6620 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6621 * stack will need rebasing, and we'll need to remove our work
6622 * areas each time
6623 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006624 restart:
6625#endif
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006626
6627 amount = expdest - ((char *)stackblock() + resetloc);
6628 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006629 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006630
6631 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006632 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006633 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006634 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006635 if (rmesc != startp) {
6636 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006637 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006638 }
6639 }
6640 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006641 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02006642 /*
6643 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6644 * The result is a_\_z_c (not a\_\_z_c)!
6645 *
6646 * The search pattern and replace string treat backslashes differently!
6647 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6648 * and string. It's only used on the first call.
6649 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006650 preglob(str, IF_BASH_PATTERN_SUBST(
Ron Yorston417622c2015-05-18 09:59:14 +02006651 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006652 RMESCAPE_SLASH : ) 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006653
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006654#if BASH_PATTERN_SUBST
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006655 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006656 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006657 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006658
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006659 if (!repl) {
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006660 repl = strchr(str, CTLESC);
6661 if (repl)
Ron Yorston417622c2015-05-18 09:59:14 +02006662 *repl++ = '\0';
6663 else
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006664 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006665 }
Ron Yorston417622c2015-05-18 09:59:14 +02006666 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006667
6668 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006669 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006670 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006671
6672 len = 0;
6673 idx = startp;
6674 end = str - 1;
6675 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006676 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006677 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006678 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006679 if (!loc) {
6680 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006681 char *restart_detect = stackblock();
6682 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006683 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006684 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006685 idx++;
6686 len++;
6687 STPUTC(*idx, expdest);
6688 }
6689 if (stackblock() != restart_detect)
6690 goto restart;
6691 idx++;
6692 len++;
6693 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006694 /* continue; - prone to quadratic behavior, smarter code: */
6695 if (idx >= end)
6696 break;
6697 if (str[0] == '*') {
6698 /* Pattern is "*foo". If "*foo" does not match "long_string",
6699 * it would never match "ong_string" etc, no point in trying.
6700 */
6701 goto skip_matching;
6702 }
6703 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006704 }
6705
6706 if (subtype == VSREPLACEALL) {
6707 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006708 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006709 idx++;
6710 idx++;
6711 rmesc++;
6712 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006713 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006714 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006715 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006716
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006717 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006718 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006719 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006720 if (quotes && *loc == '\\') {
6721 STPUTC(CTLESC, expdest);
6722 len++;
6723 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006724 STPUTC(*loc, expdest);
6725 if (stackblock() != restart_detect)
6726 goto restart;
6727 len++;
6728 }
6729
6730 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006731 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006732 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006733 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006734 STPUTC(*idx, expdest);
6735 if (stackblock() != restart_detect)
6736 goto restart;
6737 len++;
6738 idx++;
6739 }
6740 break;
6741 }
6742 }
6743
6744 /* We've put the replaced text into a buffer at workloc, now
6745 * move it to the right place and adjust the stack.
6746 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006747 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006748 startp = (char *)stackblock() + startloc;
6749 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006750 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006751 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006752 STADJUST(-amount, expdest);
6753 return startp;
6754 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006755#endif /* BASH_PATTERN_SUBST */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006756
6757 subtype -= VSTRIMRIGHT;
6758#if DEBUG
6759 if (subtype < 0 || subtype > 7)
6760 abort();
6761#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006762 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006763 zero = subtype >> 1;
6764 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6765 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6766
6767 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6768 if (loc) {
6769 if (zero) {
6770 memmove(startp, loc, str - loc);
6771 loc = startp + (str - loc) - 1;
6772 }
6773 *loc = '\0';
6774 amount = loc - expdest;
6775 STADJUST(amount, expdest);
6776 }
6777 return loc;
6778}
6779
6780/*
6781 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006782 * name parameter (examples):
6783 * ash -c 'echo $1' name:'1='
6784 * ash -c 'echo $qwe' name:'qwe='
6785 * ash -c 'echo $$' name:'$='
6786 * ash -c 'echo ${$}' name:'$='
6787 * ash -c 'echo ${$##q}' name:'$=q'
6788 * ash -c 'echo ${#$}' name:'$='
6789 * note: examples with bad shell syntax:
6790 * ash -c 'echo ${#$1}' name:'$=1'
6791 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006792 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02006793static NOINLINE ssize_t
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006794varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int *quotedp)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006795{
Mike Frysinger98c52642009-04-02 10:02:37 +00006796 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006797 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006798 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006799 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006800 int sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006801 int quoted = *quotedp;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006802 int subtype = varflags & VSTYPE;
6803 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6804 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006805 int syntax;
6806
6807 sep = (flags & EXP_FULL) << CHAR_BIT;
6808 syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006809
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006810 switch (*name) {
6811 case '$':
6812 num = rootpid;
6813 goto numvar;
6814 case '?':
6815 num = exitstatus;
6816 goto numvar;
6817 case '#':
6818 num = shellparam.nparam;
6819 goto numvar;
6820 case '!':
6821 num = backgndpid;
6822 if (num == 0)
6823 return -1;
6824 numvar:
6825 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006826 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006827 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00006828 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006829 for (i = NOPTS - 1; i >= 0; i--) {
6830 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00006831 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006832 len++;
6833 }
6834 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006835 check_1char_name:
6836#if 0
6837 /* handles cases similar to ${#$1} */
6838 if (name[2] != '\0')
6839 raise_error_syntax("bad substitution");
6840#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006841 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006842 case '@':
6843 if (quoted && sep)
6844 goto param;
6845 /* fall through */
6846 case '*': {
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006847 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006848 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006849
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006850 if (quoted)
6851 sep = 0;
6852 sep |= ifsset() ? ifsval()[0] : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006853 param:
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006854 sepc = sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006855 *quotedp = !sepc;
6856 ap = shellparam.p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006857 if (!ap)
6858 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006859 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006860 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006861
6862 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006863 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006864 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006865 }
6866 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006867 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006868 } /* case '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006869 case '0':
6870 case '1':
6871 case '2':
6872 case '3':
6873 case '4':
6874 case '5':
6875 case '6':
6876 case '7':
6877 case '8':
6878 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02006879 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006880 if (num < 0 || num > shellparam.nparam)
6881 return -1;
6882 p = num ? shellparam.p[num - 1] : arg0;
6883 goto value;
6884 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006885 /* NB: name has form "VAR=..." */
6886
6887 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6888 * which should be considered before we check variables. */
6889 if (var_str_list) {
6890 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6891 p = NULL;
6892 do {
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00006893 char *str, *eq;
6894 str = var_str_list->text;
6895 eq = strchr(str, '=');
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006896 if (!eq) /* stop at first non-assignment */
6897 break;
6898 eq++;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00006899 if (name_len == (unsigned)(eq - str)
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006900 && strncmp(str, name, name_len) == 0
6901 ) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006902 p = eq;
6903 /* goto value; - WRONG! */
6904 /* think "A=1 A=2 B=$A" */
6905 }
6906 var_str_list = var_str_list->next;
6907 } while (var_str_list);
6908 if (p)
6909 goto value;
6910 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006911 p = lookupvar(name);
6912 value:
6913 if (!p)
6914 return -1;
6915
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006916 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006917#if ENABLE_UNICODE_SUPPORT
6918 if (subtype == VSLENGTH && len > 0) {
6919 reinit_unicode_for_ash();
6920 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00006921 STADJUST(-len, expdest);
6922 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006923 len = unicode_strlen(p);
6924 }
6925 }
6926#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006927 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006928 }
6929
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006930 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006931 STADJUST(-len, expdest);
6932 return len;
6933}
6934
6935/*
6936 * Expand a variable, and return a pointer to the next character in the
6937 * input string.
6938 */
6939static char *
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006940evalvar(char *p, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006941{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006942 char varflags;
6943 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02006944 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006945 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006946 char *var;
6947 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006948 int startloc;
6949 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006950
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006951 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006952 subtype = varflags & VSTYPE;
Denys Vlasenko88e15702016-10-26 01:55:56 +02006953
6954 if (!subtype)
6955 raise_error_syntax("bad substitution");
6956
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006957 quoted = flag & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006958 var = p;
6959 easy = (!quoted || (*var == '@' && shellparam.nparam));
6960 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02006961 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006962
6963 again:
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006964 varlen = varvalue(var, varflags, flag, var_str_list, &quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006965 if (varflags & VSNUL)
6966 varlen--;
6967
6968 if (subtype == VSPLUS) {
6969 varlen = -1 - varlen;
6970 goto vsplus;
6971 }
6972
6973 if (subtype == VSMINUS) {
6974 vsplus:
6975 if (varlen < 0) {
6976 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006977 p,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006978 flag | EXP_TILDE | EXP_WORD,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006979 var_str_list
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006980 );
6981 goto end;
6982 }
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006983 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006984 }
6985
6986 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006987 if (varlen >= 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006988 goto record;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006989
6990 subevalvar(p, var, 0, subtype, startloc, varflags,
6991 flag & ~QUOTES_ESC, var_str_list);
6992 varflags &= ~VSNUL;
6993 /*
6994 * Remove any recorded regions beyond
6995 * start of variable
6996 */
6997 removerecordregions(startloc);
6998 goto again;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006999 }
7000
7001 if (varlen < 0 && uflag)
7002 varunset(p, var, 0, 0);
7003
7004 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007005 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007006 goto record;
7007 }
7008
7009 if (subtype == VSNORMAL) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007010 record:
7011 if (!easy)
7012 goto end;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007013 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007014 goto end;
7015 }
7016
7017#if DEBUG
7018 switch (subtype) {
7019 case VSTRIMLEFT:
7020 case VSTRIMLEFTMAX:
7021 case VSTRIMRIGHT:
7022 case VSTRIMRIGHTMAX:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007023#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007024 case VSSUBSTR:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007025#endif
7026#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007027 case VSREPLACE:
7028 case VSREPLACEALL:
7029#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007030 break;
7031 default:
7032 abort();
7033 }
7034#endif
7035
7036 if (varlen >= 0) {
7037 /*
7038 * Terminate the string and start recording the pattern
7039 * right after it
7040 */
7041 STPUTC('\0', expdest);
7042 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007043 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007044 startloc, varflags, flag, var_str_list)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007045 int amount = expdest - (
7046 (char *)stackblock() + patloc - 1
7047 );
7048 STADJUST(-amount, expdest);
7049 }
7050 /* Remove any recorded regions beyond start of variable */
7051 removerecordregions(startloc);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007052 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007053 }
7054
7055 end:
7056 if (subtype != VSNORMAL) { /* skip to end of alternative */
7057 int nesting = 1;
7058 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007059 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007060 if (c == CTLESC)
7061 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02007062 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007063 if (varlen >= 0)
7064 argbackq = argbackq->next;
7065 } else if (c == CTLVAR) {
7066 if ((*p++ & VSTYPE) != VSNORMAL)
7067 nesting++;
7068 } else if (c == CTLENDVAR) {
7069 if (--nesting == 0)
7070 break;
7071 }
7072 }
7073 }
7074 return p;
7075}
7076
7077/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007078 * Add a file name to the list.
7079 */
7080static void
7081addfname(const char *name)
7082{
7083 struct strlist *sp;
7084
Denis Vlasenko597906c2008-02-20 16:38:54 +00007085 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02007086 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007087 *exparg.lastp = sp;
7088 exparg.lastp = &sp->next;
7089}
7090
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007091/* If we want to use glob() from libc... */
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007092#if !ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007093
7094/* Add the result of glob() to the list */
7095static void
7096addglob(const glob_t *pglob)
7097{
7098 char **p = pglob->gl_pathv;
7099
7100 do {
7101 addfname(*p);
7102 } while (*++p);
7103}
7104static void
7105expandmeta(struct strlist *str /*, int flag*/)
7106{
7107 /* TODO - EXP_REDIR */
7108
7109 while (str) {
7110 char *p;
7111 glob_t pglob;
7112 int i;
7113
7114 if (fflag)
7115 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007116
7117 /* Avoid glob() (and thus, stat() et al) for words like "echo" */
7118 p = str->text;
7119 while (*p) {
7120 if (*p == '*')
7121 goto need_glob;
7122 if (*p == '?')
7123 goto need_glob;
7124 if (*p == '[')
7125 goto need_glob;
7126 p++;
7127 }
7128 goto nometa;
7129
7130 need_glob:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007131 INT_OFF;
7132 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007133// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7134// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7135//
7136// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7137// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7138// Which means you need to unescape the string, right? Not so fast:
7139// if there _is_ a file named "file\?" (with backslash), it is returned
7140// as "file\?" too (whichever pattern you used to find it, say, "file*").
7141// You DONT KNOW by looking at the result whether you need to unescape it.
7142//
7143// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7144// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7145// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7146// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7147// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7148// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7149 i = glob(p, 0, NULL, &pglob);
7150 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007151 if (p != str->text)
7152 free(p);
7153 switch (i) {
7154 case 0:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007155#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007156 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7157 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7158 goto nometa2;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007159#endif
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007160 addglob(&pglob);
7161 globfree(&pglob);
7162 INT_ON;
7163 break;
7164 case GLOB_NOMATCH:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007165 //nometa2:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007166 globfree(&pglob);
7167 INT_ON;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007168 nometa:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007169 *exparg.lastp = str;
7170 rmescapes(str->text, 0);
7171 exparg.lastp = &str->next;
7172 break;
7173 default: /* GLOB_NOSPACE */
7174 globfree(&pglob);
7175 INT_ON;
7176 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7177 }
7178 str = str->next;
7179 }
7180}
7181
7182#else
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007183/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007184
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007185/*
7186 * Do metacharacter (i.e. *, ?, [...]) expansion.
7187 */
7188static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007189expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007190{
7191 char *p;
7192 const char *cp;
7193 char *start;
7194 char *endname;
7195 int metaflag;
7196 struct stat statb;
7197 DIR *dirp;
7198 struct dirent *dp;
7199 int atend;
7200 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007201 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007202
7203 metaflag = 0;
7204 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007205 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007206 if (*p == '*' || *p == '?')
7207 metaflag = 1;
7208 else if (*p == '[') {
7209 char *q = p + 1;
7210 if (*q == '!')
7211 q++;
7212 for (;;) {
7213 if (*q == '\\')
7214 q++;
7215 if (*q == '/' || *q == '\0')
7216 break;
7217 if (*++q == ']') {
7218 metaflag = 1;
7219 break;
7220 }
7221 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007222 } else {
7223 if (*p == '\\')
7224 esc++;
7225 if (p[esc] == '/') {
7226 if (metaflag)
7227 break;
7228 start = p + esc + 1;
7229 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007230 }
7231 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007232 if (metaflag == 0) { /* we've reached the end of the file name */
7233 if (enddir != expdir)
7234 metaflag++;
7235 p = name;
7236 do {
7237 if (*p == '\\')
7238 p++;
7239 *enddir++ = *p;
7240 } while (*p++);
7241 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7242 addfname(expdir);
7243 return;
7244 }
7245 endname = p;
7246 if (name < start) {
7247 p = name;
7248 do {
7249 if (*p == '\\')
7250 p++;
7251 *enddir++ = *p++;
7252 } while (p < start);
7253 }
7254 if (enddir == expdir) {
7255 cp = ".";
7256 } else if (enddir == expdir + 1 && *expdir == '/') {
7257 cp = "/";
7258 } else {
7259 cp = expdir;
7260 enddir[-1] = '\0';
7261 }
7262 dirp = opendir(cp);
7263 if (dirp == NULL)
7264 return;
7265 if (enddir != expdir)
7266 enddir[-1] = '/';
7267 if (*endname == 0) {
7268 atend = 1;
7269 } else {
7270 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007271 *endname = '\0';
7272 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007273 }
7274 matchdot = 0;
7275 p = start;
7276 if (*p == '\\')
7277 p++;
7278 if (*p == '.')
7279 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007280 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007281 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007282 continue;
7283 if (pmatch(start, dp->d_name)) {
7284 if (atend) {
7285 strcpy(enddir, dp->d_name);
7286 addfname(expdir);
7287 } else {
7288 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7289 continue;
7290 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007291 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007292 }
7293 }
7294 }
7295 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007296 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007297 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007298}
7299
7300static struct strlist *
7301msort(struct strlist *list, int len)
7302{
7303 struct strlist *p, *q = NULL;
7304 struct strlist **lpp;
7305 int half;
7306 int n;
7307
7308 if (len <= 1)
7309 return list;
7310 half = len >> 1;
7311 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007312 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007313 q = p;
7314 p = p->next;
7315 }
7316 q->next = NULL; /* terminate first half of list */
7317 q = msort(list, half); /* sort first half of list */
7318 p = msort(p, len - half); /* sort second half */
7319 lpp = &list;
7320 for (;;) {
7321#if ENABLE_LOCALE_SUPPORT
7322 if (strcoll(p->text, q->text) < 0)
7323#else
7324 if (strcmp(p->text, q->text) < 0)
7325#endif
7326 {
7327 *lpp = p;
7328 lpp = &p->next;
7329 p = *lpp;
7330 if (p == NULL) {
7331 *lpp = q;
7332 break;
7333 }
7334 } else {
7335 *lpp = q;
7336 lpp = &q->next;
7337 q = *lpp;
7338 if (q == NULL) {
7339 *lpp = p;
7340 break;
7341 }
7342 }
7343 }
7344 return list;
7345}
7346
7347/*
7348 * Sort the results of file name expansion. It calculates the number of
7349 * strings to sort and then calls msort (short for merge sort) to do the
7350 * work.
7351 */
7352static struct strlist *
7353expsort(struct strlist *str)
7354{
7355 int len;
7356 struct strlist *sp;
7357
7358 len = 0;
7359 for (sp = str; sp; sp = sp->next)
7360 len++;
7361 return msort(str, len);
7362}
7363
7364static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007365expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007366{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00007367 static const char metachars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007368 '*', '?', '[', 0
7369 };
7370 /* TODO - EXP_REDIR */
7371
7372 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007373 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007374 struct strlist **savelastp;
7375 struct strlist *sp;
7376 char *p;
7377
7378 if (fflag)
7379 goto nometa;
7380 if (!strpbrk(str->text, metachars))
7381 goto nometa;
7382 savelastp = exparg.lastp;
7383
7384 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007385 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007386 {
7387 int i = strlen(str->text);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007388//BUGGY estimation of how long expanded name can be
7389 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007390 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007391 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007392 free(expdir);
7393 if (p != str->text)
7394 free(p);
7395 INT_ON;
7396 if (exparg.lastp == savelastp) {
7397 /*
7398 * no matches
7399 */
7400 nometa:
7401 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007402 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007403 exparg.lastp = &str->next;
7404 } else {
7405 *exparg.lastp = NULL;
7406 *savelastp = sp = expsort(*savelastp);
7407 while (sp->next != NULL)
7408 sp = sp->next;
7409 exparg.lastp = &sp->next;
7410 }
7411 str = str->next;
7412 }
7413}
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007414#endif /* ENABLE_ASH_INTERNAL_GLOB */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007415
7416/*
7417 * Perform variable substitution and command substitution on an argument,
7418 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7419 * perform splitting and file name expansion. When arglist is NULL, perform
7420 * here document expansion.
7421 */
7422static void
7423expandarg(union node *arg, struct arglist *arglist, int flag)
7424{
7425 struct strlist *sp;
7426 char *p;
7427
7428 argbackq = arg->narg.backquote;
7429 STARTSTACKSTR(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007430 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007431 argstr(arg->narg.text, flag,
7432 /* var_str_list: */ arglist ? arglist->list : NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007433 p = _STPUTC('\0', expdest);
7434 expdest = p - 1;
7435 if (arglist == NULL) {
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007436 /* here document expanded */
7437 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007438 }
7439 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007440 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007441 exparg.lastp = &exparg.list;
7442 /*
7443 * TODO - EXP_REDIR
7444 */
7445 if (flag & EXP_FULL) {
7446 ifsbreakup(p, &exparg);
7447 *exparg.lastp = NULL;
7448 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007449 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007450 } else {
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007451 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007452 rmescapes(p, 0);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007453 TRACE(("expandarg: rmescapes:'%s'\n", p));
7454 }
Denis Vlasenko597906c2008-02-20 16:38:54 +00007455 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007456 sp->text = p;
7457 *exparg.lastp = sp;
7458 exparg.lastp = &sp->next;
7459 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007460 *exparg.lastp = NULL;
7461 if (exparg.list) {
7462 *arglist->lastp = exparg.list;
7463 arglist->lastp = exparg.lastp;
7464 }
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007465
7466 out:
7467 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007468}
7469
7470/*
7471 * Expand shell variables and backquotes inside a here document.
7472 */
7473static void
7474expandhere(union node *arg, int fd)
7475{
Ron Yorston549deab2015-05-18 09:57:51 +02007476 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007477 full_write(fd, stackblock(), expdest - (char *)stackblock());
7478}
7479
7480/*
7481 * Returns true if the pattern matches the string.
7482 */
7483static int
7484patmatch(char *pattern, const char *string)
7485{
Ron Yorston549deab2015-05-18 09:57:51 +02007486 return pmatch(preglob(pattern, 0), string);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007487}
7488
7489/*
7490 * See if a pattern matches in a case statement.
7491 */
7492static int
7493casematch(union node *pattern, char *val)
7494{
7495 struct stackmark smark;
7496 int result;
7497
7498 setstackmark(&smark);
7499 argbackq = pattern->narg.backquote;
7500 STARTSTACKSTR(expdest);
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007501 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7502 /* var_str_list: */ NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007503 STACKSTRNUL(expdest);
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007504 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007505 result = patmatch(stackblock(), val);
7506 popstackmark(&smark);
7507 return result;
7508}
7509
7510
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007511/* ============ find_command */
7512
7513struct builtincmd {
7514 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007515 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007516 /* unsigned flags; */
7517};
7518#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007519/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007520 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007521#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007522#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007523
7524struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007525 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007526 union param {
7527 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007528 /* index >= 0 for commands without path (slashes) */
7529 /* (TODO: what exactly does the value mean? PATH position?) */
7530 /* index == -1 for commands with slashes */
7531 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007532 const struct builtincmd *cmd;
7533 struct funcnode *func;
7534 } u;
7535};
7536/* values of cmdtype */
7537#define CMDUNKNOWN -1 /* no entry in table for command */
7538#define CMDNORMAL 0 /* command is an executable program */
7539#define CMDFUNCTION 1 /* command is a shell function */
7540#define CMDBUILTIN 2 /* command is a shell builtin */
7541
7542/* action to find_command() */
7543#define DO_ERR 0x01 /* prints errors */
7544#define DO_ABS 0x02 /* checks absolute paths */
7545#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7546#define DO_ALTPATH 0x08 /* using alternate path */
7547#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7548
7549static void find_command(char *, struct cmdentry *, int, const char *);
7550
7551
7552/* ============ Hashing commands */
7553
7554/*
7555 * When commands are first encountered, they are entered in a hash table.
7556 * This ensures that a full path search will not have to be done for them
7557 * on each invocation.
7558 *
7559 * We should investigate converting to a linear search, even though that
7560 * would make the command name "hash" a misnomer.
7561 */
7562
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007563struct tblentry {
7564 struct tblentry *next; /* next entry in hash chain */
7565 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007566 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007567 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007568 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007569};
7570
Denis Vlasenko01631112007-12-16 17:20:38 +00007571static struct tblentry **cmdtable;
7572#define INIT_G_cmdtable() do { \
7573 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7574} while (0)
7575
7576static int builtinloc = -1; /* index in path of %builtin, or -1 */
7577
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007578
7579static void
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007580tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007581{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007582#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007583 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007584 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007585 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007586 while (*envp)
7587 putenv(*envp++);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007588 run_applet_no_and_exit(applet_no, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007589 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007590 /* re-exec ourselves with the new arguments */
7591 execve(bb_busybox_exec_path, argv, envp);
7592 /* If they called chroot or otherwise made the binary no longer
7593 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007594 }
7595#endif
7596
7597 repeat:
7598#ifdef SYSV
7599 do {
7600 execve(cmd, argv, envp);
7601 } while (errno == EINTR);
7602#else
7603 execve(cmd, argv, envp);
7604#endif
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007605 if (cmd != (char*) bb_busybox_exec_path && errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007606 /* Run "cmd" as a shell script:
7607 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7608 * "If the execve() function fails with ENOEXEC, the shell
7609 * shall execute a command equivalent to having a shell invoked
7610 * with the command name as its first operand,
7611 * with any remaining arguments passed to the new shell"
7612 *
7613 * That is, do not use $SHELL, user's shell, or /bin/sh;
7614 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007615 *
7616 * Note that bash reads ~80 chars of the file, and if it sees
7617 * a zero byte before it sees newline, it doesn't try to
7618 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007619 * message and exit code 126. For one, this prevents attempts
7620 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007621 */
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007622 argv[0] = cmd;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007623 cmd = (char*) bb_busybox_exec_path;
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007624 /* NB: this is only possible because all callers of shellexec()
7625 * ensure that the argv[-1] slot exists!
7626 */
7627 argv--;
7628 argv[0] = (char*) "ash";
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007629 goto repeat;
7630 }
7631}
7632
7633/*
7634 * Exec a program. Never returns. If you change this routine, you may
7635 * have to change the find_command routine as well.
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007636 * argv[-1] must exist and be writable! See tryexec() for why.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007637 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007638static void shellexec(char **, const char *, int) NORETURN;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007639static void
7640shellexec(char **argv, const char *path, int idx)
7641{
7642 char *cmdname;
7643 int e;
7644 char **envp;
7645 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007646 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007647
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007648 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007649 if (strchr(argv[0], '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007650#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007651 || (applet_no = find_applet_by_name(argv[0])) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007652#endif
7653 ) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007654 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007655 if (applet_no >= 0) {
7656 /* We tried execing ourself, but it didn't work.
7657 * Maybe /proc/self/exe doesn't exist?
7658 * Try $PATH search.
7659 */
7660 goto try_PATH;
7661 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007662 e = errno;
7663 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007664 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007665 e = ENOENT;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007666 while ((cmdname = path_advance(&path, argv[0])) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007667 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007668 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007669 if (errno != ENOENT && errno != ENOTDIR)
7670 e = errno;
7671 }
7672 stunalloc(cmdname);
7673 }
7674 }
7675
7676 /* Map to POSIX errors */
7677 switch (e) {
7678 case EACCES:
7679 exerrno = 126;
7680 break;
7681 case ENOENT:
7682 exerrno = 127;
7683 break;
7684 default:
7685 exerrno = 2;
7686 break;
7687 }
7688 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007689 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7690 argv[0], e, suppress_int));
Denys Vlasenko061a0902016-10-25 17:24:25 +02007691 ash_msg_and_raise(EXEXIT, "%s: %s", argv[0], errmsg(e, "not found"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007692 /* NOTREACHED */
7693}
7694
7695static void
7696printentry(struct tblentry *cmdp)
7697{
7698 int idx;
7699 const char *path;
7700 char *name;
7701
7702 idx = cmdp->param.index;
7703 path = pathval();
7704 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007705 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007706 stunalloc(name);
7707 } while (--idx >= 0);
7708 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7709}
7710
7711/*
7712 * Clear out command entries. The argument specifies the first entry in
7713 * PATH which has changed.
7714 */
7715static void
7716clearcmdentry(int firstchange)
7717{
7718 struct tblentry **tblp;
7719 struct tblentry **pp;
7720 struct tblentry *cmdp;
7721
7722 INT_OFF;
7723 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7724 pp = tblp;
7725 while ((cmdp = *pp) != NULL) {
7726 if ((cmdp->cmdtype == CMDNORMAL &&
7727 cmdp->param.index >= firstchange)
7728 || (cmdp->cmdtype == CMDBUILTIN &&
7729 builtinloc >= firstchange)
7730 ) {
7731 *pp = cmdp->next;
7732 free(cmdp);
7733 } else {
7734 pp = &cmdp->next;
7735 }
7736 }
7737 }
7738 INT_ON;
7739}
7740
7741/*
7742 * Locate a command in the command hash table. If "add" is nonzero,
7743 * add the command to the table if it is not already present. The
7744 * variable "lastcmdentry" is set to point to the address of the link
7745 * pointing to the entry, so that delete_cmd_entry can delete the
7746 * entry.
7747 *
7748 * Interrupts must be off if called with add != 0.
7749 */
7750static struct tblentry **lastcmdentry;
7751
7752static struct tblentry *
7753cmdlookup(const char *name, int add)
7754{
7755 unsigned int hashval;
7756 const char *p;
7757 struct tblentry *cmdp;
7758 struct tblentry **pp;
7759
7760 p = name;
7761 hashval = (unsigned char)*p << 4;
7762 while (*p)
7763 hashval += (unsigned char)*p++;
7764 hashval &= 0x7FFF;
7765 pp = &cmdtable[hashval % CMDTABLESIZE];
7766 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7767 if (strcmp(cmdp->cmdname, name) == 0)
7768 break;
7769 pp = &cmdp->next;
7770 }
7771 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007772 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7773 + strlen(name)
7774 /* + 1 - already done because
7775 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007776 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007777 cmdp->cmdtype = CMDUNKNOWN;
7778 strcpy(cmdp->cmdname, name);
7779 }
7780 lastcmdentry = pp;
7781 return cmdp;
7782}
7783
7784/*
7785 * Delete the command entry returned on the last lookup.
7786 */
7787static void
7788delete_cmd_entry(void)
7789{
7790 struct tblentry *cmdp;
7791
7792 INT_OFF;
7793 cmdp = *lastcmdentry;
7794 *lastcmdentry = cmdp->next;
7795 if (cmdp->cmdtype == CMDFUNCTION)
7796 freefunc(cmdp->param.func);
7797 free(cmdp);
7798 INT_ON;
7799}
7800
7801/*
7802 * Add a new command entry, replacing any existing command entry for
7803 * the same name - except special builtins.
7804 */
7805static void
7806addcmdentry(char *name, struct cmdentry *entry)
7807{
7808 struct tblentry *cmdp;
7809
7810 cmdp = cmdlookup(name, 1);
7811 if (cmdp->cmdtype == CMDFUNCTION) {
7812 freefunc(cmdp->param.func);
7813 }
7814 cmdp->cmdtype = entry->cmdtype;
7815 cmdp->param = entry->u;
7816 cmdp->rehash = 0;
7817}
7818
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007819static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007820hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007821{
7822 struct tblentry **pp;
7823 struct tblentry *cmdp;
7824 int c;
7825 struct cmdentry entry;
7826 char *name;
7827
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007828 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007829 clearcmdentry(0);
7830 return 0;
7831 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007832
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007833 if (*argptr == NULL) {
7834 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7835 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7836 if (cmdp->cmdtype == CMDNORMAL)
7837 printentry(cmdp);
7838 }
7839 }
7840 return 0;
7841 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007842
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007843 c = 0;
7844 while ((name = *argptr) != NULL) {
7845 cmdp = cmdlookup(name, 0);
7846 if (cmdp != NULL
7847 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007848 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7849 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007850 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007851 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007852 find_command(name, &entry, DO_ERR, pathval());
7853 if (entry.cmdtype == CMDUNKNOWN)
7854 c = 1;
7855 argptr++;
7856 }
7857 return c;
7858}
7859
7860/*
7861 * Called when a cd is done. Marks all commands so the next time they
7862 * are executed they will be rehashed.
7863 */
7864static void
7865hashcd(void)
7866{
7867 struct tblentry **pp;
7868 struct tblentry *cmdp;
7869
7870 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7871 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007872 if (cmdp->cmdtype == CMDNORMAL
7873 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02007874 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007875 && builtinloc > 0)
7876 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007877 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007878 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007879 }
7880 }
7881}
7882
7883/*
7884 * Fix command hash table when PATH changed.
7885 * Called before PATH is changed. The argument is the new value of PATH;
7886 * pathval() still returns the old value at this point.
7887 * Called with interrupts off.
7888 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007889static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007890changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007891{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007892 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007893 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007894 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007895 int idx_bltin;
7896
7897 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007898 firstchange = 9999; /* assume no change */
7899 idx = 0;
7900 idx_bltin = -1;
7901 for (;;) {
7902 if (*old != *new) {
7903 firstchange = idx;
7904 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007905 || (*old == ':' && *new == '\0')
7906 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007907 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007908 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007909 old = new; /* ignore subsequent differences */
7910 }
7911 if (*new == '\0')
7912 break;
7913 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7914 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007915 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007916 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007917 new++;
7918 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007919 }
7920 if (builtinloc < 0 && idx_bltin >= 0)
7921 builtinloc = idx_bltin; /* zap builtins */
7922 if (builtinloc >= 0 && idx_bltin < 0)
7923 firstchange = 0;
7924 clearcmdentry(firstchange);
7925 builtinloc = idx_bltin;
7926}
Ron Yorston95ebcf72015-11-03 09:42:23 +00007927enum {
7928 TEOF,
7929 TNL,
7930 TREDIR,
7931 TWORD,
7932 TSEMI,
7933 TBACKGND,
7934 TAND,
7935 TOR,
7936 TPIPE,
7937 TLP,
7938 TRP,
7939 TENDCASE,
7940 TENDBQUOTE,
7941 TNOT,
7942 TCASE,
7943 TDO,
7944 TDONE,
7945 TELIF,
7946 TELSE,
7947 TESAC,
7948 TFI,
7949 TFOR,
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007950#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +00007951 TFUNCTION,
7952#endif
7953 TIF,
7954 TIN,
7955 TTHEN,
7956 TUNTIL,
7957 TWHILE,
7958 TBEGIN,
7959 TEND
7960};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007961typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007962
Denys Vlasenko888527c2016-10-02 16:54:17 +02007963/* Nth bit indicates if token marks the end of a list */
7964enum {
7965 tokendlist = 0
7966 /* 0 */ | (1u << TEOF)
7967 /* 1 */ | (0u << TNL)
7968 /* 2 */ | (0u << TREDIR)
7969 /* 3 */ | (0u << TWORD)
7970 /* 4 */ | (0u << TSEMI)
7971 /* 5 */ | (0u << TBACKGND)
7972 /* 6 */ | (0u << TAND)
7973 /* 7 */ | (0u << TOR)
7974 /* 8 */ | (0u << TPIPE)
7975 /* 9 */ | (0u << TLP)
7976 /* 10 */ | (1u << TRP)
7977 /* 11 */ | (1u << TENDCASE)
7978 /* 12 */ | (1u << TENDBQUOTE)
7979 /* 13 */ | (0u << TNOT)
7980 /* 14 */ | (0u << TCASE)
7981 /* 15 */ | (1u << TDO)
7982 /* 16 */ | (1u << TDONE)
7983 /* 17 */ | (1u << TELIF)
7984 /* 18 */ | (1u << TELSE)
7985 /* 19 */ | (1u << TESAC)
7986 /* 20 */ | (1u << TFI)
7987 /* 21 */ | (0u << TFOR)
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007988#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02007989 /* 22 */ | (0u << TFUNCTION)
Denys Vlasenko80729a42016-10-02 22:33:15 +02007990#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02007991 /* 23 */ | (0u << TIF)
7992 /* 24 */ | (0u << TIN)
7993 /* 25 */ | (1u << TTHEN)
7994 /* 26 */ | (0u << TUNTIL)
7995 /* 27 */ | (0u << TWHILE)
7996 /* 28 */ | (0u << TBEGIN)
7997 /* 29 */ | (1u << TEND)
7998 , /* thus far 29 bits used */
7999};
8000
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008001static const char *const tokname_array[] = {
Denys Vlasenko888527c2016-10-02 16:54:17 +02008002 "end of file",
8003 "newline",
8004 "redirection",
8005 "word",
8006 ";",
8007 "&",
8008 "&&",
8009 "||",
8010 "|",
8011 "(",
8012 ")",
8013 ";;",
8014 "`",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008015#define KWDOFFSET 13
8016 /* the following are keywords */
Denys Vlasenko888527c2016-10-02 16:54:17 +02008017 "!",
8018 "case",
8019 "do",
8020 "done",
8021 "elif",
8022 "else",
8023 "esac",
8024 "fi",
8025 "for",
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008026#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008027 "function",
Ron Yorston95ebcf72015-11-03 09:42:23 +00008028#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008029 "if",
8030 "in",
8031 "then",
8032 "until",
8033 "while",
8034 "{",
8035 "}",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008036};
8037
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008038/* Wrapper around strcmp for qsort/bsearch/... */
8039static int
8040pstrcmp(const void *a, const void *b)
8041{
Denys Vlasenko888527c2016-10-02 16:54:17 +02008042 return strcmp((char*)a, *(char**)b);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008043}
8044
8045static const char *const *
8046findkwd(const char *s)
8047{
8048 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00008049 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8050 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008051}
8052
8053/*
8054 * Locate and print what a word is...
8055 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008056static int
Ron Yorston3f221112015-08-03 13:47:33 +01008057describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008058{
8059 struct cmdentry entry;
8060 struct tblentry *cmdp;
8061#if ENABLE_ASH_ALIAS
8062 const struct alias *ap;
8063#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008064
8065 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008066
8067 if (describe_command_verbose) {
8068 out1str(command);
8069 }
8070
8071 /* First look at the keywords */
8072 if (findkwd(command)) {
8073 out1str(describe_command_verbose ? " is a shell keyword" : command);
8074 goto out;
8075 }
8076
8077#if ENABLE_ASH_ALIAS
8078 /* Then look at the aliases */
8079 ap = lookupalias(command, 0);
8080 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008081 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008082 out1str("alias ");
8083 printalias(ap);
8084 return 0;
8085 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00008086 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008087 goto out;
8088 }
8089#endif
8090 /* Then check if it is a tracked alias */
8091 cmdp = cmdlookup(command, 0);
8092 if (cmdp != NULL) {
8093 entry.cmdtype = cmdp->cmdtype;
8094 entry.u = cmdp->param;
8095 } else {
8096 /* Finally use brute force */
8097 find_command(command, &entry, DO_ABS, path);
8098 }
8099
8100 switch (entry.cmdtype) {
8101 case CMDNORMAL: {
8102 int j = entry.u.index;
8103 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008104 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008105 p = command;
8106 } else {
8107 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008108 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008109 stunalloc(p);
8110 } while (--j >= 0);
8111 }
8112 if (describe_command_verbose) {
8113 out1fmt(" is%s %s",
8114 (cmdp ? " a tracked alias for" : nullstr), p
8115 );
8116 } else {
8117 out1str(p);
8118 }
8119 break;
8120 }
8121
8122 case CMDFUNCTION:
8123 if (describe_command_verbose) {
8124 out1str(" is a shell function");
8125 } else {
8126 out1str(command);
8127 }
8128 break;
8129
8130 case CMDBUILTIN:
8131 if (describe_command_verbose) {
8132 out1fmt(" is a %sshell builtin",
8133 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8134 "special " : nullstr
8135 );
8136 } else {
8137 out1str(command);
8138 }
8139 break;
8140
8141 default:
8142 if (describe_command_verbose) {
8143 out1str(": not found\n");
8144 }
8145 return 127;
8146 }
8147 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008148 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008149 return 0;
8150}
8151
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008152static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008153typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008154{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008155 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008156 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008157 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008158
Denis Vlasenko46846e22007-05-20 13:08:31 +00008159 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008160 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008161 i++;
8162 verbose = 0;
8163 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008164 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008165 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008166 }
8167 return err;
8168}
8169
8170#if ENABLE_ASH_CMDCMD
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008171/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8172static char **
8173parse_command_args(char **argv, const char **path)
8174{
8175 char *cp, c;
8176
8177 for (;;) {
8178 cp = *++argv;
8179 if (!cp)
8180 return NULL;
8181 if (*cp++ != '-')
8182 break;
8183 c = *cp++;
8184 if (!c)
8185 break;
8186 if (c == '-' && !*cp) {
8187 if (!*++argv)
8188 return NULL;
8189 break;
8190 }
8191 do {
8192 switch (c) {
8193 case 'p':
8194 *path = bb_default_path;
8195 break;
8196 default:
8197 /* run 'typecmd' for other options */
8198 return NULL;
8199 }
8200 c = *cp++;
8201 } while (c);
8202 }
8203 return argv;
8204}
8205
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008206static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008207commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008208{
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008209 char *cmd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008210 int c;
8211 enum {
8212 VERIFY_BRIEF = 1,
8213 VERIFY_VERBOSE = 2,
8214 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008215 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008216
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008217 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8218 * never reaches this function.
8219 */
8220
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008221 while ((c = nextopt("pvV")) != '\0')
8222 if (c == 'V')
8223 verify |= VERIFY_VERBOSE;
8224 else if (c == 'v')
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008225 /*verify |= VERIFY_BRIEF*/;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008226#if DEBUG
8227 else if (c != 'p')
8228 abort();
8229#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008230 else
8231 path = bb_default_path;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008232
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008233 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008234 cmd = *argptr;
8235 if (/*verify && */ cmd)
8236 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008237
8238 return 0;
8239}
8240#endif
8241
8242
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008243/*static int funcblocksize; // size of structures in function */
8244/*static int funcstringsize; // size of strings in node */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008245static void *funcblock; /* block to allocate function from */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008246static char *funcstring_end; /* end of block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008247
Eric Andersencb57d552001-06-28 07:25:16 +00008248/* flags in argument to evaltree */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008249#define EV_EXIT 01 /* exit after evaluating tree */
8250#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Eric Andersencb57d552001-06-28 07:25:16 +00008251
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008252static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008253 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8254 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8255 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8256 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8257 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8258 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8259 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8260 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8261 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8262 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8263 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8264 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8265 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8266 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8267 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8268 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8269 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008270#if BASH_REDIR_OUTPUT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008271 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008272#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008273 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8274 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8275 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8276 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8277 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8278 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8279 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8280 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8281 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008282};
8283
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008284static int calcsize(int funcblocksize, union node *n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008285
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008286static int
8287sizenodelist(int funcblocksize, struct nodelist *lp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008288{
8289 while (lp) {
8290 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008291 funcblocksize = calcsize(funcblocksize, lp->n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008292 lp = lp->next;
8293 }
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008294 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008295}
8296
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008297static int
8298calcsize(int funcblocksize, union node *n)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008299{
8300 if (n == NULL)
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008301 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008302 funcblocksize += nodesize[n->type];
8303 switch (n->type) {
8304 case NCMD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008305 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8306 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8307 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008308 break;
8309 case NPIPE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008310 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008311 break;
8312 case NREDIR:
8313 case NBACKGND:
8314 case NSUBSHELL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008315 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8316 funcblocksize = calcsize(funcblocksize, n->nredir.n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008317 break;
8318 case NAND:
8319 case NOR:
8320 case NSEMI:
8321 case NWHILE:
8322 case NUNTIL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008323 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8324 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008325 break;
8326 case NIF:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008327 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8328 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8329 funcblocksize = calcsize(funcblocksize, n->nif.test);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008330 break;
8331 case NFOR:
Denys Vlasenko561639a2016-10-07 04:28:33 +02008332 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008333 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8334 funcblocksize = calcsize(funcblocksize, n->nfor.args);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008335 break;
8336 case NCASE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008337 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8338 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008339 break;
8340 case NCLIST:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008341 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8342 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8343 funcblocksize = calcsize(funcblocksize, n->nclist.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008344 break;
8345 case NDEFUN:
8346 case NARG:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008347 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
Denys Vlasenko561639a2016-10-07 04:28:33 +02008348 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008349 funcblocksize = calcsize(funcblocksize, n->narg.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008350 break;
8351 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008352#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008353 case NTO2:
8354#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008355 case NCLOBBER:
8356 case NFROM:
8357 case NFROMTO:
8358 case NAPPEND:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008359 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8360 funcblocksize = calcsize(funcblocksize, n->nfile.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008361 break;
8362 case NTOFD:
8363 case NFROMFD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008364 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8365 funcblocksize = calcsize(funcblocksize, n->ndup.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008366 break;
8367 case NHERE:
8368 case NXHERE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008369 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8370 funcblocksize = calcsize(funcblocksize, n->nhere.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008371 break;
8372 case NNOT:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008373 funcblocksize = calcsize(funcblocksize, n->nnot.com);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008374 break;
8375 };
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008376 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008377}
8378
8379static char *
8380nodeckstrdup(char *s)
8381{
Denys Vlasenko561639a2016-10-07 04:28:33 +02008382 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008383 return strcpy(funcstring_end, s);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008384}
8385
8386static union node *copynode(union node *);
8387
8388static struct nodelist *
8389copynodelist(struct nodelist *lp)
8390{
8391 struct nodelist *start;
8392 struct nodelist **lpp;
8393
8394 lpp = &start;
8395 while (lp) {
8396 *lpp = funcblock;
8397 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8398 (*lpp)->n = copynode(lp->n);
8399 lp = lp->next;
8400 lpp = &(*lpp)->next;
8401 }
8402 *lpp = NULL;
8403 return start;
8404}
8405
8406static union node *
8407copynode(union node *n)
8408{
8409 union node *new;
8410
8411 if (n == NULL)
8412 return NULL;
8413 new = funcblock;
8414 funcblock = (char *) funcblock + nodesize[n->type];
8415
8416 switch (n->type) {
8417 case NCMD:
8418 new->ncmd.redirect = copynode(n->ncmd.redirect);
8419 new->ncmd.args = copynode(n->ncmd.args);
8420 new->ncmd.assign = copynode(n->ncmd.assign);
8421 break;
8422 case NPIPE:
8423 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008424 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008425 break;
8426 case NREDIR:
8427 case NBACKGND:
8428 case NSUBSHELL:
8429 new->nredir.redirect = copynode(n->nredir.redirect);
8430 new->nredir.n = copynode(n->nredir.n);
8431 break;
8432 case NAND:
8433 case NOR:
8434 case NSEMI:
8435 case NWHILE:
8436 case NUNTIL:
8437 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8438 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8439 break;
8440 case NIF:
8441 new->nif.elsepart = copynode(n->nif.elsepart);
8442 new->nif.ifpart = copynode(n->nif.ifpart);
8443 new->nif.test = copynode(n->nif.test);
8444 break;
8445 case NFOR:
8446 new->nfor.var = nodeckstrdup(n->nfor.var);
8447 new->nfor.body = copynode(n->nfor.body);
8448 new->nfor.args = copynode(n->nfor.args);
8449 break;
8450 case NCASE:
8451 new->ncase.cases = copynode(n->ncase.cases);
8452 new->ncase.expr = copynode(n->ncase.expr);
8453 break;
8454 case NCLIST:
8455 new->nclist.body = copynode(n->nclist.body);
8456 new->nclist.pattern = copynode(n->nclist.pattern);
8457 new->nclist.next = copynode(n->nclist.next);
8458 break;
8459 case NDEFUN:
8460 case NARG:
8461 new->narg.backquote = copynodelist(n->narg.backquote);
8462 new->narg.text = nodeckstrdup(n->narg.text);
8463 new->narg.next = copynode(n->narg.next);
8464 break;
8465 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008466#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008467 case NTO2:
8468#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008469 case NCLOBBER:
8470 case NFROM:
8471 case NFROMTO:
8472 case NAPPEND:
8473 new->nfile.fname = copynode(n->nfile.fname);
8474 new->nfile.fd = n->nfile.fd;
8475 new->nfile.next = copynode(n->nfile.next);
8476 break;
8477 case NTOFD:
8478 case NFROMFD:
8479 new->ndup.vname = copynode(n->ndup.vname);
8480 new->ndup.dupfd = n->ndup.dupfd;
8481 new->ndup.fd = n->ndup.fd;
8482 new->ndup.next = copynode(n->ndup.next);
8483 break;
8484 case NHERE:
8485 case NXHERE:
8486 new->nhere.doc = copynode(n->nhere.doc);
8487 new->nhere.fd = n->nhere.fd;
8488 new->nhere.next = copynode(n->nhere.next);
8489 break;
8490 case NNOT:
8491 new->nnot.com = copynode(n->nnot.com);
8492 break;
8493 };
8494 new->type = n->type;
8495 return new;
8496}
8497
8498/*
8499 * Make a copy of a parse tree.
8500 */
8501static struct funcnode *
8502copyfunc(union node *n)
8503{
8504 struct funcnode *f;
8505 size_t blocksize;
8506
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008507 /*funcstringsize = 0;*/
8508 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8509 f = ckzalloc(blocksize /* + funcstringsize */);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008510 funcblock = (char *) f + offsetof(struct funcnode, n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008511 funcstring_end = (char *) f + blocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008512 copynode(n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008513 /* f->count = 0; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008514 return f;
8515}
8516
8517/*
8518 * Define a shell function.
8519 */
8520static void
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008521defun(union node *func)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008522{
8523 struct cmdentry entry;
8524
8525 INT_OFF;
8526 entry.cmdtype = CMDFUNCTION;
8527 entry.u.func = copyfunc(func);
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008528 addcmdentry(func->narg.text, &entry);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008529 INT_ON;
8530}
8531
Denis Vlasenko4b875702009-03-19 13:30:04 +00008532/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008533#define SKIPBREAK (1 << 0)
8534#define SKIPCONT (1 << 1)
8535#define SKIPFUNC (1 << 2)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008536static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008537static int skipcount; /* number of levels to skip */
8538static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008539static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008540
Denis Vlasenko4b875702009-03-19 13:30:04 +00008541/* Forward decl way out to parsing code - dotrap needs it */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008542static int evalstring(char *s, int flags);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008543
Denis Vlasenko4b875702009-03-19 13:30:04 +00008544/* Called to execute a trap.
8545 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008546 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008547 *
8548 * Perhaps we should avoid entering new trap handlers
8549 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008550 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008551static void
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008552dotrap(void)
8553{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008554 uint8_t *g;
8555 int sig;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008556 uint8_t last_status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008557
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008558 if (!pending_sig)
8559 return;
8560
8561 last_status = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008562 pending_sig = 0;
Denys Vlasenkode892052016-10-02 01:49:13 +02008563 barrier();
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008564
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008565 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008566 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008567 char *p;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008568
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008569 if (!*g)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008570 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008571
8572 if (evalskip) {
8573 pending_sig = sig;
8574 break;
8575 }
8576
8577 p = trap[sig];
Denis Vlasenko4b875702009-03-19 13:30:04 +00008578 /* non-trapped SIGINT is handled separately by raise_interrupt,
8579 * don't upset it by resetting gotsig[SIGINT-1] */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008580 if (sig == SIGINT && !p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008581 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008582
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008583 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008584 *g = 0;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008585 if (!p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008586 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008587 evalstring(p, 0);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008588 }
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008589 exitstatus = last_status;
8590 TRACE(("dotrap returns\n"));
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008591}
8592
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008593/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008594static int evalloop(union node *, int);
8595static int evalfor(union node *, int);
8596static int evalcase(union node *, int);
8597static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008598static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008599static int evalpipe(union node *, int);
8600static int evalcommand(union node *, int);
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008601static int evalbltin(const struct builtincmd *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008602static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008603
Eric Andersen62483552001-07-10 06:09:16 +00008604/*
Eric Andersenc470f442003-07-28 09:56:35 +00008605 * Evaluate a parse tree. The value is left in the global variable
8606 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008607 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008608static int
Eric Andersenc470f442003-07-28 09:56:35 +00008609evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008610{
Eric Andersenc470f442003-07-28 09:56:35 +00008611 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008612 int (*evalfn)(union node *, int);
8613 int status = 0;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008614
Eric Andersenc470f442003-07-28 09:56:35 +00008615 if (n == NULL) {
8616 TRACE(("evaltree(NULL) called\n"));
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02008617 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00008618 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008619 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008620
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008621 dotrap();
8622
Eric Andersenc470f442003-07-28 09:56:35 +00008623 switch (n->type) {
8624 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008625#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008626 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008627 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008628 break;
8629#endif
8630 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008631 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008632 goto setstatus;
8633 case NREDIR:
8634 expredir(n->nredir.redirect);
8635 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8636 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008637 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008638 }
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02008639 if (n->nredir.redirect)
8640 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
Eric Andersenc470f442003-07-28 09:56:35 +00008641 goto setstatus;
8642 case NCMD:
8643 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008644 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008645 if (eflag && !(flags & EV_TESTED))
8646 checkexit = ~0;
8647 goto calleval;
8648 case NFOR:
8649 evalfn = evalfor;
8650 goto calleval;
8651 case NWHILE:
8652 case NUNTIL:
8653 evalfn = evalloop;
8654 goto calleval;
8655 case NSUBSHELL:
8656 case NBACKGND:
8657 evalfn = evalsubshell;
Denys Vlasenkocf98b0c2016-10-25 18:19:39 +02008658 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00008659 case NPIPE:
8660 evalfn = evalpipe;
8661 goto checkexit;
8662 case NCASE:
8663 evalfn = evalcase;
8664 goto calleval;
8665 case NAND:
8666 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008667 case NSEMI: {
8668
Eric Andersenc470f442003-07-28 09:56:35 +00008669#if NAND + 1 != NOR
8670#error NAND + 1 != NOR
8671#endif
8672#if NOR + 1 != NSEMI
8673#error NOR + 1 != NSEMI
8674#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008675 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008676 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00008677 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008678 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008679 );
Denys Vlasenkobc1a0082016-10-02 15:31:33 +02008680 if ((!status) == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00008681 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008682 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008683 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008684 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008685 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008686 status = evalfn(n, flags);
8687 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008688 }
Eric Andersenc470f442003-07-28 09:56:35 +00008689 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008690 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008691 if (evalskip)
8692 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008693 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00008694 n = n->nif.ifpart;
8695 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008696 }
8697 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008698 n = n->nif.elsepart;
8699 goto evaln;
8700 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008701 status = 0;
8702 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00008703 case NDEFUN:
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008704 defun(n);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008705 /* Not necessary. To test it:
8706 * "false; f() { qwerty; }; echo $?" should print 0.
8707 */
8708 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008709 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00008710 exitstatus = status;
8711 break;
8712 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008713 out:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008714 /* Order of checks below is important:
8715 * signal handlers trigger before exit caused by "set -e".
8716 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008717 dotrap();
8718
8719 if (checkexit & status)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008720 raise_exception(EXEXIT);
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008721 if (flags & EV_EXIT)
8722 raise_exception(EXEXIT);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008723
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008724 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008725 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00008726}
8727
Eric Andersenc470f442003-07-28 09:56:35 +00008728#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8729static
8730#endif
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008731int evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
Eric Andersenc470f442003-07-28 09:56:35 +00008732
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02008733static int
8734skiploop(void)
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008735{
8736 int skip = evalskip;
8737
8738 switch (skip) {
8739 case 0:
8740 break;
8741 case SKIPBREAK:
8742 case SKIPCONT:
8743 if (--skipcount <= 0) {
8744 evalskip = 0;
8745 break;
8746 }
8747 skip = SKIPBREAK;
8748 break;
8749 }
8750 return skip;
8751}
8752
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008753static int
Eric Andersenc470f442003-07-28 09:56:35 +00008754evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008755{
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008756 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00008757 int status;
8758
8759 loopnest++;
8760 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008761 flags &= EV_TESTED;
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008762 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008763 int i;
8764
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008765 i = evaltree(n->nbinary.ch1, EV_TESTED);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008766 skip = skiploop();
8767 if (skip == SKIPFUNC)
8768 status = i;
8769 if (skip)
8770 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00008771 if (n->type != NWHILE)
8772 i = !i;
8773 if (i != 0)
8774 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008775 status = evaltree(n->nbinary.ch2, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008776 skip = skiploop();
8777 } while (!(skip & ~SKIPCONT));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008778 loopnest--;
8779
8780 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008781}
8782
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008783static int
Eric Andersenc470f442003-07-28 09:56:35 +00008784evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008785{
8786 struct arglist arglist;
8787 union node *argp;
8788 struct strlist *sp;
8789 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008790 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008791
8792 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008793 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008794 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008795 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02008796 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersencb57d552001-06-28 07:25:16 +00008797 }
8798 *arglist.lastp = NULL;
8799
Eric Andersencb57d552001-06-28 07:25:16 +00008800 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008801 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008802 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008803 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008804 status = evaltree(n->nfor.body, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008805 if (skiploop() & ~SKIPCONT)
Eric Andersencb57d552001-06-28 07:25:16 +00008806 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008807 }
8808 loopnest--;
Eric Andersencb57d552001-06-28 07:25:16 +00008809 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008810
8811 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008812}
8813
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008814static int
Eric Andersenc470f442003-07-28 09:56:35 +00008815evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008816{
8817 union node *cp;
8818 union node *patp;
8819 struct arglist arglist;
8820 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008821 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008822
8823 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008824 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008825 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00008826 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008827 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8828 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008829 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008830 /* Ensure body is non-empty as otherwise
8831 * EV_EXIT may prevent us from setting the
8832 * exit status.
8833 */
8834 if (evalskip == 0 && cp->nclist.body) {
8835 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008836 }
8837 goto out;
8838 }
8839 }
8840 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008841 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008842 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008843
8844 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008845}
8846
Eric Andersenc470f442003-07-28 09:56:35 +00008847/*
8848 * Kick off a subshell to evaluate a tree.
8849 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008850static int
Eric Andersenc470f442003-07-28 09:56:35 +00008851evalsubshell(union node *n, int flags)
8852{
8853 struct job *jp;
8854 int backgnd = (n->type == NBACKGND);
8855 int status;
8856
8857 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02008858 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00008859 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008860 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008861 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008862 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02008863 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008864 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008865 flags |= EV_EXIT;
8866 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02008867 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00008868 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00008869 redirect(n->nredir.redirect, 0);
8870 evaltreenr(n->nredir.n, flags);
8871 /* never returns */
8872 }
Denys Vlasenko70392332016-10-27 02:31:55 +02008873 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00008874 status = 0;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008875 if (!backgnd)
Eric Andersenc470f442003-07-28 09:56:35 +00008876 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00008877 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008878 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00008879}
8880
Eric Andersenc470f442003-07-28 09:56:35 +00008881/*
8882 * Compute the names of the files in a redirection list.
8883 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00008884static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008885static void
8886expredir(union node *n)
8887{
8888 union node *redir;
8889
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008890 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00008891 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008892
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008893 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008894 fn.lastp = &fn.list;
8895 switch (redir->type) {
8896 case NFROMTO:
8897 case NFROM:
8898 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008899#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008900 case NTO2:
8901#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008902 case NCLOBBER:
8903 case NAPPEND:
8904 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02008905 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008906#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008907 store_expfname:
8908#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008909#if 0
8910// By the design of stack allocator, the loop of this kind:
8911// while true; do while true; do break; done </dev/null; done
8912// will look like a memory leak: ash plans to free expfname's
8913// of "/dev/null" as soon as it finishes running the loop
8914// (in this case, never).
8915// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01008916 if (redir->nfile.expfname)
8917 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008918// It results in corrupted state of stacked allocations.
8919#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008920 redir->nfile.expfname = fn.list->text;
8921 break;
8922 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008923 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00008924 if (redir->ndup.vname) {
8925 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008926 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008927 ash_msg_and_raise_error("redir error");
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008928#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008929//FIXME: we used expandarg with different args!
8930 if (!isdigit_str9(fn.list->text)) {
8931 /* >&file, not >&fd */
8932 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8933 ash_msg_and_raise_error("redir error");
8934 redir->type = NTO2;
8935 goto store_expfname;
8936 }
8937#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008938 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008939 }
8940 break;
8941 }
8942 }
8943}
8944
Eric Andersencb57d552001-06-28 07:25:16 +00008945/*
Eric Andersencb57d552001-06-28 07:25:16 +00008946 * Evaluate a pipeline. All the processes in the pipeline are children
8947 * of the process creating the pipeline. (This differs from some versions
8948 * of the shell, which make the last process in a pipeline the parent
8949 * of all the rest.)
8950 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008951static int
Eric Andersenc470f442003-07-28 09:56:35 +00008952evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008953{
8954 struct job *jp;
8955 struct nodelist *lp;
8956 int pipelen;
8957 int prevfd;
8958 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008959 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008960
Eric Andersenc470f442003-07-28 09:56:35 +00008961 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00008962 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008963 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00008964 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008965 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008966 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008967 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00008968 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008969 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008970 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00008971 pip[1] = -1;
8972 if (lp->next) {
8973 if (pipe(pip) < 0) {
8974 close(prevfd);
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00008975 ash_msg_and_raise_error("pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00008976 }
8977 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008978 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02008979 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008980 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00008981 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008982 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00008983 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008984 if (prevfd > 0) {
8985 dup2(prevfd, 0);
8986 close(prevfd);
8987 }
8988 if (pip[1] > 1) {
8989 dup2(pip[1], 1);
8990 close(pip[1]);
8991 }
Eric Andersenc470f442003-07-28 09:56:35 +00008992 evaltreenr(lp->n, flags);
8993 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00008994 }
Denys Vlasenko70392332016-10-27 02:31:55 +02008995 /* parent */
Eric Andersencb57d552001-06-28 07:25:16 +00008996 if (prevfd >= 0)
8997 close(prevfd);
8998 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00008999 /* Don't want to trigger debugging */
9000 if (pip[1] != -1)
9001 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009002 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009003 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009004 status = waitforjob(jp);
9005 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00009006 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009007 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009008
9009 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009010}
9011
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009012/*
9013 * Controls whether the shell is interactive or not.
9014 */
9015static void
9016setinteractive(int on)
9017{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009018 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009019
9020 if (++on == is_interactive)
9021 return;
9022 is_interactive = on;
9023 setsignal(SIGINT);
9024 setsignal(SIGQUIT);
9025 setsignal(SIGTERM);
9026#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9027 if (is_interactive > 1) {
9028 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009029 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009030
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009031 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009032 /* note: ash and hush share this string */
9033 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009034 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9035 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009036 bb_banner,
9037 "built-in shell (ash)"
9038 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009039 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009040 }
9041 }
9042#endif
9043}
9044
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009045static void
9046optschanged(void)
9047{
9048#if DEBUG
9049 opentrace();
9050#endif
9051 setinteractive(iflag);
9052 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009053#if ENABLE_FEATURE_EDITING_VI
9054 if (viflag)
9055 line_input_state->flags |= VI_MODE;
9056 else
9057 line_input_state->flags &= ~VI_MODE;
9058#else
9059 viflag = 0; /* forcibly keep the option off */
9060#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009061}
9062
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009063static struct localvar *localvars;
9064
9065/*
9066 * Called after a function returns.
9067 * Interrupts must be off.
9068 */
9069static void
9070poplocalvars(void)
9071{
9072 struct localvar *lvp;
9073 struct var *vp;
9074
9075 while ((lvp = localvars) != NULL) {
9076 localvars = lvp->next;
9077 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02009078 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009079 if (vp == NULL) { /* $- saved */
9080 memcpy(optlist, lvp->text, sizeof(optlist));
9081 free((char*)lvp->text);
9082 optschanged();
9083 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009084 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009085 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009086 if (vp->var_func)
9087 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009088 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009089 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009090 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009091 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009092 }
9093 free(lvp);
9094 }
9095}
9096
9097static int
9098evalfun(struct funcnode *func, int argc, char **argv, int flags)
9099{
9100 volatile struct shparam saveparam;
9101 struct localvar *volatile savelocalvars;
9102 struct jmploc *volatile savehandler;
9103 struct jmploc jmploc;
9104 int e;
9105
9106 saveparam = shellparam;
9107 savelocalvars = localvars;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009108 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009109 e = setjmp(jmploc.loc);
9110 if (e) {
9111 goto funcdone;
9112 }
9113 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009114 exception_handler = &jmploc;
9115 localvars = NULL;
Denis Vlasenko01631112007-12-16 17:20:38 +00009116 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009117 func->count++;
9118 funcnest++;
9119 INT_ON;
9120 shellparam.nparam = argc - 1;
9121 shellparam.p = argv + 1;
9122#if ENABLE_ASH_GETOPTS
9123 shellparam.optind = 1;
9124 shellparam.optoff = -1;
9125#endif
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009126 evaltree(func->n.narg.next, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00009127 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009128 INT_OFF;
9129 funcnest--;
9130 freefunc(func);
9131 poplocalvars();
9132 localvars = savelocalvars;
9133 freeparam(&shellparam);
9134 shellparam = saveparam;
9135 exception_handler = savehandler;
9136 INT_ON;
9137 evalskip &= ~SKIPFUNC;
9138 return e;
9139}
9140
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009141/*
9142 * Make a variable a local variable. When a variable is made local, it's
9143 * value and flags are saved in a localvar structure. The saved values
9144 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009145 * "-" as a special case: it makes changes to "set +-options" local
9146 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009147 */
9148static void
9149mklocal(char *name)
9150{
9151 struct localvar *lvp;
9152 struct var **vpp;
9153 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009154 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009155
9156 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009157 /* Cater for duplicate "local". Examples:
9158 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9159 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9160 */
9161 lvp = localvars;
9162 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009163 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009164 if (eq)
9165 setvareq(name, 0);
9166 /* else:
9167 * it's a duplicate "local VAR" declaration, do nothing
9168 */
Denys Vlasenko06b11492016-11-04 16:43:18 +01009169 goto ret;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009170 }
9171 lvp = lvp->next;
9172 }
9173
9174 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009175 if (LONE_DASH(name)) {
9176 char *p;
9177 p = ckmalloc(sizeof(optlist));
9178 lvp->text = memcpy(p, optlist, sizeof(optlist));
9179 vp = NULL;
9180 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009181 vpp = hashvar(name);
9182 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009183 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009184 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009185 if (eq)
9186 setvareq(name, VSTRFIXED);
9187 else
9188 setvar(name, NULL, VSTRFIXED);
9189 vp = *vpp; /* the new variable */
9190 lvp->flags = VUNSET;
9191 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009192 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009193 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009194 /* make sure neither "struct var" nor string gets freed
9195 * during (un)setting:
9196 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009197 vp->flags |= VSTRFIXED|VTEXTFIXED;
9198 if (eq)
9199 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009200 else
9201 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009202 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009203 }
9204 }
9205 lvp->vp = vp;
9206 lvp->next = localvars;
9207 localvars = lvp;
Denys Vlasenko06b11492016-11-04 16:43:18 +01009208 ret:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009209 INT_ON;
9210}
9211
9212/*
9213 * The "local" command.
9214 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009215static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009216localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009217{
9218 char *name;
9219
Ron Yorstonef2386b2015-10-29 16:19:14 +00009220 if (!funcnest)
9221 ash_msg_and_raise_error("not in a function");
9222
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009223 argv = argptr;
9224 while ((name = *argv++) != NULL) {
9225 mklocal(name);
9226 }
9227 return 0;
9228}
9229
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009230static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009231falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009232{
9233 return 1;
9234}
9235
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009236static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009237truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009238{
9239 return 0;
9240}
9241
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009242static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009243execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009244{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009245 if (argv[1]) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009246 iflag = 0; /* exit on error */
9247 mflag = 0;
9248 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009249 /* We should set up signals for "exec CMD"
9250 * the same way as for "CMD" without "exec".
9251 * But optschanged->setinteractive->setsignal
9252 * still thought we are a root shell. Therefore, for example,
9253 * SIGQUIT is still set to IGN. Fix it:
9254 */
9255 shlvl++;
9256 setsignal(SIGQUIT);
9257 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9258 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9259 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9260
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009261 shellexec(argv + 1, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009262 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009263 }
9264 return 0;
9265}
9266
9267/*
9268 * The return command.
9269 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009270static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009271returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009272{
9273 /*
9274 * If called outside a function, do what ksh does;
9275 * skip the rest of the file.
9276 */
Denys Vlasenko6a0710e2016-09-30 14:18:34 +02009277 evalskip = SKIPFUNC;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009278 return argv[1] ? number(argv[1]) : exitstatus;
9279}
9280
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009281/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009282static int breakcmd(int, char **) FAST_FUNC;
9283static int dotcmd(int, char **) FAST_FUNC;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009284static int evalcmd(int, char **, int) FAST_FUNC;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009285static int exitcmd(int, char **) FAST_FUNC;
9286static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009287#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009288static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009289#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009290#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009291static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009292#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009293#if MAX_HISTORY
9294static int historycmd(int, char **) FAST_FUNC;
9295#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009296#if ENABLE_FEATURE_SH_MATH
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009297static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009298#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009299static int readcmd(int, char **) FAST_FUNC;
9300static int setcmd(int, char **) FAST_FUNC;
9301static int shiftcmd(int, char **) FAST_FUNC;
9302static int timescmd(int, char **) FAST_FUNC;
9303static int trapcmd(int, char **) FAST_FUNC;
9304static int umaskcmd(int, char **) FAST_FUNC;
9305static int unsetcmd(int, char **) FAST_FUNC;
9306static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009307
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009308#define BUILTIN_NOSPEC "0"
9309#define BUILTIN_SPECIAL "1"
9310#define BUILTIN_REGULAR "2"
9311#define BUILTIN_SPEC_REG "3"
9312#define BUILTIN_ASSIGN "4"
9313#define BUILTIN_SPEC_ASSG "5"
9314#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009315#define BUILTIN_SPEC_REG_ASSG "7"
9316
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009317/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko265062d2017-01-10 15:13:30 +01009318#if ENABLE_ASH_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009319static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009320#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009321#if ENABLE_ASH_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009322static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009323#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009324#if ENABLE_ASH_TEST || BASH_TEST2
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009325static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009326#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009327
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009328/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009329static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009330 { BUILTIN_SPEC_REG "." , dotcmd },
9331 { BUILTIN_SPEC_REG ":" , truecmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009332#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009333 { BUILTIN_REGULAR "[" , testcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009334#endif
9335#if BASH_TEST2
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009336 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009337#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009338#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009339 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009340#endif
9341#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009342 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009343#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009344 { BUILTIN_SPEC_REG "break" , breakcmd },
9345 { BUILTIN_REGULAR "cd" , cdcmd },
9346 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009347#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009348 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009349#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009350 { BUILTIN_SPEC_REG "continue", breakcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009351#if ENABLE_ASH_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009352 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009353#endif
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009354 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009355 { BUILTIN_SPEC_REG "exec" , execcmd },
9356 { BUILTIN_SPEC_REG "exit" , exitcmd },
9357 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9358 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009359#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009360 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009361#endif
9362#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009363 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009364#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009365 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009366#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009367 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009368#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009369#if MAX_HISTORY
9370 { BUILTIN_NOSPEC "history" , historycmd },
9371#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009372#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009373 { BUILTIN_REGULAR "jobs" , jobscmd },
9374 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009375#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009376#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009377 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009378#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009379 { BUILTIN_ASSIGN "local" , localcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009380#if ENABLE_ASH_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009381 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009382#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009383 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9384 { BUILTIN_REGULAR "read" , readcmd },
9385 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9386 { BUILTIN_SPEC_REG "return" , returncmd },
9387 { BUILTIN_SPEC_REG "set" , setcmd },
9388 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009389#if BASH_SOURCE
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009390 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009391#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009392#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009393 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009394#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009395 { BUILTIN_SPEC_REG "times" , timescmd },
9396 { BUILTIN_SPEC_REG "trap" , trapcmd },
9397 { BUILTIN_REGULAR "true" , truecmd },
9398 { BUILTIN_NOSPEC "type" , typecmd },
9399 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9400 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009401#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009402 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009403#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009404 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9405 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009406};
9407
Denis Vlasenko80591b02008-03-25 07:49:43 +00009408/* Should match the above table! */
9409#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009410 /* . : */ 2 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009411 /* [ */ 1 * ENABLE_ASH_TEST + \
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009412 /* [[ */ 1 * BASH_TEST2 + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009413 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9414 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9415 /* break cd cddir */ 3)
9416#define EVALCMD (COMMANDCMD + \
9417 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9418 /* continue */ 1 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009419 /* echo */ 1 * ENABLE_ASH_ECHO + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009420 0)
9421#define EXECCMD (EVALCMD + \
9422 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009423
9424/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009425 * Search the table of builtin commands.
9426 */
Denys Vlasenko888527c2016-10-02 16:54:17 +02009427static int
9428pstrcmp1(const void *a, const void *b)
9429{
9430 return strcmp((char*)a, *(char**)b + 1);
9431}
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009432static struct builtincmd *
9433find_builtin(const char *name)
9434{
9435 struct builtincmd *bp;
9436
9437 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009438 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denys Vlasenko888527c2016-10-02 16:54:17 +02009439 pstrcmp1
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009440 );
9441 return bp;
9442}
9443
9444/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009445 * Execute a simple command.
9446 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009447static int
9448isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009449{
9450 const char *q = endofname(p);
9451 if (p == q)
9452 return 0;
9453 return *q == '=';
9454}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009455static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009456bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009457{
9458 /* Preserve exitstatus of a previous possible redirection
9459 * as POSIX mandates */
9460 return back_exitstatus;
9461}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009462static int
Eric Andersenc470f442003-07-28 09:56:35 +00009463evalcommand(union node *cmd, int flags)
9464{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009465 static const struct builtincmd null_bltin = {
9466 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009467 };
Eric Andersenc470f442003-07-28 09:56:35 +00009468 struct stackmark smark;
9469 union node *argp;
9470 struct arglist arglist;
9471 struct arglist varlist;
9472 char **argv;
9473 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009474 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009475 struct cmdentry cmdentry;
9476 struct job *jp;
9477 char *lastarg;
9478 const char *path;
9479 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009480 int status;
9481 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00009482 struct builtincmd *bcmd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009483 smallint cmd_is_exec;
9484 smallint pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009485
9486 /* First expand the arguments. */
9487 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9488 setstackmark(&smark);
9489 back_exitstatus = 0;
9490
9491 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009492 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009493 varlist.lastp = &varlist.list;
9494 *varlist.lastp = NULL;
9495 arglist.lastp = &arglist.list;
9496 *arglist.lastp = NULL;
9497
9498 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009499 if (cmd->ncmd.args) {
Paul Foxc3850c82005-07-20 18:23:39 +00009500 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9501 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9502 }
9503
Eric Andersenc470f442003-07-28 09:56:35 +00009504 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9505 struct strlist **spp;
9506
9507 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00009508 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00009509 expandarg(argp, &arglist, EXP_VARTILDE);
9510 else
9511 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9512
Eric Andersenc470f442003-07-28 09:56:35 +00009513 for (sp = *spp; sp; sp = sp->next)
9514 argc++;
9515 }
9516
Denys Vlasenko65a8b852016-10-26 22:29:11 +02009517 /* Reserve one extra spot at the front for shellexec. */
9518 nargv = stalloc(sizeof(char *) * (argc + 2));
9519 argv = ++nargv;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009520 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009521 TRACE(("evalcommand arg: %s\n", sp->text));
9522 *nargv++ = sp->text;
9523 }
9524 *nargv = NULL;
9525
9526 lastarg = NULL;
9527 if (iflag && funcnest == 0 && argc > 0)
9528 lastarg = nargv[-1];
9529
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009530 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009531 expredir(cmd->ncmd.redirect);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009532 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009533
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009534 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009535 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9536 struct strlist **spp;
9537 char *p;
9538
9539 spp = varlist.lastp;
9540 expandarg(argp, &varlist, EXP_VARTILDE);
9541
9542 /*
9543 * Modify the command lookup path, if a PATH= assignment
9544 * is present
9545 */
9546 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009547 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009548 path = p;
9549 }
9550
9551 /* Print the command if xflag is set. */
9552 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009553 int n;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009554 const char *p = " %s" + 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009555
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009556 fdprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009557 sp = varlist.list;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009558 for (n = 0; n < 2; n++) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009559 while (sp) {
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009560 fdprintf(preverrout_fd, p, sp->text);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009561 sp = sp->next;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009562 p = " %s";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009563 }
9564 sp = arglist.list;
9565 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009566 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009567 }
9568
9569 cmd_is_exec = 0;
9570 spclbltin = -1;
9571
9572 /* Now locate the command. */
9573 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009574 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02009575#if ENABLE_ASH_CMDCMD
9576 const char *oldpath = path + 5;
9577#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009578 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009579 for (;;) {
9580 find_command(argv[0], &cmdentry, cmd_flag, path);
9581 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009582 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009583 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009584 goto bail;
9585 }
9586
9587 /* implement bltin and command here */
9588 if (cmdentry.cmdtype != CMDBUILTIN)
9589 break;
9590 if (spclbltin < 0)
9591 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9592 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009593 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009594#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009595 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009596 path = oldpath;
9597 nargv = parse_command_args(argv, &path);
9598 if (!nargv)
9599 break;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02009600 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
9601 * nargv => "PROG". path is updated if -p.
9602 */
Eric Andersenc470f442003-07-28 09:56:35 +00009603 argc -= nargv - argv;
9604 argv = nargv;
9605 cmd_flag |= DO_NOFUNC;
9606 } else
9607#endif
9608 break;
9609 }
9610 }
9611
9612 if (status) {
Ron Yorstonea7d2f62017-01-03 11:18:23 +01009613 bail:
9614 exitstatus = status;
9615
Eric Andersenc470f442003-07-28 09:56:35 +00009616 /* We have a redirection error. */
9617 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009618 raise_exception(EXERROR);
Ron Yorstonea7d2f62017-01-03 11:18:23 +01009619
Eric Andersenc470f442003-07-28 09:56:35 +00009620 goto out;
9621 }
9622
9623 /* Execute the command. */
9624 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009625 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009626
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009627#if ENABLE_FEATURE_SH_NOFORK
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009628/* (1) BUG: if variables are set, we need to fork, or save/restore them
9629 * around run_nofork_applet() call.
9630 * (2) Should this check also be done in forkshell()?
9631 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9632 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009633 /* find_command() encodes applet_no as (-2 - applet_no) */
9634 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009635 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009636 listsetvar(varlist.list, VEXPORT|VSTACK);
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009637 /* run <applet>_main() */
Ron Yorston5ccb0e92016-10-20 12:24:02 +01009638 status = run_nofork_applet(applet_no, argv);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009639 break;
9640 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009641#endif
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009642 /* Can we avoid forking off? For example, very last command
9643 * in a script or a subshell does not need forking,
9644 * we can just exec it.
9645 */
Denys Vlasenko238bf182010-05-18 15:49:07 +02009646 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009647 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009648 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00009649 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009650 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009651 /* parent */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009652 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009653 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009654 TRACE(("forked child exited with %d\n", status));
Eric Andersenc470f442003-07-28 09:56:35 +00009655 break;
9656 }
Denys Vlasenko238bf182010-05-18 15:49:07 +02009657 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009658 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +02009659 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +00009660 }
9661 listsetvar(varlist.list, VEXPORT|VSTACK);
9662 shellexec(argv, path, cmdentry.u.index);
9663 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009664 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +00009665 case CMDBUILTIN:
9666 cmdenviron = varlist.list;
9667 if (cmdenviron) {
9668 struct strlist *list = cmdenviron;
9669 int i = VNOSET;
9670 if (spclbltin > 0 || argc == 0) {
9671 i = 0;
9672 if (cmd_is_exec && argc > 1)
9673 i = VEXPORT;
9674 }
9675 listsetvar(list, i);
9676 }
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009677 /* Tight loop with builtins only:
9678 * "while kill -0 $child; do true; done"
9679 * will never exit even if $child died, unless we do this
9680 * to reap the zombie and make kill detect that it's gone: */
9681 dowait(DOWAIT_NONBLOCK, NULL);
9682
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009683 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009684 if (exception_type == EXERROR && spclbltin <= 0) {
9685 FORCE_INT_ON;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02009686 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009687 }
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009688 raise:
9689 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009690 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009691 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009692
9693 case CMDFUNCTION:
9694 listsetvar(varlist.list, 0);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009695 /* See above for the rationale */
9696 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009697 if (evalfun(cmdentry.u.func, argc, argv, flags))
9698 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009699 readstatus:
9700 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009701 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009702 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +00009703
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009704 out:
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02009705 if (cmd->ncmd.redirect)
9706 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009707 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +00009708 /* dsl: I think this is intended to be used to support
9709 * '_' in 'vi' command mode during line editing...
9710 * However I implemented that within libedit itself.
9711 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009712 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009713 }
Eric Andersenc470f442003-07-28 09:56:35 +00009714 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009715
9716 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009717}
9718
9719static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009720evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009721{
Eric Andersenc470f442003-07-28 09:56:35 +00009722 char *volatile savecmdname;
9723 struct jmploc *volatile savehandler;
9724 struct jmploc jmploc;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009725 int status;
Eric Andersenc470f442003-07-28 09:56:35 +00009726 int i;
9727
9728 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009729 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009730 i = setjmp(jmploc.loc);
9731 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +00009732 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009733 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00009734 commandname = argv[0];
9735 argptr = argv + 1;
9736 optptr = NULL; /* initialize nextopt */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009737 if (cmd == EVALCMD)
9738 status = evalcmd(argc, argv, flags);
9739 else
9740 status = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009741 flush_stdout_stderr();
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009742 status |= ferror(stdout);
9743 exitstatus = status;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009744 cmddone:
Rob Landleyf296f0b2006-07-06 01:09:21 +00009745 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009746 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009747 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +00009748
9749 return i;
9750}
9751
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009752static int
9753goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009754{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02009755 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009756}
9757
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009758
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009759/*
9760 * Search for a command. This is called before we fork so that the
9761 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009762 * the child. The check for "goodname" is an overly conservative
9763 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009764 */
Eric Andersenc470f442003-07-28 09:56:35 +00009765static void
9766prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009767{
9768 struct cmdentry entry;
9769
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009770 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9771 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009772}
9773
Eric Andersencb57d552001-06-28 07:25:16 +00009774
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009775/* ============ Builtin commands
9776 *
9777 * Builtin commands whose functions are closely tied to evaluation
9778 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +00009779 */
9780
9781/*
Eric Andersencb57d552001-06-28 07:25:16 +00009782 * Handle break and continue commands. Break, continue, and return are
9783 * all handled by setting the evalskip flag. The evaluation routines
9784 * above all check this flag, and if it is set they start skipping
9785 * commands rather than executing them. The variable skipcount is
9786 * the number of loops to break/continue, or the number of function
9787 * levels to return. (The latter is always 1.) It should probably
9788 * be an error to break out of more loops than exist, but it isn't
9789 * in the standard shell so we don't make it one here.
9790 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009791static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009792breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009793{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009794 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009795
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00009796 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009797 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009798 if (n > loopnest)
9799 n = loopnest;
9800 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009801 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00009802 skipcount = n;
9803 }
9804 return 0;
9805}
9806
Eric Andersenc470f442003-07-28 09:56:35 +00009807
Denys Vlasenko70392332016-10-27 02:31:55 +02009808/*
Eric Andersen90898442003-08-06 11:20:52 +00009809 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00009810 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009811
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009812enum {
9813 INPUT_PUSH_FILE = 1,
9814 INPUT_NOFILE_OK = 2,
9815};
Eric Andersencb57d552001-06-28 07:25:16 +00009816
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009817static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009818/* values of checkkwd variable */
9819#define CHKALIAS 0x1
9820#define CHKKWD 0x2
9821#define CHKNL 0x4
9822
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009823/*
9824 * Push a string back onto the input at this current parsefile level.
9825 * We handle aliases this way.
9826 */
9827#if !ENABLE_ASH_ALIAS
9828#define pushstring(s, ap) pushstring(s)
9829#endif
9830static void
9831pushstring(char *s, struct alias *ap)
9832{
9833 struct strpush *sp;
9834 int len;
9835
9836 len = strlen(s);
9837 INT_OFF;
9838 if (g_parsefile->strpush) {
9839 sp = ckzalloc(sizeof(*sp));
9840 sp->prev = g_parsefile->strpush;
9841 } else {
9842 sp = &(g_parsefile->basestrpush);
9843 }
9844 g_parsefile->strpush = sp;
9845 sp->prev_string = g_parsefile->next_to_pgetc;
9846 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009847 sp->unget = g_parsefile->unget;
9848 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009849#if ENABLE_ASH_ALIAS
9850 sp->ap = ap;
9851 if (ap) {
9852 ap->flag |= ALIASINUSE;
9853 sp->string = s;
9854 }
9855#endif
9856 g_parsefile->next_to_pgetc = s;
9857 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009858 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009859 INT_ON;
9860}
9861
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009862static void
9863popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009864{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009865 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +00009866
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009867 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009868#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009869 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009870 if (g_parsefile->next_to_pgetc[-1] == ' '
9871 || g_parsefile->next_to_pgetc[-1] == '\t'
9872 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009873 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009874 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009875 if (sp->string != sp->ap->val) {
9876 free(sp->string);
9877 }
9878 sp->ap->flag &= ~ALIASINUSE;
9879 if (sp->ap->flag & ALIASDEAD) {
9880 unalias(sp->ap->name);
9881 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009882 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009883#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009884 g_parsefile->next_to_pgetc = sp->prev_string;
9885 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009886 g_parsefile->unget = sp->unget;
9887 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009888 g_parsefile->strpush = sp->prev;
9889 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009890 free(sp);
9891 INT_ON;
9892}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009893
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009894static int
9895preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009896{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009897 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00009898 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009899
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009900 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +00009901#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +00009902 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009903 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +01009904 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009905 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009906 int timeout = -1;
9907# if ENABLE_ASH_IDLE_TIMEOUT
9908 if (iflag) {
9909 const char *tmout_var = lookupvar("TMOUT");
9910 if (tmout_var) {
9911 timeout = atoi(tmout_var) * 1000;
9912 if (timeout <= 0)
9913 timeout = -1;
9914 }
9915 }
9916# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009917# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009918 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009919# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02009920 reinit_unicode_for_ash();
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009921 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009922 if (nr == 0) {
Denys Vlasenko4b89d512016-11-25 03:41:03 +01009923 /* ^C pressed, "convert" to SIGINT */
9924 write(STDOUT_FILENO, "^C", 2);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009925 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009926 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009927 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009928 raise(SIGINT);
9929 return 1;
9930 }
Denys Vlasenko8660aeb2016-11-24 17:44:02 +01009931 exitstatus = 128 + SIGINT;
Denys Vlasenko4b89d512016-11-25 03:41:03 +01009932 bb_putchar('\n');
Eric Andersenc470f442003-07-28 09:56:35 +00009933 goto retry;
9934 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009935 if (nr < 0) {
9936 if (errno == 0) {
9937 /* Ctrl+D pressed */
9938 nr = 0;
9939 }
9940# if ENABLE_ASH_IDLE_TIMEOUT
9941 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +02009942 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009943 exitshell();
9944 }
9945# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009946 }
Eric Andersencb57d552001-06-28 07:25:16 +00009947 }
9948#else
Ron Yorston61d6ae22015-04-19 10:50:25 +01009949 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00009950#endif
9951
Denys Vlasenko80c5b682011-05-08 21:21:10 +02009952#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +00009953 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00009954 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +00009955 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +00009956 if (flags >= 0 && (flags & O_NONBLOCK)) {
9957 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00009958 if (fcntl(0, F_SETFL, flags) >= 0) {
9959 out2str("sh: turning off NDELAY mode\n");
9960 goto retry;
9961 }
9962 }
9963 }
9964 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +00009965#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009966 return nr;
9967}
9968
9969/*
9970 * Refill the input buffer and return the next input character:
9971 *
9972 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009973 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9974 * or we are reading from a string so we can't refill the buffer,
9975 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +02009976 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +00009977 * 4) Process input up to the next newline, deleting nul characters.
9978 */
Denis Vlasenko727752d2008-11-28 03:41:47 +00009979//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9980#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009981static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009982static int
Eric Andersenc470f442003-07-28 09:56:35 +00009983preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009984{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009985 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +00009986 int more;
Eric Andersencb57d552001-06-28 07:25:16 +00009987
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009988 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +00009989#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009990 if (g_parsefile->left_in_line == -1
9991 && g_parsefile->strpush->ap
9992 && g_parsefile->next_to_pgetc[-1] != ' '
9993 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +00009994 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009995 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +00009996 return PEOA;
9997 }
Eric Andersen2870d962001-07-02 17:27:21 +00009998#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009999 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010000 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010001 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010002 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010003 * "pgetc" needs refilling.
10004 */
10005
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010006 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010007 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010008 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010009 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010010 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010011 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010012 /* even in failure keep left_in_line and next_to_pgetc
10013 * in lock step, for correct multi-layer pungetc.
10014 * left_in_line was decremented before preadbuffer(),
10015 * must inc next_to_pgetc: */
10016 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010017 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010018 }
Eric Andersencb57d552001-06-28 07:25:16 +000010019
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010020 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010021 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010022 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010023 again:
10024 more = preadfd();
10025 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010026 /* don't try reading again */
10027 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010028 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010029 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010030 return PEOF;
10031 }
10032 }
10033
Denis Vlasenko727752d2008-11-28 03:41:47 +000010034 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010035 * Set g_parsefile->left_in_line
10036 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010037 * NUL chars are deleted.
10038 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010039 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010040 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010041 char c;
Eric Andersencb57d552001-06-28 07:25:16 +000010042
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010043 more--;
Eric Andersenc470f442003-07-28 09:56:35 +000010044
Denis Vlasenko727752d2008-11-28 03:41:47 +000010045 c = *q;
10046 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010047 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010048 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010049 q++;
10050 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010051 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010052 break;
10053 }
Eric Andersencb57d552001-06-28 07:25:16 +000010054 }
10055
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010056 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010057 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10058 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010059 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010060 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010061 }
10062 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010063 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +000010064
Eric Andersencb57d552001-06-28 07:25:16 +000010065 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010066 char save = *q;
10067 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010068 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010069 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +000010070 }
10071
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010072 pgetc_debug("preadbuffer at %d:%p'%s'",
10073 g_parsefile->left_in_line,
10074 g_parsefile->next_to_pgetc,
10075 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +010010076 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010077}
10078
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010079static void
10080nlprompt(void)
10081{
10082 g_parsefile->linno++;
10083 setprompt_if(doprompt, 2);
10084}
10085static void
10086nlnoprompt(void)
10087{
10088 g_parsefile->linno++;
10089 needprompt = doprompt;
10090}
10091
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010092static int
10093pgetc(void)
10094{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010095 int c;
10096
10097 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010098 g_parsefile->left_in_line,
10099 g_parsefile->next_to_pgetc,
10100 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010101 if (g_parsefile->unget)
10102 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010103
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010104 if (--g_parsefile->left_in_line >= 0)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +010010105 c = (unsigned char)*g_parsefile->next_to_pgetc++;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010106 else
10107 c = preadbuffer();
10108
10109 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10110 g_parsefile->lastc[0] = c;
10111
10112 return c;
10113}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010114
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010115#if ENABLE_ASH_ALIAS
10116static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010117pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010118{
10119 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010120 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010121 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010122 g_parsefile->left_in_line,
10123 g_parsefile->next_to_pgetc,
10124 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010125 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010126 } while (c == PEOA);
10127 return c;
10128}
10129#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010130# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010131#endif
10132
10133/*
10134 * Read a line from the script.
10135 */
10136static char *
10137pfgets(char *line, int len)
10138{
10139 char *p = line;
10140 int nleft = len;
10141 int c;
10142
10143 while (--nleft > 0) {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010144 c = pgetc_without_PEOA();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010145 if (c == PEOF) {
10146 if (p == line)
10147 return NULL;
10148 break;
10149 }
10150 *p++ = c;
10151 if (c == '\n')
10152 break;
10153 }
10154 *p = '\0';
10155 return line;
10156}
10157
Eric Andersenc470f442003-07-28 09:56:35 +000010158/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010159 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010160 * PEOF may be pushed back.
10161 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010162static void
Eric Andersenc470f442003-07-28 09:56:35 +000010163pungetc(void)
10164{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010165 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010166}
10167
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010168/* This one eats backslash+newline */
10169static int
10170pgetc_eatbnl(void)
10171{
10172 int c;
10173
10174 while ((c = pgetc()) == '\\') {
10175 if (pgetc() != '\n') {
10176 pungetc();
10177 break;
10178 }
10179
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010180 nlprompt();
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010181 }
10182
10183 return c;
10184}
10185
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010186/*
10187 * To handle the "." command, a stack of input files is used. Pushfile
10188 * adds a new entry to the stack and popfile restores the previous level.
10189 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010190static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010191pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010192{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010193 struct parsefile *pf;
10194
Denis Vlasenko597906c2008-02-20 16:38:54 +000010195 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010196 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010197 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010198 /*pf->strpush = NULL; - ckzalloc did it */
10199 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010200 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010201 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010202}
10203
10204static void
10205popfile(void)
10206{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010207 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010208
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010010209 if (pf == &basepf)
10210 return;
10211
Denis Vlasenkob012b102007-02-19 22:43:01 +000010212 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010213 if (pf->pf_fd >= 0)
10214 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010215 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010216 while (pf->strpush)
10217 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010218 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010219 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010220 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010221}
10222
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010223/*
10224 * Return to top level.
10225 */
10226static void
10227popallfiles(void)
10228{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010229 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010230 popfile();
10231}
10232
10233/*
10234 * Close the file(s) that the shell is reading commands from. Called
10235 * after a fork is done.
10236 */
10237static void
10238closescript(void)
10239{
10240 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010241 if (g_parsefile->pf_fd > 0) {
10242 close(g_parsefile->pf_fd);
10243 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010244 }
10245}
10246
10247/*
10248 * Like setinputfile, but takes an open file descriptor. Call this with
10249 * interrupts off.
10250 */
10251static void
10252setinputfd(int fd, int push)
10253{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010254 if (push) {
10255 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010256 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010257 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010258 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010259 if (g_parsefile->buf == NULL)
10260 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010261 g_parsefile->left_in_buffer = 0;
10262 g_parsefile->left_in_line = 0;
10263 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010264}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010265
Eric Andersenc470f442003-07-28 09:56:35 +000010266/*
10267 * Set the input to take input from a file. If push is set, push the
10268 * old input onto the stack first.
10269 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010270static int
10271setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010272{
10273 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010274
Denis Vlasenkob012b102007-02-19 22:43:01 +000010275 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010276 fd = open(fname, O_RDONLY);
10277 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010278 if (flags & INPUT_NOFILE_OK)
10279 goto out;
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010280 exitstatus = 127;
Denis Vlasenko9604e1b2009-03-03 18:47:56 +000010281 ash_msg_and_raise_error("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010282 }
Denys Vlasenko64774602016-10-26 15:24:30 +020010283 if (fd < 10)
10284 fd = savefd(fd);
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020010285 else
10286 close_on_exec_on(fd);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010287 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010288 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010289 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010290 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010291}
10292
Eric Andersencb57d552001-06-28 07:25:16 +000010293/*
10294 * Like setinputfile, but takes input from a string.
10295 */
Eric Andersenc470f442003-07-28 09:56:35 +000010296static void
10297setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010298{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010299 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010300 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010301 g_parsefile->next_to_pgetc = string;
10302 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010303 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010304 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010305 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010306}
10307
10308
Denys Vlasenko70392332016-10-27 02:31:55 +020010309/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010310 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010311 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010312
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010313#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010314
Denys Vlasenko23841622015-10-09 15:52:03 +020010315/* Hash of mtimes of mailboxes */
10316static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010317/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010318static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010319
Eric Andersencb57d552001-06-28 07:25:16 +000010320/*
Eric Andersenc470f442003-07-28 09:56:35 +000010321 * Print appropriate message(s) if mail has arrived.
10322 * If mail_var_path_changed is set,
10323 * then the value of MAIL has mail_var_path_changed,
10324 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010325 */
Eric Andersenc470f442003-07-28 09:56:35 +000010326static void
10327chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010328{
Eric Andersencb57d552001-06-28 07:25:16 +000010329 const char *mpath;
10330 char *p;
10331 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010332 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010333 struct stackmark smark;
10334 struct stat statb;
10335
Eric Andersencb57d552001-06-28 07:25:16 +000010336 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010337 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010338 new_hash = 0;
10339 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010340 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010341 if (p == NULL)
10342 break;
10343 if (*p == '\0')
10344 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010345 for (q = p; *q; q++)
10346 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010347#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010348 if (q[-1] != '/')
10349 abort();
10350#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010351 q[-1] = '\0'; /* delete trailing '/' */
10352 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010353 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010354 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010355 /* Very simplistic "hash": just a sum of all mtimes */
10356 new_hash += (unsigned)statb.st_mtime;
10357 }
10358 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010359 if (mailtime_hash != 0)
10360 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010361 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010362 }
Eric Andersenc470f442003-07-28 09:56:35 +000010363 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010364 popstackmark(&smark);
10365}
Eric Andersencb57d552001-06-28 07:25:16 +000010366
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010367static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010368changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010369{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010370 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010371}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010372
Denis Vlasenko131ae172007-02-18 13:00:19 +000010373#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010374
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010375
10376/* ============ ??? */
10377
Eric Andersencb57d552001-06-28 07:25:16 +000010378/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010379 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010380 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010381static void
10382setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010383{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010384 char **newparam;
10385 char **ap;
10386 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010387
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010388 for (nparam = 0; argv[nparam]; nparam++)
10389 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010390 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10391 while (*argv) {
10392 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010393 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010394 *ap = NULL;
10395 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010396 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010397 shellparam.nparam = nparam;
10398 shellparam.p = newparam;
10399#if ENABLE_ASH_GETOPTS
10400 shellparam.optind = 1;
10401 shellparam.optoff = -1;
10402#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010403}
10404
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010405/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010406 * Process shell options. The global variable argptr contains a pointer
10407 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010408 *
10409 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10410 * For a non-interactive shell, an error condition encountered
10411 * by a special built-in ... shall cause the shell to write a diagnostic message
10412 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010413 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010414 * ...
10415 * Utility syntax error (option or operand error) Shall exit
10416 * ...
10417 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10418 * we see that bash does not do that (set "finishes" with error code 1 instead,
10419 * and shell continues), and people rely on this behavior!
10420 * Testcase:
10421 * set -o barfoo 2>/dev/null
10422 * echo $?
10423 *
10424 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010425 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010426static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010427plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010428{
10429 int i;
10430
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010431 if (name) {
10432 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010433 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010434 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010435 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010436 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010437 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010438 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010439 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010440 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010441 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010442 if (val) {
10443 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10444 } else {
10445 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10446 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010447 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010448 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010449}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010450static void
10451setoption(int flag, int val)
10452{
10453 int i;
10454
10455 for (i = 0; i < NOPTS; i++) {
10456 if (optletters(i) == flag) {
10457 optlist[i] = val;
10458 return;
10459 }
10460 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010461 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010462 /* NOTREACHED */
10463}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010464static int
Eric Andersenc470f442003-07-28 09:56:35 +000010465options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +000010466{
10467 char *p;
10468 int val;
10469 int c;
10470
10471 if (cmdline)
10472 minusc = NULL;
10473 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010474 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010475 if (c != '-' && c != '+')
10476 break;
10477 argptr++;
10478 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010479 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010480 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010481 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010482 if (!cmdline) {
10483 /* "-" means turn off -x and -v */
10484 if (p[0] == '\0')
10485 xflag = vflag = 0;
10486 /* "--" means reset params */
10487 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010488 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010489 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010490 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010491 }
Eric Andersencb57d552001-06-28 07:25:16 +000010492 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010493 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010494 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010495 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010496 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010497 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010498 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010499 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010500 /* it already printed err message */
10501 return 1; /* error */
10502 }
Eric Andersencb57d552001-06-28 07:25:16 +000010503 if (*argptr)
10504 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010505 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10506 isloginsh = 1;
10507 /* bash does not accept +-login, we also won't */
10508 } else if (cmdline && val && (c == '-')) { /* long options */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010509 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +000010510 isloginsh = 1;
10511 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010512 } else {
10513 setoption(c, val);
10514 }
10515 }
10516 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010517 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010518}
10519
Eric Andersencb57d552001-06-28 07:25:16 +000010520/*
Eric Andersencb57d552001-06-28 07:25:16 +000010521 * The shift builtin command.
10522 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010523static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010524shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010525{
10526 int n;
10527 char **ap1, **ap2;
10528
10529 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010530 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010531 n = number(argv[1]);
10532 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010533 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010534 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010535 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010536 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010537 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010538 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010539 }
10540 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010541 while ((*ap2++ = *ap1++) != NULL)
10542 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010543#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010544 shellparam.optind = 1;
10545 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010546#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010547 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010548 return 0;
10549}
10550
Eric Andersencb57d552001-06-28 07:25:16 +000010551/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010552 * POSIX requires that 'set' (but not export or readonly) output the
10553 * variables in lexicographic order - by the locale's collating order (sigh).
10554 * Maybe we could keep them in an ordered balanced binary tree
10555 * instead of hashed lists.
10556 * For now just roll 'em through qsort for printing...
10557 */
10558static int
10559showvars(const char *sep_prefix, int on, int off)
10560{
10561 const char *sep;
10562 char **ep, **epend;
10563
10564 ep = listvars(on, off, &epend);
10565 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10566
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010567 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010568
10569 for (; ep < epend; ep++) {
10570 const char *p;
10571 const char *q;
10572
10573 p = strchrnul(*ep, '=');
10574 q = nullstr;
10575 if (*p)
10576 q = single_quote(++p);
10577 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10578 }
10579 return 0;
10580}
10581
10582/*
Eric Andersencb57d552001-06-28 07:25:16 +000010583 * The set command builtin.
10584 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010585static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010586setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010587{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010588 int retval;
10589
Denis Vlasenko68404f12008-03-17 09:00:54 +000010590 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010591 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010592
Denis Vlasenkob012b102007-02-19 22:43:01 +000010593 INT_OFF;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010594 retval = options(/*cmdline:*/ 0);
10595 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010596 optschanged();
10597 if (*argptr != NULL) {
10598 setparam(argptr);
10599 }
Eric Andersencb57d552001-06-28 07:25:16 +000010600 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010601 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010602 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010603}
10604
Denis Vlasenko131ae172007-02-18 13:00:19 +000010605#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010606static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010607change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010608{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010609 uint32_t t;
10610
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010611 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010612 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010613 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010614 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010615 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010616 vrandom.flags &= ~VNOFUNC;
10617 } else {
10618 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010619 t = strtoul(value, NULL, 10);
10620 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010621 }
Eric Andersenef02f822004-03-11 13:34:24 +000010622}
Eric Andersen16767e22004-03-16 05:14:10 +000010623#endif
10624
Denis Vlasenko131ae172007-02-18 13:00:19 +000010625#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010626static int
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010627getopts(char *optstr, char *optvar, char **optfirst)
Eric Andersencb57d552001-06-28 07:25:16 +000010628{
10629 char *p, *q;
10630 char c = '?';
10631 int done = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010632 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000010633 char **optnext;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010634 int ind = shellparam.optind;
10635 int off = shellparam.optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010636
Denys Vlasenko9c541002015-10-07 15:44:36 +020010637 sbuf[1] = '\0';
10638
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010639 shellparam.optind = -1;
10640 optnext = optfirst + ind - 1;
Eric Andersena48b0a32003-10-22 10:56:47 +000010641
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010642 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
Eric Andersencb57d552001-06-28 07:25:16 +000010643 p = NULL;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010644 else
10645 p = optnext[-1] + off;
Eric Andersencb57d552001-06-28 07:25:16 +000010646 if (p == NULL || *p == '\0') {
10647 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010648 p = *optnext;
10649 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010650 atend:
Eric Andersencb57d552001-06-28 07:25:16 +000010651 p = NULL;
10652 done = 1;
10653 goto out;
10654 }
10655 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010656 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010657 goto atend;
10658 }
10659
10660 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010661 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010662 if (*q == '\0') {
10663 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010664 sbuf[0] = c;
10665 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010666 setvar0("OPTARG", sbuf);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010667 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010668 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010669 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010670 }
10671 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010672 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010673 }
10674 if (*++q == ':')
10675 q++;
10676 }
10677
10678 if (*++q == ':') {
10679 if (*p == '\0' && (p = *optnext) == NULL) {
10680 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010681 sbuf[0] = c;
10682 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010683 setvar0("OPTARG", sbuf);
Eric Andersencb57d552001-06-28 07:25:16 +000010684 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010685 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010686 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010687 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010688 c = '?';
10689 }
Eric Andersenc470f442003-07-28 09:56:35 +000010690 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010691 }
10692
10693 if (p == *optnext)
10694 optnext++;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010695 setvar0("OPTARG", p);
Eric Andersencb57d552001-06-28 07:25:16 +000010696 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010697 } else
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010698 setvar0("OPTARG", nullstr);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010699 out:
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010700 ind = optnext - optfirst + 1;
10701 setvar("OPTIND", itoa(ind), VNOFUNC);
Denys Vlasenko9c541002015-10-07 15:44:36 +020010702 sbuf[0] = c;
10703 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010704 setvar0(optvar, sbuf);
10705
10706 shellparam.optoff = p ? p - *(optnext - 1) : -1;
10707 shellparam.optind = ind;
10708
Eric Andersencb57d552001-06-28 07:25:16 +000010709 return done;
10710}
Eric Andersenc470f442003-07-28 09:56:35 +000010711
10712/*
10713 * The getopts builtin. Shellparam.optnext points to the next argument
10714 * to be processed. Shellparam.optptr points to the next character to
10715 * be processed in the current argument. If shellparam.optnext is NULL,
10716 * then it's the first time getopts has been called.
10717 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010718static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000010719getoptscmd(int argc, char **argv)
10720{
10721 char **optbase;
10722
10723 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010724 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010725 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000010726 optbase = shellparam.p;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010727 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
Eric Andersenc470f442003-07-28 09:56:35 +000010728 shellparam.optind = 1;
10729 shellparam.optoff = -1;
10730 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010731 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010732 optbase = &argv[3];
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010733 if ((unsigned)shellparam.optind > argc - 2) {
Eric Andersenc470f442003-07-28 09:56:35 +000010734 shellparam.optind = 1;
10735 shellparam.optoff = -1;
10736 }
10737 }
10738
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010739 return getopts(argv[1], argv[2], optbase);
Eric Andersenc470f442003-07-28 09:56:35 +000010740}
Denis Vlasenko131ae172007-02-18 13:00:19 +000010741#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000010742
Eric Andersencb57d552001-06-28 07:25:16 +000010743
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010744/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000010745
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010746struct heredoc {
10747 struct heredoc *next; /* next here document in list */
10748 union node *here; /* redirection node */
10749 char *eofmark; /* string indicating end of input */
10750 smallint striptabs; /* if set, strip leading tabs */
10751};
10752
10753static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010754static smallint quoteflag; /* set if (part of) last token was quoted */
10755static token_id_t lasttoken; /* last token read (integer id Txxx) */
10756static struct heredoc *heredoclist; /* list of here documents to read */
10757static char *wordtext; /* text of last word returned by readtoken */
10758static struct nodelist *backquotelist;
10759static union node *redirnode;
10760static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010761
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010762static const char *
10763tokname(char *buf, int tok)
10764{
10765 if (tok < TSEMI)
Denys Vlasenko888527c2016-10-02 16:54:17 +020010766 return tokname_array[tok];
10767 sprintf(buf, "\"%s\"", tokname_array[tok]);
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010768 return buf;
10769}
10770
10771/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010772 * Called when an unexpected token is read during the parse. The argument
10773 * is the token that is expected, or -1 if more than one type of token can
10774 * occur at this point.
10775 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010776static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010777static void
10778raise_error_unexpected_syntax(int token)
10779{
10780 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010781 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010782 int l;
10783
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010784 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010785 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010786 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010787 raise_error_syntax(msg);
10788 /* NOTREACHED */
10789}
Eric Andersencb57d552001-06-28 07:25:16 +000010790
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010791#define EOFMARKLEN 79
Eric Andersencb57d552001-06-28 07:25:16 +000010792
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010793/* parsing is heavily cross-recursive, need these forward decls */
10794static union node *andor(void);
10795static union node *pipeline(void);
10796static union node *parse_command(void);
10797static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000010798static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010799static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000010800
Eric Andersenc470f442003-07-28 09:56:35 +000010801static union node *
10802list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000010803{
10804 union node *n1, *n2, *n3;
10805 int tok;
10806
Eric Andersencb57d552001-06-28 07:25:16 +000010807 n1 = NULL;
10808 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010809 switch (peektoken()) {
10810 case TNL:
10811 if (!(nlflag & 1))
10812 break;
10813 parseheredoc();
10814 return n1;
10815
10816 case TEOF:
10817 if (!n1 && (nlflag & 1))
10818 n1 = NODE_EOF;
10819 parseheredoc();
10820 return n1;
10821 }
10822
10823 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko888527c2016-10-02 16:54:17 +020010824 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
Ron Yorstonc0e00762015-10-29 11:30:55 +000010825 return n1;
10826 nlflag |= 2;
10827
Eric Andersencb57d552001-06-28 07:25:16 +000010828 n2 = andor();
10829 tok = readtoken();
10830 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000010831 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010832 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010833 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010834 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010835 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000010836 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010837 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010838 n2 = n3;
10839 }
10840 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000010841 }
10842 }
10843 if (n1 == NULL) {
10844 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010845 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010846 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010847 n3->type = NSEMI;
10848 n3->nbinary.ch1 = n1;
10849 n3->nbinary.ch2 = n2;
10850 n1 = n3;
10851 }
10852 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010853 case TNL:
10854 case TEOF:
10855 tokpushback = 1;
10856 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000010857 case TBACKGND:
10858 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000010859 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010860 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000010861 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010862 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010863 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010864 return n1;
10865 }
10866 }
10867}
10868
Eric Andersenc470f442003-07-28 09:56:35 +000010869static union node *
10870andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010871{
Eric Andersencb57d552001-06-28 07:25:16 +000010872 union node *n1, *n2, *n3;
10873 int t;
10874
Eric Andersencb57d552001-06-28 07:25:16 +000010875 n1 = pipeline();
10876 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010877 t = readtoken();
10878 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000010879 t = NAND;
10880 } else if (t == TOR) {
10881 t = NOR;
10882 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010883 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010884 return n1;
10885 }
Eric Andersenc470f442003-07-28 09:56:35 +000010886 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010887 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010888 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010889 n3->type = t;
10890 n3->nbinary.ch1 = n1;
10891 n3->nbinary.ch2 = n2;
10892 n1 = n3;
10893 }
10894}
10895
Eric Andersenc470f442003-07-28 09:56:35 +000010896static union node *
10897pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010898{
Eric Andersencb57d552001-06-28 07:25:16 +000010899 union node *n1, *n2, *pipenode;
10900 struct nodelist *lp, *prev;
10901 int negate;
10902
10903 negate = 0;
10904 TRACE(("pipeline: entered\n"));
10905 if (readtoken() == TNOT) {
10906 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000010907 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010908 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010909 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010910 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010911 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010912 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000010913 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010914 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010915 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000010916 pipenode->npipe.cmdlist = lp;
10917 lp->n = n1;
10918 do {
10919 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010920 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000010921 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010922 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010923 prev->next = lp;
10924 } while (readtoken() == TPIPE);
10925 lp->next = NULL;
10926 n1 = pipenode;
10927 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010928 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010929 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010930 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000010931 n2->type = NNOT;
10932 n2->nnot.com = n1;
10933 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010934 }
10935 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000010936}
10937
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010938static union node *
10939makename(void)
10940{
10941 union node *n;
10942
Denis Vlasenko597906c2008-02-20 16:38:54 +000010943 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010944 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010945 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010946 n->narg.text = wordtext;
10947 n->narg.backquote = backquotelist;
10948 return n;
10949}
10950
10951static void
10952fixredir(union node *n, const char *text, int err)
10953{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010954 int fd;
10955
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010956 TRACE(("Fix redir %s %d\n", text, err));
10957 if (!err)
10958 n->ndup.vname = NULL;
10959
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010960 fd = bb_strtou(text, NULL, 10);
10961 if (!errno && fd >= 0)
10962 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010963 else if (LONE_DASH(text))
10964 n->ndup.dupfd = -1;
10965 else {
10966 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010967 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010968 n->ndup.vname = makename();
10969 }
10970}
10971
10972/*
10973 * Returns true if the text contains nothing to expand (no dollar signs
10974 * or backquotes).
10975 */
10976static int
Denis Vlasenko68819d12008-12-15 11:26:36 +000010977noexpand(const char *text)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010978{
Denys Vlasenkocd716832009-11-28 22:14:02 +010010979 unsigned char c;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010980
Denys Vlasenkocd716832009-11-28 22:14:02 +010010981 while ((c = *text++) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010982 if (c == CTLQUOTEMARK)
10983 continue;
10984 if (c == CTLESC)
Denys Vlasenkocd716832009-11-28 22:14:02 +010010985 text++;
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010010986 else if (SIT(c, BASESYNTAX) == CCTL)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010987 return 0;
10988 }
10989 return 1;
10990}
10991
10992static void
10993parsefname(void)
10994{
10995 union node *n = redirnode;
10996
10997 if (readtoken() != TWORD)
10998 raise_error_unexpected_syntax(-1);
10999 if (n->type == NHERE) {
11000 struct heredoc *here = heredoc;
11001 struct heredoc *p;
11002 int i;
11003
11004 if (quoteflag == 0)
11005 n->type = NXHERE;
11006 TRACE(("Here document %d\n", n->type));
11007 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011008 raise_error_syntax("illegal eof marker for << redirection");
Denys Vlasenkob6c84342009-08-29 20:23:20 +020011009 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011010 here->eofmark = wordtext;
11011 here->next = NULL;
11012 if (heredoclist == NULL)
11013 heredoclist = here;
11014 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011015 for (p = heredoclist; p->next; p = p->next)
11016 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011017 p->next = here;
11018 }
11019 } else if (n->type == NTOFD || n->type == NFROMFD) {
11020 fixredir(n, wordtext, 0);
11021 } else {
11022 n->nfile.fname = makename();
11023 }
11024}
Eric Andersencb57d552001-06-28 07:25:16 +000011025
Eric Andersenc470f442003-07-28 09:56:35 +000011026static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011027simplecmd(void)
11028{
11029 union node *args, **app;
11030 union node *n = NULL;
11031 union node *vars, **vpp;
11032 union node **rpp, *redir;
11033 int savecheckkwd;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011034#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011035 smallint double_brackets_flag = 0;
11036#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011037 IF_BASH_FUNCTION(smallint function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011038
11039 args = NULL;
11040 app = &args;
11041 vars = NULL;
11042 vpp = &vars;
11043 redir = NULL;
11044 rpp = &redir;
11045
11046 savecheckkwd = CHKALIAS;
11047 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000011048 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011049 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011050 t = readtoken();
11051 switch (t) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011052#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011053 case TFUNCTION:
11054 if (peektoken() != TWORD)
11055 raise_error_unexpected_syntax(TWORD);
11056 function_flag = 1;
11057 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011058#endif
11059#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011060 case TAND: /* "&&" */
11061 case TOR: /* "||" */
11062 if (!double_brackets_flag) {
11063 tokpushback = 1;
11064 goto out;
11065 }
11066 wordtext = (char *) (t == TAND ? "-a" : "-o");
11067#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011068 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011069 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011070 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011071 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011072 n->narg.text = wordtext;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011073#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011074 if (strcmp("[[", wordtext) == 0)
11075 double_brackets_flag = 1;
11076 else if (strcmp("]]", wordtext) == 0)
11077 double_brackets_flag = 0;
11078#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011079 n->narg.backquote = backquotelist;
11080 if (savecheckkwd && isassignment(wordtext)) {
11081 *vpp = n;
11082 vpp = &n->narg.next;
11083 } else {
11084 *app = n;
11085 app = &n->narg.next;
11086 savecheckkwd = 0;
11087 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011088#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011089 if (function_flag) {
11090 checkkwd = CHKNL | CHKKWD;
11091 switch (peektoken()) {
11092 case TBEGIN:
11093 case TIF:
11094 case TCASE:
11095 case TUNTIL:
11096 case TWHILE:
11097 case TFOR:
11098 goto do_func;
11099 case TLP:
11100 function_flag = 0;
11101 break;
11102 case TWORD:
11103 if (strcmp("[[", wordtext) == 0)
11104 goto do_func;
11105 /* fall through */
11106 default:
11107 raise_error_unexpected_syntax(-1);
11108 }
11109 }
11110#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011111 break;
11112 case TREDIR:
11113 *rpp = n = redirnode;
11114 rpp = &n->nfile.next;
11115 parsefname(); /* read name of redirection file */
11116 break;
11117 case TLP:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011118 IF_BASH_FUNCTION(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011119 if (args && app == &args->narg.next
11120 && !vars && !redir
11121 ) {
11122 struct builtincmd *bcmd;
11123 const char *name;
11124
11125 /* We have a function */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011126 if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011127 raise_error_unexpected_syntax(TRP);
11128 name = n->narg.text;
11129 if (!goodname(name)
11130 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11131 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011132 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011133 }
11134 n->type = NDEFUN;
11135 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11136 n->narg.next = parse_command();
11137 return n;
11138 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011139 IF_BASH_FUNCTION(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011140 /* fall through */
11141 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011142 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011143 goto out;
11144 }
11145 }
11146 out:
11147 *app = NULL;
11148 *vpp = NULL;
11149 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011150 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011151 n->type = NCMD;
11152 n->ncmd.args = args;
11153 n->ncmd.assign = vars;
11154 n->ncmd.redirect = redir;
11155 return n;
11156}
11157
11158static union node *
11159parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011160{
Eric Andersencb57d552001-06-28 07:25:16 +000011161 union node *n1, *n2;
11162 union node *ap, **app;
11163 union node *cp, **cpp;
11164 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011165 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011166 int t;
11167
11168 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011169 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011170
Eric Andersencb57d552001-06-28 07:25:16 +000011171 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011172 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011173 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011174 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011175 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011176 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011177 n1->type = NIF;
11178 n1->nif.test = list(0);
11179 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011180 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011181 n1->nif.ifpart = list(0);
11182 n2 = n1;
11183 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011184 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011185 n2 = n2->nif.elsepart;
11186 n2->type = NIF;
11187 n2->nif.test = list(0);
11188 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011189 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011190 n2->nif.ifpart = list(0);
11191 }
11192 if (lasttoken == TELSE)
11193 n2->nif.elsepart = list(0);
11194 else {
11195 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011196 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011197 }
Eric Andersenc470f442003-07-28 09:56:35 +000011198 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011199 break;
11200 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011201 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011202 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011203 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011204 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011205 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011206 got = readtoken();
11207 if (got != TDO) {
Denys Vlasenko888527c2016-10-02 16:54:17 +020011208 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
Denis Vlasenko131ae172007-02-18 13:00:19 +000011209 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011210 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011211 }
11212 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011213 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011214 break;
11215 }
11216 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011217 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011218 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011219 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011220 n1->type = NFOR;
11221 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011222 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011223 if (readtoken() == TIN) {
11224 app = &ap;
11225 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011226 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011227 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011228 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011229 n2->narg.text = wordtext;
11230 n2->narg.backquote = backquotelist;
11231 *app = n2;
11232 app = &n2->narg.next;
11233 }
11234 *app = NULL;
11235 n1->nfor.args = ap;
11236 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011237 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011238 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011239 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011240 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011241 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011242 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011243 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011244 n1->nfor.args = n2;
11245 /*
11246 * Newline or semicolon here is optional (but note
11247 * that the original Bourne shell only allowed NL).
11248 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011249 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011250 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011251 }
Eric Andersenc470f442003-07-28 09:56:35 +000011252 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011253 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011254 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011255 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011256 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011257 break;
11258 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011259 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011260 n1->type = NCASE;
11261 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011262 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011263 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011264 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011265 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011266 n2->narg.text = wordtext;
11267 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011268 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11269 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011270 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011271 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011272 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011273 checkkwd = CHKNL | CHKKWD;
11274 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011275 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011276 if (lasttoken == TLP)
11277 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011278 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011279 cp->type = NCLIST;
11280 app = &cp->nclist.pattern;
11281 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011282 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011283 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011284 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011285 ap->narg.text = wordtext;
11286 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011287 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011288 break;
11289 app = &ap->narg.next;
11290 readtoken();
11291 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011292 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011293 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011294 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011295 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011296
Eric Andersenc470f442003-07-28 09:56:35 +000011297 cpp = &cp->nclist.next;
11298
11299 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011300 t = readtoken();
11301 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011302 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011303 raise_error_unexpected_syntax(TENDCASE);
11304 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011305 }
Eric Andersenc470f442003-07-28 09:56:35 +000011306 }
Eric Andersencb57d552001-06-28 07:25:16 +000011307 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011308 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011309 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011310 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011311 n1->type = NSUBSHELL;
11312 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011313 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011314 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011315 break;
11316 case TBEGIN:
11317 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011318 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011319 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011320 IF_BASH_FUNCTION(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011321 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011322 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011323 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011324 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011325 }
11326
Eric Andersenc470f442003-07-28 09:56:35 +000011327 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011328 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011329
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011330 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011331 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011332 checkkwd = CHKKWD | CHKALIAS;
11333 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011334 while (readtoken() == TREDIR) {
11335 *rpp = n2 = redirnode;
11336 rpp = &n2->nfile.next;
11337 parsefname();
11338 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011339 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011340 *rpp = NULL;
11341 if (redir) {
11342 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011343 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011344 n2->type = NREDIR;
11345 n2->nredir.n = n1;
11346 n1 = n2;
11347 }
11348 n1->nredir.redirect = redir;
11349 }
Eric Andersencb57d552001-06-28 07:25:16 +000011350 return n1;
11351}
11352
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011353#if BASH_DOLLAR_SQUOTE
Denys Vlasenko37dc08b2016-10-02 04:38:07 +020011354static int
11355decode_dollar_squote(void)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011356{
11357 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11358 int c, cnt;
11359 char *p;
11360 char buf[4];
11361
11362 c = pgetc();
11363 p = strchr(C_escapes, c);
11364 if (p) {
11365 buf[0] = c;
11366 p = buf;
11367 cnt = 3;
11368 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11369 do {
11370 c = pgetc();
11371 *++p = c;
11372 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11373 pungetc();
11374 } else if (c == 'x') { /* \xHH */
11375 do {
11376 c = pgetc();
11377 *++p = c;
11378 } while (isxdigit(c) && --cnt);
11379 pungetc();
11380 if (cnt == 3) { /* \x but next char is "bad" */
11381 c = 'x';
11382 goto unrecognized;
11383 }
11384 } else { /* simple seq like \\ or \t */
11385 p++;
11386 }
11387 *p = '\0';
11388 p = buf;
11389 c = bb_process_escape_sequence((void*)&p);
11390 } else { /* unrecognized "\z": print both chars unless ' or " */
11391 if (c != '\'' && c != '"') {
11392 unrecognized:
11393 c |= 0x100; /* "please encode \, then me" */
11394 }
11395 }
11396 return c;
11397}
11398#endif
11399
Eric Andersencb57d552001-06-28 07:25:16 +000011400/*
11401 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11402 * is not NULL, read a here document. In the latter case, eofmark is the
11403 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011404 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011405 * is the first character of the input token or document.
11406 *
11407 * Because C does not have internal subroutines, I have simulated them
11408 * using goto's to implement the subroutine linkage. The following macros
11409 * will run code that appears at the end of readtoken1.
11410 */
Eric Andersen2870d962001-07-02 17:27:21 +000011411#define CHECKEND() {goto checkend; checkend_return:;}
11412#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11413#define PARSESUB() {goto parsesub; parsesub_return:;}
11414#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11415#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11416#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011417static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011418readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011419{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011420 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011421 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011422 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020011423 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +000011424 char line[EOFMARKLEN + 1];
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011425 struct nodelist *bqlist;
11426 smallint quotef;
11427 smallint dblquote;
11428 smallint oldstyle;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011429 IF_FEATURE_SH_MATH(smallint prevsyntax;) /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011430#if ENABLE_ASH_EXPAND_PRMT
11431 smallint pssyntax; /* we are expanding a prompt string */
11432#endif
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011433 int varnest; /* levels of variables expansion */
Denys Vlasenko0b883582016-12-23 16:49:07 +010011434 IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */
11435 IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011436 int dqvarnest; /* levels of variables expansion within double quotes */
11437
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011438 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011439
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011440 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011441 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011442 quotef = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011443 IF_FEATURE_SH_MATH(prevsyntax = 0;)
Denis Vlasenko46a53062007-09-24 18:30:02 +000011444#if ENABLE_ASH_EXPAND_PRMT
11445 pssyntax = (syntax == PSSYNTAX);
11446 if (pssyntax)
11447 syntax = DQSYNTAX;
11448#endif
11449 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011450 varnest = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011451 IF_FEATURE_SH_MATH(arinest = 0;)
11452 IF_FEATURE_SH_MATH(parenlevel = 0;)
Eric Andersencb57d552001-06-28 07:25:16 +000011453 dqvarnest = 0;
11454
11455 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011456 loop:
11457 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011458 CHECKEND(); /* set c to PEOF if at end of here document */
11459 for (;;) { /* until end of line or end of word */
11460 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11461 switch (SIT(c, syntax)) {
11462 case CNL: /* '\n' */
11463 if (syntax == BASESYNTAX)
11464 goto endword; /* exit outer loop */
11465 USTPUTC(c, out);
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011466 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011467 c = pgetc();
11468 goto loop; /* continue outer loop */
11469 case CWORD:
11470 USTPUTC(c, out);
11471 break;
11472 case CCTL:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011473#if BASH_DOLLAR_SQUOTE
Denys Vlasenko958581a2010-09-12 15:04:27 +020011474 if (c == '\\' && bash_dollar_squote) {
11475 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020011476 if (c == '\0') {
11477 /* skip $'\000', $'\x00' (like bash) */
11478 break;
11479 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011480 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020011481 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011482 c = (unsigned char)c;
Denys Vlasenko13f20912016-09-25 20:54:25 +020011483 if (eofmark == NULL || dblquote)
11484 USTPUTC(CTLESC, out);
11485 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011486 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011487 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011488#endif
Denys Vlasenko13f20912016-09-25 20:54:25 +020011489 if (eofmark == NULL || dblquote)
11490 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011491 USTPUTC(c, out);
11492 break;
11493 case CBACK: /* backslash */
11494 c = pgetc_without_PEOA();
11495 if (c == PEOF) {
11496 USTPUTC(CTLESC, out);
11497 USTPUTC('\\', out);
11498 pungetc();
11499 } else if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011500 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011501 } else {
11502#if ENABLE_ASH_EXPAND_PRMT
11503 if (c == '$' && pssyntax) {
Eric Andersenc470f442003-07-28 09:56:35 +000011504 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011505 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011506 }
Denis Vlasenko46a53062007-09-24 18:30:02 +000011507#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011508 /* Backslash is retained if we are in "str" and next char isn't special */
11509 if (dblquote
11510 && c != '\\'
11511 && c != '`'
11512 && c != '$'
11513 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011514 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011515 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011516 }
Ron Yorston549deab2015-05-18 09:57:51 +020011517 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011518 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011519 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011520 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011521 break;
11522 case CSQUOTE:
11523 syntax = SQSYNTAX;
11524 quotemark:
11525 if (eofmark == NULL) {
11526 USTPUTC(CTLQUOTEMARK, out);
11527 }
11528 break;
11529 case CDQUOTE:
11530 syntax = DQSYNTAX;
11531 dblquote = 1;
11532 goto quotemark;
11533 case CENDQUOTE:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011534 IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020011535 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011536 USTPUTC(c, out);
11537 } else {
11538 if (dqvarnest == 0) {
11539 syntax = BASESYNTAX;
11540 dblquote = 0;
11541 }
11542 quotef = 1;
11543 goto quotemark;
11544 }
11545 break;
11546 case CVAR: /* '$' */
11547 PARSESUB(); /* parse substitution */
11548 break;
11549 case CENDVAR: /* '}' */
11550 if (varnest > 0) {
11551 varnest--;
11552 if (dqvarnest > 0) {
11553 dqvarnest--;
11554 }
11555 c = CTLENDVAR;
11556 }
11557 USTPUTC(c, out);
11558 break;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011559#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko958581a2010-09-12 15:04:27 +020011560 case CLP: /* '(' in arithmetic */
11561 parenlevel++;
11562 USTPUTC(c, out);
11563 break;
11564 case CRP: /* ')' in arithmetic */
11565 if (parenlevel > 0) {
11566 parenlevel--;
11567 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011568 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020011569 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011570 if (--arinest == 0) {
11571 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011572 }
11573 } else {
11574 /*
11575 * unbalanced parens
11576 * (don't 2nd guess - no error)
11577 */
11578 pungetc();
11579 }
11580 }
11581 USTPUTC(c, out);
11582 break;
11583#endif
11584 case CBQUOTE: /* '`' */
11585 PARSEBACKQOLD();
11586 break;
11587 case CENDFILE:
11588 goto endword; /* exit outer loop */
11589 case CIGN:
11590 break;
11591 default:
11592 if (varnest == 0) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011593#if BASH_REDIR_OUTPUT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011594 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011595//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020011596 if (pgetc() == '>')
11597 c = 0x100 + '>'; /* flag &> */
11598 pungetc();
11599 }
11600#endif
11601 goto endword; /* exit outer loop */
11602 }
11603 IF_ASH_ALIAS(if (c != PEOA))
11604 USTPUTC(c, out);
11605 }
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020011606 c = pgetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011607 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011608 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011609
Denys Vlasenko0b883582016-12-23 16:49:07 +010011610#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000011611 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011612 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011613#endif
Ron Yorston0e056f72015-07-01 16:45:40 +010011614 if (syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011615 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011616 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011617 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011618 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011619 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011620 }
11621 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011622 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011623 out = stackblock();
11624 if (eofmark == NULL) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011625 if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011626 && quotef == 0
11627 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011628 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011629 PARSEREDIR(); /* passed as params: out, c */
11630 lasttoken = TREDIR;
11631 return lasttoken;
11632 }
11633 /* else: non-number X seen, interpret it
11634 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011635 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011636 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011637 }
11638 quoteflag = quotef;
11639 backquotelist = bqlist;
11640 grabstackblock(len);
11641 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011642 lasttoken = TWORD;
11643 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011644/* end of readtoken routine */
11645
Eric Andersencb57d552001-06-28 07:25:16 +000011646/*
11647 * Check to see whether we are at the end of the here document. When this
11648 * is called, c is set to the first character of the next input line. If
11649 * we are at the end of the here document, this routine sets the c to PEOF.
11650 */
Eric Andersenc470f442003-07-28 09:56:35 +000011651checkend: {
11652 if (eofmark) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000011653#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011654 if (c == PEOA)
11655 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011656#endif
11657 if (striptabs) {
11658 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011659 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011660 }
Eric Andersenc470f442003-07-28 09:56:35 +000011661 }
11662 if (c == *eofmark) {
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011663 if (pfgets(line, sizeof(line)) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000011664 char *p, *q;
Denys Vlasenko350e6862016-10-26 16:26:45 +020011665 int cc;
Eric Andersencb57d552001-06-28 07:25:16 +000011666
Eric Andersenc470f442003-07-28 09:56:35 +000011667 p = line;
Denys Vlasenko350e6862016-10-26 16:26:45 +020011668 for (q = eofmark + 1;; p++, q++) {
11669 cc = *p;
11670 if (cc == '\n')
11671 cc = 0;
11672 if (!*q || cc != *q)
11673 break;
11674 }
11675 if (cc == *q) {
Eric Andersenc470f442003-07-28 09:56:35 +000011676 c = PEOF;
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011677 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011678 } else {
11679 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011680 }
11681 }
11682 }
11683 }
Eric Andersenc470f442003-07-28 09:56:35 +000011684 goto checkend_return;
11685}
Eric Andersencb57d552001-06-28 07:25:16 +000011686
Eric Andersencb57d552001-06-28 07:25:16 +000011687/*
11688 * Parse a redirection operator. The variable "out" points to a string
11689 * specifying the fd to be redirected. The variable "c" contains the
11690 * first character of the redirection operator.
11691 */
Eric Andersenc470f442003-07-28 09:56:35 +000011692parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011693 /* out is already checked to be a valid number or "" */
11694 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000011695 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000011696
Denis Vlasenko597906c2008-02-20 16:38:54 +000011697 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000011698 if (c == '>') {
11699 np->nfile.fd = 1;
11700 c = pgetc();
11701 if (c == '>')
11702 np->type = NAPPEND;
11703 else if (c == '|')
11704 np->type = NCLOBBER;
11705 else if (c == '&')
11706 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011707 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000011708 else {
11709 np->type = NTO;
11710 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011711 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000011712 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011713#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000011714 else if (c == 0x100 + '>') { /* this flags &> redirection */
11715 np->nfile.fd = 1;
11716 pgetc(); /* this is '>', no need to check */
11717 np->type = NTO2;
11718 }
11719#endif
11720 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000011721 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011722 c = pgetc();
11723 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000011724 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011725 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011726 np = stzalloc(sizeof(struct nhere));
11727 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011728 }
11729 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011730 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000011731 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011732 c = pgetc();
11733 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000011734 heredoc->striptabs = 1;
11735 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011736 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011737 pungetc();
11738 }
11739 break;
11740
11741 case '&':
11742 np->type = NFROMFD;
11743 break;
11744
11745 case '>':
11746 np->type = NFROMTO;
11747 break;
11748
11749 default:
11750 np->type = NFROM;
11751 pungetc();
11752 break;
11753 }
Eric Andersencb57d552001-06-28 07:25:16 +000011754 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011755 if (fd >= 0)
11756 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011757 redirnode = np;
11758 goto parseredir_return;
11759}
Eric Andersencb57d552001-06-28 07:25:16 +000011760
Eric Andersencb57d552001-06-28 07:25:16 +000011761/*
11762 * Parse a substitution. At this point, we have read the dollar sign
11763 * and nothing else.
11764 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000011765
11766/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11767 * (assuming ascii char codes, as the original implementation did) */
11768#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011769 (((unsigned)(c) - 33 < 32) \
11770 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000011771parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010011772 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011773 int typeloc;
Eric Andersencb57d552001-06-28 07:25:16 +000011774
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011775 c = pgetc_eatbnl();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011776 if (c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011777 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000011778 ) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011779#if BASH_DOLLAR_SQUOTE
Ron Yorston84ba50c2016-04-03 22:43:14 +010011780 if (syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011781 bash_dollar_squote = 1;
11782 else
11783#endif
11784 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011785 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011786 } else if (c == '(') {
11787 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011788 if (pgetc_eatbnl() == '(') {
Denys Vlasenko0b883582016-12-23 16:49:07 +010011789#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000011790 PARSEARITH();
11791#else
Mike Frysinger98a6f562008-06-09 09:38:45 +000011792 raise_error_syntax("you disabled math support for $((arith)) syntax");
Eric Andersenc470f442003-07-28 09:56:35 +000011793#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011794 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011795 pungetc();
11796 PARSEBACKQNEW();
11797 }
11798 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011799 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000011800 USTPUTC(CTLVAR, out);
11801 typeloc = out - (char *)stackblock();
Denys Vlasenko3df14102016-10-26 16:41:13 +020011802 STADJUST(1, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011803 subtype = VSNORMAL;
11804 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011805 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011806 subtype = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011807 }
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011808 varname:
Denys Vlasenko3df14102016-10-26 16:41:13 +020011809 if (is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011810 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011811 do {
11812 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011813 c = pgetc_eatbnl();
Denys Vlasenko3df14102016-10-26 16:41:13 +020011814 } while (is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011815 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011816 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011817 do {
11818 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011819 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011820 } while (isdigit(c));
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011821 } else if (is_special(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011822 /* $[{[#]]<specialchar>[}] */
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011823 int cc = c;
11824
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011825 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011826 if (!subtype && cc == '#') {
11827 subtype = VSLENGTH;
11828 if (c == '_' || isalnum(c))
11829 goto varname;
11830 cc = c;
11831 c = pgetc_eatbnl();
11832 if (cc == '}' || c != '}') {
11833 pungetc();
11834 subtype = 0;
11835 c = cc;
11836 cc = '#';
11837 }
11838 }
11839 USTPUTC(cc, out);
Denis Vlasenko559691a2008-10-05 18:39:31 +000011840 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020011841 goto badsub;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011842 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011843 if (c != '}' && subtype == VSLENGTH) {
11844 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020011845 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011846 }
Eric Andersencb57d552001-06-28 07:25:16 +000011847
Eric Andersenc470f442003-07-28 09:56:35 +000011848 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011849 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011850 /* ${VAR...} but not $VAR or ${#VAR} */
11851 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000011852 switch (c) {
11853 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011854 c = pgetc_eatbnl();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011855#if BASH_SUBSTR
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011856 /* This check is only needed to not misinterpret
11857 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
11858 * constructs.
11859 */
11860 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011861 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011862 pungetc();
Denys Vlasenko88e15702016-10-26 01:55:56 +020011863 break; /* "goto badsub" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011864 }
11865#endif
Denys Vlasenko3df14102016-10-26 16:41:13 +020011866 subtype = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000011867 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011868 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011869 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000011870 if (p == NULL)
Denys Vlasenko88e15702016-10-26 01:55:56 +020011871 break;
Denys Vlasenko3df14102016-10-26 16:41:13 +020011872 subtype |= p - types + VSNORMAL;
Eric Andersenc470f442003-07-28 09:56:35 +000011873 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011874 }
Eric Andersenc470f442003-07-28 09:56:35 +000011875 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011876 case '#': {
11877 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011878 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011879 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011880 if (c != cc)
Denys Vlasenko88e15702016-10-26 01:55:56 +020011881 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011882 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011883 break;
11884 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011885#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011886 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011887 /* ${v/[/]pattern/repl} */
11888//TODO: encode pattern and repl separately.
11889// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011890 subtype = VSREPLACE;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011891 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011892 if (c != '/')
Denys Vlasenko88e15702016-10-26 01:55:56 +020011893 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011894 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011895 break;
11896#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011897 }
Eric Andersenc470f442003-07-28 09:56:35 +000011898 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020011899 badsub:
Eric Andersenc470f442003-07-28 09:56:35 +000011900 pungetc();
11901 }
Denys Vlasenko3df14102016-10-26 16:41:13 +020011902 ((unsigned char *)stackblock())[typeloc] = subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011903 if (subtype != VSNORMAL) {
11904 varnest++;
Denys Vlasenko3df14102016-10-26 16:41:13 +020011905 if (dblquote)
Eric Andersenc470f442003-07-28 09:56:35 +000011906 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000011907 }
Denys Vlasenko88e15702016-10-26 01:55:56 +020011908 STPUTC('=', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011909 }
Eric Andersenc470f442003-07-28 09:56:35 +000011910 goto parsesub_return;
11911}
Eric Andersencb57d552001-06-28 07:25:16 +000011912
Eric Andersencb57d552001-06-28 07:25:16 +000011913/*
11914 * Called to parse command substitutions. Newstyle is set if the command
11915 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11916 * list of commands (passed by reference), and savelen is the number of
11917 * characters on the top of the stack which must be preserved.
11918 */
Eric Andersenc470f442003-07-28 09:56:35 +000011919parsebackq: {
11920 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011921 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010011922 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000011923 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011924 smallint saveprompt = 0;
11925
Eric Andersenc470f442003-07-28 09:56:35 +000011926 str = NULL;
11927 savelen = out - (char *)stackblock();
11928 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011929 /*
11930 * FIXME: this can allocate very large block on stack and SEGV.
11931 * Example:
11932 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020011933 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011934 * a hundred command substitutions stack overflows.
11935 * With larger prepended string, SEGV happens sooner.
11936 */
Ron Yorston072fc602015-07-01 16:46:18 +010011937 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000011938 memcpy(str, stackblock(), savelen);
11939 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011940
Eric Andersenc470f442003-07-28 09:56:35 +000011941 if (oldstyle) {
11942 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010011943 * treatment to some slashes, and then push the string and
11944 * reread it as input, interpreting it normally.
11945 */
Eric Andersenc470f442003-07-28 09:56:35 +000011946 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000011947 size_t psavelen;
11948 char *pstr;
11949
Eric Andersenc470f442003-07-28 09:56:35 +000011950 STARTSTACKSTR(pout);
11951 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011952 int pc;
11953
11954 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011955 pc = pgetc();
11956 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000011957 case '`':
11958 goto done;
11959
11960 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011961 pc = pgetc();
11962 if (pc == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011963 nlprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011964 /*
11965 * If eating a newline, avoid putting
11966 * the newline into the new character
11967 * stream (via the STPUTC after the
11968 * switch).
11969 */
11970 continue;
11971 }
11972 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011973 && (!dblquote || pc != '"')
11974 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000011975 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011976 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011977 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000011978 break;
11979 }
11980 /* fall through */
11981
11982 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011983 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011984 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011985 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000011986
11987 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011988 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011989 break;
11990
11991 default:
11992 break;
11993 }
11994 STPUTC(pc, pout);
11995 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011996 done:
Eric Andersenc470f442003-07-28 09:56:35 +000011997 STPUTC('\0', pout);
11998 psavelen = pout - (char *)stackblock();
11999 if (psavelen > 0) {
12000 pstr = grabstackstr(pout);
12001 setinputstring(pstr);
12002 }
12003 }
12004 nlpp = &bqlist;
12005 while (*nlpp)
12006 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012007 *nlpp = stzalloc(sizeof(**nlpp));
12008 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012009
12010 if (oldstyle) {
12011 saveprompt = doprompt;
12012 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012013 }
12014
Eric Andersenc470f442003-07-28 09:56:35 +000012015 n = list(2);
12016
12017 if (oldstyle)
12018 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012019 else if (readtoken() != TRP)
12020 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000012021
12022 (*nlpp)->n = n;
12023 if (oldstyle) {
12024 /*
12025 * Start reading from old file again, ignoring any pushed back
12026 * tokens left from the backquote parsing
12027 */
12028 popfile();
12029 tokpushback = 0;
12030 }
12031 while (stackblocksize() <= savelen)
12032 growstackblock();
12033 STARTSTACKSTR(out);
12034 if (str) {
12035 memcpy(out, str, savelen);
12036 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012037 }
Ron Yorston549deab2015-05-18 09:57:51 +020012038 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012039 if (oldstyle)
12040 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012041 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000012042}
12043
Denys Vlasenko0b883582016-12-23 16:49:07 +010012044#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000012045/*
12046 * Parse an arithmetic expansion (indicate start of one and set state)
12047 */
Eric Andersenc470f442003-07-28 09:56:35 +000012048parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000012049 if (++arinest == 1) {
12050 prevsyntax = syntax;
12051 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000012052 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020012053 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012054 goto parsearith_return;
12055}
12056#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012057} /* end of readtoken */
12058
Eric Andersencb57d552001-06-28 07:25:16 +000012059/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012060 * Read the next input token.
12061 * If the token is a word, we set backquotelist to the list of cmds in
12062 * backquotes. We set quoteflag to true if any part of the word was
12063 * quoted.
12064 * If the token is TREDIR, then we set redirnode to a structure containing
12065 * the redirection.
12066 * In all cases, the variable startlinno is set to the number of the line
12067 * on which the token starts.
12068 *
12069 * [Change comment: here documents and internal procedures]
12070 * [Readtoken shouldn't have any arguments. Perhaps we should make the
12071 * word parsing code into a separate routine. In this case, readtoken
12072 * doesn't need to have any internal procedures, but parseword does.
12073 * We could also make parseoperator in essence the main routine, and
12074 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000012075 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012076#define NEW_xxreadtoken
12077#ifdef NEW_xxreadtoken
12078/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012079static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000012080 '\n', '(', ')', /* singles */
12081 '&', '|', ';', /* doubles */
12082 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012083};
Eric Andersencb57d552001-06-28 07:25:16 +000012084
Denis Vlasenko834dee72008-10-07 09:18:30 +000012085#define xxreadtoken_singles 3
12086#define xxreadtoken_doubles 3
12087
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012088static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012089 TNL, TLP, TRP, /* only single occurrence allowed */
12090 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12091 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012092 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012093};
12094
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012095static int
12096xxreadtoken(void)
12097{
12098 int c;
12099
12100 if (tokpushback) {
12101 tokpushback = 0;
12102 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012103 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012104 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012105 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012106 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012107 c = pgetc();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000012108 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012109 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012110
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012111 if (c == '#') {
12112 while ((c = pgetc()) != '\n' && c != PEOF)
12113 continue;
12114 pungetc();
12115 } else if (c == '\\') {
12116 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012117 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012118 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012119 }
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012120 nlprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012121 } else {
12122 const char *p;
12123
12124 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12125 if (c != PEOF) {
12126 if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012127 nlnoprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012128 }
12129
12130 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000012131 if (p == NULL)
12132 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012133
Denis Vlasenko834dee72008-10-07 09:18:30 +000012134 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12135 int cc = pgetc();
12136 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012137 p += xxreadtoken_doubles + 1;
12138 } else {
12139 pungetc();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012140#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012141 if (c == '&' && cc == '>') /* &> */
12142 break; /* return readtoken1(...) */
12143#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012144 }
12145 }
12146 }
12147 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12148 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012149 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012150 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012151
12152 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012153}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012154#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012155#define RETURN(token) return lasttoken = token
12156static int
12157xxreadtoken(void)
12158{
12159 int c;
12160
12161 if (tokpushback) {
12162 tokpushback = 0;
12163 return lasttoken;
12164 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012165 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012166 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012167 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012168 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012169 switch (c) {
12170 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012171 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012172 continue;
12173 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012174 while ((c = pgetc()) != '\n' && c != PEOF)
12175 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012176 pungetc();
12177 continue;
12178 case '\\':
12179 if (pgetc() == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012180 nlprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012181 continue;
12182 }
12183 pungetc();
12184 goto breakloop;
12185 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012186 nlnoprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012187 RETURN(TNL);
12188 case PEOF:
12189 RETURN(TEOF);
12190 case '&':
12191 if (pgetc() == '&')
12192 RETURN(TAND);
12193 pungetc();
12194 RETURN(TBACKGND);
12195 case '|':
12196 if (pgetc() == '|')
12197 RETURN(TOR);
12198 pungetc();
12199 RETURN(TPIPE);
12200 case ';':
12201 if (pgetc() == ';')
12202 RETURN(TENDCASE);
12203 pungetc();
12204 RETURN(TSEMI);
12205 case '(':
12206 RETURN(TLP);
12207 case ')':
12208 RETURN(TRP);
12209 default:
12210 goto breakloop;
12211 }
12212 }
12213 breakloop:
12214 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12215#undef RETURN
12216}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012217#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012218
12219static int
12220readtoken(void)
12221{
12222 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012223 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012224#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012225 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012226#endif
12227
12228#if ENABLE_ASH_ALIAS
12229 top:
12230#endif
12231
12232 t = xxreadtoken();
12233
12234 /*
12235 * eat newlines
12236 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012237 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012238 while (t == TNL) {
12239 parseheredoc();
12240 t = xxreadtoken();
12241 }
12242 }
12243
12244 if (t != TWORD || quoteflag) {
12245 goto out;
12246 }
12247
12248 /*
12249 * check for keywords
12250 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012251 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012252 const char *const *pp;
12253
12254 pp = findkwd(wordtext);
12255 if (pp) {
12256 lasttoken = t = pp - tokname_array;
Denys Vlasenko888527c2016-10-02 16:54:17 +020012257 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012258 goto out;
12259 }
12260 }
12261
12262 if (checkkwd & CHKALIAS) {
12263#if ENABLE_ASH_ALIAS
12264 struct alias *ap;
12265 ap = lookupalias(wordtext, 1);
12266 if (ap != NULL) {
12267 if (*ap->val) {
12268 pushstring(ap->val, ap);
12269 }
12270 goto top;
12271 }
12272#endif
12273 }
12274 out:
12275 checkkwd = 0;
12276#if DEBUG
12277 if (!alreadyseen)
Denys Vlasenko888527c2016-10-02 16:54:17 +020012278 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012279 else
Denys Vlasenko888527c2016-10-02 16:54:17 +020012280 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012281#endif
12282 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012283}
12284
Ron Yorstonc0e00762015-10-29 11:30:55 +000012285static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012286peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012287{
12288 int t;
12289
12290 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012291 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012292 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012293}
Eric Andersencb57d552001-06-28 07:25:16 +000012294
12295/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012296 * Read and parse a command. Returns NODE_EOF on end of file.
12297 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012298 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012299static union node *
12300parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012301{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012302 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012303 checkkwd = 0;
12304 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012305 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012306 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012307 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012308 return list(1);
12309}
12310
12311/*
12312 * Input any here documents.
12313 */
12314static void
12315parseheredoc(void)
12316{
12317 struct heredoc *here;
12318 union node *n;
12319
12320 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012321 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012322
12323 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012324 setprompt_if(needprompt, 2);
12325 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012326 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012327 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012328 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012329 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012330 n->narg.text = wordtext;
12331 n->narg.backquote = backquotelist;
12332 here->here->nhere.doc = n;
12333 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012334 }
Eric Andersencb57d552001-06-28 07:25:16 +000012335}
12336
12337
12338/*
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012339 * called by editline -- any expansions to the prompt should be added here.
Eric Andersencb57d552001-06-28 07:25:16 +000012340 */
Denis Vlasenko131ae172007-02-18 13:00:19 +000012341#if ENABLE_ASH_EXPAND_PRMT
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012342static const char *
12343expandstr(const char *ps)
12344{
12345 union node n;
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012346 int saveprompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012347
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000012348 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12349 * and token processing _can_ alter it (delete NULs etc). */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012350 setinputstring((char *)ps);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012351
12352 saveprompt = doprompt;
12353 doprompt = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000012354 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012355 doprompt = saveprompt;
12356
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012357 popfile();
12358
12359 n.narg.type = NARG;
12360 n.narg.next = NULL;
12361 n.narg.text = wordtext;
12362 n.narg.backquote = backquotelist;
12363
Ron Yorston549deab2015-05-18 09:57:51 +020012364 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012365 return stackblock();
12366}
12367#endif
12368
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012369/*
12370 * Execute a command or commands contained in a string.
12371 */
12372static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012373evalstring(char *s, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000012374{
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012375 struct jmploc *volatile savehandler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012376 struct jmploc jmploc;
12377 int ex;
12378
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012379 union node *n;
12380 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012381 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012382
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012383 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012384 setinputstring(s);
12385 setstackmark(&smark);
12386
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012387 status = 0;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012388 /* On exception inside execution loop, we must popfile().
12389 * Try interactively:
12390 * readonly a=a
12391 * command eval "a=b" # throws "is read only" error
12392 * "command BLTIN" is not supposed to abort (even in non-interactive use).
12393 * But if we skip popfile(), we hit EOF in eval's string, and exit.
12394 */
12395 savehandler = exception_handler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012396 ex = setjmp(jmploc.loc);
12397 if (ex)
12398 goto out;
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012399 exception_handler = &jmploc;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012400
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012401 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012402 int i;
12403
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012404 i = evaltree(n, flags);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012405 if (n)
12406 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012407 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012408 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012409 break;
12410 }
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012411 out:
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012412 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012413 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012414 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012415
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012416 exception_handler = savehandler;
12417 if (ex)
12418 longjmp(exception_handler->loc, ex);
12419
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012420 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000012421}
12422
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012423/*
12424 * The eval command.
12425 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012426static int FAST_FUNC
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012427evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012428{
12429 char *p;
12430 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012431
Denis Vlasenko68404f12008-03-17 09:00:54 +000012432 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012433 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012434 argv += 2;
12435 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012436 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012437 for (;;) {
12438 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012439 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012440 if (p == NULL)
12441 break;
12442 STPUTC(' ', concat);
12443 }
12444 STPUTC('\0', concat);
12445 p = grabstackstr(concat);
12446 }
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012447 return evalstring(p, flags & EV_TESTED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012448 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012449 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012450}
12451
12452/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012453 * Read and execute commands.
12454 * "Top" is nonzero for the top level command loop;
12455 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012456 */
12457static int
12458cmdloop(int top)
12459{
12460 union node *n;
12461 struct stackmark smark;
12462 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012463 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012464 int numeof = 0;
12465
12466 TRACE(("cmdloop(%d) called\n", top));
12467 for (;;) {
12468 int skip;
12469
12470 setstackmark(&smark);
12471#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012472 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020012473 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012474#endif
12475 inter = 0;
12476 if (iflag && top) {
12477 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012478 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012479 }
12480 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012481#if DEBUG
12482 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012483 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012484#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012485 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012486 if (!top || numeof >= 50)
12487 break;
12488 if (!stoppedjobs()) {
12489 if (!Iflag)
12490 break;
12491 out2str("\nUse \"exit\" to leave shell.\n");
12492 }
12493 numeof++;
12494 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012495 int i;
12496
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012497 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12498 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012499 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012500 i = evaltree(n, 0);
12501 if (n)
12502 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012503 }
12504 popstackmark(&smark);
12505 skip = evalskip;
12506
12507 if (skip) {
Denys Vlasenko6a0710e2016-09-30 14:18:34 +020012508 evalskip &= ~SKIPFUNC;
Denys Vlasenko0840c912016-10-01 15:27:44 +020012509 break;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012510 }
12511 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012512 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012513}
12514
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012515/*
12516 * Take commands from a file. To be compatible we should do a path
12517 * search for the file, which is necessary to find sub-commands.
12518 */
12519static char *
12520find_dot_file(char *name)
12521{
12522 char *fullname;
12523 const char *path = pathval();
12524 struct stat statb;
12525
12526 /* don't try this for absolute or relative paths */
12527 if (strchr(name, '/'))
12528 return name;
12529
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012530 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012531 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12532 /*
12533 * Don't bother freeing here, since it will
12534 * be freed by the caller.
12535 */
12536 return fullname;
12537 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012538 if (fullname != name)
12539 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012540 }
12541
12542 /* not found in the PATH */
12543 ash_msg_and_raise_error("%s: not found", name);
12544 /* NOTREACHED */
12545}
12546
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012547static int FAST_FUNC
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012548dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012549{
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012550 /* "false; . empty_file; echo $?" should print 0, not 1: */
12551 int status = 0;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012552 char *fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012553 char **argv;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012554 char *args_need_save;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012555 struct strlist *sp;
12556 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012557
12558 for (sp = cmdenviron; sp; sp = sp->next)
Denis Vlasenko4222ae42007-02-25 02:37:49 +000012559 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012560
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012561 nextopt(nullstr); /* handle possible "--" */
12562 argv = argptr;
12563
12564 if (!argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012565 /* bash says: "bash: .: filename argument required" */
12566 return 2; /* bash compat */
12567 }
12568
Denys Vlasenko091f8312013-03-17 14:25:22 +010012569 /* This aborts if file isn't found, which is POSIXly correct.
12570 * bash returns exitcode 1 instead.
12571 */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012572 fullname = find_dot_file(argv[0]);
12573 argv++;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012574 args_need_save = argv[0];
12575 if (args_need_save) { /* . FILE ARGS, ARGS exist */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012576 int argc;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012577 saveparam = shellparam;
12578 shellparam.malloced = 0;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012579 argc = 1;
12580 while (argv[argc])
12581 argc++;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012582 shellparam.nparam = argc;
12583 shellparam.p = argv;
12584 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012585
Denys Vlasenko091f8312013-03-17 14:25:22 +010012586 /* This aborts if file can't be opened, which is POSIXly correct.
12587 * bash returns exitcode 1 instead.
12588 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012589 setinputfile(fullname, INPUT_PUSH_FILE);
12590 commandname = fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012591 status = cmdloop(0);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012592 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012593
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012594 if (args_need_save) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012595 freeparam(&shellparam);
12596 shellparam = saveparam;
12597 };
12598
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012599 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012600}
12601
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012602static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012603exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012604{
12605 if (stoppedjobs())
12606 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012607 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012608 exitstatus = number(argv[1]);
12609 raise_exception(EXEXIT);
12610 /* NOTREACHED */
12611}
12612
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012613/*
12614 * Read a file containing shell functions.
12615 */
12616static void
12617readcmdfile(char *name)
12618{
12619 setinputfile(name, INPUT_PUSH_FILE);
12620 cmdloop(0);
12621 popfile();
12622}
12623
12624
Denis Vlasenkocc571512007-02-23 21:10:35 +000012625/* ============ find_command inplementation */
12626
12627/*
12628 * Resolve a command name. If you change this routine, you may have to
12629 * change the shellexec routine as well.
12630 */
12631static void
12632find_command(char *name, struct cmdentry *entry, int act, const char *path)
12633{
12634 struct tblentry *cmdp;
12635 int idx;
12636 int prev;
12637 char *fullname;
12638 struct stat statb;
12639 int e;
12640 int updatetbl;
12641 struct builtincmd *bcmd;
12642
12643 /* If name contains a slash, don't use PATH or hash table */
12644 if (strchr(name, '/') != NULL) {
12645 entry->u.index = -1;
12646 if (act & DO_ABS) {
12647 while (stat(name, &statb) < 0) {
12648#ifdef SYSV
12649 if (errno == EINTR)
12650 continue;
12651#endif
12652 entry->cmdtype = CMDUNKNOWN;
12653 return;
12654 }
12655 }
12656 entry->cmdtype = CMDNORMAL;
12657 return;
12658 }
12659
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012660/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012661
12662 updatetbl = (path == pathval());
12663 if (!updatetbl) {
12664 act |= DO_ALTPATH;
12665 if (strstr(path, "%builtin") != NULL)
12666 act |= DO_ALTBLTIN;
12667 }
12668
12669 /* If name is in the table, check answer will be ok */
12670 cmdp = cmdlookup(name, 0);
12671 if (cmdp != NULL) {
12672 int bit;
12673
12674 switch (cmdp->cmdtype) {
12675 default:
12676#if DEBUG
12677 abort();
12678#endif
12679 case CMDNORMAL:
12680 bit = DO_ALTPATH;
12681 break;
12682 case CMDFUNCTION:
12683 bit = DO_NOFUNC;
12684 break;
12685 case CMDBUILTIN:
12686 bit = DO_ALTBLTIN;
12687 break;
12688 }
12689 if (act & bit) {
12690 updatetbl = 0;
12691 cmdp = NULL;
12692 } else if (cmdp->rehash == 0)
12693 /* if not invalidated by cd, we're done */
12694 goto success;
12695 }
12696
12697 /* If %builtin not in path, check for builtin next */
12698 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012699 if (bcmd) {
12700 if (IS_BUILTIN_REGULAR(bcmd))
12701 goto builtin_success;
12702 if (act & DO_ALTPATH) {
12703 if (!(act & DO_ALTBLTIN))
12704 goto builtin_success;
12705 } else if (builtinloc <= 0) {
12706 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000012707 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012708 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000012709
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012710#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000012711 {
12712 int applet_no = find_applet_by_name(name);
12713 if (applet_no >= 0) {
12714 entry->cmdtype = CMDNORMAL;
12715 entry->u.index = -2 - applet_no;
12716 return;
12717 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012718 }
12719#endif
12720
Denis Vlasenkocc571512007-02-23 21:10:35 +000012721 /* We have to search path. */
12722 prev = -1; /* where to start */
12723 if (cmdp && cmdp->rehash) { /* doing a rehash */
12724 if (cmdp->cmdtype == CMDBUILTIN)
12725 prev = builtinloc;
12726 else
12727 prev = cmdp->param.index;
12728 }
12729
12730 e = ENOENT;
12731 idx = -1;
12732 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012733 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000012734 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012735 /* NB: code below will still use fullname
12736 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012737 idx++;
12738 if (pathopt) {
12739 if (prefix(pathopt, "builtin")) {
12740 if (bcmd)
12741 goto builtin_success;
12742 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000012743 }
12744 if ((act & DO_NOFUNC)
12745 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020012746 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012747 continue;
12748 }
12749 }
12750 /* if rehash, don't redo absolute path names */
12751 if (fullname[0] == '/' && idx <= prev) {
12752 if (idx < prev)
12753 continue;
12754 TRACE(("searchexec \"%s\": no change\n", name));
12755 goto success;
12756 }
12757 while (stat(fullname, &statb) < 0) {
12758#ifdef SYSV
12759 if (errno == EINTR)
12760 continue;
12761#endif
12762 if (errno != ENOENT && errno != ENOTDIR)
12763 e = errno;
12764 goto loop;
12765 }
12766 e = EACCES; /* if we fail, this will be the error */
12767 if (!S_ISREG(statb.st_mode))
12768 continue;
12769 if (pathopt) { /* this is a %func directory */
12770 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012771 /* NB: stalloc will return space pointed by fullname
12772 * (because we don't have any intervening allocations
12773 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012774 readcmdfile(fullname);
12775 cmdp = cmdlookup(name, 0);
12776 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12777 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12778 stunalloc(fullname);
12779 goto success;
12780 }
12781 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12782 if (!updatetbl) {
12783 entry->cmdtype = CMDNORMAL;
12784 entry->u.index = idx;
12785 return;
12786 }
12787 INT_OFF;
12788 cmdp = cmdlookup(name, 1);
12789 cmdp->cmdtype = CMDNORMAL;
12790 cmdp->param.index = idx;
12791 INT_ON;
12792 goto success;
12793 }
12794
12795 /* We failed. If there was an entry for this command, delete it */
12796 if (cmdp && updatetbl)
12797 delete_cmd_entry();
12798 if (act & DO_ERR)
12799 ash_msg("%s: %s", name, errmsg(e, "not found"));
12800 entry->cmdtype = CMDUNKNOWN;
12801 return;
12802
12803 builtin_success:
12804 if (!updatetbl) {
12805 entry->cmdtype = CMDBUILTIN;
12806 entry->u.cmd = bcmd;
12807 return;
12808 }
12809 INT_OFF;
12810 cmdp = cmdlookup(name, 1);
12811 cmdp->cmdtype = CMDBUILTIN;
12812 cmdp->param.cmd = bcmd;
12813 INT_ON;
12814 success:
12815 cmdp->rehash = 0;
12816 entry->cmdtype = cmdp->cmdtype;
12817 entry->u = cmdp->param;
12818}
12819
12820
Eric Andersencb57d552001-06-28 07:25:16 +000012821/*
Eric Andersencb57d552001-06-28 07:25:16 +000012822 * The trap builtin.
12823 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012824static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012825trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012826{
12827 char *action;
12828 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012829 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012830
Eric Andersenc470f442003-07-28 09:56:35 +000012831 nextopt(nullstr);
12832 ap = argptr;
12833 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012834 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012835 char *tr = trap_ptr[signo];
12836 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012837 /* note: bash adds "SIG", but only if invoked
12838 * as "bash". If called as "sh", or if set -o posix,
12839 * then it prints short signal names.
12840 * We are printing short names: */
12841 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012842 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012843 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012844 /* trap_ptr != trap only if we are in special-cased `trap` code.
12845 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012846 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012847 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000012848 }
12849 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012850 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012851 if (trap_ptr != trap) {
12852 free(trap_ptr);
12853 trap_ptr = trap;
12854 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012855 */
Eric Andersencb57d552001-06-28 07:25:16 +000012856 return 0;
12857 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012858
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012859 action = NULL;
12860 if (ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000012861 action = *ap++;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012862 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012863 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012864 signo = get_signum(*ap);
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012865 if (signo < 0) {
12866 /* Mimic bash message exactly */
12867 ash_msg("%s: invalid signal specification", *ap);
12868 exitcode = 1;
12869 goto next;
12870 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000012871 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000012872 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000012873 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000012874 action = NULL;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020012875 else {
12876 if (action[0]) /* not NULL and not "" and not "-" */
12877 may_have_traps = 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012878 action = ckstrdup(action);
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020012879 }
Eric Andersencb57d552001-06-28 07:25:16 +000012880 }
Denis Vlasenko60818682007-09-28 22:07:23 +000012881 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000012882 trap[signo] = action;
12883 if (signo != 0)
12884 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012885 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012886 next:
Eric Andersencb57d552001-06-28 07:25:16 +000012887 ap++;
12888 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012889 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012890}
12891
Eric Andersenc470f442003-07-28 09:56:35 +000012892
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012893/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000012894
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012895#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012896static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012897helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012898{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000012899 unsigned col;
12900 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000012901
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020012902 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000012903 "Built-in commands:\n"
12904 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000012905 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012906 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000012907 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000012908 if (col > 60) {
12909 out1fmt("\n");
12910 col = 0;
12911 }
12912 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012913# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000012914 {
12915 const char *a = applet_names;
12916 while (*a) {
12917 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12918 if (col > 60) {
12919 out1fmt("\n");
12920 col = 0;
12921 }
Ron Yorston2b919582016-04-08 11:57:20 +010012922 while (*a++ != '\0')
12923 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000012924 }
12925 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012926# endif
Denys Vlasenkoebedb942016-10-02 18:45:09 +020012927 newline_and_flush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000012928 return EXIT_SUCCESS;
12929}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012930#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012931
Flemming Madsend96ffda2013-04-07 18:47:24 +020012932#if MAX_HISTORY
12933static int FAST_FUNC
12934historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12935{
12936 show_history(line_input_state);
12937 return EXIT_SUCCESS;
12938}
12939#endif
12940
Eric Andersencb57d552001-06-28 07:25:16 +000012941/*
Eric Andersencb57d552001-06-28 07:25:16 +000012942 * The export and readonly commands.
12943 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012944static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012945exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012946{
12947 struct var *vp;
12948 char *name;
12949 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012950 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020012951 char opt;
12952 int flag;
12953 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000012954
Denys Vlasenkod5275882012-10-01 13:41:17 +020012955 /* "readonly" in bash accepts, but ignores -n.
12956 * We do the same: it saves a conditional in nextopt's param.
12957 */
12958 flag_off = 0;
12959 while ((opt = nextopt("np")) != '\0') {
12960 if (opt == 'n')
12961 flag_off = VEXPORT;
12962 }
12963 flag = VEXPORT;
12964 if (argv[0][0] == 'r') {
12965 flag = VREADONLY;
12966 flag_off = 0; /* readonly ignores -n */
12967 }
12968 flag_off = ~flag_off;
12969
12970 /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */
12971 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012972 aptr = argptr;
12973 name = *aptr;
12974 if (name) {
12975 do {
12976 p = strchr(name, '=');
12977 if (p != NULL) {
12978 p++;
12979 } else {
12980 vp = *findvar(hashvar(name), name);
12981 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020012982 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012983 continue;
12984 }
Eric Andersencb57d552001-06-28 07:25:16 +000012985 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012986 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012987 } while ((name = *++aptr) != NULL);
12988 return 0;
12989 }
Eric Andersencb57d552001-06-28 07:25:16 +000012990 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012991
12992 /* No arguments. Show the list of exported or readonly vars.
12993 * -n is ignored.
12994 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012995 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012996 return 0;
12997}
12998
Eric Andersencb57d552001-06-28 07:25:16 +000012999/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013000 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000013001 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013002static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013003unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000013004{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013005 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000013006
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013007 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013008 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013009 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000013010}
13011
Eric Andersencb57d552001-06-28 07:25:16 +000013012/*
Eric Andersencb57d552001-06-28 07:25:16 +000013013 * The unset builtin command. We unset the function before we unset the
13014 * variable to allow a function to be unset when there is a readonly variable
13015 * with the same name.
13016 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013017static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013018unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013019{
13020 char **ap;
13021 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013022 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013023 int ret = 0;
13024
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013025 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000013026 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000013027 }
Eric Andersencb57d552001-06-28 07:25:16 +000013028
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013029 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013030 if (flag != 'f') {
13031 i = unsetvar(*ap);
13032 ret |= i;
13033 if (!(i & 2))
13034 continue;
13035 }
13036 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000013037 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000013038 }
Eric Andersenc470f442003-07-28 09:56:35 +000013039 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000013040}
13041
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000013042static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013043 ' ', offsetof(struct tms, tms_utime),
13044 '\n', offsetof(struct tms, tms_stime),
13045 ' ', offsetof(struct tms, tms_cutime),
13046 '\n', offsetof(struct tms, tms_cstime),
13047 0
13048};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013049static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013050timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013051{
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020013052 unsigned long clk_tck, s, t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013053 const unsigned char *p;
13054 struct tms buf;
13055
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020013056 clk_tck = bb_clk_tck();
Eric Andersencb57d552001-06-28 07:25:16 +000013057 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013058
13059 p = timescmd_str;
13060 do {
13061 t = *(clock_t *)(((char *) &buf) + p[1]);
13062 s = t / clk_tck;
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020013063 t = t % clk_tck;
13064 out1fmt("%lum%lu.%03lus%c",
13065 s / 60, s % 60,
13066 (t * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013067 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013068 p += 2;
13069 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013070
Eric Andersencb57d552001-06-28 07:25:16 +000013071 return 0;
13072}
13073
Denys Vlasenko0b883582016-12-23 16:49:07 +010013074#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000013075/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013076 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013077 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000013078 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013079 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000013080 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013081static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013082letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013083{
Denis Vlasenko68404f12008-03-17 09:00:54 +000013084 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000013085
Denis Vlasenko68404f12008-03-17 09:00:54 +000013086 argv++;
13087 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000013088 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000013089 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013090 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013091 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013092
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000013093 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000013094}
Eric Andersenc470f442003-07-28 09:56:35 +000013095#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013096
Eric Andersenc470f442003-07-28 09:56:35 +000013097/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013098 * The read builtin. Options:
13099 * -r Do not interpret '\' specially
13100 * -s Turn off echo (tty only)
13101 * -n NCHARS Read NCHARS max
13102 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13103 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13104 * -u FD Read from given FD instead of fd 0
Eric Andersenc470f442003-07-28 09:56:35 +000013105 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013106 * TODO: bash also has:
13107 * -a ARRAY Read into array[0],[1],etc
13108 * -d DELIM End on DELIM char, not newline
13109 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000013110 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013111static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013112readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013113{
Denys Vlasenko73067272010-01-12 22:11:24 +010013114 char *opt_n = NULL;
13115 char *opt_p = NULL;
13116 char *opt_t = NULL;
13117 char *opt_u = NULL;
13118 int read_flags = 0;
13119 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000013120 int i;
13121
Denys Vlasenko73067272010-01-12 22:11:24 +010013122 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000013123 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000013124 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010013125 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013126 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013127 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010013128 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013129 break;
13130 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010013131 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000013132 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013133 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010013134 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013135 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013136 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010013137 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000013138 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013139 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010013140 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013141 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013142 default:
13143 break;
13144 }
Eric Andersenc470f442003-07-28 09:56:35 +000013145 }
Paul Fox02eb9342005-09-07 16:56:02 +000013146
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013147 /* "read -s" needs to save/restore termios, can't allow ^C
13148 * to jump out of it.
13149 */
13150 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013151 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010013152 argptr,
13153 bltinlookup("IFS"), /* can be NULL */
13154 read_flags,
13155 opt_n,
13156 opt_p,
13157 opt_t,
13158 opt_u
13159 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013160 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000013161
Denys Vlasenko73067272010-01-12 22:11:24 +010013162 if ((uintptr_t)r > 1)
13163 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000013164
Denys Vlasenko73067272010-01-12 22:11:24 +010013165 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000013166}
13167
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013168static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020013169umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013170{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013171 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000013172
Eric Andersenc470f442003-07-28 09:56:35 +000013173 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000013174 int symbolic_mode = 0;
13175
13176 while (nextopt("S") != '\0') {
13177 symbolic_mode = 1;
13178 }
13179
Denis Vlasenkob012b102007-02-19 22:43:01 +000013180 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013181 mask = umask(0);
13182 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013183 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013184
Denys Vlasenko6283f982015-10-07 16:56:20 +020013185 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013186 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013187 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013188 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013189 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013190
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013191 i = 2;
13192 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013193 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013194 *p++ = permuser[i];
13195 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013196 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013197 if (!(mask & 0400)) *p++ = 'r';
13198 if (!(mask & 0200)) *p++ = 'w';
13199 if (!(mask & 0100)) *p++ = 'x';
13200 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013201 if (--i < 0)
13202 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013203 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013204 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013205 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013206 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013207 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013208 }
13209 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013210 char *modestr = *argptr;
13211 /* numeric umasks are taken as-is */
13212 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
13213 if (!isdigit(modestr[0]))
13214 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013215 mask = bb_parse_mode(modestr, mask);
13216 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013217 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013218 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013219 if (!isdigit(modestr[0]))
13220 mask ^= 0777;
13221 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013222 }
13223 return 0;
13224}
13225
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013226static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013227ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013228{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013229 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013230}
13231
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013232/* ============ main() and helpers */
13233
13234/*
13235 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013236 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013237static void
13238exitshell(void)
13239{
13240 struct jmploc loc;
13241 char *p;
13242 int status;
13243
Denys Vlasenkobede2152011-09-04 16:12:33 +020013244#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13245 save_history(line_input_state);
13246#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013247 status = exitstatus;
13248 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13249 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013250 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013251 status = exitstatus;
13252 goto out;
13253 }
13254 exception_handler = &loc;
13255 p = trap[0];
13256 if (p) {
13257 trap[0] = NULL;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013258 evalskip = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013259 evalstring(p, 0);
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013260 /*free(p); - we'll exit soon */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013261 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013262 out:
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013263 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13264 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13265 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013266 setjobctl(0);
Denys Vlasenkocaee80c2016-10-25 20:49:53 +020013267 flush_stdout_stderr();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013268 _exit(status);
13269 /* NOTREACHED */
13270}
13271
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013272static void
13273init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013274{
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013275 /* we will never free this */
13276 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013277
Denys Vlasenko458c1f22016-10-27 23:51:19 +020013278 sigmode[SIGCHLD - 1] = S_DFL;
13279 setsignal(SIGCHLD);
13280
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013281 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13282 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13283 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013284 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013285
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013286 {
13287 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013288 const char *p;
13289 struct stat st1, st2;
13290
13291 initvar();
13292 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenkob6838b52016-09-30 11:33:47 +020013293 p = endofname(*envp);
13294 if (p != *envp && *p == '=') {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013295 setvareq(*envp, VEXPORT|VTEXTFIXED);
13296 }
13297 }
13298
Denys Vlasenkoe627ac92016-09-30 14:36:59 +020013299 setvareq((char*)defoptindvar, VTEXTFIXED);
13300
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013301 setvar0("PPID", utoa(getppid()));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013302#if BASH_SHLVL_VAR
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013303 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013304 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013305#endif
13306#if BASH_HOSTNAME_VAR
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013307 if (!lookupvar("HOSTNAME")) {
13308 struct utsname uts;
13309 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013310 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013311 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013312#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013313 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013314 if (p) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013315 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013316 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13317 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013318 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013319 }
13320 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013321 setpwd(p, 0);
13322 }
13323}
13324
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013325
13326//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013327//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013328//usage:#define ash_full_usage "\n\n"
13329//usage: "Unix shell interpreter"
13330
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013331/*
13332 * Process the shell command line arguments.
13333 */
13334static void
Denis Vlasenko68404f12008-03-17 09:00:54 +000013335procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013336{
13337 int i;
13338 const char *xminusc;
13339 char **xargv;
13340
13341 xargv = argv;
13342 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013343 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013344 xargv++;
13345 for (i = 0; i < NOPTS; i++)
13346 optlist[i] = 2;
13347 argptr = xargv;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013348 if (options(/*cmdline:*/ 1)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013349 /* it already printed err message */
13350 raise_exception(EXERROR);
13351 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013352 xargv = argptr;
13353 xminusc = minusc;
13354 if (*xargv == NULL) {
13355 if (xminusc)
13356 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13357 sflag = 1;
13358 }
13359 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13360 iflag = 1;
13361 if (mflag == 2)
13362 mflag = iflag;
13363 for (i = 0; i < NOPTS; i++)
13364 if (optlist[i] == 2)
13365 optlist[i] = 0;
13366#if DEBUG == 2
13367 debug = 1;
13368#endif
13369 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13370 if (xminusc) {
13371 minusc = *xargv++;
13372 if (*xargv)
13373 goto setarg0;
13374 } else if (!sflag) {
13375 setinputfile(*xargv, 0);
13376 setarg0:
13377 arg0 = *xargv++;
13378 commandname = arg0;
13379 }
13380
13381 shellparam.p = xargv;
13382#if ENABLE_ASH_GETOPTS
13383 shellparam.optind = 1;
13384 shellparam.optoff = -1;
13385#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013386 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013387 while (*xargv) {
13388 shellparam.nparam++;
13389 xargv++;
13390 }
13391 optschanged();
13392}
13393
13394/*
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013395 * Read /etc/profile, ~/.profile, $ENV.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013396 */
13397static void
13398read_profile(const char *name)
13399{
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013400 name = expandstr(name);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013401 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13402 return;
Denys Vlasenko0840c912016-10-01 15:27:44 +020013403 cmdloop(0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013404 popfile();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013405}
13406
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013407/*
13408 * This routine is called when an error or an interrupt occurs in an
13409 * interactive shell and control is returned to the main command loop.
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013410 * (In dash, this function is auto-generated by build machinery).
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013411 */
13412static void
13413reset(void)
13414{
13415 /* from eval.c: */
13416 evalskip = 0;
13417 loopnest = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013418
13419 /* from expand.c: */
13420 ifsfree();
13421
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013422 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013423 g_parsefile->left_in_buffer = 0;
13424 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013425 popallfiles();
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013426
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013427 /* from redir.c: */
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020013428 while (redirlist)
13429 popredir(/*drop:*/ 0, /*restore:*/ 0);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013430}
13431
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013432#if PROFILE
13433static short profile_buf[16384];
13434extern int etext();
13435#endif
13436
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013437/*
13438 * Main routine. We initialize things, parse the arguments, execute
13439 * profiles if we're a login shell, and then call cmdloop to execute
13440 * commands. The setjmp call sets up the location to jump to when an
13441 * exception occurs. When an exception occurs the variable "state"
13442 * is used to figure out how far we had gotten.
13443 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013444int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013445int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013446{
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013447 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013448 struct jmploc jmploc;
13449 struct stackmark smark;
13450
Denis Vlasenko01631112007-12-16 17:20:38 +000013451 /* Initialize global data */
13452 INIT_G_misc();
13453 INIT_G_memstack();
13454 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013455#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013456 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013457#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013458 INIT_G_cmdtable();
13459
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013460#if PROFILE
13461 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13462#endif
13463
13464#if ENABLE_FEATURE_EDITING
13465 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13466#endif
13467 state = 0;
13468 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013469 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013470 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013471
13472 reset();
13473
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013474 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013475 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013476 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013477 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013478 }
13479 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020013480 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013481 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013482
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013483 popstackmark(&smark);
13484 FORCE_INT_ON; /* enable interrupts */
13485 if (s == 1)
13486 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013487 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013488 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013489 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013490 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013491 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013492 }
13493 exception_handler = &jmploc;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013494 rootpid = getpid();
13495
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013496 init();
13497 setstackmark(&smark);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013498 procargs(argv);
Denys Vlasenko474ed062016-10-30 18:30:29 +010013499#if DEBUG
13500 TRACE(("Shell args: "));
13501 trace_puts_args(argv);
13502#endif
Denis Vlasenko68404f12008-03-17 09:00:54 +000013503
Denys Vlasenko6088e132010-12-25 23:58:42 +010013504 if (argv[0] && argv[0][0] == '-')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013505 isloginsh = 1;
13506 if (isloginsh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013507 const char *hp;
13508
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013509 state = 1;
13510 read_profile("/etc/profile");
13511 state1:
13512 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013513 hp = lookupvar("HOME");
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013514 if (hp)
13515 read_profile("$HOME/.profile");
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013516 }
13517 state2:
13518 state = 3;
13519 if (
13520#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013521 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013522#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013523 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013524 ) {
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013525 const char *shinit = lookupvar("ENV");
13526 if (shinit != NULL && *shinit != '\0')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013527 read_profile(shinit);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013528 }
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013529 popstackmark(&smark);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013530 state3:
13531 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013532 if (minusc) {
13533 /* evalstring pushes parsefile stack.
13534 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013535 * is one of stacked source fds.
13536 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013537 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013538 // ^^ not necessary since now we special-case fd 0
13539 // in is_hidden_fd() to not be considered "hidden fd"
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013540 evalstring(minusc, 0);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013541 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013542
13543 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020013544#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013545 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013546 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013547 if (!hp) {
13548 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013549 if (hp) {
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013550 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013551 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013552 free((char*)hp);
13553 hp = lookupvar("HISTFILE");
13554 }
13555 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013556 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013557 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013558# if ENABLE_FEATURE_SH_HISTFILESIZE
13559 hp = lookupvar("HISTFILESIZE");
13560 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13561# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013562 }
13563#endif
13564 state4: /* XXX ??? - why isn't this before the "if" statement */
13565 cmdloop(1);
13566 }
13567#if PROFILE
13568 monitor(0);
13569#endif
13570#ifdef GPROF
13571 {
13572 extern void _mcleanup(void);
13573 _mcleanup();
13574 }
13575#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013576 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013577 exitshell();
13578 /* NOTREACHED */
13579}
13580
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013581
Eric Andersendf82f612001-06-28 07:46:40 +000013582/*-
13583 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013584 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013585 *
13586 * This code is derived from software contributed to Berkeley by
13587 * Kenneth Almquist.
13588 *
13589 * Redistribution and use in source and binary forms, with or without
13590 * modification, are permitted provided that the following conditions
13591 * are met:
13592 * 1. Redistributions of source code must retain the above copyright
13593 * notice, this list of conditions and the following disclaimer.
13594 * 2. Redistributions in binary form must reproduce the above copyright
13595 * notice, this list of conditions and the following disclaimer in the
13596 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013597 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013598 * may be used to endorse or promote products derived from this software
13599 * without specific prior written permission.
13600 *
13601 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13602 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13603 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13604 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13605 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13606 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13607 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13608 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13609 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13610 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13611 * SUCH DAMAGE.
13612 */