blob: e73134580d5ac682ba31a0dfef68cf4261d8e144 [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 */
18
Eric Andersenc470f442003-07-28 09:56:35 +000019/*
Denis Vlasenko653d8e72009-03-19 21:59:35 +000020 * The following should be set to reflect the type of system you have:
Eric Andersenc470f442003-07-28 09:56:35 +000021 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
22 * define SYSV if you are running under System V.
23 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
24 * define DEBUG=2 to compile in and turn on debugging.
25 *
Tanguy Pruvot823694d2012-11-18 13:20:29 +010026 * When debugging is on (DEBUG is 1 and "set -o debug" was executed),
27 * debugging info will be written to ./trace and a quit signal
28 * will generate a core dump.
Eric Andersenc470f442003-07-28 09:56:35 +000029 */
Denis Vlasenkof1733952009-03-19 23:21:55 +000030#define DEBUG 0
Denis Vlasenko653d8e72009-03-19 21:59:35 +000031/* Tweak debug output verbosity here */
32#define DEBUG_TIME 0
33#define DEBUG_PID 1
34#define DEBUG_SIG 1
35
Eric Andersenc470f442003-07-28 09:56:35 +000036#define PROFILE 0
Denis Vlasenko0e6f6612008-02-15 15:02:15 +000037
Denis Vlasenko0e6f6612008-02-15 15:02:15 +000038#define JOBS ENABLE_ASH_JOB_CONTROL
Eric Andersenc470f442003-07-28 09:56:35 +000039
Denis Vlasenkob012b102007-02-19 22:43:01 +000040#include <paths.h>
41#include <setjmp.h>
42#include <fnmatch.h>
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020043#include <sys/times.h>
Denys Vlasenko73067272010-01-12 22:11:24 +010044
Denys Vlasenko20704f02011-03-23 17:59:27 +010045#include "busybox.h" /* for applet_names */
46#include "unicode.h"
47
Denys Vlasenko73067272010-01-12 22:11:24 +010048#include "shell_common.h"
Denys Vlasenko26777aa2010-11-22 23:49:10 +010049#if ENABLE_SH_MATH_SUPPORT
50# include "math.h"
51#endif
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020052#if ENABLE_ASH_RANDOM_SUPPORT
53# include "random.h"
Denys Vlasenko36df0482009-10-19 16:07:28 +020054#else
55# define CLEAR_RANDOM_T(rnd) ((void)0)
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020056#endif
Denis Vlasenko61befda2008-11-25 01:36:03 +000057
Denys Vlasenko1fcbff22010-06-26 02:40:08 +020058#include "NUM_APPLETS.h"
Denys Vlasenko14974842010-03-23 01:08:26 +010059#if NUM_APPLETS == 1
Denis Vlasenko61befda2008-11-25 01:36:03 +000060/* STANDALONE does not make sense, and won't compile */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020061# undef CONFIG_FEATURE_SH_STANDALONE
62# undef ENABLE_FEATURE_SH_STANDALONE
63# undef IF_FEATURE_SH_STANDALONE
Denys Vlasenko14974842010-03-23 01:08:26 +010064# undef IF_NOT_FEATURE_SH_STANDALONE
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020065# define ENABLE_FEATURE_SH_STANDALONE 0
66# define IF_FEATURE_SH_STANDALONE(...)
67# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
Eric Andersencb57d552001-06-28 07:25:16 +000068#endif
69
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000070#ifndef PIPE_BUF
Denis Vlasenko653d8e72009-03-19 21:59:35 +000071# define PIPE_BUF 4096 /* amount of buffering in a pipe */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000072#endif
73
Denys Vlasenko153fcaa2010-02-21 05:17:41 +010074#if !BB_MMU
Denis Vlasenko653d8e72009-03-19 21:59:35 +000075# error "Do not even bother, ash will not run on NOMMU machine"
Denis Vlasenkob012b102007-02-19 22:43:01 +000076#endif
77
Denys Vlasenko771f1992010-07-16 14:31:34 +020078//config:config ASH
79//config: bool "ash"
80//config: default y
81//config: depends on !NOMMU
82//config: help
83//config: Tha 'ash' shell adds about 60k in the default configuration and is
84//config: the most complete and most pedantically correct shell included with
85//config: busybox. This shell is actually a derivative of the Debian 'dash'
86//config: shell (by Herbert Xu), which was created by porting the 'ash' shell
87//config: (written by Kenneth Almquist) from NetBSD.
88//config:
89//config:config ASH_BASH_COMPAT
90//config: bool "bash-compatible extensions"
91//config: default y
92//config: depends on ASH
93//config: help
94//config: Enable bash-compatible extensions.
95//config:
Denys Vlasenko046341e2011-02-04 17:53:59 +010096//config:config ASH_IDLE_TIMEOUT
97//config: bool "Idle timeout variable"
98//config: default n
99//config: depends on ASH
100//config: help
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100101//config: Enables bash-like auto-logout after $TMOUT seconds of idle time.
Denys Vlasenko046341e2011-02-04 17:53:59 +0100102//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200103//config:config ASH_JOB_CONTROL
104//config: bool "Job control"
105//config: default y
106//config: depends on ASH
107//config: help
108//config: Enable job control in the ash shell.
109//config:
110//config:config ASH_ALIAS
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100111//config: bool "Alias support"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200112//config: default y
113//config: depends on ASH
114//config: help
115//config: Enable alias support in the ash shell.
116//config:
117//config:config ASH_GETOPTS
118//config: bool "Builtin getopt to parse positional parameters"
119//config: default y
120//config: depends on ASH
121//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100122//config: Enable support for getopts builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200123//config:
124//config:config ASH_BUILTIN_ECHO
125//config: bool "Builtin version of 'echo'"
126//config: default y
127//config: depends on ASH
128//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100129//config: Enable support for echo builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200130//config:
131//config:config ASH_BUILTIN_PRINTF
132//config: bool "Builtin version of 'printf'"
133//config: default y
134//config: depends on ASH
135//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100136//config: Enable support for printf builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200137//config:
138//config:config ASH_BUILTIN_TEST
139//config: bool "Builtin version of 'test'"
140//config: default y
141//config: depends on ASH
142//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100143//config: Enable support for test builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200144//config:
145//config:config ASH_CMDCMD
146//config: bool "'command' command to override shell builtins"
147//config: default y
148//config: depends on ASH
149//config: help
150//config: Enable support for the ash 'command' builtin, which allows
151//config: you to run the specified command with the specified arguments,
152//config: even when there is an ash builtin command with the same name.
153//config:
154//config:config ASH_MAIL
155//config: bool "Check for new mail on interactive shells"
156//config: default n
157//config: depends on ASH
158//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100159//config: Enable "check for new mail" function in the ash shell.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200160//config:
161//config:config ASH_OPTIMIZE_FOR_SIZE
162//config: bool "Optimize for size instead of speed"
163//config: default y
164//config: depends on ASH
165//config: help
166//config: Compile ash for reduced size at the price of speed.
167//config:
168//config:config ASH_RANDOM_SUPPORT
169//config: bool "Pseudorandom generator and $RANDOM variable"
170//config: default y
171//config: depends on ASH
172//config: help
173//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
174//config: Each read of "$RANDOM" will generate a new pseudorandom value.
175//config: You can reset the generator by using a specified start value.
176//config: After "unset RANDOM" the generator will switch off and this
177//config: variable will no longer have special treatment.
178//config:
179//config:config ASH_EXPAND_PRMT
180//config: bool "Expand prompt string"
181//config: default y
182//config: depends on ASH
183//config: help
184//config: "PS#" may contain volatile content, such as backquote commands.
185//config: This option recreates the prompt string from the environment
186//config: variable each time it is displayed.
Denys Vlasenko51ca7762010-07-16 17:16:40 +0200187//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200188
Denys Vlasenko20704f02011-03-23 17:59:27 +0100189//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
190//applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, sh))
191//applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, bash))
192
193//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
194//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
195
Denis Vlasenkob012b102007-02-19 22:43:01 +0000196
Denis Vlasenko01631112007-12-16 17:20:38 +0000197/* ============ Hash table sizes. Configurable. */
198
199#define VTABSIZE 39
200#define ATABSIZE 39
201#define CMDTABLESIZE 31 /* should be prime */
202
203
Denis Vlasenkob012b102007-02-19 22:43:01 +0000204/* ============ Shell options */
205
206static const char *const optletters_optnames[] = {
207 "e" "errexit",
208 "f" "noglob",
209 "I" "ignoreeof",
210 "i" "interactive",
211 "m" "monitor",
212 "n" "noexec",
213 "s" "stdin",
214 "x" "xtrace",
215 "v" "verbose",
216 "C" "noclobber",
217 "a" "allexport",
218 "b" "notify",
219 "u" "nounset",
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100220 "\0" "vi"
Michael Abbott359da5e2009-12-04 23:03:29 +0100221#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100222 ,"\0" "pipefail"
Michael Abbott359da5e2009-12-04 23:03:29 +0100223#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000224#if DEBUG
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000225 ,"\0" "nolog"
226 ,"\0" "debug"
Denis Vlasenkob012b102007-02-19 22:43:01 +0000227#endif
228};
229
Denys Vlasenko285ad152009-12-04 23:02:27 +0100230#define optletters(n) optletters_optnames[n][0]
231#define optnames(n) (optletters_optnames[n] + 1)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000232
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000233enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
Denis Vlasenkob012b102007-02-19 22:43:01 +0000234
Eric Andersenc470f442003-07-28 09:56:35 +0000235
Denis Vlasenkob012b102007-02-19 22:43:01 +0000236/* ============ Misc data */
Eric Andersenc470f442003-07-28 09:56:35 +0000237
Denys Vlasenkoea8b2522010-06-02 12:57:26 +0200238#define msg_illnum "Illegal number: %s"
Denis Vlasenkoaa744452007-02-23 01:04:22 +0000239
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +0000240/*
Eric Andersenc470f442003-07-28 09:56:35 +0000241 * We enclose jmp_buf in a structure so that we can declare pointers to
242 * jump locations. The global variable handler contains the location to
Denis Vlasenkof1733952009-03-19 23:21:55 +0000243 * jump to when an exception occurs, and the global variable exception_type
Eric Andersenaff114c2004-04-14 17:51:38 +0000244 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000245 * exception handlers, the user should save the value of handler on entry
246 * to an inner scope, set handler to point to a jmploc structure for the
247 * inner scope, and restore handler on exit from the scope.
248 */
Eric Andersenc470f442003-07-28 09:56:35 +0000249struct jmploc {
250 jmp_buf loc;
251};
Denis Vlasenko01631112007-12-16 17:20:38 +0000252
253struct globals_misc {
254 /* pid of main shell */
255 int rootpid;
256 /* shell level: 0 for the main shell, 1 for its children, and so on */
257 int shlvl;
258#define rootshell (!shlvl)
259 char *minusc; /* argument to -c option */
260
261 char *curdir; // = nullstr; /* current working directory */
262 char *physdir; // = nullstr; /* physical working directory */
263
264 char *arg0; /* value of $0 */
265
266 struct jmploc *exception_handler;
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000267
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200268 volatile int suppress_int; /* counter */
269 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000270 /* last pending signal */
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200271 volatile /*sig_atomic_t*/ smallint pending_sig;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000272 smallint exception_type; /* kind of exception (0..5) */
Denis Vlasenko01631112007-12-16 17:20:38 +0000273 /* exceptions */
Eric Andersenc470f442003-07-28 09:56:35 +0000274#define EXINT 0 /* SIGINT received */
275#define EXERROR 1 /* a generic error */
276#define EXSHELLPROC 2 /* execute a shell procedure */
277#define EXEXEC 3 /* command execution failed */
278#define EXEXIT 4 /* exit the shell */
279#define EXSIG 5 /* trapped signal in wait(1) */
Eric Andersen2870d962001-07-02 17:27:21 +0000280
Denis Vlasenko01631112007-12-16 17:20:38 +0000281 smallint isloginsh;
Denis Vlasenkob07a4962008-06-22 13:16:23 +0000282 char nullstr[1]; /* zero length string */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000283
284 char optlist[NOPTS];
285#define eflag optlist[0]
286#define fflag optlist[1]
287#define Iflag optlist[2]
288#define iflag optlist[3]
289#define mflag optlist[4]
290#define nflag optlist[5]
291#define sflag optlist[6]
292#define xflag optlist[7]
293#define vflag optlist[8]
294#define Cflag optlist[9]
295#define aflag optlist[10]
296#define bflag optlist[11]
297#define uflag optlist[12]
298#define viflag optlist[13]
Michael Abbott359da5e2009-12-04 23:03:29 +0100299#if ENABLE_ASH_BASH_COMPAT
300# define pipefail optlist[14]
301#else
302# define pipefail 0
303#endif
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000304#if DEBUG
Michael Abbott359da5e2009-12-04 23:03:29 +0100305# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT]
306# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT]
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000307#endif
308
309 /* trap handler commands */
Denis Vlasenko01631112007-12-16 17:20:38 +0000310 /*
311 * Sigmode records the current value of the signal handlers for the various
312 * modes. A value of zero means that the current handler is not known.
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000313 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
Denis Vlasenko01631112007-12-16 17:20:38 +0000314 */
315 char sigmode[NSIG - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000316#define S_DFL 1 /* default signal handling (SIG_DFL) */
317#define S_CATCH 2 /* signal is caught */
318#define S_IGN 3 /* signal is ignored (SIG_IGN) */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000319#define S_HARD_IGN 4 /* signal is ignored permenantly */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000320
Denis Vlasenko01631112007-12-16 17:20:38 +0000321 /* indicates specified signal received */
Denis Vlasenko4b875702009-03-19 13:30:04 +0000322 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
Denys Vlasenko238bf182010-05-18 15:49:07 +0200323 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000324 char *trap[NSIG];
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200325 char **trap_ptr; /* used only by "trap hack" */
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000326
327 /* Rarely referenced stuff */
328#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200329 random_t random_gen;
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000330#endif
331 pid_t backgndpid; /* pid of last background process */
332 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
Denis Vlasenko01631112007-12-16 17:20:38 +0000333};
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000334extern struct globals_misc *const ash_ptr_to_globals_misc;
335#define G_misc (*ash_ptr_to_globals_misc)
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000336#define rootpid (G_misc.rootpid )
337#define shlvl (G_misc.shlvl )
338#define minusc (G_misc.minusc )
339#define curdir (G_misc.curdir )
340#define physdir (G_misc.physdir )
341#define arg0 (G_misc.arg0 )
Denis Vlasenko01631112007-12-16 17:20:38 +0000342#define exception_handler (G_misc.exception_handler)
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000343#define exception_type (G_misc.exception_type )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200344#define suppress_int (G_misc.suppress_int )
345#define pending_int (G_misc.pending_int )
346#define pending_sig (G_misc.pending_sig )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000347#define isloginsh (G_misc.isloginsh )
348#define nullstr (G_misc.nullstr )
349#define optlist (G_misc.optlist )
350#define sigmode (G_misc.sigmode )
351#define gotsig (G_misc.gotsig )
Denys Vlasenko238bf182010-05-18 15:49:07 +0200352#define may_have_traps (G_misc.may_have_traps )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000353#define trap (G_misc.trap )
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200354#define trap_ptr (G_misc.trap_ptr )
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200355#define random_gen (G_misc.random_gen )
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000356#define backgndpid (G_misc.backgndpid )
357#define job_warning (G_misc.job_warning)
Denis Vlasenko01631112007-12-16 17:20:38 +0000358#define INIT_G_misc() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000359 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
360 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +0000361 curdir = nullstr; \
362 physdir = nullstr; \
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200363 trap_ptr = trap; \
Denis Vlasenko01631112007-12-16 17:20:38 +0000364} while (0)
365
366
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000367/* ============ DEBUG */
368#if DEBUG
369static void trace_printf(const char *fmt, ...);
370static void trace_vprintf(const char *fmt, va_list va);
371# define TRACE(param) trace_printf param
372# define TRACEV(param) trace_vprintf param
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000373# define close(fd) do { \
374 int dfd = (fd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000375 if (close(dfd) < 0) \
Denys Vlasenko883cea42009-07-11 15:31:59 +0200376 bb_error_msg("bug on %d: closing %d(0x%x)", \
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000377 __LINE__, dfd, dfd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000378} while (0)
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000379#else
380# define TRACE(param)
381# define TRACEV(param)
382#endif
383
384
Denis Vlasenko559691a2008-10-05 18:39:31 +0000385/* ============ Utility functions */
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000386#define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
387
Denis Vlasenko559691a2008-10-05 18:39:31 +0000388static int isdigit_str9(const char *str)
389{
390 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
391 while (--maxlen && isdigit(*str))
392 str++;
393 return (*str == '\0');
394}
Denis Vlasenko01631112007-12-16 17:20:38 +0000395
Denys Vlasenko8837c5d2010-06-02 12:56:18 +0200396static const char *var_end(const char *var)
397{
398 while (*var)
399 if (*var++ == '=')
400 break;
401 return var;
402}
403
Denis Vlasenko559691a2008-10-05 18:39:31 +0000404
405/* ============ Interrupts / exceptions */
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100406
407static void exitshell(void) NORETURN;
408
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000409/*
Eric Andersen2870d962001-07-02 17:27:21 +0000410 * These macros allow the user to suspend the handling of interrupt signals
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000411 * over a period of time. This is similar to SIGHOLD or to sigblock, but
Eric Andersen2870d962001-07-02 17:27:21 +0000412 * much more efficient and portable. (But hacking the kernel is so much
413 * more fun than worrying about efficiency and portability. :-))
414 */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000415#define INT_OFF do { \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200416 suppress_int++; \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000417 xbarrier(); \
418} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000419
420/*
421 * Called to raise an exception. Since C doesn't include exceptions, we
422 * just do a longjmp to the exception handler. The type of exception is
Denis Vlasenko4b875702009-03-19 13:30:04 +0000423 * stored in the global variable "exception_type".
Denis Vlasenkob012b102007-02-19 22:43:01 +0000424 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000425static void raise_exception(int) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000426static void
427raise_exception(int e)
428{
429#if DEBUG
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000430 if (exception_handler == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000431 abort();
432#endif
433 INT_OFF;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000434 exception_type = e;
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000435 longjmp(exception_handler->loc, 1);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000436}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000437#if DEBUG
438#define raise_exception(e) do { \
439 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
440 raise_exception(e); \
441} while (0)
442#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000443
444/*
445 * Called from trap.c when a SIGINT is received. (If the user specifies
446 * that SIGINT is to be trapped or ignored using the trap builtin, then
447 * this routine is not called.) Suppressint is nonzero when interrupts
448 * are held using the INT_OFF macro. (The test for iflag is just
449 * defensive programming.)
450 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000451static void raise_interrupt(void) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000452static void
453raise_interrupt(void)
454{
Denis Vlasenko4b875702009-03-19 13:30:04 +0000455 int ex_type;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000456
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200457 pending_int = 0;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000458 /* Signal is not automatically unmasked after it is raised,
459 * do it ourself - unmask all signals */
Denis Vlasenko3f165fa2008-03-17 08:29:08 +0000460 sigprocmask_allsigs(SIG_UNBLOCK);
Denys Vlasenko238bf182010-05-18 15:49:07 +0200461 /* pending_sig = 0; - now done in signal_handler() */
Denis Vlasenko7c139b42007-03-21 20:17:27 +0000462
Denis Vlasenko4b875702009-03-19 13:30:04 +0000463 ex_type = EXSIG;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000464 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
465 if (!(rootshell && iflag)) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000466 /* Kill ourself with SIGINT */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000467 signal(SIGINT, SIG_DFL);
468 raise(SIGINT);
469 }
Denis Vlasenko4b875702009-03-19 13:30:04 +0000470 ex_type = EXINT;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000471 }
Denis Vlasenko4b875702009-03-19 13:30:04 +0000472 raise_exception(ex_type);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000473 /* NOTREACHED */
474}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000475#if DEBUG
476#define raise_interrupt() do { \
477 TRACE(("raising interrupt on line %d\n", __LINE__)); \
478 raise_interrupt(); \
479} while (0)
480#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000481
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000482static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000483int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000484{
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +0000485 xbarrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200486 if (--suppress_int == 0 && pending_int) {
Denis Vlasenkob012b102007-02-19 22:43:01 +0000487 raise_interrupt();
488 }
489}
490#define INT_ON int_on()
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000491static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000492force_int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000493{
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +0000494 xbarrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200495 suppress_int = 0;
496 if (pending_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000497 raise_interrupt();
498}
499#define FORCE_INT_ON force_int_on()
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000500
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200501#define SAVE_INT(v) ((v) = suppress_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000502
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000503#define RESTORE_INT(v) do { \
504 xbarrier(); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200505 suppress_int = (v); \
506 if (suppress_int == 0 && pending_int) \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000507 raise_interrupt(); \
508} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000509
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000510
Denis Vlasenkobc54cff2007-02-23 01:05:52 +0000511/* ============ Stdout/stderr output */
Eric Andersenc470f442003-07-28 09:56:35 +0000512
Eric Andersenc470f442003-07-28 09:56:35 +0000513static void
Denis Vlasenkob012b102007-02-19 22:43:01 +0000514outstr(const char *p, FILE *file)
Denis Vlasenkoe5570da2007-02-19 22:41:55 +0000515{
Denis Vlasenkob012b102007-02-19 22:43:01 +0000516 INT_OFF;
517 fputs(p, file);
518 INT_ON;
519}
520
521static void
522flush_stdout_stderr(void)
523{
524 INT_OFF;
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100525 fflush_all();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000526 INT_ON;
527}
528
529static void
530outcslow(int c, FILE *dest)
531{
532 INT_OFF;
533 putc(c, dest);
534 fflush(dest);
535 INT_ON;
536}
537
538static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
539static int
540out1fmt(const char *fmt, ...)
541{
542 va_list ap;
543 int r;
544
545 INT_OFF;
546 va_start(ap, fmt);
547 r = vprintf(fmt, ap);
548 va_end(ap);
549 INT_ON;
550 return r;
551}
552
553static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
554static int
555fmtstr(char *outbuf, size_t length, const char *fmt, ...)
556{
557 va_list ap;
558 int ret;
559
560 va_start(ap, fmt);
561 INT_OFF;
562 ret = vsnprintf(outbuf, length, fmt, ap);
563 va_end(ap);
564 INT_ON;
565 return ret;
566}
567
568static void
569out1str(const char *p)
570{
571 outstr(p, stdout);
572}
573
574static void
575out2str(const char *p)
576{
577 outstr(p, stderr);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100578 flush_stdout_stderr();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000579}
580
581
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000582/* ============ Parser structures */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +0000583
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000584/* control characters in argument strings */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100585#define CTL_FIRST CTLESC
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200586#define CTLESC ((unsigned char)'\201') /* escape next character */
587#define CTLVAR ((unsigned char)'\202') /* variable defn */
588#define CTLENDVAR ((unsigned char)'\203')
589#define CTLBACKQ ((unsigned char)'\204')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000590#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
591/* CTLBACKQ | CTLQUOTE == '\205' */
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200592#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
593#define CTLENDARI ((unsigned char)'\207')
594#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100595#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000596
597/* variable substitution byte (follows CTLVAR) */
598#define VSTYPE 0x0f /* type of variable substitution */
599#define VSNUL 0x10 /* colon--treat the empty string as unset */
600#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
601
602/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000603#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
604#define VSMINUS 0x2 /* ${var-text} */
605#define VSPLUS 0x3 /* ${var+text} */
606#define VSQUESTION 0x4 /* ${var?message} */
607#define VSASSIGN 0x5 /* ${var=text} */
608#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
609#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
610#define VSTRIMLEFT 0x8 /* ${var#pattern} */
611#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
612#define VSLENGTH 0xa /* ${#var} */
613#if ENABLE_ASH_BASH_COMPAT
614#define VSSUBSTR 0xc /* ${var:position:length} */
615#define VSREPLACE 0xd /* ${var/pattern/replacement} */
616#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
617#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000618
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000619static const char dolatstr[] ALIGN1 = {
620 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
621};
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000622
Denis Vlasenko559691a2008-10-05 18:39:31 +0000623#define NCMD 0
624#define NPIPE 1
625#define NREDIR 2
626#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000627#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000628#define NAND 5
629#define NOR 6
630#define NSEMI 7
631#define NIF 8
632#define NWHILE 9
633#define NUNTIL 10
634#define NFOR 11
635#define NCASE 12
636#define NCLIST 13
637#define NDEFUN 14
638#define NARG 15
639#define NTO 16
640#if ENABLE_ASH_BASH_COMPAT
641#define NTO2 17
642#endif
643#define NCLOBBER 18
644#define NFROM 19
645#define NFROMTO 20
646#define NAPPEND 21
647#define NTOFD 22
648#define NFROMFD 23
649#define NHERE 24
650#define NXHERE 25
651#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000652#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000653
654union node;
655
656struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000657 smallint type; /* Nxxxx */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000658 union node *assign;
659 union node *args;
660 union node *redirect;
661};
662
663struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000664 smallint type;
665 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000666 struct nodelist *cmdlist;
667};
668
669struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000670 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000671 union node *n;
672 union node *redirect;
673};
674
675struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000676 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000677 union node *ch1;
678 union node *ch2;
679};
680
681struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000682 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000683 union node *test;
684 union node *ifpart;
685 union node *elsepart;
686};
687
688struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000689 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000690 union node *args;
691 union node *body;
692 char *var;
693};
694
695struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000696 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000697 union node *expr;
698 union node *cases;
699};
700
701struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000702 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000703 union node *next;
704 union node *pattern;
705 union node *body;
706};
707
708struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000709 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000710 union node *next;
711 char *text;
712 struct nodelist *backquote;
713};
714
Denis Vlasenko559691a2008-10-05 18:39:31 +0000715/* nfile and ndup layout must match!
716 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
717 * that it is actually NTO2 (>&file), and change its type.
718 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000719struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000720 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000721 union node *next;
722 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000723 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000724 union node *fname;
725 char *expfname;
726};
727
728struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000729 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000730 union node *next;
731 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000732 int dupfd;
733 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000734 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000735};
736
737struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000738 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000739 union node *next;
740 int fd;
741 union node *doc;
742};
743
744struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000745 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000746 union node *com;
747};
748
749union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000750 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000751 struct ncmd ncmd;
752 struct npipe npipe;
753 struct nredir nredir;
754 struct nbinary nbinary;
755 struct nif nif;
756 struct nfor nfor;
757 struct ncase ncase;
758 struct nclist nclist;
759 struct narg narg;
760 struct nfile nfile;
761 struct ndup ndup;
762 struct nhere nhere;
763 struct nnot nnot;
764};
765
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200766/*
767 * NODE_EOF is returned by parsecmd when it encounters an end of file.
768 * It must be distinct from NULL.
769 */
770#define NODE_EOF ((union node *) -1L)
771
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000772struct nodelist {
773 struct nodelist *next;
774 union node *n;
775};
776
777struct funcnode {
778 int count;
779 union node n;
780};
781
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000782/*
783 * Free a parse tree.
784 */
785static void
786freefunc(struct funcnode *f)
787{
788 if (f && --f->count < 0)
789 free(f);
790}
791
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000792
793/* ============ Debugging output */
794
795#if DEBUG
796
797static FILE *tracefile;
798
799static void
800trace_printf(const char *fmt, ...)
801{
802 va_list va;
803
804 if (debug != 1)
805 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000806 if (DEBUG_TIME)
807 fprintf(tracefile, "%u ", (int) time(NULL));
808 if (DEBUG_PID)
809 fprintf(tracefile, "[%u] ", (int) getpid());
810 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200811 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000812 va_start(va, fmt);
813 vfprintf(tracefile, fmt, va);
814 va_end(va);
815}
816
817static void
818trace_vprintf(const char *fmt, va_list va)
819{
820 if (debug != 1)
821 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000822 if (DEBUG_TIME)
823 fprintf(tracefile, "%u ", (int) time(NULL));
824 if (DEBUG_PID)
825 fprintf(tracefile, "[%u] ", (int) getpid());
826 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200827 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000828 vfprintf(tracefile, fmt, va);
829}
830
831static void
832trace_puts(const char *s)
833{
834 if (debug != 1)
835 return;
836 fputs(s, tracefile);
837}
838
839static void
840trace_puts_quoted(char *s)
841{
842 char *p;
843 char c;
844
845 if (debug != 1)
846 return;
847 putc('"', tracefile);
848 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100849 switch ((unsigned char)*p) {
850 case '\n': c = 'n'; goto backslash;
851 case '\t': c = 't'; goto backslash;
852 case '\r': c = 'r'; goto backslash;
853 case '\"': c = '\"'; goto backslash;
854 case '\\': c = '\\'; goto backslash;
855 case CTLESC: c = 'e'; goto backslash;
856 case CTLVAR: c = 'v'; goto backslash;
857 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
858 case CTLBACKQ: c = 'q'; goto backslash;
859 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000860 backslash:
861 putc('\\', tracefile);
862 putc(c, tracefile);
863 break;
864 default:
865 if (*p >= ' ' && *p <= '~')
866 putc(*p, tracefile);
867 else {
868 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +0100869 putc((*p >> 6) & 03, tracefile);
870 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000871 putc(*p & 07, tracefile);
872 }
873 break;
874 }
875 }
876 putc('"', tracefile);
877}
878
879static void
880trace_puts_args(char **ap)
881{
882 if (debug != 1)
883 return;
884 if (!*ap)
885 return;
886 while (1) {
887 trace_puts_quoted(*ap);
888 if (!*++ap) {
889 putc('\n', tracefile);
890 break;
891 }
892 putc(' ', tracefile);
893 }
894}
895
896static void
897opentrace(void)
898{
899 char s[100];
900#ifdef O_APPEND
901 int flags;
902#endif
903
904 if (debug != 1) {
905 if (tracefile)
906 fflush(tracefile);
907 /* leave open because libedit might be using it */
908 return;
909 }
910 strcpy(s, "./trace");
911 if (tracefile) {
912 if (!freopen(s, "a", tracefile)) {
913 fprintf(stderr, "Can't re-open %s\n", s);
914 debug = 0;
915 return;
916 }
917 } else {
918 tracefile = fopen(s, "a");
919 if (tracefile == NULL) {
920 fprintf(stderr, "Can't open %s\n", s);
921 debug = 0;
922 return;
923 }
924 }
925#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000926 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000927 if (flags >= 0)
928 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
929#endif
930 setlinebuf(tracefile);
931 fputs("\nTracing started.\n", tracefile);
932}
933
934static void
935indent(int amount, char *pfx, FILE *fp)
936{
937 int i;
938
939 for (i = 0; i < amount; i++) {
940 if (pfx && i == amount - 1)
941 fputs(pfx, fp);
942 putc('\t', fp);
943 }
944}
945
946/* little circular references here... */
947static void shtree(union node *n, int ind, char *pfx, FILE *fp);
948
949static void
950sharg(union node *arg, FILE *fp)
951{
952 char *p;
953 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100954 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000955
956 if (arg->type != NARG) {
957 out1fmt("<node type %d>\n", arg->type);
958 abort();
959 }
960 bqlist = arg->narg.backquote;
961 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100962 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000963 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -0700964 p++;
965 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000966 break;
967 case CTLVAR:
968 putc('$', fp);
969 putc('{', fp);
970 subtype = *++p;
971 if (subtype == VSLENGTH)
972 putc('#', fp);
973
Dan Fandrich77d48722010-09-07 23:38:28 -0700974 while (*p != '=') {
975 putc(*p, fp);
976 p++;
977 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000978
979 if (subtype & VSNUL)
980 putc(':', fp);
981
982 switch (subtype & VSTYPE) {
983 case VSNORMAL:
984 putc('}', fp);
985 break;
986 case VSMINUS:
987 putc('-', fp);
988 break;
989 case VSPLUS:
990 putc('+', fp);
991 break;
992 case VSQUESTION:
993 putc('?', fp);
994 break;
995 case VSASSIGN:
996 putc('=', fp);
997 break;
998 case VSTRIMLEFT:
999 putc('#', fp);
1000 break;
1001 case VSTRIMLEFTMAX:
1002 putc('#', fp);
1003 putc('#', fp);
1004 break;
1005 case VSTRIMRIGHT:
1006 putc('%', fp);
1007 break;
1008 case VSTRIMRIGHTMAX:
1009 putc('%', fp);
1010 putc('%', fp);
1011 break;
1012 case VSLENGTH:
1013 break;
1014 default:
1015 out1fmt("<subtype %d>", subtype);
1016 }
1017 break;
1018 case CTLENDVAR:
1019 putc('}', fp);
1020 break;
1021 case CTLBACKQ:
1022 case CTLBACKQ|CTLQUOTE:
1023 putc('$', fp);
1024 putc('(', fp);
1025 shtree(bqlist->n, -1, NULL, fp);
1026 putc(')', fp);
1027 break;
1028 default:
1029 putc(*p, fp);
1030 break;
1031 }
1032 }
1033}
1034
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001035static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001036shcmd(union node *cmd, FILE *fp)
1037{
1038 union node *np;
1039 int first;
1040 const char *s;
1041 int dftfd;
1042
1043 first = 1;
1044 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001045 if (!first)
1046 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001047 sharg(np, fp);
1048 first = 0;
1049 }
1050 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001051 if (!first)
1052 putc(' ', fp);
1053 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001054 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001055 case NTO: s = ">>"+1; dftfd = 1; break;
1056 case NCLOBBER: s = ">|"; dftfd = 1; break;
1057 case NAPPEND: s = ">>"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001058#if ENABLE_ASH_BASH_COMPAT
1059 case NTO2:
1060#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001061 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001062 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001063 case NFROMFD: s = "<&"; break;
1064 case NFROMTO: s = "<>"; break;
1065 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001066 }
1067 if (np->nfile.fd != dftfd)
1068 fprintf(fp, "%d", np->nfile.fd);
1069 fputs(s, fp);
1070 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1071 fprintf(fp, "%d", np->ndup.dupfd);
1072 } else {
1073 sharg(np->nfile.fname, fp);
1074 }
1075 first = 0;
1076 }
1077}
1078
1079static void
1080shtree(union node *n, int ind, char *pfx, FILE *fp)
1081{
1082 struct nodelist *lp;
1083 const char *s;
1084
1085 if (n == NULL)
1086 return;
1087
1088 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001089
1090 if (n == NODE_EOF) {
1091 fputs("<EOF>", fp);
1092 return;
1093 }
1094
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001095 switch (n->type) {
1096 case NSEMI:
1097 s = "; ";
1098 goto binop;
1099 case NAND:
1100 s = " && ";
1101 goto binop;
1102 case NOR:
1103 s = " || ";
1104 binop:
1105 shtree(n->nbinary.ch1, ind, NULL, fp);
1106 /* if (ind < 0) */
1107 fputs(s, fp);
1108 shtree(n->nbinary.ch2, ind, NULL, fp);
1109 break;
1110 case NCMD:
1111 shcmd(n, fp);
1112 if (ind >= 0)
1113 putc('\n', fp);
1114 break;
1115 case NPIPE:
1116 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001117 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001118 if (lp->next)
1119 fputs(" | ", fp);
1120 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001121 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001122 fputs(" &", fp);
1123 if (ind >= 0)
1124 putc('\n', fp);
1125 break;
1126 default:
1127 fprintf(fp, "<node type %d>", n->type);
1128 if (ind >= 0)
1129 putc('\n', fp);
1130 break;
1131 }
1132}
1133
1134static void
1135showtree(union node *n)
1136{
1137 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001138 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001139}
1140
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001141#endif /* DEBUG */
1142
1143
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001144/* ============ Parser data */
1145
1146/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001147 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1148 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001149struct strlist {
1150 struct strlist *next;
1151 char *text;
1152};
1153
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001154struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001155
Denis Vlasenkob012b102007-02-19 22:43:01 +00001156struct strpush {
1157 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001158 char *prev_string;
1159 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001160#if ENABLE_ASH_ALIAS
1161 struct alias *ap; /* if push was associated with an alias */
1162#endif
1163 char *string; /* remember the string since it may change */
1164};
1165
1166struct parsefile {
1167 struct parsefile *prev; /* preceding file on stack */
1168 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001169 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001170 int left_in_line; /* number of chars left in this line */
1171 int left_in_buffer; /* number of chars left in this buffer past the line */
1172 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001173 char *buf; /* input buffer */
1174 struct strpush *strpush; /* for pushing strings at this level */
1175 struct strpush basestrpush; /* so pushing one is fast */
1176};
1177
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001178static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001179static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001180static int startlinno; /* line # where last token started */
1181static char *commandname; /* currently executing command */
1182static struct strlist *cmdenviron; /* environment for builtin command */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001183static uint8_t exitstatus; /* exit status of last command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001184
1185
1186/* ============ Message printing */
1187
1188static void
1189ash_vmsg(const char *msg, va_list ap)
1190{
1191 fprintf(stderr, "%s: ", arg0);
1192 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001193 if (strcmp(arg0, commandname))
1194 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001195 if (!iflag || g_parsefile->pf_fd > 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001196 fprintf(stderr, "line %d: ", startlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001197 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001198 vfprintf(stderr, msg, ap);
1199 outcslow('\n', stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001200}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001201
1202/*
1203 * Exverror is called to raise the error exception. If the second argument
1204 * is not NULL then error prints an error message using printf style
1205 * formatting. It then raises the error exception.
1206 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001207static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001208static void
1209ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001210{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001211#if DEBUG
1212 if (msg) {
1213 TRACE(("ash_vmsg_and_raise(%d, \"", cond));
1214 TRACEV((msg, ap));
1215 TRACE(("\") pid=%d\n", getpid()));
1216 } else
1217 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
1218 if (msg)
1219#endif
1220 ash_vmsg(msg, ap);
1221
1222 flush_stdout_stderr();
1223 raise_exception(cond);
1224 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001225}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001226
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001227static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001228static void
1229ash_msg_and_raise_error(const char *msg, ...)
1230{
1231 va_list ap;
1232
1233 va_start(ap, msg);
1234 ash_vmsg_and_raise(EXERROR, msg, ap);
1235 /* NOTREACHED */
1236 va_end(ap);
1237}
1238
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001239static void raise_error_syntax(const char *) NORETURN;
1240static void
1241raise_error_syntax(const char *msg)
1242{
1243 ash_msg_and_raise_error("syntax error: %s", msg);
1244 /* NOTREACHED */
1245}
1246
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001247static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001248static void
1249ash_msg_and_raise(int cond, const char *msg, ...)
1250{
1251 va_list ap;
1252
1253 va_start(ap, msg);
1254 ash_vmsg_and_raise(cond, msg, ap);
1255 /* NOTREACHED */
1256 va_end(ap);
1257}
1258
1259/*
1260 * error/warning routines for external builtins
1261 */
1262static void
1263ash_msg(const char *fmt, ...)
1264{
1265 va_list ap;
1266
1267 va_start(ap, fmt);
1268 ash_vmsg(fmt, ap);
1269 va_end(ap);
1270}
1271
1272/*
1273 * Return a string describing an error. The returned string may be a
1274 * pointer to a static buffer that will be overwritten on the next call.
1275 * Action describes the operation that got the error.
1276 */
1277static const char *
1278errmsg(int e, const char *em)
1279{
1280 if (e == ENOENT || e == ENOTDIR) {
1281 return em;
1282 }
1283 return strerror(e);
1284}
1285
1286
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001287/* ============ Memory allocation */
1288
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001289#if 0
1290/* I consider these wrappers nearly useless:
1291 * ok, they return you to nearest exception handler, but
1292 * how much memory do you leak in the process, making
1293 * memory starvation worse?
1294 */
1295static void *
1296ckrealloc(void * p, size_t nbytes)
1297{
1298 p = realloc(p, nbytes);
1299 if (!p)
Tanguy Pruvot6d9e2a32011-07-04 05:52:52 +02001300 ash_msg_and_raise_error("%s", bb_msg_memory_exhausted);
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001301 return p;
1302}
1303
1304static void *
1305ckmalloc(size_t nbytes)
1306{
1307 return ckrealloc(NULL, nbytes);
1308}
1309
1310static void *
1311ckzalloc(size_t nbytes)
1312{
1313 return memset(ckmalloc(nbytes), 0, nbytes);
1314}
1315
1316static char *
1317ckstrdup(const char *s)
1318{
1319 char *p = strdup(s);
1320 if (!p)
Tanguy Pruvot6d9e2a32011-07-04 05:52:52 +02001321 ash_msg_and_raise_error("%s", bb_msg_memory_exhausted);
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001322 return p;
1323}
1324#else
1325/* Using bbox equivalents. They exit if out of memory */
1326# define ckrealloc xrealloc
1327# define ckmalloc xmalloc
1328# define ckzalloc xzalloc
1329# define ckstrdup xstrdup
1330#endif
1331
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001332/*
1333 * It appears that grabstackstr() will barf with such alignments
1334 * because stalloc() will return a string allocated in a new stackblock.
1335 */
1336#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1337enum {
1338 /* Most machines require the value returned from malloc to be aligned
1339 * in some way. The following macro will get this right
1340 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001341 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001342 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001343 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001344};
1345
1346struct stack_block {
1347 struct stack_block *prev;
1348 char space[MINSIZE];
1349};
1350
1351struct stackmark {
1352 struct stack_block *stackp;
1353 char *stacknxt;
1354 size_t stacknleft;
1355 struct stackmark *marknext;
1356};
1357
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001358
Denis Vlasenko01631112007-12-16 17:20:38 +00001359struct globals_memstack {
1360 struct stack_block *g_stackp; // = &stackbase;
1361 struct stackmark *markp;
1362 char *g_stacknxt; // = stackbase.space;
1363 char *sstrend; // = stackbase.space + MINSIZE;
1364 size_t g_stacknleft; // = MINSIZE;
1365 int herefd; // = -1;
1366 struct stack_block stackbase;
1367};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001368extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1369#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001370#define g_stackp (G_memstack.g_stackp )
1371#define markp (G_memstack.markp )
1372#define g_stacknxt (G_memstack.g_stacknxt )
1373#define sstrend (G_memstack.sstrend )
1374#define g_stacknleft (G_memstack.g_stacknleft)
1375#define herefd (G_memstack.herefd )
1376#define stackbase (G_memstack.stackbase )
1377#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001378 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1379 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001380 g_stackp = &stackbase; \
1381 g_stacknxt = stackbase.space; \
1382 g_stacknleft = MINSIZE; \
1383 sstrend = stackbase.space + MINSIZE; \
1384 herefd = -1; \
1385} while (0)
1386
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001387
Denis Vlasenko01631112007-12-16 17:20:38 +00001388#define stackblock() ((void *)g_stacknxt)
1389#define stackblocksize() g_stacknleft
1390
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001391/*
1392 * Parse trees for commands are allocated in lifo order, so we use a stack
1393 * to make this more efficient, and also to avoid all sorts of exception
1394 * handling code to handle interrupts in the middle of a parse.
1395 *
1396 * The size 504 was chosen because the Ultrix malloc handles that size
1397 * well.
1398 */
1399static void *
1400stalloc(size_t nbytes)
1401{
1402 char *p;
1403 size_t aligned;
1404
1405 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001406 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001407 size_t len;
1408 size_t blocksize;
1409 struct stack_block *sp;
1410
1411 blocksize = aligned;
1412 if (blocksize < MINSIZE)
1413 blocksize = MINSIZE;
1414 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1415 if (len < blocksize)
Tanguy Pruvot6d9e2a32011-07-04 05:52:52 +02001416 ash_msg_and_raise_error("%s", bb_msg_memory_exhausted);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001417 INT_OFF;
1418 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001419 sp->prev = g_stackp;
1420 g_stacknxt = sp->space;
1421 g_stacknleft = blocksize;
1422 sstrend = g_stacknxt + blocksize;
1423 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001424 INT_ON;
1425 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001426 p = g_stacknxt;
1427 g_stacknxt += aligned;
1428 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001429 return p;
1430}
1431
Denis Vlasenko597906c2008-02-20 16:38:54 +00001432static void *
1433stzalloc(size_t nbytes)
1434{
1435 return memset(stalloc(nbytes), 0, nbytes);
1436}
1437
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001438static void
1439stunalloc(void *p)
1440{
1441#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001442 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001443 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001444 abort();
1445 }
1446#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001447 g_stacknleft += g_stacknxt - (char *)p;
1448 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001449}
1450
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001451/*
1452 * Like strdup but works with the ash stack.
1453 */
1454static char *
1455ststrdup(const char *p)
1456{
1457 size_t len = strlen(p) + 1;
1458 return memcpy(stalloc(len), p, len);
1459}
1460
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001461static void
1462setstackmark(struct stackmark *mark)
1463{
Denis Vlasenko01631112007-12-16 17:20:38 +00001464 mark->stackp = g_stackp;
1465 mark->stacknxt = g_stacknxt;
1466 mark->stacknleft = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001467 mark->marknext = markp;
1468 markp = mark;
1469}
1470
1471static void
1472popstackmark(struct stackmark *mark)
1473{
1474 struct stack_block *sp;
1475
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001476 if (!mark->stackp)
1477 return;
1478
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001479 INT_OFF;
1480 markp = mark->marknext;
Denis Vlasenko01631112007-12-16 17:20:38 +00001481 while (g_stackp != mark->stackp) {
1482 sp = g_stackp;
1483 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001484 free(sp);
1485 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001486 g_stacknxt = mark->stacknxt;
1487 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001488 sstrend = mark->stacknxt + mark->stacknleft;
1489 INT_ON;
1490}
1491
1492/*
1493 * When the parser reads in a string, it wants to stick the string on the
1494 * stack and only adjust the stack pointer when it knows how big the
1495 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1496 * of space on top of the stack and stackblocklen returns the length of
1497 * this block. Growstackblock will grow this space by at least one byte,
1498 * possibly moving it (like realloc). Grabstackblock actually allocates the
1499 * part of the block that has been used.
1500 */
1501static void
1502growstackblock(void)
1503{
1504 size_t newlen;
1505
Denis Vlasenko01631112007-12-16 17:20:38 +00001506 newlen = g_stacknleft * 2;
1507 if (newlen < g_stacknleft)
Tanguy Pruvot6d9e2a32011-07-04 05:52:52 +02001508 ash_msg_and_raise_error("%s", bb_msg_memory_exhausted);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001509 if (newlen < 128)
1510 newlen += 128;
1511
Denis Vlasenko01631112007-12-16 17:20:38 +00001512 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001513 struct stack_block *oldstackp;
1514 struct stackmark *xmark;
1515 struct stack_block *sp;
1516 struct stack_block *prevstackp;
1517 size_t grosslen;
1518
1519 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001520 oldstackp = g_stackp;
1521 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001522 prevstackp = sp->prev;
1523 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1524 sp = ckrealloc(sp, grosslen);
1525 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001526 g_stackp = sp;
1527 g_stacknxt = sp->space;
1528 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001529 sstrend = sp->space + newlen;
1530
1531 /*
1532 * Stack marks pointing to the start of the old block
1533 * must be relocated to point to the new block
1534 */
1535 xmark = markp;
1536 while (xmark != NULL && xmark->stackp == oldstackp) {
Denis Vlasenko01631112007-12-16 17:20:38 +00001537 xmark->stackp = g_stackp;
1538 xmark->stacknxt = g_stacknxt;
1539 xmark->stacknleft = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001540 xmark = xmark->marknext;
1541 }
1542 INT_ON;
1543 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001544 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001545 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001546 char *p = stalloc(newlen);
1547
1548 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001549 g_stacknxt = memcpy(p, oldspace, oldlen);
1550 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001551 }
1552}
1553
1554static void
1555grabstackblock(size_t len)
1556{
1557 len = SHELL_ALIGN(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001558 g_stacknxt += len;
1559 g_stacknleft -= len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001560}
1561
1562/*
1563 * The following routines are somewhat easier to use than the above.
1564 * The user declares a variable of type STACKSTR, which may be declared
1565 * to be a register. The macro STARTSTACKSTR initializes things. Then
1566 * the user uses the macro STPUTC to add characters to the string. In
1567 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1568 * grown as necessary. When the user is done, she can just leave the
1569 * string there and refer to it using stackblock(). Or she can allocate
1570 * the space for it using grabstackstr(). If it is necessary to allow
1571 * someone else to use the stack temporarily and then continue to grow
1572 * the string, the user should use grabstack to allocate the space, and
1573 * then call ungrabstr(p) to return to the previous mode of operation.
1574 *
1575 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1576 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1577 * is space for at least one character.
1578 */
1579static void *
1580growstackstr(void)
1581{
1582 size_t len = stackblocksize();
1583 if (herefd >= 0 && len >= 1024) {
1584 full_write(herefd, stackblock(), len);
1585 return stackblock();
1586 }
1587 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001588 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001589}
1590
1591/*
1592 * Called from CHECKSTRSPACE.
1593 */
1594static char *
1595makestrspace(size_t newlen, char *p)
1596{
Denis Vlasenko01631112007-12-16 17:20:38 +00001597 size_t len = p - g_stacknxt;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001598 size_t size = stackblocksize();
1599
1600 for (;;) {
1601 size_t nleft;
1602
1603 size = stackblocksize();
1604 nleft = size - len;
1605 if (nleft >= newlen)
1606 break;
1607 growstackblock();
1608 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001609 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001610}
1611
1612static char *
1613stack_nputstr(const char *s, size_t n, char *p)
1614{
1615 p = makestrspace(n, p);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001616 p = (char *)memcpy(p, s, n) + n;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001617 return p;
1618}
1619
1620static char *
1621stack_putstr(const char *s, char *p)
1622{
1623 return stack_nputstr(s, strlen(s), p);
1624}
1625
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001626static char *
1627_STPUTC(int c, char *p)
1628{
1629 if (p == sstrend)
1630 p = growstackstr();
1631 *p++ = c;
1632 return p;
1633}
1634
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001635#define STARTSTACKSTR(p) ((p) = stackblock())
1636#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001637#define CHECKSTRSPACE(n, p) do { \
1638 char *q = (p); \
1639 size_t l = (n); \
1640 size_t m = sstrend - q; \
1641 if (l > m) \
1642 (p) = makestrspace(l, q); \
1643} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001644#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001645#define STACKSTRNUL(p) do { \
1646 if ((p) == sstrend) \
1647 (p) = growstackstr(); \
1648 *(p) = '\0'; \
1649} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001650#define STUNPUTC(p) (--(p))
1651#define STTOPC(p) ((p)[-1])
1652#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001653
1654#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001655#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001656#define stackstrend() ((void *)sstrend)
1657
1658
1659/* ============ String helpers */
1660
1661/*
1662 * prefix -- see if pfx is a prefix of string.
1663 */
1664static char *
1665prefix(const char *string, const char *pfx)
1666{
1667 while (*pfx) {
1668 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001669 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001670 }
1671 return (char *) string;
1672}
1673
1674/*
1675 * Check for a valid number. This should be elsewhere.
1676 */
1677static int
1678is_number(const char *p)
1679{
1680 do {
1681 if (!isdigit(*p))
1682 return 0;
1683 } while (*++p != '\0');
1684 return 1;
1685}
1686
1687/*
1688 * Convert a string of digits to an integer, printing an error message on
1689 * failure.
1690 */
1691static int
1692number(const char *s)
1693{
1694 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001695 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001696 return atoi(s);
1697}
1698
1699/*
1700 * Produce a possibly single quoted string suitable as input to the shell.
1701 * The return string is allocated on the stack.
1702 */
1703static char *
1704single_quote(const char *s)
1705{
1706 char *p;
1707
1708 STARTSTACKSTR(p);
1709
1710 do {
1711 char *q;
1712 size_t len;
1713
1714 len = strchrnul(s, '\'') - s;
1715
1716 q = p = makestrspace(len + 3, p);
1717
1718 *q++ = '\'';
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001719 q = (char *)memcpy(q, s, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001720 *q++ = '\'';
1721 s += len;
1722
1723 STADJUST(q - p, p);
1724
Denys Vlasenkocd716832009-11-28 22:14:02 +01001725 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001726 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001727 len = 0;
1728 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001729
1730 q = p = makestrspace(len + 3, p);
1731
1732 *q++ = '"';
Denys Vlasenkocd716832009-11-28 22:14:02 +01001733 q = (char *)memcpy(q, s - len, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001734 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001735
1736 STADJUST(q - p, p);
1737 } while (*s);
1738
Denys Vlasenkocd716832009-11-28 22:14:02 +01001739 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001740
1741 return stackblock();
1742}
1743
1744
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001745/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001746
1747static char **argptr; /* argument list for builtin commands */
1748static char *optionarg; /* set by nextopt (like getopt) */
1749static char *optptr; /* used by nextopt */
1750
1751/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001752 * XXX - should get rid of. Have all builtins use getopt(3).
1753 * The library getopt must have the BSD extension static variable
1754 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001755 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001756 * Standard option processing (a la getopt) for builtin routines.
1757 * The only argument that is passed to nextopt is the option string;
1758 * the other arguments are unnecessary. It returns the character,
1759 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001760 */
1761static int
1762nextopt(const char *optstring)
1763{
1764 char *p;
1765 const char *q;
1766 char c;
1767
1768 p = optptr;
1769 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001770 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001771 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001772 if (p == NULL)
1773 return '\0';
1774 if (*p != '-')
1775 return '\0';
1776 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001777 return '\0';
1778 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001779 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001780 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001781 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001782 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001783 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001784 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001785 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001786 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001787 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001788 if (*++q == ':')
1789 q++;
1790 }
1791 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001792 if (*p == '\0') {
1793 p = *argptr++;
1794 if (p == NULL)
1795 ash_msg_and_raise_error("no arg for -%c option", c);
1796 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001797 optionarg = p;
1798 p = NULL;
1799 }
1800 optptr = p;
1801 return c;
1802}
1803
1804
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001805/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001806
Denis Vlasenko01631112007-12-16 17:20:38 +00001807/*
1808 * The parsefile structure pointed to by the global variable parsefile
1809 * contains information about the current file being read.
1810 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001811struct shparam {
1812 int nparam; /* # of positional parameters (without $0) */
1813#if ENABLE_ASH_GETOPTS
1814 int optind; /* next parameter to be processed by getopts */
1815 int optoff; /* used by getopts */
1816#endif
1817 unsigned char malloced; /* if parameter list dynamically allocated */
1818 char **p; /* parameter list */
1819};
1820
1821/*
1822 * Free the list of positional parameters.
1823 */
1824static void
1825freeparam(volatile struct shparam *param)
1826{
Denis Vlasenko01631112007-12-16 17:20:38 +00001827 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001828 char **ap, **ap1;
1829 ap = ap1 = param->p;
1830 while (*ap)
1831 free(*ap++);
1832 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001833 }
1834}
1835
1836#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001837static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001838#endif
1839
1840struct var {
1841 struct var *next; /* next entry in hash list */
1842 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001843 const char *var_text; /* name=value */
1844 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001845 /* the variable gets set/unset */
1846};
1847
1848struct localvar {
1849 struct localvar *next; /* next local variable in list */
1850 struct var *vp; /* the variable that was made local */
1851 int flags; /* saved flags */
1852 const char *text; /* saved text */
1853};
1854
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001855/* flags */
1856#define VEXPORT 0x01 /* variable is exported */
1857#define VREADONLY 0x02 /* variable cannot be modified */
1858#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1859#define VTEXTFIXED 0x08 /* text is statically allocated */
1860#define VSTACK 0x10 /* text is allocated on the stack */
1861#define VUNSET 0x20 /* the variable is not set */
1862#define VNOFUNC 0x40 /* don't call the callback function */
1863#define VNOSET 0x80 /* do not set variable - just readonly test */
1864#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001865#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001866# define VDYNAMIC 0x200 /* dynamic variable */
1867#else
1868# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001869#endif
1870
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001871
Denis Vlasenko01631112007-12-16 17:20:38 +00001872/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001873#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001874static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001875change_lc_all(const char *value)
1876{
1877 if (value && *value != '\0')
1878 setlocale(LC_ALL, value);
1879}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001880static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001881change_lc_ctype(const char *value)
1882{
1883 if (value && *value != '\0')
1884 setlocale(LC_CTYPE, value);
1885}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001886#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001887#if ENABLE_ASH_MAIL
1888static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01001889static void changemail(const char *var_value) FAST_FUNC;
1890#else
1891# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001892#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001893static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001894#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001895static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001896#endif
1897
Denis Vlasenko01631112007-12-16 17:20:38 +00001898static const struct {
1899 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001900 const char *var_text;
1901 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00001902} varinit_data[] = {
Denys Vlasenko6e73af52012-07-14 01:07:39 +02001903 /*
1904 * Note: VEXPORT would not work correctly here for NOFORK applets:
1905 * some environment strings may be constant.
1906 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001907 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001908#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001909 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
1910 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001911#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001912 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1913 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1914 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1915 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001916#if ENABLE_ASH_GETOPTS
Denis Vlasenko01631112007-12-16 17:20:38 +00001917 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001918#endif
1919#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001920 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001921#endif
1922#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001923 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
1924 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001925#endif
1926#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001927 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001928#endif
1929};
1930
Denis Vlasenko0b769642008-07-24 07:54:57 +00001931struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00001932
1933struct globals_var {
1934 struct shparam shellparam; /* $@ current positional parameters */
1935 struct redirtab *redirlist;
1936 int g_nullredirs;
1937 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1938 struct var *vartab[VTABSIZE];
1939 struct var varinit[ARRAY_SIZE(varinit_data)];
1940};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001941extern struct globals_var *const ash_ptr_to_globals_var;
1942#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00001943#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00001944//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00001945#define g_nullredirs (G_var.g_nullredirs )
1946#define preverrout_fd (G_var.preverrout_fd)
1947#define vartab (G_var.vartab )
1948#define varinit (G_var.varinit )
1949#define INIT_G_var() do { \
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00001950 unsigned i; \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001951 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1952 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001953 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001954 varinit[i].flags = varinit_data[i].flags; \
1955 varinit[i].var_text = varinit_data[i].var_text; \
1956 varinit[i].var_func = varinit_data[i].var_func; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001957 } \
1958} while (0)
1959
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001960#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001961#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001962# define vmail (&vifs)[1]
1963# define vmpath (&vmail)[1]
1964# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001965#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001966# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001967#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001968#define vps1 (&vpath)[1]
1969#define vps2 (&vps1)[1]
1970#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001971#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001972# define voptind (&vps4)[1]
1973# if ENABLE_ASH_RANDOM_SUPPORT
1974# define vrandom (&voptind)[1]
1975# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001976#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001977# if ENABLE_ASH_RANDOM_SUPPORT
1978# define vrandom (&vps4)[1]
1979# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001980#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001981
1982/*
1983 * The following macros access the values of the above variables.
1984 * They have to skip over the name. They return the null string
1985 * for unset variables.
1986 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001987#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001988#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001989#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001990# define mailval() (vmail.var_text + 5)
1991# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001992# define mpathset() ((vmpath.flags & VUNSET) == 0)
1993#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001994#define pathval() (vpath.var_text + 5)
1995#define ps1val() (vps1.var_text + 4)
1996#define ps2val() (vps2.var_text + 4)
1997#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001998#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001999# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002000#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002001
Denis Vlasenko01631112007-12-16 17:20:38 +00002002#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002003static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002004getoptsreset(const char *value)
2005{
2006 shellparam.optind = number(value);
2007 shellparam.optoff = -1;
2008}
2009#endif
2010
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002011/* math.h has these, otherwise define our private copies */
2012#if !ENABLE_SH_MATH_SUPPORT
2013#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
2014#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002015/*
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002016 * Return the pointer to the first char which is not part of a legal variable name
2017 * (a letter or underscore followed by letters, underscores, and digits).
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002018 */
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002019static const char*
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002020endofname(const char *name)
2021{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002022 if (!is_name(*name))
2023 return name;
2024 while (*++name) {
2025 if (!is_in_name(*name))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002026 break;
2027 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002028 return name;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002029}
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002030#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002031
2032/*
2033 * Compares two strings up to the first = or '\0'. The first
2034 * string must be terminated by '='; the second may be terminated by
2035 * either '=' or '\0'.
2036 */
2037static int
2038varcmp(const char *p, const char *q)
2039{
2040 int c, d;
2041
2042 while ((c = *p) == (d = *q)) {
2043 if (!c || c == '=')
2044 goto out;
2045 p++;
2046 q++;
2047 }
2048 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002049 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002050 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002051 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002052 out:
2053 return c - d;
2054}
2055
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002056/*
2057 * Find the appropriate entry in the hash table from the name.
2058 */
2059static struct var **
2060hashvar(const char *p)
2061{
2062 unsigned hashval;
2063
2064 hashval = ((unsigned char) *p) << 4;
2065 while (*p && *p != '=')
2066 hashval += (unsigned char) *p++;
2067 return &vartab[hashval % VTABSIZE];
2068}
2069
2070static int
2071vpcmp(const void *a, const void *b)
2072{
2073 return varcmp(*(const char **)a, *(const char **)b);
2074}
2075
2076/*
2077 * This routine initializes the builtin variables.
2078 */
2079static void
2080initvar(void)
2081{
2082 struct var *vp;
2083 struct var *end;
2084 struct var **vpp;
2085
2086 /*
2087 * PS1 depends on uid
2088 */
2089#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002090 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002091#else
2092 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002093 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002094#endif
2095 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002096 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002097 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002098 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002099 vp->next = *vpp;
2100 *vpp = vp;
2101 } while (++vp < end);
2102}
2103
2104static struct var **
2105findvar(struct var **vpp, const char *name)
2106{
2107 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002108 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002109 break;
2110 }
2111 }
2112 return vpp;
2113}
2114
2115/*
2116 * Find the value of a variable. Returns NULL if not set.
2117 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002118static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002119lookupvar(const char *name)
2120{
2121 struct var *v;
2122
2123 v = *findvar(hashvar(name), name);
2124 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002125#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002126 /*
2127 * Dynamic variables are implemented roughly the same way they are
2128 * in bash. Namely, they're "special" so long as they aren't unset.
2129 * As soon as they're unset, they're no longer dynamic, and dynamic
2130 * lookup will no longer happen at that point. -- PFM.
2131 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002132 if (v->flags & VDYNAMIC)
2133 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002134#endif
2135 if (!(v->flags & VUNSET))
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002136 return var_end(v->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002137 }
2138 return NULL;
2139}
2140
2141/*
2142 * Search the environment of a builtin command.
2143 */
Mike Frysinger98c52642009-04-02 10:02:37 +00002144static const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002145bltinlookup(const char *name)
2146{
2147 struct strlist *sp;
2148
2149 for (sp = cmdenviron; sp; sp = sp->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002150 if (varcmp(sp->text, name) == 0)
2151 return var_end(sp->text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002152 }
2153 return lookupvar(name);
2154}
2155
2156/*
2157 * Same as setvar except that the variable and value are passed in
2158 * the first argument as name=value. Since the first argument will
2159 * be actually stored in the table, it should not be a string that
2160 * will go away.
2161 * Called with interrupts off.
2162 */
2163static void
2164setvareq(char *s, int flags)
2165{
2166 struct var *vp, **vpp;
2167
2168 vpp = hashvar(s);
2169 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2170 vp = *findvar(vpp, s);
2171 if (vp) {
2172 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2173 const char *n;
2174
2175 if (flags & VNOSAVE)
2176 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002177 n = vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002178 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2179 }
2180
2181 if (flags & VNOSET)
2182 return;
2183
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002184 if (vp->var_func && !(flags & VNOFUNC))
2185 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002186
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002187 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2188 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002189
2190 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2191 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002192 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002193 if (flags & VNOSET)
2194 return;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002195 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002196 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002197 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002198 *vpp = vp;
2199 }
2200 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2201 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002202 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002203 vp->flags = flags;
2204}
2205
2206/*
2207 * Set the value of a variable. The flags argument is ored with the
2208 * flags of the variable. If val is NULL, the variable is unset.
2209 */
2210static void
2211setvar(const char *name, const char *val, int flags)
2212{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002213 const char *q;
2214 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002215 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002216 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002217 size_t vallen;
2218
2219 q = endofname(name);
2220 p = strchrnul(q, '=');
2221 namelen = p - name;
2222 if (!namelen || p != q)
2223 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2224 vallen = 0;
2225 if (val == NULL) {
2226 flags |= VUNSET;
2227 } else {
2228 vallen = strlen(val);
2229 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002230
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002231 INT_OFF;
2232 nameeq = ckmalloc(namelen + vallen + 2);
Tanguy Pruvot6fef6a32012-05-05 15:26:43 +02002233 p = (char*) ((uint32_t) memcpy(nameeq, name, namelen) + namelen);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002234 if (val) {
2235 *p++ = '=';
Tanguy Pruvot6fef6a32012-05-05 15:26:43 +02002236 p = (char*) ((uint32_t) memcpy(p, val, vallen) + vallen);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002237 }
2238 *p = '\0';
2239 setvareq(nameeq, flags | VNOSAVE);
2240 INT_ON;
2241}
2242
Denys Vlasenko03dad222010-01-12 23:29:57 +01002243static void FAST_FUNC
2244setvar2(const char *name, const char *val)
2245{
2246 setvar(name, val, 0);
2247}
2248
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002249#if ENABLE_ASH_GETOPTS
2250/*
2251 * Safe version of setvar, returns 1 on success 0 on failure.
2252 */
2253static int
2254setvarsafe(const char *name, const char *val, int flags)
2255{
2256 int err;
2257 volatile int saveint;
2258 struct jmploc *volatile savehandler = exception_handler;
2259 struct jmploc jmploc;
2260
2261 SAVE_INT(saveint);
2262 if (setjmp(jmploc.loc))
2263 err = 1;
2264 else {
2265 exception_handler = &jmploc;
2266 setvar(name, val, flags);
2267 err = 0;
2268 }
2269 exception_handler = savehandler;
2270 RESTORE_INT(saveint);
2271 return err;
2272}
2273#endif
2274
2275/*
2276 * Unset the specified variable.
2277 */
2278static int
2279unsetvar(const char *s)
2280{
2281 struct var **vpp;
2282 struct var *vp;
2283 int retval;
2284
2285 vpp = findvar(hashvar(s), s);
2286 vp = *vpp;
2287 retval = 2;
2288 if (vp) {
2289 int flags = vp->flags;
2290
2291 retval = 1;
2292 if (flags & VREADONLY)
2293 goto out;
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002294#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002295 vp->flags &= ~VDYNAMIC;
2296#endif
2297 if (flags & VUNSET)
2298 goto ok;
2299 if ((flags & VSTRFIXED) == 0) {
2300 INT_OFF;
2301 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002302 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002303 *vpp = vp->next;
2304 free(vp);
2305 INT_ON;
2306 } else {
2307 setvar(s, 0, 0);
2308 vp->flags &= ~VEXPORT;
2309 }
2310 ok:
2311 retval = 0;
2312 }
2313 out:
2314 return retval;
2315}
2316
2317/*
2318 * Process a linked list of variable assignments.
2319 */
2320static void
2321listsetvar(struct strlist *list_set_var, int flags)
2322{
2323 struct strlist *lp = list_set_var;
2324
2325 if (!lp)
2326 return;
2327 INT_OFF;
2328 do {
2329 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002330 lp = lp->next;
2331 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002332 INT_ON;
2333}
2334
2335/*
2336 * Generate a list of variables satisfying the given conditions.
2337 */
2338static char **
2339listvars(int on, int off, char ***end)
2340{
2341 struct var **vpp;
2342 struct var *vp;
2343 char **ep;
2344 int mask;
2345
2346 STARTSTACKSTR(ep);
2347 vpp = vartab;
2348 mask = on | off;
2349 do {
2350 for (vp = *vpp; vp; vp = vp->next) {
2351 if ((vp->flags & mask) == on) {
2352 if (ep == stackstrend())
2353 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002354 *ep++ = (char*)vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002355 }
2356 }
2357 } while (++vpp < vartab + VTABSIZE);
2358 if (ep == stackstrend())
2359 ep = growstackstr();
2360 if (end)
2361 *end = ep;
2362 *ep++ = NULL;
2363 return grabstackstr(ep);
2364}
2365
2366
2367/* ============ Path search helper
2368 *
2369 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002370 * of the path before the first call; path_advance will update
2371 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002372 * the possible path expansions in sequence. If an option (indicated by
2373 * a percent sign) appears in the path entry then the global variable
2374 * pathopt will be set to point to it; otherwise pathopt will be set to
2375 * NULL.
2376 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002377static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002378
2379static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002380path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002381{
2382 const char *p;
2383 char *q;
2384 const char *start;
2385 size_t len;
2386
2387 if (*path == NULL)
2388 return NULL;
2389 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002390 for (p = start; *p && *p != ':' && *p != '%'; p++)
2391 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002392 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2393 while (stackblocksize() < len)
2394 growstackblock();
2395 q = stackblock();
2396 if (p != start) {
2397 memcpy(q, start, p - start);
2398 q += p - start;
2399 *q++ = '/';
2400 }
2401 strcpy(q, name);
2402 pathopt = NULL;
2403 if (*p == '%') {
2404 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002405 while (*p && *p != ':')
2406 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002407 }
2408 if (*p == ':')
2409 *path = p + 1;
2410 else
2411 *path = NULL;
2412 return stalloc(len);
2413}
2414
2415
2416/* ============ Prompt */
2417
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002418static smallint doprompt; /* if set, prompt the user */
2419static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002420
2421#if ENABLE_FEATURE_EDITING
2422static line_input_t *line_input_state;
2423static const char *cmdedit_prompt;
2424static void
2425putprompt(const char *s)
2426{
2427 if (ENABLE_ASH_EXPAND_PRMT) {
2428 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002429 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002430 return;
2431 }
2432 cmdedit_prompt = s;
2433}
2434#else
2435static void
2436putprompt(const char *s)
2437{
2438 out2str(s);
2439}
2440#endif
2441
2442#if ENABLE_ASH_EXPAND_PRMT
2443/* expandstr() needs parsing machinery, so it is far away ahead... */
2444static const char *expandstr(const char *ps);
2445#else
2446#define expandstr(s) s
2447#endif
2448
2449static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002450setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002451{
2452 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002453 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2454
2455 if (!do_set)
2456 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002457
2458 needprompt = 0;
2459
2460 switch (whichprompt) {
2461 case 1:
2462 prompt = ps1val();
2463 break;
2464 case 2:
2465 prompt = ps2val();
2466 break;
2467 default: /* 0 */
2468 prompt = nullstr;
2469 }
2470#if ENABLE_ASH_EXPAND_PRMT
2471 setstackmark(&smark);
2472 stalloc(stackblocksize());
2473#endif
2474 putprompt(expandstr(prompt));
2475#if ENABLE_ASH_EXPAND_PRMT
2476 popstackmark(&smark);
2477#endif
2478}
2479
2480
2481/* ============ The cd and pwd commands */
2482
2483#define CD_PHYSICAL 1
2484#define CD_PRINT 2
2485
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002486static int
2487cdopt(void)
2488{
2489 int flags = 0;
2490 int i, j;
2491
2492 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002493 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002494 if (i != j) {
2495 flags ^= CD_PHYSICAL;
2496 j = i;
2497 }
2498 }
2499
2500 return flags;
2501}
2502
2503/*
2504 * Update curdir (the name of the current directory) in response to a
2505 * cd command.
2506 */
2507static const char *
2508updatepwd(const char *dir)
2509{
2510 char *new;
2511 char *p;
2512 char *cdcomppath;
2513 const char *lim;
2514
2515 cdcomppath = ststrdup(dir);
2516 STARTSTACKSTR(new);
2517 if (*dir != '/') {
2518 if (curdir == nullstr)
2519 return 0;
2520 new = stack_putstr(curdir, new);
2521 }
2522 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002523 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002524 if (*dir != '/') {
2525 if (new[-1] != '/')
2526 USTPUTC('/', new);
2527 if (new > lim && *lim == '/')
2528 lim++;
2529 } else {
2530 USTPUTC('/', new);
2531 cdcomppath++;
2532 if (dir[1] == '/' && dir[2] != '/') {
2533 USTPUTC('/', new);
2534 cdcomppath++;
2535 lim++;
2536 }
2537 }
2538 p = strtok(cdcomppath, "/");
2539 while (p) {
2540 switch (*p) {
2541 case '.':
2542 if (p[1] == '.' && p[2] == '\0') {
2543 while (new > lim) {
2544 STUNPUTC(new);
2545 if (new[-1] == '/')
2546 break;
2547 }
2548 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002549 }
2550 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002551 break;
2552 /* fall through */
2553 default:
2554 new = stack_putstr(p, new);
2555 USTPUTC('/', new);
2556 }
2557 p = strtok(0, "/");
2558 }
2559 if (new > lim)
2560 STUNPUTC(new);
2561 *new = 0;
2562 return stackblock();
2563}
2564
2565/*
2566 * Find out what the current directory is. If we already know the current
2567 * directory, this routine returns immediately.
2568 */
2569static char *
2570getpwd(void)
2571{
Denis Vlasenko01631112007-12-16 17:20:38 +00002572 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002573 return dir ? dir : nullstr;
2574}
2575
2576static void
2577setpwd(const char *val, int setold)
2578{
2579 char *oldcur, *dir;
2580
2581 oldcur = dir = curdir;
2582
2583 if (setold) {
2584 setvar("OLDPWD", oldcur, VEXPORT);
2585 }
2586 INT_OFF;
2587 if (physdir != nullstr) {
2588 if (physdir != oldcur)
2589 free(physdir);
2590 physdir = nullstr;
2591 }
2592 if (oldcur == val || !val) {
2593 char *s = getpwd();
2594 physdir = s;
2595 if (!val)
2596 dir = s;
2597 } else
2598 dir = ckstrdup(val);
2599 if (oldcur != dir && oldcur != nullstr) {
2600 free(oldcur);
2601 }
2602 curdir = dir;
2603 INT_ON;
2604 setvar("PWD", dir, VEXPORT);
2605}
2606
2607static void hashcd(void);
2608
2609/*
2610 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2611 * know that the current directory has changed.
2612 */
2613static int
2614docd(const char *dest, int flags)
2615{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002616 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002617 int err;
2618
2619 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2620
2621 INT_OFF;
2622 if (!(flags & CD_PHYSICAL)) {
2623 dir = updatepwd(dest);
2624 if (dir)
2625 dest = dir;
2626 }
2627 err = chdir(dest);
2628 if (err)
2629 goto out;
2630 setpwd(dir, 1);
2631 hashcd();
2632 out:
2633 INT_ON;
2634 return err;
2635}
2636
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002637static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002638cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002639{
2640 const char *dest;
2641 const char *path;
2642 const char *p;
2643 char c;
2644 struct stat statb;
2645 int flags;
2646
2647 flags = cdopt();
2648 dest = *argptr;
2649 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002650 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002651 else if (LONE_DASH(dest)) {
2652 dest = bltinlookup("OLDPWD");
2653 flags |= CD_PRINT;
2654 }
2655 if (!dest)
2656 dest = nullstr;
2657 if (*dest == '/')
2658 goto step7;
2659 if (*dest == '.') {
2660 c = dest[1];
2661 dotdot:
2662 switch (c) {
2663 case '\0':
2664 case '/':
2665 goto step6;
2666 case '.':
2667 c = dest[2];
2668 if (c != '.')
2669 goto dotdot;
2670 }
2671 }
2672 if (!*dest)
2673 dest = ".";
2674 path = bltinlookup("CDPATH");
2675 if (!path) {
2676 step6:
2677 step7:
2678 p = dest;
2679 goto docd;
2680 }
2681 do {
2682 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002683 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002684 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2685 if (c && c != ':')
2686 flags |= CD_PRINT;
2687 docd:
2688 if (!docd(p, flags))
2689 goto out;
2690 break;
2691 }
2692 } while (path);
2693 ash_msg_and_raise_error("can't cd to %s", dest);
2694 /* NOTREACHED */
2695 out:
2696 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002697 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002698 return 0;
2699}
2700
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002701static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002702pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002703{
2704 int flags;
2705 const char *dir = curdir;
2706
2707 flags = cdopt();
2708 if (flags) {
2709 if (physdir == nullstr)
2710 setpwd(dir, 0);
2711 dir = physdir;
2712 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002713 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002714 return 0;
2715}
2716
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002717
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002718/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002719
Denis Vlasenko834dee72008-10-07 09:18:30 +00002720
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002721#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002722
Eric Andersenc470f442003-07-28 09:56:35 +00002723/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002724#define CWORD 0 /* character is nothing special */
2725#define CNL 1 /* newline character */
2726#define CBACK 2 /* a backslash character */
2727#define CSQUOTE 3 /* single quote */
2728#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002729#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002730#define CBQUOTE 6 /* backwards single quote */
2731#define CVAR 7 /* a dollar sign */
2732#define CENDVAR 8 /* a '}' character */
2733#define CLP 9 /* a left paren in arithmetic */
2734#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002735#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002736#define CCTL 12 /* like CWORD, except it must be escaped */
2737#define CSPCL 13 /* these terminate a word */
2738#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002739
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002740#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002741#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002742# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002743#endif
2744
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002745#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002746
Mike Frysinger98c52642009-04-02 10:02:37 +00002747#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002748# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002749#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002750# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002751#endif
Denys Vlasenko068d3862009-11-29 01:41:11 +01002752static const uint16_t S_I_T[] = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002753#if ENABLE_ASH_ALIAS
2754 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2755#endif
2756 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2757 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2758 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2759 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2760 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2761 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2762 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2763 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2764 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2765 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2766 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002767#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002768 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2769 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2770 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2771#endif
2772#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002773};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002774/* Constants below must match table above */
2775enum {
2776#if ENABLE_ASH_ALIAS
2777 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2778#endif
2779 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2780 CNL_CNL_CNL_CNL , /* 2 */
2781 CWORD_CCTL_CCTL_CWORD , /* 3 */
2782 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2783 CVAR_CVAR_CWORD_CVAR , /* 5 */
2784 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2785 CSPCL_CWORD_CWORD_CLP , /* 7 */
2786 CSPCL_CWORD_CWORD_CRP , /* 8 */
2787 CBACK_CBACK_CCTL_CBACK , /* 9 */
2788 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2789 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2790 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2791 CWORD_CWORD_CWORD_CWORD , /* 13 */
2792 CCTL_CCTL_CCTL_CCTL , /* 14 */
2793};
Eric Andersen2870d962001-07-02 17:27:21 +00002794
Denys Vlasenkocd716832009-11-28 22:14:02 +01002795/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2796 * caller must ensure proper cast on it if c is *char_ptr!
2797 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002798/* Values for syntax param */
2799#define BASESYNTAX 0 /* not in quotes */
2800#define DQSYNTAX 1 /* in double quotes */
2801#define SQSYNTAX 2 /* in single quotes */
2802#define ARISYNTAX 3 /* in arithmetic */
2803#define PSSYNTAX 4 /* prompt. never passed to SIT() */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002804
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002805#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002806
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002807static int
2808SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002809{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00002810 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
Denys Vlasenkocd716832009-11-28 22:14:02 +01002811# if ENABLE_ASH_ALIAS
2812 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002813 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
2814 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
2815 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2816 11, 3 /* "}~" */
2817 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002818# else
2819 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002820 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
2821 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
2822 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2823 10, 2 /* "}~" */
2824 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002825# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002826 const char *s;
2827 int indx;
2828
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002829 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002830 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002831# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002832 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002833 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002834 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002835# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002836 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002837 /* Cast is purely for paranoia here,
2838 * just in case someone passed signed char to us */
2839 if ((unsigned char)c >= CTL_FIRST
2840 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002841 ) {
2842 return CCTL;
2843 }
2844 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002845 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002846 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002847 indx = syntax_index_table[s - spec_symbls];
2848 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002849 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002850}
2851
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002852#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002853
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002854static const uint8_t syntax_index_table[] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002855 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002856 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2857 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2858 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2859 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2860 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2861 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2862 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2866 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2867 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2872 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2877 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2889 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2890 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2891 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2892 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2893 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2894 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2895 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2896 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2897 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2898 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2899 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2900 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2901 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2902 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
2903 /* 47 "/" */ CWORD_CCTL_CCTL_CWORD,
2904 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2905 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2906 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2907 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2908 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2909 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2910 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2911 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2912 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2913 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2914 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2915 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2916 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2917 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2918 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2919 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2920 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2921 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2922 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2923 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2924 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2925 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2926 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2927 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2928 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2929 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2948 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2949 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2950 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2953 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
2981 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2982 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
2983 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
2984 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2985 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2986 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2987 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2988 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2989 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2990 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2991 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2992 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2993 /* 137 */ CWORD_CWORD_CWORD_CWORD,
2994 /* 138 */ CWORD_CWORD_CWORD_CWORD,
2995 /* 139 */ CWORD_CWORD_CWORD_CWORD,
2996 /* 140 */ CWORD_CWORD_CWORD_CWORD,
2997 /* 141 */ CWORD_CWORD_CWORD_CWORD,
2998 /* 142 */ CWORD_CWORD_CWORD_CWORD,
2999 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3000 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3001 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3002 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3003 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3004 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3005 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3006 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3007 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3008 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3009 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3010 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3011 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3012 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3013 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3014 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3015 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3016 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3017 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3018 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3019 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3020 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3021 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3029 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3042 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3047 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003112 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003113# if ENABLE_ASH_ALIAS
3114 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3115# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003116};
3117
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003118# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003119
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003120#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003121
Eric Andersen2870d962001-07-02 17:27:21 +00003122
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003123/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003124
Denis Vlasenko131ae172007-02-18 13:00:19 +00003125#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003126
3127#define ALIASINUSE 1
3128#define ALIASDEAD 2
3129
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003130struct alias {
3131 struct alias *next;
3132 char *name;
3133 char *val;
3134 int flag;
3135};
3136
Denis Vlasenko01631112007-12-16 17:20:38 +00003137
3138static struct alias **atab; // [ATABSIZE];
3139#define INIT_G_alias() do { \
3140 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3141} while (0)
3142
Eric Andersen2870d962001-07-02 17:27:21 +00003143
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003144static struct alias **
3145__lookupalias(const char *name) {
3146 unsigned int hashval;
3147 struct alias **app;
3148 const char *p;
3149 unsigned int ch;
3150
3151 p = name;
3152
3153 ch = (unsigned char)*p;
3154 hashval = ch << 4;
3155 while (ch) {
3156 hashval += ch;
3157 ch = (unsigned char)*++p;
3158 }
3159 app = &atab[hashval % ATABSIZE];
3160
3161 for (; *app; app = &(*app)->next) {
3162 if (strcmp(name, (*app)->name) == 0) {
3163 break;
3164 }
3165 }
3166
3167 return app;
3168}
3169
3170static struct alias *
3171lookupalias(const char *name, int check)
3172{
3173 struct alias *ap = *__lookupalias(name);
3174
3175 if (check && ap && (ap->flag & ALIASINUSE))
3176 return NULL;
3177 return ap;
3178}
3179
3180static struct alias *
3181freealias(struct alias *ap)
3182{
3183 struct alias *next;
3184
3185 if (ap->flag & ALIASINUSE) {
3186 ap->flag |= ALIASDEAD;
3187 return ap;
3188 }
3189
3190 next = ap->next;
3191 free(ap->name);
3192 free(ap->val);
3193 free(ap);
3194 return next;
3195}
Eric Andersencb57d552001-06-28 07:25:16 +00003196
Eric Andersenc470f442003-07-28 09:56:35 +00003197static void
3198setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003199{
3200 struct alias *ap, **app;
3201
3202 app = __lookupalias(name);
3203 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003204 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003205 if (ap) {
3206 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003207 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003208 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003209 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003210 ap->flag &= ~ALIASDEAD;
3211 } else {
3212 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003213 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003214 ap->name = ckstrdup(name);
3215 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003216 /*ap->flag = 0; - ckzalloc did it */
3217 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003218 *app = ap;
3219 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003220 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003221}
3222
Eric Andersenc470f442003-07-28 09:56:35 +00003223static int
3224unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003225{
Eric Andersencb57d552001-06-28 07:25:16 +00003226 struct alias **app;
3227
3228 app = __lookupalias(name);
3229
3230 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003231 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003232 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003233 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003234 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003235 }
3236
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003237 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003238}
3239
Eric Andersenc470f442003-07-28 09:56:35 +00003240static void
3241rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003242{
Eric Andersencb57d552001-06-28 07:25:16 +00003243 struct alias *ap, **app;
3244 int i;
3245
Denis Vlasenkob012b102007-02-19 22:43:01 +00003246 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003247 for (i = 0; i < ATABSIZE; i++) {
3248 app = &atab[i];
3249 for (ap = *app; ap; ap = *app) {
3250 *app = freealias(*app);
3251 if (ap == *app) {
3252 app = &ap->next;
3253 }
3254 }
3255 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003256 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003257}
3258
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003259static void
3260printalias(const struct alias *ap)
3261{
3262 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3263}
3264
Eric Andersencb57d552001-06-28 07:25:16 +00003265/*
3266 * TODO - sort output
3267 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003268static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003269aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003270{
3271 char *n, *v;
3272 int ret = 0;
3273 struct alias *ap;
3274
Denis Vlasenko68404f12008-03-17 09:00:54 +00003275 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003276 int i;
3277
Denis Vlasenko68404f12008-03-17 09:00:54 +00003278 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003279 for (ap = atab[i]; ap; ap = ap->next) {
3280 printalias(ap);
3281 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003282 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003283 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003284 }
3285 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003286 v = strchr(n+1, '=');
3287 if (v == NULL) { /* n+1: funny ksh stuff */
3288 ap = *__lookupalias(n);
3289 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003290 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003291 ret = 1;
3292 } else
3293 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003294 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003295 *v++ = '\0';
3296 setalias(n, v);
3297 }
3298 }
3299
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003300 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003301}
3302
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003303static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003304unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003305{
3306 int i;
3307
3308 while ((i = nextopt("a")) != '\0') {
3309 if (i == 'a') {
3310 rmaliases();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003311 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003312 }
3313 }
3314 for (i = 0; *argptr; argptr++) {
3315 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003316 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003317 i = 1;
3318 }
3319 }
3320
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003321 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003322}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003323
Denis Vlasenko131ae172007-02-18 13:00:19 +00003324#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003325
Eric Andersenc470f442003-07-28 09:56:35 +00003326
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003327/* ============ jobs.c */
3328
3329/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003330#define FORK_FG 0
3331#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003332#define FORK_NOJOB 2
3333
3334/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003335#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3336#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3337#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003338
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003339/*
3340 * A job structure contains information about a job. A job is either a
3341 * single process or a set of processes contained in a pipeline. In the
3342 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3343 * array of pids.
3344 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003345struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003346 pid_t ps_pid; /* process id */
3347 int ps_status; /* last process status from wait() */
3348 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003349};
3350
3351struct job {
3352 struct procstat ps0; /* status of process */
3353 struct procstat *ps; /* status or processes when more than one */
3354#if JOBS
3355 int stopstatus; /* status of a stopped job */
3356#endif
3357 uint32_t
3358 nprocs: 16, /* number of processes */
3359 state: 8,
3360#define JOBRUNNING 0 /* at least one proc running */
3361#define JOBSTOPPED 1 /* all procs are stopped */
3362#define JOBDONE 2 /* all procs are completed */
3363#if JOBS
3364 sigint: 1, /* job was killed by SIGINT */
3365 jobctl: 1, /* job running under job control */
3366#endif
3367 waited: 1, /* true if this entry has been waited for */
3368 used: 1, /* true if this entry is in used */
3369 changed: 1; /* true if status has changed */
3370 struct job *prev_job; /* previous job */
3371};
3372
Denis Vlasenko68404f12008-03-17 09:00:54 +00003373static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003374static int forkshell(struct job *, union node *, int);
3375static int waitforjob(struct job *);
3376
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003377#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003378enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003379#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003380#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003381static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003382static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003383#endif
3384
3385/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003386 * Ignore a signal.
3387 */
3388static void
3389ignoresig(int signo)
3390{
3391 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3392 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3393 /* No, need to do it */
3394 signal(signo, SIG_IGN);
3395 }
3396 sigmode[signo - 1] = S_HARD_IGN;
3397}
3398
3399/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003400 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003401 */
3402static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003403signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003404{
3405 gotsig[signo - 1] = 1;
3406
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003407 if (signo == SIGINT && !trap[SIGINT]) {
3408 if (!suppress_int) {
3409 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003410 raise_interrupt(); /* does not return */
3411 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003412 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003413 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003414 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003415 }
3416}
3417
3418/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003419 * Set the signal handler for the specified signal. The routine figures
3420 * out what it should be set to.
3421 */
3422static void
3423setsignal(int signo)
3424{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003425 char *t;
3426 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003427 struct sigaction act;
3428
3429 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003430 new_act = S_DFL;
3431 if (t != NULL) { /* trap for this sig is set */
3432 new_act = S_CATCH;
3433 if (t[0] == '\0') /* trap is "": ignore this sig */
3434 new_act = S_IGN;
3435 }
3436
3437 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003438 switch (signo) {
3439 case SIGINT:
3440 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003441 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003442 break;
3443 case SIGQUIT:
3444#if DEBUG
3445 if (debug)
3446 break;
3447#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003448 /* man bash:
3449 * "In all cases, bash ignores SIGQUIT. Non-builtin
3450 * commands run by bash have signal handlers
3451 * set to the values inherited by the shell
3452 * from its parent". */
3453 new_act = S_IGN;
3454 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003455 case SIGTERM:
3456 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003457 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003458 break;
3459#if JOBS
3460 case SIGTSTP:
3461 case SIGTTOU:
3462 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003463 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003464 break;
3465#endif
3466 }
3467 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003468//TODO: if !rootshell, we reset SIGQUIT to DFL,
3469//whereas we have to restore it to what shell got on entry
3470//from the parent. See comment above
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003471
3472 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003473 cur_act = *t;
3474 if (cur_act == 0) {
3475 /* current setting is not yet known */
3476 if (sigaction(signo, NULL, &act)) {
3477 /* pretend it worked; maybe we should give a warning,
3478 * but other shells don't. We don't alter sigmode,
3479 * so we retry every time.
3480 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003481 return;
3482 }
3483 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003484 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003485 if (mflag
3486 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3487 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003488 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003489 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003490 }
3491 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003492 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003493 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003494
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003495 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003496 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003497 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003498 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003499 break;
3500 case S_IGN:
3501 act.sa_handler = SIG_IGN;
3502 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003503 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003504
3505 /* flags and mask matter only if !DFL and !IGN, but we do it
3506 * for all cases for more deterministic behavior:
3507 */
3508 act.sa_flags = 0;
3509 sigfillset(&act.sa_mask);
3510
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003511 sigaction_set(signo, &act);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003512
3513 *t = new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003514}
3515
3516/* mode flags for set_curjob */
3517#define CUR_DELETE 2
3518#define CUR_RUNNING 1
3519#define CUR_STOPPED 0
3520
3521/* mode flags for dowait */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003522#define DOWAIT_NONBLOCK WNOHANG
3523#define DOWAIT_BLOCK 0
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003524
3525#if JOBS
3526/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003527static int initialpgrp; //references:2
3528static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003529#endif
3530/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003531static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003532/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003533static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003534/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003535static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003536/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003537static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003538
3539static void
3540set_curjob(struct job *jp, unsigned mode)
3541{
3542 struct job *jp1;
3543 struct job **jpp, **curp;
3544
3545 /* first remove from list */
3546 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003547 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003548 jp1 = *jpp;
3549 if (jp1 == jp)
3550 break;
3551 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003552 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003553 *jpp = jp1->prev_job;
3554
3555 /* Then re-insert in correct position */
3556 jpp = curp;
3557 switch (mode) {
3558 default:
3559#if DEBUG
3560 abort();
3561#endif
3562 case CUR_DELETE:
3563 /* job being deleted */
3564 break;
3565 case CUR_RUNNING:
3566 /* newly created job or backgrounded job,
Tanguy Pruvot823694d2012-11-18 13:20:29 +01003567 * put after all stopped jobs.
3568 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003569 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003570 jp1 = *jpp;
3571#if JOBS
3572 if (!jp1 || jp1->state != JOBSTOPPED)
3573#endif
3574 break;
3575 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003576 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003577 /* FALLTHROUGH */
3578#if JOBS
3579 case CUR_STOPPED:
3580#endif
3581 /* newly stopped job - becomes curjob */
3582 jp->prev_job = *jpp;
3583 *jpp = jp;
3584 break;
3585 }
3586}
3587
3588#if JOBS || DEBUG
3589static int
3590jobno(const struct job *jp)
3591{
3592 return jp - jobtab + 1;
3593}
3594#endif
3595
3596/*
3597 * Convert a job name to a job structure.
3598 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003599#if !JOBS
3600#define getjob(name, getctl) getjob(name)
3601#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003602static struct job *
3603getjob(const char *name, int getctl)
3604{
3605 struct job *jp;
3606 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003607 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003608 unsigned num;
3609 int c;
3610 const char *p;
3611 char *(*match)(const char *, const char *);
3612
3613 jp = curjob;
3614 p = name;
3615 if (!p)
3616 goto currentjob;
3617
3618 if (*p != '%')
3619 goto err;
3620
3621 c = *++p;
3622 if (!c)
3623 goto currentjob;
3624
3625 if (!p[1]) {
3626 if (c == '+' || c == '%') {
3627 currentjob:
3628 err_msg = "No current job";
3629 goto check;
3630 }
3631 if (c == '-') {
3632 if (jp)
3633 jp = jp->prev_job;
3634 err_msg = "No previous job";
3635 check:
3636 if (!jp)
3637 goto err;
3638 goto gotit;
3639 }
3640 }
3641
3642 if (is_number(p)) {
3643 num = atoi(p);
3644 if (num < njobs) {
3645 jp = jobtab + num - 1;
3646 if (jp->used)
3647 goto gotit;
3648 goto err;
3649 }
3650 }
3651
3652 match = prefix;
3653 if (*p == '?') {
3654 match = strstr;
3655 p++;
3656 }
3657
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003658 found = NULL;
3659 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003660 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003661 if (found)
3662 goto err;
3663 found = jp;
3664 err_msg = "%s: ambiguous";
3665 }
3666 jp = jp->prev_job;
3667 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003668 if (!found)
3669 goto err;
3670 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003671
3672 gotit:
3673#if JOBS
3674 err_msg = "job %s not created under job control";
3675 if (getctl && jp->jobctl == 0)
3676 goto err;
3677#endif
3678 return jp;
3679 err:
3680 ash_msg_and_raise_error(err_msg, name);
3681}
3682
3683/*
3684 * Mark a job structure as unused.
3685 */
3686static void
3687freejob(struct job *jp)
3688{
3689 struct procstat *ps;
3690 int i;
3691
3692 INT_OFF;
3693 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003694 if (ps->ps_cmd != nullstr)
3695 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003696 }
3697 if (jp->ps != &jp->ps0)
3698 free(jp->ps);
3699 jp->used = 0;
3700 set_curjob(jp, CUR_DELETE);
3701 INT_ON;
3702}
3703
3704#if JOBS
3705static void
3706xtcsetpgrp(int fd, pid_t pgrp)
3707{
3708 if (tcsetpgrp(fd, pgrp))
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003709 ash_msg_and_raise_error("can't set tty process group (%m)");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003710}
3711
3712/*
3713 * Turn job control on and off.
3714 *
3715 * Note: This code assumes that the third arg to ioctl is a character
3716 * pointer, which is true on Berkeley systems but not System V. Since
3717 * System V doesn't have job control yet, this isn't a problem now.
3718 *
3719 * Called with interrupts off.
3720 */
3721static void
3722setjobctl(int on)
3723{
3724 int fd;
3725 int pgrp;
3726
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003727 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003728 return;
3729 if (on) {
3730 int ofd;
3731 ofd = fd = open(_PATH_TTY, O_RDWR);
3732 if (fd < 0) {
3733 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3734 * That sometimes helps to acquire controlling tty.
3735 * Obviously, a workaround for bugs when someone
3736 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003737 fd = 2;
3738 while (!isatty(fd))
3739 if (--fd < 0)
3740 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003741 }
3742 fd = fcntl(fd, F_DUPFD, 10);
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003743 if (ofd >= 0)
3744 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003745 if (fd < 0)
3746 goto out;
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003747 /* fd is a tty at this point */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003748 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003749 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003750 pgrp = tcgetpgrp(fd);
3751 if (pgrp < 0) {
3752 out:
3753 ash_msg("can't access tty; job control turned off");
3754 mflag = on = 0;
3755 goto close;
3756 }
3757 if (pgrp == getpgrp())
3758 break;
Tanguy Pruvot8aeb3712011-06-30 08:59:26 +02003759 killpg_busybox(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003760 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003761 initialpgrp = pgrp;
3762
3763 setsignal(SIGTSTP);
3764 setsignal(SIGTTOU);
3765 setsignal(SIGTTIN);
3766 pgrp = rootpid;
3767 setpgid(0, pgrp);
3768 xtcsetpgrp(fd, pgrp);
3769 } else {
3770 /* turning job control off */
3771 fd = ttyfd;
3772 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003773 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003774 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003775 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003776 setpgid(0, pgrp);
3777 setsignal(SIGTSTP);
3778 setsignal(SIGTTOU);
3779 setsignal(SIGTTIN);
3780 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003781 if (fd >= 0)
3782 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003783 fd = -1;
3784 }
3785 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003786 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003787}
3788
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003789static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003790killcmd(int argc, char **argv)
3791{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003792 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003793 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003794 do {
3795 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003796 /*
3797 * "kill %N" - job kill
3798 * Converting to pgrp / pid kill
3799 */
3800 struct job *jp;
3801 char *dst;
3802 int j, n;
3803
3804 jp = getjob(argv[i], 0);
3805 /*
3806 * In jobs started under job control, we signal
3807 * entire process group by kill -PGRP_ID.
3808 * This happens, f.e., in interactive shell.
3809 *
3810 * Otherwise, we signal each child via
3811 * kill PID1 PID2 PID3.
3812 * Testcases:
3813 * sh -c 'sleep 1|sleep 1 & kill %1'
3814 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3815 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3816 */
3817 n = jp->nprocs; /* can't be 0 (I hope) */
3818 if (jp->jobctl)
3819 n = 1;
3820 dst = alloca(n * sizeof(int)*4);
3821 argv[i] = dst;
3822 for (j = 0; j < n; j++) {
3823 struct procstat *ps = &jp->ps[j];
3824 /* Skip non-running and not-stopped members
3825 * (i.e. dead members) of the job
3826 */
3827 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3828 continue;
3829 /*
3830 * kill_main has matching code to expect
3831 * leading space. Needed to not confuse
3832 * negative pids with "kill -SIGNAL_NO" syntax
3833 */
3834 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3835 }
3836 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003837 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003838 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003839 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003840 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003841}
3842
3843static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01003844showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003845{
Denys Vlasenko285ad152009-12-04 23:02:27 +01003846 struct procstat *ps;
3847 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003848
Denys Vlasenko285ad152009-12-04 23:02:27 +01003849 psend = jp->ps + jp->nprocs;
3850 for (ps = jp->ps + 1; ps < psend; ps++)
3851 printf(" | %s", ps->ps_cmd);
3852 outcslow('\n', stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003853 flush_stdout_stderr();
3854}
3855
3856
3857static int
3858restartjob(struct job *jp, int mode)
3859{
3860 struct procstat *ps;
3861 int i;
3862 int status;
3863 pid_t pgid;
3864
3865 INT_OFF;
3866 if (jp->state == JOBDONE)
3867 goto out;
3868 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003869 pgid = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003870 if (mode == FORK_FG)
3871 xtcsetpgrp(ttyfd, pgid);
Tanguy Pruvot8aeb3712011-06-30 08:59:26 +02003872 killpg_busybox(pgid, SIGCONT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003873 ps = jp->ps;
3874 i = jp->nprocs;
3875 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003876 if (WIFSTOPPED(ps->ps_status)) {
3877 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003878 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003879 ps++;
3880 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003881 out:
3882 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3883 INT_ON;
3884 return status;
3885}
3886
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003887static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003888fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003889{
3890 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003891 int mode;
3892 int retval;
3893
3894 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3895 nextopt(nullstr);
3896 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003897 do {
3898 jp = getjob(*argv, 1);
3899 if (mode == FORK_BG) {
3900 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01003901 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003902 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003903 out1str(jp->ps[0].ps_cmd);
3904 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003905 retval = restartjob(jp, mode);
3906 } while (*argv && *++argv);
3907 return retval;
3908}
3909#endif
3910
3911static int
3912sprint_status(char *s, int status, int sigonly)
3913{
3914 int col;
3915 int st;
3916
3917 col = 0;
3918 if (!WIFEXITED(status)) {
3919#if JOBS
3920 if (WIFSTOPPED(status))
3921 st = WSTOPSIG(status);
3922 else
3923#endif
3924 st = WTERMSIG(status);
3925 if (sigonly) {
3926 if (st == SIGINT || st == SIGPIPE)
3927 goto out;
3928#if JOBS
3929 if (WIFSTOPPED(status))
3930 goto out;
3931#endif
3932 }
3933 st &= 0x7f;
Tanguy Pruvot8aeb3712011-06-30 08:59:26 +02003934 col = fmtstr(s, 32, "%s", strsignal(st));
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01003935//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003936 if (WCOREDUMP(status)) {
3937 col += fmtstr(s + col, 16, " (core dumped)");
3938 }
3939 } else if (!sigonly) {
3940 st = WEXITSTATUS(status);
3941 if (st)
3942 col = fmtstr(s, 16, "Done(%d)", st);
3943 else
3944 col = fmtstr(s, 16, "Done");
3945 }
3946 out:
3947 return col;
3948}
3949
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003950static int
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003951dowait(int wait_flags, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003952{
3953 int pid;
3954 int status;
3955 struct job *jp;
3956 struct job *thisjob;
3957 int state;
3958
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00003959 TRACE(("dowait(0x%x) called\n", wait_flags));
3960
3961 /* Do a wait system call. If job control is compiled in, we accept
3962 * stopped processes. wait_flags may have WNOHANG, preventing blocking.
3963 * NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003964 if (doing_jobctl)
3965 wait_flags |= WUNTRACED;
3966 pid = waitpid(-1, &status, wait_flags);
Denis Vlasenkob21f3792009-03-19 23:09:58 +00003967 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
3968 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003969 if (pid <= 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003970 return pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003971
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003972 INT_OFF;
3973 thisjob = NULL;
3974 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003975 struct procstat *ps;
3976 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003977 if (jp->state == JOBDONE)
3978 continue;
3979 state = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003980 ps = jp->ps;
3981 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003982 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003983 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003984 TRACE(("Job %d: changing status of proc %d "
3985 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01003986 jobno(jp), pid, ps->ps_status, status));
3987 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003988 thisjob = jp;
3989 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003990 if (ps->ps_status == -1)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003991 state = JOBRUNNING;
3992#if JOBS
3993 if (state == JOBRUNNING)
3994 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003995 if (WIFSTOPPED(ps->ps_status)) {
3996 jp->stopstatus = ps->ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003997 state = JOBSTOPPED;
3998 }
3999#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004000 } while (++ps < psend);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004001 if (thisjob)
4002 goto gotjob;
4003 }
4004#if JOBS
4005 if (!WIFSTOPPED(status))
4006#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004007 jobless--;
4008 goto out;
4009
4010 gotjob:
4011 if (state != JOBRUNNING) {
4012 thisjob->changed = 1;
4013
4014 if (thisjob->state != state) {
4015 TRACE(("Job %d: changing state from %d to %d\n",
4016 jobno(thisjob), thisjob->state, state));
4017 thisjob->state = state;
4018#if JOBS
4019 if (state == JOBSTOPPED) {
4020 set_curjob(thisjob, CUR_STOPPED);
4021 }
4022#endif
4023 }
4024 }
4025
4026 out:
4027 INT_ON;
4028
4029 if (thisjob && thisjob == job) {
4030 char s[48 + 1];
4031 int len;
4032
4033 len = sprint_status(s, status, 1);
4034 if (len) {
4035 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004036 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004037 out2str(s);
4038 }
4039 }
4040 return pid;
4041}
4042
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004043static int
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004044blocking_wait_with_raise_on_sig(void)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004045{
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004046 pid_t pid = dowait(DOWAIT_BLOCK, NULL);
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004047 if (pid <= 0 && pending_sig)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004048 raise_exception(EXSIG);
4049 return pid;
4050}
4051
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004052#if JOBS
4053static void
4054showjob(FILE *out, struct job *jp, int mode)
4055{
4056 struct procstat *ps;
4057 struct procstat *psend;
4058 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004059 int indent_col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004060 char s[80];
4061
4062 ps = jp->ps;
4063
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004064 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004065 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004066 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004067 return;
4068 }
4069
4070 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004071 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004072
4073 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004074 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004075 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004076 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004077
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004078 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004079 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004080
4081 psend = ps + jp->nprocs;
4082
4083 if (jp->state == JOBRUNNING) {
4084 strcpy(s + col, "Running");
4085 col += sizeof("Running") - 1;
4086 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004087 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004088 if (jp->state == JOBSTOPPED)
4089 status = jp->stopstatus;
4090 col += sprint_status(s + col, status, 0);
4091 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004092 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004093
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004094 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4095 * or prints several "PID | <cmdN>" lines,
4096 * depending on SHOW_PIDS bit.
4097 * We do not print status of individual processes
4098 * between PID and <cmdN>. bash does it, but not very well:
4099 * first line shows overall job status, not process status,
4100 * making it impossible to know 1st process status.
4101 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004102 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004103 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004104 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004105 s[0] = '\0';
4106 col = 33;
4107 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004108 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004109 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004110 fprintf(out, "%s%*c%s%s",
4111 s,
4112 33 - col >= 0 ? 33 - col : 0, ' ',
4113 ps == jp->ps ? "" : "| ",
4114 ps->ps_cmd
4115 );
4116 } while (++ps != psend);
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004117 outcslow('\n', out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004118
4119 jp->changed = 0;
4120
4121 if (jp->state == JOBDONE) {
4122 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4123 freejob(jp);
4124 }
4125}
4126
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004127/*
4128 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4129 * statuses have changed since the last call to showjobs.
4130 */
4131static void
4132showjobs(FILE *out, int mode)
4133{
4134 struct job *jp;
4135
Denys Vlasenko883cea42009-07-11 15:31:59 +02004136 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004137
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004138 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004139 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004140 continue;
4141
4142 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004143 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004144 showjob(out, jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004145 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004146 }
4147}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004148
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004149static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004150jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004151{
4152 int mode, m;
4153
4154 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004155 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004156 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004157 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004158 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004159 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004160 }
4161
4162 argv = argptr;
4163 if (*argv) {
4164 do
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004165 showjob(stdout, getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004166 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004167 } else {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004168 showjobs(stdout, mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004169 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004170
4171 return 0;
4172}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004173#endif /* JOBS */
4174
Michael Abbott359da5e2009-12-04 23:03:29 +01004175/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004176static int
4177getstatus(struct job *job)
4178{
4179 int status;
4180 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004181 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004182
Michael Abbott359da5e2009-12-04 23:03:29 +01004183 /* Fetch last member's status */
4184 ps = job->ps + job->nprocs - 1;
4185 status = ps->ps_status;
4186 if (pipefail) {
4187 /* "set -o pipefail" mode: use last _nonzero_ status */
4188 while (status == 0 && --ps >= job->ps)
4189 status = ps->ps_status;
4190 }
4191
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004192 retval = WEXITSTATUS(status);
4193 if (!WIFEXITED(status)) {
4194#if JOBS
4195 retval = WSTOPSIG(status);
4196 if (!WIFSTOPPED(status))
4197#endif
4198 {
4199 /* XXX: limits number of signals */
4200 retval = WTERMSIG(status);
4201#if JOBS
4202 if (retval == SIGINT)
4203 job->sigint = 1;
4204#endif
4205 }
4206 retval += 128;
4207 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004208 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004209 jobno(job), job->nprocs, status, retval));
4210 return retval;
4211}
4212
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004213static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004214waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004215{
4216 struct job *job;
4217 int retval;
4218 struct job *jp;
4219
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004220 if (pending_sig)
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004221 raise_exception(EXSIG);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004222
4223 nextopt(nullstr);
4224 retval = 0;
4225
4226 argv = argptr;
4227 if (!*argv) {
4228 /* wait for all jobs */
4229 for (;;) {
4230 jp = curjob;
4231 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004232 if (!jp) /* no running procs */
4233 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004234 if (jp->state == JOBRUNNING)
4235 break;
4236 jp->waited = 1;
4237 jp = jp->prev_job;
4238 }
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004239 blocking_wait_with_raise_on_sig();
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004240 /* man bash:
4241 * "When bash is waiting for an asynchronous command via
4242 * the wait builtin, the reception of a signal for which a trap
4243 * has been set will cause the wait builtin to return immediately
4244 * with an exit status greater than 128, immediately after which
4245 * the trap is executed."
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004246 *
4247 * blocking_wait_with_raise_on_sig raises signal handlers
4248 * if it gets no pid (pid < 0). However,
4249 * if child sends us a signal *and immediately exits*,
4250 * blocking_wait_with_raise_on_sig gets pid > 0
4251 * and does not handle pending_sig. Check this case: */
4252 if (pending_sig)
4253 raise_exception(EXSIG);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004254 }
4255 }
4256
4257 retval = 127;
4258 do {
4259 if (**argv != '%') {
4260 pid_t pid = number(*argv);
4261 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004262 while (1) {
4263 if (!job)
4264 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004265 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004266 break;
4267 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004268 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004269 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004270 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004271 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004272 /* loop until process terminated or stopped */
4273 while (job->state == JOBRUNNING)
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004274 blocking_wait_with_raise_on_sig();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004275 job->waited = 1;
4276 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004277 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004278 } while (*++argv);
4279
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004280 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004281 return retval;
4282}
4283
4284static struct job *
4285growjobtab(void)
4286{
4287 size_t len;
4288 ptrdiff_t offset;
4289 struct job *jp, *jq;
4290
4291 len = njobs * sizeof(*jp);
4292 jq = jobtab;
4293 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4294
4295 offset = (char *)jp - (char *)jq;
4296 if (offset) {
4297 /* Relocate pointers */
4298 size_t l = len;
4299
4300 jq = (struct job *)((char *)jq + l);
4301 while (l) {
4302 l -= sizeof(*jp);
4303 jq--;
4304#define joff(p) ((struct job *)((char *)(p) + l))
4305#define jmove(p) (p) = (void *)((char *)(p) + offset)
4306 if (joff(jp)->ps == &jq->ps0)
4307 jmove(joff(jp)->ps);
4308 if (joff(jp)->prev_job)
4309 jmove(joff(jp)->prev_job);
4310 }
4311 if (curjob)
4312 jmove(curjob);
4313#undef joff
4314#undef jmove
4315 }
4316
4317 njobs += 4;
4318 jobtab = jp;
4319 jp = (struct job *)((char *)jp + len);
4320 jq = jp + 3;
4321 do {
4322 jq->used = 0;
4323 } while (--jq >= jp);
4324 return jp;
4325}
4326
4327/*
4328 * Return a new job structure.
4329 * Called with interrupts off.
4330 */
4331static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004332makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004333{
4334 int i;
4335 struct job *jp;
4336
4337 for (i = njobs, jp = jobtab; ; jp++) {
4338 if (--i < 0) {
4339 jp = growjobtab();
4340 break;
4341 }
4342 if (jp->used == 0)
4343 break;
4344 if (jp->state != JOBDONE || !jp->waited)
4345 continue;
4346#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004347 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004348 continue;
4349#endif
4350 freejob(jp);
4351 break;
4352 }
4353 memset(jp, 0, sizeof(*jp));
4354#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004355 /* jp->jobctl is a bitfield.
4356 * "jp->jobctl |= jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004357 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004358 jp->jobctl = 1;
4359#endif
4360 jp->prev_job = curjob;
4361 curjob = jp;
4362 jp->used = 1;
4363 jp->ps = &jp->ps0;
4364 if (nprocs > 1) {
4365 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4366 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004367 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004368 jobno(jp)));
4369 return jp;
4370}
4371
4372#if JOBS
4373/*
4374 * Return a string identifying a command (to be printed by the
4375 * jobs command).
4376 */
4377static char *cmdnextc;
4378
4379static void
4380cmdputs(const char *s)
4381{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004382 static const char vstype[VSTYPE + 1][3] = {
4383 "", "}", "-", "+", "?", "=",
4384 "%", "%%", "#", "##"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00004385 IF_ASH_BASH_COMPAT(, ":", "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004386 };
4387
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004388 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004389 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004390 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004391 unsigned char c;
4392 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004393 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004394
Denys Vlasenko46a14772009-12-10 21:27:13 +01004395 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004396 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4397 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004398 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004399 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004400 switch (c) {
4401 case CTLESC:
4402 c = *p++;
4403 break;
4404 case CTLVAR:
4405 subtype = *p++;
4406 if ((subtype & VSTYPE) == VSLENGTH)
4407 str = "${#";
4408 else
4409 str = "${";
4410 if (!(subtype & VSQUOTE) == !(quoted & 1))
4411 goto dostr;
4412 quoted ^= 1;
4413 c = '"';
4414 break;
4415 case CTLENDVAR:
4416 str = "\"}" + !(quoted & 1);
4417 quoted >>= 1;
4418 subtype = 0;
4419 goto dostr;
4420 case CTLBACKQ:
4421 str = "$(...)";
4422 goto dostr;
4423 case CTLBACKQ+CTLQUOTE:
4424 str = "\"$(...)\"";
4425 goto dostr;
Mike Frysinger98c52642009-04-02 10:02:37 +00004426#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004427 case CTLARI:
4428 str = "$((";
4429 goto dostr;
4430 case CTLENDARI:
4431 str = "))";
4432 goto dostr;
4433#endif
4434 case CTLQUOTEMARK:
4435 quoted ^= 1;
4436 c = '"';
4437 break;
4438 case '=':
4439 if (subtype == 0)
4440 break;
4441 if ((subtype & VSTYPE) != VSNORMAL)
4442 quoted <<= 1;
4443 str = vstype[subtype & VSTYPE];
4444 if (subtype & VSNUL)
4445 c = ':';
4446 else
4447 goto checkstr;
4448 break;
4449 case '\'':
4450 case '\\':
4451 case '"':
4452 case '$':
4453 /* These can only happen inside quotes */
4454 cc[0] = c;
4455 str = cc;
4456 c = '\\';
4457 break;
4458 default:
4459 break;
4460 }
4461 USTPUTC(c, nextc);
4462 checkstr:
4463 if (!str)
4464 continue;
4465 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004466 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004467 USTPUTC(c, nextc);
4468 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004469 } /* while *p++ not NUL */
4470
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004471 if (quoted & 1) {
4472 USTPUTC('"', nextc);
4473 }
4474 *nextc = 0;
4475 cmdnextc = nextc;
4476}
4477
4478/* cmdtxt() and cmdlist() call each other */
4479static void cmdtxt(union node *n);
4480
4481static void
4482cmdlist(union node *np, int sep)
4483{
4484 for (; np; np = np->narg.next) {
4485 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004486 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004487 cmdtxt(np);
4488 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004489 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004490 }
4491}
4492
4493static void
4494cmdtxt(union node *n)
4495{
4496 union node *np;
4497 struct nodelist *lp;
4498 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004499
4500 if (!n)
4501 return;
4502 switch (n->type) {
4503 default:
4504#if DEBUG
4505 abort();
4506#endif
4507 case NPIPE:
4508 lp = n->npipe.cmdlist;
4509 for (;;) {
4510 cmdtxt(lp->n);
4511 lp = lp->next;
4512 if (!lp)
4513 break;
4514 cmdputs(" | ");
4515 }
4516 break;
4517 case NSEMI:
4518 p = "; ";
4519 goto binop;
4520 case NAND:
4521 p = " && ";
4522 goto binop;
4523 case NOR:
4524 p = " || ";
4525 binop:
4526 cmdtxt(n->nbinary.ch1);
4527 cmdputs(p);
4528 n = n->nbinary.ch2;
4529 goto donode;
4530 case NREDIR:
4531 case NBACKGND:
4532 n = n->nredir.n;
4533 goto donode;
4534 case NNOT:
4535 cmdputs("!");
4536 n = n->nnot.com;
4537 donode:
4538 cmdtxt(n);
4539 break;
4540 case NIF:
4541 cmdputs("if ");
4542 cmdtxt(n->nif.test);
4543 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004544 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004545 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004546 cmdputs("; else ");
4547 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004548 } else {
4549 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004550 }
4551 p = "; fi";
4552 goto dotail;
4553 case NSUBSHELL:
4554 cmdputs("(");
4555 n = n->nredir.n;
4556 p = ")";
4557 goto dotail;
4558 case NWHILE:
4559 p = "while ";
4560 goto until;
4561 case NUNTIL:
4562 p = "until ";
4563 until:
4564 cmdputs(p);
4565 cmdtxt(n->nbinary.ch1);
4566 n = n->nbinary.ch2;
4567 p = "; done";
4568 dodo:
4569 cmdputs("; do ");
4570 dotail:
4571 cmdtxt(n);
4572 goto dotail2;
4573 case NFOR:
4574 cmdputs("for ");
4575 cmdputs(n->nfor.var);
4576 cmdputs(" in ");
4577 cmdlist(n->nfor.args, 1);
4578 n = n->nfor.body;
4579 p = "; done";
4580 goto dodo;
4581 case NDEFUN:
4582 cmdputs(n->narg.text);
4583 p = "() { ... }";
4584 goto dotail2;
4585 case NCMD:
4586 cmdlist(n->ncmd.args, 1);
4587 cmdlist(n->ncmd.redirect, 0);
4588 break;
4589 case NARG:
4590 p = n->narg.text;
4591 dotail2:
4592 cmdputs(p);
4593 break;
4594 case NHERE:
4595 case NXHERE:
4596 p = "<<...";
4597 goto dotail2;
4598 case NCASE:
4599 cmdputs("case ");
4600 cmdputs(n->ncase.expr->narg.text);
4601 cmdputs(" in ");
4602 for (np = n->ncase.cases; np; np = np->nclist.next) {
4603 cmdtxt(np->nclist.pattern);
4604 cmdputs(") ");
4605 cmdtxt(np->nclist.body);
4606 cmdputs(";; ");
4607 }
4608 p = "esac";
4609 goto dotail2;
4610 case NTO:
4611 p = ">";
4612 goto redir;
4613 case NCLOBBER:
4614 p = ">|";
4615 goto redir;
4616 case NAPPEND:
4617 p = ">>";
4618 goto redir;
Denis Vlasenko559691a2008-10-05 18:39:31 +00004619#if ENABLE_ASH_BASH_COMPAT
4620 case NTO2:
4621#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004622 case NTOFD:
4623 p = ">&";
4624 goto redir;
4625 case NFROM:
4626 p = "<";
4627 goto redir;
4628 case NFROMFD:
4629 p = "<&";
4630 goto redir;
4631 case NFROMTO:
4632 p = "<>";
4633 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004634 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004635 cmdputs(p);
4636 if (n->type == NTOFD || n->type == NFROMFD) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004637 cmdputs(utoa(n->ndup.dupfd));
4638 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004639 }
4640 n = n->nfile.fname;
4641 goto donode;
4642 }
4643}
4644
4645static char *
4646commandtext(union node *n)
4647{
4648 char *name;
4649
4650 STARTSTACKSTR(cmdnextc);
4651 cmdtxt(n);
4652 name = stackblock();
4653 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4654 name, cmdnextc, cmdnextc));
4655 return ckstrdup(name);
4656}
4657#endif /* JOBS */
4658
4659/*
4660 * Fork off a subshell. If we are doing job control, give the subshell its
4661 * own process group. Jp is a job structure that the job is to be added to.
4662 * N is the command that will be evaluated by the child. Both jp and n may
4663 * be NULL. The mode parameter can be one of the following:
4664 * FORK_FG - Fork off a foreground process.
4665 * FORK_BG - Fork off a background process.
4666 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4667 * process group even if job control is on.
4668 *
4669 * When job control is turned off, background processes have their standard
4670 * input redirected to /dev/null (except for the second and later processes
4671 * in a pipeline).
4672 *
4673 * Called with interrupts off.
4674 */
4675/*
4676 * Clear traps on a fork.
4677 */
4678static void
4679clear_traps(void)
4680{
4681 char **tp;
4682
4683 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004684 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004685 INT_OFF;
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004686 if (trap_ptr == trap)
4687 free(*tp);
4688 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004689 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004690 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004691 setsignal(tp - trap);
4692 INT_ON;
4693 }
4694 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004695 may_have_traps = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004696}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004697
4698/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004699static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004700
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004701/* Called after fork(), in child */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004702static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004703forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004704{
4705 int oldlvl;
4706
4707 TRACE(("Child shell %d\n", getpid()));
4708 oldlvl = shlvl;
4709 shlvl++;
4710
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004711 /* man bash: "Non-builtin commands run by bash have signal handlers
4712 * set to the values inherited by the shell from its parent".
4713 * Do we do it correctly? */
4714
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004715 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004716
4717 if (mode == FORK_NOJOB /* is it `xxx` ? */
4718 && n && n->type == NCMD /* is it single cmd? */
4719 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004720 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004721 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4722 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4723 ) {
4724 TRACE(("Trap hack\n"));
4725 /* Awful hack for `trap` or $(trap).
4726 *
4727 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4728 * contains an example where "trap" is executed in a subshell:
4729 *
4730 * save_traps=$(trap)
4731 * ...
4732 * eval "$save_traps"
4733 *
4734 * Standard does not say that "trap" in subshell shall print
4735 * parent shell's traps. It only says that its output
4736 * must have suitable form, but then, in the above example
4737 * (which is not supposed to be normative), it implies that.
4738 *
4739 * bash (and probably other shell) does implement it
4740 * (traps are reset to defaults, but "trap" still shows them),
4741 * but as a result, "trap" logic is hopelessly messed up:
4742 *
4743 * # trap
4744 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4745 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4746 * # true | trap <--- trap is in subshell - no output (ditto)
4747 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4748 * trap -- 'echo Ho' SIGWINCH
4749 * # echo `(trap)` <--- in subshell in subshell - output
4750 * trap -- 'echo Ho' SIGWINCH
4751 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4752 * trap -- 'echo Ho' SIGWINCH
4753 *
4754 * The rules when to forget and when to not forget traps
4755 * get really complex and nonsensical.
4756 *
4757 * Our solution: ONLY bare $(trap) or `trap` is special.
4758 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004759 /* Save trap handler strings for trap builtin to print */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004760 trap_ptr = memcpy(xmalloc(sizeof(trap)), trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004761 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004762 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004763 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004764#if JOBS
4765 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004766 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004767 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004768 pid_t pgrp;
4769
4770 if (jp->nprocs == 0)
4771 pgrp = getpid();
4772 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004773 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004774 /* this can fail because we are doing it in the parent also */
4775 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004776 if (mode == FORK_FG)
4777 xtcsetpgrp(ttyfd, pgrp);
4778 setsignal(SIGTSTP);
4779 setsignal(SIGTTOU);
4780 } else
4781#endif
4782 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004783 /* man bash: "When job control is not in effect,
4784 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004785 ignoresig(SIGINT);
4786 ignoresig(SIGQUIT);
4787 if (jp->nprocs == 0) {
4788 close(0);
4789 if (open(bb_dev_null, O_RDONLY) != 0)
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00004790 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004791 }
4792 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004793 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004794 if (iflag) { /* why if iflag only? */
4795 setsignal(SIGINT);
4796 setsignal(SIGTERM);
4797 }
4798 /* man bash:
4799 * "In all cases, bash ignores SIGQUIT. Non-builtin
4800 * commands run by bash have signal handlers
4801 * set to the values inherited by the shell
4802 * from its parent".
4803 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004804 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004805 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004806#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02004807 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01004808 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004809 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004810 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02004811 /* "jobs": we do not want to clear job list for it,
4812 * instead we remove only _its_ own_ job from job list.
4813 * This makes "jobs .... | cat" more useful.
4814 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004815 freejob(curjob);
4816 return;
4817 }
4818#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004819 for (jp = curjob; jp; jp = jp->prev_job)
4820 freejob(jp);
4821 jobless = 0;
4822}
4823
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004824/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00004825#if !JOBS
4826#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4827#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004828static void
4829forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4830{
4831 TRACE(("In parent shell: child = %d\n", pid));
4832 if (!jp) {
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004833 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4834 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004835 jobless++;
4836 return;
4837 }
4838#if JOBS
4839 if (mode != FORK_NOJOB && jp->jobctl) {
4840 int pgrp;
4841
4842 if (jp->nprocs == 0)
4843 pgrp = pid;
4844 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004845 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004846 /* This can fail because we are doing it in the child also */
4847 setpgid(pid, pgrp);
4848 }
4849#endif
4850 if (mode == FORK_BG) {
4851 backgndpid = pid; /* set $! */
4852 set_curjob(jp, CUR_RUNNING);
4853 }
4854 if (jp) {
4855 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01004856 ps->ps_pid = pid;
4857 ps->ps_status = -1;
4858 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004859#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004860 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004861 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004862#endif
4863 }
4864}
4865
4866static int
4867forkshell(struct job *jp, union node *n, int mode)
4868{
4869 int pid;
4870
4871 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4872 pid = fork();
4873 if (pid < 0) {
4874 TRACE(("Fork failed, errno=%d", errno));
4875 if (jp)
4876 freejob(jp);
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +00004877 ash_msg_and_raise_error("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004878 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02004879 if (pid == 0) {
4880 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004881 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004882 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004883 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004884 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004885 return pid;
4886}
4887
4888/*
4889 * Wait for job to finish.
4890 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004891 * Under job control we have the problem that while a child process
4892 * is running interrupts generated by the user are sent to the child
4893 * but not to the shell. This means that an infinite loop started by
4894 * an interactive user may be hard to kill. With job control turned off,
4895 * an interactive user may place an interactive program inside a loop.
4896 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004897 * these interrupts to also abort the loop. The approach we take here
4898 * is to have the shell ignore interrupt signals while waiting for a
4899 * foreground process to terminate, and then send itself an interrupt
4900 * signal if the child process was terminated by an interrupt signal.
4901 * Unfortunately, some programs want to do a bit of cleanup and then
4902 * exit on interrupt; unless these processes terminate themselves by
4903 * sending a signal to themselves (instead of calling exit) they will
4904 * confuse this approach.
4905 *
4906 * Called with interrupts off.
4907 */
4908static int
4909waitforjob(struct job *jp)
4910{
4911 int st;
4912
4913 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004914
4915 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004916 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004917 /* In non-interactive shells, we _can_ get
4918 * a keyboard signal here and be EINTRed,
4919 * but we just loop back, waiting for command to complete.
4920 *
4921 * man bash:
4922 * "If bash is waiting for a command to complete and receives
4923 * a signal for which a trap has been set, the trap
4924 * will not be executed until the command completes."
4925 *
4926 * Reality is that even if trap is not set, bash
4927 * will not act on the signal until command completes.
4928 * Try this. sleep5intoff.c:
4929 * #include <signal.h>
4930 * #include <unistd.h>
4931 * int main() {
4932 * sigset_t set;
4933 * sigemptyset(&set);
4934 * sigaddset(&set, SIGINT);
4935 * sigaddset(&set, SIGQUIT);
4936 * sigprocmask(SIG_BLOCK, &set, NULL);
4937 * sleep(5);
4938 * return 0;
4939 * }
4940 * $ bash -c './sleep5intoff; echo hi'
4941 * ^C^C^C^C <--- pressing ^C once a second
4942 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004943 * $ bash -c './sleep5intoff; echo hi'
4944 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
4945 * $ _
4946 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004947 dowait(DOWAIT_BLOCK, jp);
4948 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004949 INT_ON;
4950
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004951 st = getstatus(jp);
4952#if JOBS
4953 if (jp->jobctl) {
4954 xtcsetpgrp(ttyfd, rootpid);
4955 /*
4956 * This is truly gross.
4957 * If we're doing job control, then we did a TIOCSPGRP which
4958 * caused us (the shell) to no longer be in the controlling
4959 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4960 * intuit from the subprocess exit status whether a SIGINT
4961 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4962 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004963 if (jp->sigint) /* TODO: do the same with all signals */
4964 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004965 }
4966 if (jp->state == JOBDONE)
4967#endif
4968 freejob(jp);
4969 return st;
4970}
4971
4972/*
4973 * return 1 if there are stopped jobs, otherwise 0
4974 */
4975static int
4976stoppedjobs(void)
4977{
4978 struct job *jp;
4979 int retval;
4980
4981 retval = 0;
4982 if (job_warning)
4983 goto out;
4984 jp = curjob;
4985 if (jp && jp->state == JOBSTOPPED) {
4986 out2str("You have stopped jobs.\n");
4987 job_warning = 2;
4988 retval++;
4989 }
4990 out:
4991 return retval;
4992}
4993
4994
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00004995/* ============ redir.c
4996 *
4997 * Code for dealing with input/output redirection.
4998 */
4999
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005000#undef EMPTY
5001#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005002#define EMPTY -2 /* marks an unused slot in redirtab */
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005003#define CLOSED -3 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005004
5005/*
5006 * Open a file in noclobber mode.
5007 * The code was copied from bash.
5008 */
5009static int
5010noclobberopen(const char *fname)
5011{
5012 int r, fd;
5013 struct stat finfo, finfo2;
5014
5015 /*
5016 * If the file exists and is a regular file, return an error
5017 * immediately.
5018 */
5019 r = stat(fname, &finfo);
5020 if (r == 0 && S_ISREG(finfo.st_mode)) {
5021 errno = EEXIST;
5022 return -1;
5023 }
5024
5025 /*
5026 * If the file was not present (r != 0), make sure we open it
5027 * exclusively so that if it is created before we open it, our open
5028 * will fail. Make sure that we do not truncate an existing file.
5029 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5030 * file was not a regular file, we leave O_EXCL off.
5031 */
5032 if (r != 0)
5033 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5034 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5035
5036 /* If the open failed, return the file descriptor right away. */
5037 if (fd < 0)
5038 return fd;
5039
5040 /*
5041 * OK, the open succeeded, but the file may have been changed from a
5042 * non-regular file to a regular file between the stat and the open.
5043 * We are assuming that the O_EXCL open handles the case where FILENAME
5044 * did not exist and is symlinked to an existing file between the stat
5045 * and open.
5046 */
5047
5048 /*
5049 * If we can open it and fstat the file descriptor, and neither check
5050 * revealed that it was a regular file, and the file has not been
5051 * replaced, return the file descriptor.
5052 */
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005053 if (fstat(fd, &finfo2) == 0
5054 && !S_ISREG(finfo2.st_mode)
5055 && finfo.st_dev == finfo2.st_dev
5056 && finfo.st_ino == finfo2.st_ino
5057 ) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005058 return fd;
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005059 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005060
5061 /* The file has been replaced. badness. */
5062 close(fd);
5063 errno = EEXIST;
5064 return -1;
5065}
5066
5067/*
5068 * Handle here documents. Normally we fork off a process to write the
5069 * data to a pipe. If the document is short, we can stuff the data in
5070 * the pipe without forking.
5071 */
5072/* openhere needs this forward reference */
5073static void expandhere(union node *arg, int fd);
5074static int
5075openhere(union node *redir)
5076{
5077 int pip[2];
5078 size_t len = 0;
5079
5080 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005081 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005082 if (redir->type == NHERE) {
5083 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005084 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005085 full_write(pip[1], redir->nhere.doc->narg.text, len);
5086 goto out;
5087 }
5088 }
5089 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005090 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005091 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005092 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5093 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5094 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5095 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005096 signal(SIGPIPE, SIG_DFL);
5097 if (redir->type == NHERE)
5098 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005099 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005100 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005101 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005102 }
5103 out:
5104 close(pip[1]);
5105 return pip[0];
5106}
5107
5108static int
5109openredirect(union node *redir)
5110{
5111 char *fname;
5112 int f;
5113
Tanguy Pruvot823694d2012-11-18 13:20:29 +01005114 fname = redir->nfile.expfname;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005115 switch (redir->nfile.type) {
5116 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005117 f = open(fname, O_RDONLY);
5118 if (f < 0)
5119 goto eopen;
5120 break;
5121 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005122 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005123 if (f < 0)
5124 goto ecreate;
5125 break;
5126 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00005127#if ENABLE_ASH_BASH_COMPAT
5128 case NTO2:
5129#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005130 /* Take care of noclobber mode. */
5131 if (Cflag) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005132 f = noclobberopen(fname);
5133 if (f < 0)
5134 goto ecreate;
5135 break;
5136 }
5137 /* FALLTHROUGH */
5138 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005139 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5140 if (f < 0)
5141 goto ecreate;
5142 break;
5143 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005144 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5145 if (f < 0)
5146 goto ecreate;
5147 break;
5148 default:
5149#if DEBUG
5150 abort();
5151#endif
5152 /* Fall through to eliminate warning. */
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005153/* Our single caller does this itself */
Denis Vlasenko0b769642008-07-24 07:54:57 +00005154// case NTOFD:
5155// case NFROMFD:
5156// f = -1;
5157// break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005158 case NHERE:
5159 case NXHERE:
5160 f = openhere(redir);
5161 break;
5162 }
5163
5164 return f;
5165 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005166 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005167 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005168 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005169}
5170
5171/*
5172 * Copy a file descriptor to be >= to. Returns -1
5173 * if the source file descriptor is closed, EMPTY if there are no unused
5174 * file descriptors left.
5175 */
Denis Vlasenko5a867312008-07-24 19:46:38 +00005176/* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
5177 * old code was doing close(to) prior to copyfd() to achieve the same */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005178enum {
5179 COPYFD_EXACT = (int)~(INT_MAX),
5180 COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1),
5181};
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005182static int
5183copyfd(int from, int to)
5184{
5185 int newfd;
5186
Denis Vlasenko5a867312008-07-24 19:46:38 +00005187 if (to & COPYFD_EXACT) {
5188 to &= ~COPYFD_EXACT;
5189 /*if (from != to)*/
5190 newfd = dup2(from, to);
5191 } else {
5192 newfd = fcntl(from, F_DUPFD, to);
5193 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005194 if (newfd < 0) {
5195 if (errno == EMFILE)
5196 return EMPTY;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005197 /* Happens when source fd is not open: try "echo >&99" */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005198 ash_msg_and_raise_error("%d: %m", from);
5199 }
5200 return newfd;
5201}
5202
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005203/* Struct def and variable are moved down to the first usage site */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005204struct two_fd_t {
5205 int orig, copy;
5206};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005207struct redirtab {
5208 struct redirtab *next;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005209 int nullredirs;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005210 int pair_count;
Denys Vlasenko606291b2009-09-23 23:15:43 +02005211 struct two_fd_t two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005212};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005213#define redirlist (G_var.redirlist)
Denis Vlasenko0b769642008-07-24 07:54:57 +00005214
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005215static int need_to_remember(struct redirtab *rp, int fd)
5216{
5217 int i;
5218
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005219 if (!rp) /* remembering was not requested */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005220 return 0;
5221
5222 for (i = 0; i < rp->pair_count; i++) {
5223 if (rp->two_fd[i].orig == fd) {
5224 /* already remembered */
5225 return 0;
5226 }
5227 }
5228 return 1;
5229}
5230
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005231/* "hidden" fd is a fd used to read scripts, or a copy of such */
5232static int is_hidden_fd(struct redirtab *rp, int fd)
5233{
5234 int i;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005235 struct parsefile *pf;
5236
5237 if (fd == -1)
5238 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005239 /* Check open scripts' fds */
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005240 pf = g_parsefile;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005241 while (pf) {
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005242 /* We skip pf_fd == 0 case because of the following case:
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005243 * $ ash # running ash interactively
5244 * $ . ./script.sh
5245 * and in script.sh: "exec 9>&0".
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005246 * Even though top-level pf_fd _is_ 0,
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005247 * it's still ok to use it: "read" builtin uses it,
5248 * why should we cripple "exec" builtin?
5249 */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005250 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005251 return 1;
5252 }
5253 pf = pf->prev;
5254 }
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005255
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005256 if (!rp)
5257 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005258 /* Check saved fds of redirects */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005259 fd |= COPYFD_RESTORE;
5260 for (i = 0; i < rp->pair_count; i++) {
5261 if (rp->two_fd[i].copy == fd) {
5262 return 1;
5263 }
5264 }
5265 return 0;
5266}
5267
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005268/*
5269 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5270 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005271 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005272 */
5273/* flags passed to redirect */
5274#define REDIR_PUSH 01 /* save previous values of file descriptors */
5275#define REDIR_SAVEFD2 03 /* set preverrout */
5276static void
5277redirect(union node *redir, int flags)
5278{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005279 struct redirtab *sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005280 int sv_pos;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005281 int i;
5282 int fd;
5283 int newfd;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005284 int copied_fd2 = -1;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005285
Denis Vlasenko01631112007-12-16 17:20:38 +00005286 g_nullredirs++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005287 if (!redir) {
5288 return;
5289 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005290
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005291 sv = NULL;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005292 sv_pos = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005293 INT_OFF;
5294 if (flags & REDIR_PUSH) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005295 union node *tmp = redir;
5296 do {
5297 sv_pos++;
Denis Vlasenko559691a2008-10-05 18:39:31 +00005298#if ENABLE_ASH_BASH_COMPAT
Chris Metcalfc3c1fb62010-01-08 13:18:06 +01005299 if (tmp->nfile.type == NTO2)
Denis Vlasenko559691a2008-10-05 18:39:31 +00005300 sv_pos++;
5301#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005302 tmp = tmp->nfile.next;
5303 } while (tmp);
5304 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005305 sv->next = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005306 sv->pair_count = sv_pos;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005307 redirlist = sv;
Denis Vlasenko01631112007-12-16 17:20:38 +00005308 sv->nullredirs = g_nullredirs - 1;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005309 g_nullredirs = 0;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005310 while (sv_pos > 0) {
5311 sv_pos--;
5312 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5313 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005314 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005315
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005316 do {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005317 int right_fd = -1;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005318 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005319 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005320 right_fd = redir->ndup.dupfd;
5321 //bb_error_msg("doing %d > %d", fd, right_fd);
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005322 /* redirect from/to same file descriptor? */
5323 if (right_fd == fd)
5324 continue;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005325 /* "echo >&10" and 10 is a fd opened to a sh script? */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005326 if (is_hidden_fd(sv, right_fd)) {
5327 errno = EBADF; /* as if it is closed */
5328 ash_msg_and_raise_error("%d: %m", right_fd);
5329 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005330 newfd = -1;
5331 } else {
5332 newfd = openredirect(redir); /* always >= 0 */
5333 if (fd == newfd) {
5334 /* Descriptor wasn't open before redirect.
5335 * Mark it for close in the future */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005336 if (need_to_remember(sv, fd)) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005337 goto remember_to_close;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005338 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005339 continue;
5340 }
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005341 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005342#if ENABLE_ASH_BASH_COMPAT
5343 redirect_more:
5344#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005345 if (need_to_remember(sv, fd)) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005346 /* Copy old descriptor */
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005347 /* Careful to not accidentally "save"
5348 * to the same fd as right side fd in N>&M */
5349 int minfd = right_fd < 10 ? 10 : right_fd + 1;
5350 i = fcntl(fd, F_DUPFD, minfd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005351/* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5352 * are closed in popredir() in the child, preventing them from leaking
5353 * into child. (popredir() also cleans up the mess in case of failures)
5354 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005355 if (i == -1) {
5356 i = errno;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005357 if (i != EBADF) {
5358 /* Strange error (e.g. "too many files" EMFILE?) */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005359 if (newfd >= 0)
5360 close(newfd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005361 errno = i;
5362 ash_msg_and_raise_error("%d: %m", fd);
5363 /* NOTREACHED */
5364 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005365 /* EBADF: it is not open - good, remember to close it */
5366 remember_to_close:
5367 i = CLOSED;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005368 } else { /* fd is open, save its copy */
5369 /* "exec fd>&-" should not close fds
5370 * which point to script file(s).
5371 * Force them to be restored afterwards */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005372 if (is_hidden_fd(sv, fd))
5373 i |= COPYFD_RESTORE;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005374 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005375 if (fd == 2)
5376 copied_fd2 = i;
5377 sv->two_fd[sv_pos].orig = fd;
5378 sv->two_fd[sv_pos].copy = i;
5379 sv_pos++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005380 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005381 if (newfd < 0) {
5382 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005383 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005384 /* Don't want to trigger debugging */
5385 if (fd != -1)
5386 close(fd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005387 } else {
5388 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005389 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005390 } else if (fd != newfd) { /* move newfd to fd */
5391 copyfd(newfd, fd | COPYFD_EXACT);
Denis Vlasenko559691a2008-10-05 18:39:31 +00005392#if ENABLE_ASH_BASH_COMPAT
5393 if (!(redir->nfile.type == NTO2 && fd == 2))
5394#endif
5395 close(newfd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005396 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005397#if ENABLE_ASH_BASH_COMPAT
5398 if (redir->nfile.type == NTO2 && fd == 1) {
5399 /* We already redirected it to fd 1, now copy it to 2 */
5400 newfd = 1;
5401 fd = 2;
5402 goto redirect_more;
5403 }
5404#endif
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005405 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005406
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005407 INT_ON;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005408 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5409 preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005410}
5411
5412/*
5413 * Undo the effects of the last redirection.
5414 */
5415static void
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005416popredir(int drop, int restore)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005417{
5418 struct redirtab *rp;
5419 int i;
5420
Denis Vlasenko01631112007-12-16 17:20:38 +00005421 if (--g_nullredirs >= 0)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005422 return;
5423 INT_OFF;
5424 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005425 for (i = 0; i < rp->pair_count; i++) {
5426 int fd = rp->two_fd[i].orig;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005427 int copy = rp->two_fd[i].copy;
5428 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005429 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005430 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005431 continue;
5432 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005433 if (copy != EMPTY) {
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005434 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
Denis Vlasenko22f74142008-07-24 22:34:43 +00005435 copy &= ~COPYFD_RESTORE;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005436 /*close(fd);*/
Denis Vlasenko22f74142008-07-24 22:34:43 +00005437 copyfd(copy, fd | COPYFD_EXACT);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005438 }
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005439 close(copy & ~COPYFD_RESTORE);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005440 }
5441 }
5442 redirlist = rp->next;
Denis Vlasenko01631112007-12-16 17:20:38 +00005443 g_nullredirs = rp->nullredirs;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005444 free(rp);
5445 INT_ON;
5446}
5447
5448/*
5449 * Undo all redirections. Called on error or interrupt.
5450 */
5451
5452/*
5453 * Discard all saved file descriptors.
5454 */
5455static void
5456clearredir(int drop)
5457{
5458 for (;;) {
Denis Vlasenko01631112007-12-16 17:20:38 +00005459 g_nullredirs = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005460 if (!redirlist)
5461 break;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005462 popredir(drop, /*restore:*/ 0);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005463 }
5464}
5465
5466static int
5467redirectsafe(union node *redir, int flags)
5468{
5469 int err;
5470 volatile int saveint;
5471 struct jmploc *volatile savehandler = exception_handler;
5472 struct jmploc jmploc;
5473
5474 SAVE_INT(saveint);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005475 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5476 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005477 if (!err) {
5478 exception_handler = &jmploc;
5479 redirect(redir, flags);
5480 }
5481 exception_handler = savehandler;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00005482 if (err && exception_type != EXERROR)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005483 longjmp(exception_handler->loc, 1);
5484 RESTORE_INT(saveint);
5485 return err;
5486}
5487
5488
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005489/* ============ Routines to expand arguments to commands
5490 *
5491 * We have to deal with backquotes, shell variables, and file metacharacters.
5492 */
5493
Mike Frysinger98c52642009-04-02 10:02:37 +00005494#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005495static arith_t
5496ash_arith(const char *s)
5497{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005498 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005499 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005500
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005501 math_state.lookupvar = lookupvar;
5502 math_state.setvar = setvar2;
5503 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005504
5505 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005506 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005507 if (math_state.errmsg)
5508 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005509 INT_ON;
5510
5511 return result;
5512}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005513#endif
5514
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005515/*
5516 * expandarg flags
5517 */
5518#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5519#define EXP_TILDE 0x2 /* do normal tilde expansion */
5520#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5521#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5522#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5523#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
5524#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5525#define EXP_WORD 0x80 /* expand word in parameter expansion */
5526#define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
5527/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005528 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005529 */
5530#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5531#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5532#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
5533#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5534#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5535
5536/*
5537 * Structure specifying which parts of the string should be searched
5538 * for IFS characters.
5539 */
5540struct ifsregion {
5541 struct ifsregion *next; /* next region in list */
5542 int begoff; /* offset of start of region */
5543 int endoff; /* offset of end of region */
5544 int nulonly; /* search for nul bytes only */
5545};
5546
5547struct arglist {
5548 struct strlist *list;
5549 struct strlist **lastp;
5550};
5551
5552/* output of current string */
5553static char *expdest;
5554/* list of back quote expressions */
5555static struct nodelist *argbackq;
5556/* first struct in list of ifs regions */
5557static struct ifsregion ifsfirst;
5558/* last struct in list */
5559static struct ifsregion *ifslastp;
5560/* holds expanded arg list */
5561static struct arglist exparg;
5562
5563/*
5564 * Our own itoa().
5565 */
Denys Vlasenko26777aa2010-11-22 23:49:10 +01005566#if !ENABLE_SH_MATH_SUPPORT
5567/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5568typedef long arith_t;
5569# define ARITH_FMT "%ld"
5570#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005571static int
5572cvtnum(arith_t num)
5573{
5574 int len;
5575
5576 expdest = makestrspace(32, expdest);
Denys Vlasenkobed7c812010-09-16 11:50:46 +02005577 len = fmtstr(expdest, 32, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005578 STADJUST(len, expdest);
5579 return len;
5580}
5581
5582static size_t
5583esclen(const char *start, const char *p)
5584{
5585 size_t esc = 0;
5586
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005587 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005588 esc++;
5589 }
5590 return esc;
5591}
5592
5593/*
5594 * Remove any CTLESC characters from a string.
5595 */
5596static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005597rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005598{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00005599 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005600
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005601 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005602 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005603 unsigned protect_against_glob;
5604 unsigned globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005605
5606 p = strpbrk(str, qchars);
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005607 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005608 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005609
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005610 q = p;
5611 r = str;
5612 if (flag & RMESCAPE_ALLOC) {
5613 size_t len = p - str;
5614 size_t fulllen = len + strlen(p) + 1;
5615
5616 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005617 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005618 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005619 /* p and str may be invalidated by makestrspace */
5620 str = (char *)stackblock() + strloc;
5621 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005622 } else if (flag & RMESCAPE_HEAP) {
5623 r = ckmalloc(fulllen);
5624 } else {
5625 r = stalloc(fulllen);
5626 }
5627 q = r;
5628 if (len > 0) {
Denis Vlasenko29eb3592008-05-18 14:06:08 +00005629 q = (char *)memcpy(q, str, len) + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005630 }
5631 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005632
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005633 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5634 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005635 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005636 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005637 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005638// TODO: if no RMESCAPE_QUOTED in flags, inquotes never becomes 0
5639// (alternates between RMESCAPE_QUOTED and ~RMESCAPE_QUOTED). Is it ok?
5640// Note: both inquotes and protect_against_glob only affect whether
5641// CTLESC,<ch> gets converted to <ch> or to \<ch>
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005642 inquotes = ~inquotes;
5643 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005644 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005645 continue;
5646 }
5647 if (*p == '\\') {
5648 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005649 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005650 goto copy;
5651 }
Denys Vlasenkocd716832009-11-28 22:14:02 +01005652 if ((unsigned char)*p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005653 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005654 if (protect_against_glob && inquotes && *p != '/') {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005655 *q++ = '\\';
5656 }
5657 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005658 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005659 copy:
5660 *q++ = *p++;
5661 }
5662 *q = '\0';
5663 if (flag & RMESCAPE_GROW) {
5664 expdest = r;
5665 STADJUST(q - r + 1, expdest);
5666 }
5667 return r;
5668}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005669#define pmatch(a, b) !fnmatch((a), (b), 0)
5670
5671/*
5672 * Prepare a pattern for a expmeta (internal glob(3)) call.
5673 *
5674 * Returns an stalloced string.
5675 */
5676static char *
5677preglob(const char *pattern, int quoted, int flag)
5678{
5679 flag |= RMESCAPE_GLOB;
5680 if (quoted) {
5681 flag |= RMESCAPE_QUOTED;
5682 }
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005683 return rmescapes((char *)pattern, flag);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005684}
5685
5686/*
5687 * Put a string on the stack.
5688 */
5689static void
5690memtodest(const char *p, size_t len, int syntax, int quotes)
5691{
5692 char *q = expdest;
5693
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005694 q = makestrspace(quotes ? len * 2 : len, q);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005695
5696 while (len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005697 unsigned char c = *p++;
5698 if (c == '\0')
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005699 continue;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005700 if (quotes) {
5701 int n = SIT(c, syntax);
5702 if (n == CCTL || n == CBACK)
5703 USTPUTC(CTLESC, q);
5704 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005705 USTPUTC(c, q);
5706 }
5707
5708 expdest = q;
5709}
5710
5711static void
5712strtodest(const char *p, int syntax, int quotes)
5713{
5714 memtodest(p, strlen(p), syntax, quotes);
5715}
5716
5717/*
5718 * Record the fact that we have to scan this region of the
5719 * string for IFS characters.
5720 */
5721static void
5722recordregion(int start, int end, int nulonly)
5723{
5724 struct ifsregion *ifsp;
5725
5726 if (ifslastp == NULL) {
5727 ifsp = &ifsfirst;
5728 } else {
5729 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00005730 ifsp = ckzalloc(sizeof(*ifsp));
5731 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005732 ifslastp->next = ifsp;
5733 INT_ON;
5734 }
5735 ifslastp = ifsp;
5736 ifslastp->begoff = start;
5737 ifslastp->endoff = end;
5738 ifslastp->nulonly = nulonly;
5739}
5740
5741static void
5742removerecordregions(int endoff)
5743{
5744 if (ifslastp == NULL)
5745 return;
5746
5747 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005748 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005749 struct ifsregion *ifsp;
5750 INT_OFF;
5751 ifsp = ifsfirst.next->next;
5752 free(ifsfirst.next);
5753 ifsfirst.next = ifsp;
5754 INT_ON;
5755 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005756 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005757 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005758 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005759 ifslastp = &ifsfirst;
5760 ifsfirst.endoff = endoff;
5761 }
5762 return;
5763 }
5764
5765 ifslastp = &ifsfirst;
5766 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005767 ifslastp = ifslastp->next;
5768 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005769 struct ifsregion *ifsp;
5770 INT_OFF;
5771 ifsp = ifslastp->next->next;
5772 free(ifslastp->next);
5773 ifslastp->next = ifsp;
5774 INT_ON;
5775 }
5776 if (ifslastp->endoff > endoff)
5777 ifslastp->endoff = endoff;
5778}
5779
5780static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005781exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005782{
Denys Vlasenkocd716832009-11-28 22:14:02 +01005783 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005784 char *name;
5785 struct passwd *pw;
5786 const char *home;
Denys Vlasenko1166d7b2009-09-16 16:20:31 +02005787 int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005788 int startloc;
5789
5790 name = p + 1;
5791
5792 while ((c = *++p) != '\0') {
5793 switch (c) {
5794 case CTLESC:
5795 return startp;
5796 case CTLQUOTEMARK:
5797 return startp;
5798 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005799 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005800 goto done;
5801 break;
5802 case '/':
5803 case CTLENDVAR:
5804 goto done;
5805 }
5806 }
5807 done:
5808 *p = '\0';
5809 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02005810 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005811 } else {
5812 pw = getpwnam(name);
5813 if (pw == NULL)
5814 goto lose;
5815 home = pw->pw_dir;
5816 }
5817 if (!home || !*home)
5818 goto lose;
5819 *p = c;
5820 startloc = expdest - (char *)stackblock();
5821 strtodest(home, SQSYNTAX, quotes);
5822 recordregion(startloc, expdest - (char *)stackblock(), 0);
5823 return p;
5824 lose:
5825 *p = c;
5826 return startp;
5827}
5828
5829/*
5830 * Execute a command inside back quotes. If it's a builtin command, we
5831 * want to save its output in a block obtained from malloc. Otherwise
5832 * we fork off a subprocess and get the output of the command via a pipe.
5833 * Should be called with interrupts off.
5834 */
5835struct backcmd { /* result of evalbackcmd */
5836 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005837 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005838 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005839 struct job *jp; /* job structure for command */
5840};
5841
5842/* These forward decls are needed to use "eval" code for backticks handling: */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005843static uint8_t back_exitstatus; /* exit status of backquoted command */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005844#define EV_EXIT 01 /* exit after evaluating tree */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02005845static void evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005846
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02005847static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005848evalbackcmd(union node *n, struct backcmd *result)
5849{
5850 int saveherefd;
5851
5852 result->fd = -1;
5853 result->buf = NULL;
5854 result->nleft = 0;
5855 result->jp = NULL;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00005856 if (n == NULL)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005857 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005858
5859 saveherefd = herefd;
5860 herefd = -1;
5861
5862 {
5863 int pip[2];
5864 struct job *jp;
5865
5866 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005867 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko68404f12008-03-17 09:00:54 +00005868 jp = makejob(/*n,*/ 1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005869 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5870 FORCE_INT_ON;
5871 close(pip[0]);
5872 if (pip[1] != 1) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005873 /*close(1);*/
5874 copyfd(pip[1], 1 | COPYFD_EXACT);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005875 close(pip[1]);
5876 }
5877 eflag = 0;
5878 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5879 /* NOTREACHED */
5880 }
5881 close(pip[1]);
5882 result->fd = pip[0];
5883 result->jp = jp;
5884 }
5885 herefd = saveherefd;
5886 out:
5887 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5888 result->fd, result->buf, result->nleft, result->jp));
5889}
5890
5891/*
5892 * Expand stuff in backwards quotes.
5893 */
5894static void
5895expbackq(union node *cmd, int quoted, int quotes)
5896{
5897 struct backcmd in;
5898 int i;
5899 char buf[128];
5900 char *p;
5901 char *dest;
5902 int startloc;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00005903 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005904 struct stackmark smark;
5905
5906 INT_OFF;
5907 setstackmark(&smark);
5908 dest = expdest;
5909 startloc = dest - (char *)stackblock();
5910 grabstackstr(dest);
5911 evalbackcmd(cmd, &in);
5912 popstackmark(&smark);
5913
5914 p = in.buf;
5915 i = in.nleft;
5916 if (i == 0)
5917 goto read;
5918 for (;;) {
5919 memtodest(p, i, syntax, quotes);
5920 read:
5921 if (in.fd < 0)
5922 break;
Denys Vlasenko80542ba2011-05-08 21:23:43 +02005923 i = nonblock_immune_read(in.fd, buf, sizeof(buf), /*loop_on_EINTR:*/ 1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005924 TRACE(("expbackq: read returns %d\n", i));
5925 if (i <= 0)
5926 break;
5927 p = buf;
5928 }
5929
Denis Vlasenko60818682007-09-28 22:07:23 +00005930 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005931 if (in.fd >= 0) {
5932 close(in.fd);
5933 back_exitstatus = waitforjob(in.jp);
5934 }
5935 INT_ON;
5936
5937 /* Eat all trailing newlines */
5938 dest = expdest;
5939 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5940 STUNPUTC(dest);
5941 expdest = dest;
5942
5943 if (quoted == 0)
5944 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005945 TRACE(("evalbackq: size:%d:'%.*s'\n",
5946 (int)((dest - (char *)stackblock()) - startloc),
5947 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005948 stackblock() + startloc));
5949}
5950
Mike Frysinger98c52642009-04-02 10:02:37 +00005951#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005952/*
5953 * Expand arithmetic expression. Backup to start of expression,
5954 * evaluate, place result in (backed up) result, adjust string position.
5955 */
5956static void
5957expari(int quotes)
5958{
5959 char *p, *start;
5960 int begoff;
5961 int flag;
5962 int len;
5963
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00005964 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005965
5966 /*
5967 * This routine is slightly over-complicated for
5968 * efficiency. Next we scan backwards looking for the
5969 * start of arithmetic.
5970 */
5971 start = stackblock();
5972 p = expdest - 1;
5973 *p = '\0';
5974 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01005975 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005976 int esc;
5977
Denys Vlasenkocd716832009-11-28 22:14:02 +01005978 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005979 p--;
5980#if DEBUG
5981 if (p < start) {
5982 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5983 }
5984#endif
5985 }
5986
5987 esc = esclen(start, p);
5988 if (!(esc % 2)) {
5989 break;
5990 }
5991
5992 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01005993 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005994
5995 begoff = p - start;
5996
5997 removerecordregions(begoff);
5998
5999 flag = p[1];
6000
6001 expdest = p;
6002
6003 if (quotes)
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006004 rmescapes(p + 2, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006005
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00006006 len = cvtnum(ash_arith(p + 2));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006007
6008 if (flag != '"')
6009 recordregion(begoff, begoff + len, 0);
6010}
6011#endif
6012
6013/* argstr needs it */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006014static char *evalvar(char *p, int flags, struct strlist *var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006015
6016/*
6017 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6018 * characters to allow for further processing. Otherwise treat
6019 * $@ like $* since no splitting will be performed.
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006020 *
6021 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
6022 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
6023 * for correct expansion of "B=$A" word.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006024 */
6025static void
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006026argstr(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006027{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006028 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006029 '=',
6030 ':',
6031 CTLQUOTEMARK,
6032 CTLENDVAR,
6033 CTLESC,
6034 CTLVAR,
6035 CTLBACKQ,
6036 CTLBACKQ | CTLQUOTE,
Mike Frysinger98c52642009-04-02 10:02:37 +00006037#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006038 CTLENDARI,
6039#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006040 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006041 };
6042 const char *reject = spclchars;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006043 int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */
6044 int breakall = flags & EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006045 int inquotes;
6046 size_t length;
6047 int startloc;
6048
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006049 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006050 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006051 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006052 reject++;
6053 }
6054 inquotes = 0;
6055 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006056 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006057 char *q;
6058
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006059 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006060 tilde:
6061 q = p;
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006062 if ((unsigned char)*q == CTLESC && (flags & EXP_QWORD))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006063 q++;
6064 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006065 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006066 }
6067 start:
6068 startloc = expdest - (char *)stackblock();
6069 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006070 unsigned char c;
6071
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006072 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006073 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006074 if (c) {
6075 if (!(c & 0x80)
Denys Vlasenko958581a2010-09-12 15:04:27 +02006076 IF_SH_MATH_SUPPORT(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006077 ) {
6078 /* c == '=' || c == ':' || c == CTLENDARI */
6079 length++;
6080 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006081 }
6082 if (length > 0) {
6083 int newloc;
6084 expdest = stack_nputstr(p, length, expdest);
6085 newloc = expdest - (char *)stackblock();
6086 if (breakall && !inquotes && newloc > startloc) {
6087 recordregion(startloc, newloc, 0);
6088 }
6089 startloc = newloc;
6090 }
6091 p += length + 1;
6092 length = 0;
6093
6094 switch (c) {
6095 case '\0':
6096 goto breakloop;
6097 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006098 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006099 p--;
6100 continue;
6101 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006102 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006103 reject++;
6104 /* fall through */
6105 case ':':
6106 /*
6107 * sort of a hack - expand tildes in variable
6108 * assignments (after the first '=' and after ':'s).
6109 */
6110 if (*--p == '~') {
6111 goto tilde;
6112 }
6113 continue;
6114 }
6115
6116 switch (c) {
6117 case CTLENDVAR: /* ??? */
6118 goto breakloop;
6119 case CTLQUOTEMARK:
6120 /* "$@" syntax adherence hack */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006121 if (!inquotes
6122 && memcmp(p, dolatstr, 4) == 0
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006123 && ( p[4] == (char)CTLQUOTEMARK
6124 || (p[4] == (char)CTLENDVAR && p[5] == (char)CTLQUOTEMARK)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006125 )
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006126 ) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006127 p = evalvar(p + 1, flags, /* var_str_list: */ NULL) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006128 goto start;
6129 }
6130 inquotes = !inquotes;
6131 addquote:
6132 if (quotes) {
6133 p--;
6134 length++;
6135 startloc++;
6136 }
6137 break;
6138 case CTLESC:
6139 startloc++;
6140 length++;
6141 goto addquote;
6142 case CTLVAR:
Tanguy Pruvot823694d2012-11-18 13:20:29 +01006143 TRACE(("argstr: evalvar('%s')\n", p));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006144 p = evalvar(p, flags, var_str_list);
Tanguy Pruvot823694d2012-11-18 13:20:29 +01006145 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006146 goto start;
6147 case CTLBACKQ:
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006148 c = '\0';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006149 case CTLBACKQ|CTLQUOTE:
6150 expbackq(argbackq->n, c, quotes);
6151 argbackq = argbackq->next;
6152 goto start;
Mike Frysinger98c52642009-04-02 10:02:37 +00006153#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006154 case CTLENDARI:
6155 p--;
6156 expari(quotes);
6157 goto start;
6158#endif
6159 }
6160 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006161 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006162}
6163
6164static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006165scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6166 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006167{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006168 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006169 char c;
6170
6171 loc = startp;
6172 loc2 = rmesc;
6173 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006174 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006175 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006176
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006177 c = *loc2;
6178 if (zero) {
6179 *loc2 = '\0';
6180 s = rmesc;
6181 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006182 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006183
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006184 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006185 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006186 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006187 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006188 loc++;
6189 loc++;
6190 loc2++;
6191 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006192 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006193}
6194
6195static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006196scanright(char *startp, char *rmesc, char *rmescend,
6197 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006198{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006199#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6200 int try2optimize = match_at_start;
6201#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006202 int esc = 0;
6203 char *loc;
6204 char *loc2;
6205
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006206 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6207 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6208 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6209 * Logic:
6210 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6211 * and on each iteration they go back two/one char until they reach the beginning.
6212 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6213 */
6214 /* TODO: document in what other circumstances we are called. */
6215
6216 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006217 int match;
6218 char c = *loc2;
6219 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006220 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006221 *loc2 = '\0';
6222 s = rmesc;
6223 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006224 match = pmatch(pattern, s);
6225 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006226 *loc2 = c;
6227 if (match)
6228 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006229#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6230 if (try2optimize) {
6231 /* Maybe we can optimize this:
6232 * if pattern ends with unescaped *, we can avoid checking
6233 * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6234 * it wont match truncated "raw_value_of_" strings too.
6235 */
6236 unsigned plen = strlen(pattern);
6237 /* Does it end with "*"? */
6238 if (plen != 0 && pattern[--plen] == '*') {
6239 /* "xxxx*" is not escaped */
6240 /* "xxx\*" is escaped */
6241 /* "xx\\*" is not escaped */
6242 /* "x\\\*" is escaped */
6243 int slashes = 0;
6244 while (plen != 0 && pattern[--plen] == '\\')
6245 slashes++;
6246 if (!(slashes & 1))
6247 break; /* ends with unescaped "*" */
6248 }
6249 try2optimize = 0;
6250 }
6251#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006252 loc--;
6253 if (quotes) {
6254 if (--esc < 0) {
6255 esc = esclen(startp, loc);
6256 }
6257 if (esc % 2) {
6258 esc--;
6259 loc--;
6260 }
6261 }
6262 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006263 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006264}
6265
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006266static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006267static void
6268varunset(const char *end, const char *var, const char *umsg, int varflags)
6269{
6270 const char *msg;
6271 const char *tail;
6272
6273 tail = nullstr;
6274 msg = "parameter not set";
6275 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006276 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006277 if (varflags & VSNUL)
6278 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006279 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006280 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006281 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006282 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006283 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006284}
6285
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006286#if ENABLE_ASH_BASH_COMPAT
6287static char *
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006288parse_sub_pattern(char *arg, int varflags)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006289{
6290 char *idx, *repl = NULL;
6291 unsigned char c;
6292
Denys Vlasenko16149002010-08-06 22:06:21 +02006293 //char *org_arg = arg;
Denys Vlasenko33bbb272010-08-07 22:24:36 +02006294 //bb_error_msg("arg:'%s' varflags:%x", arg, varflags);
Denis Vlasenko2659c632008-06-14 06:04:59 +00006295 idx = arg;
6296 while (1) {
6297 c = *arg;
6298 if (!c)
6299 break;
6300 if (c == '/') {
6301 /* Only the first '/' seen is our separator */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006302 if (!repl) {
Denis Vlasenko2659c632008-06-14 06:04:59 +00006303 repl = idx + 1;
6304 c = '\0';
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006305 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006306 }
Denis Vlasenko2659c632008-06-14 06:04:59 +00006307 *idx++ = c;
Denis Vlasenko2659c632008-06-14 06:04:59 +00006308 arg++;
Denys Vlasenko33bbb272010-08-07 22:24:36 +02006309 /*
6310 * Example: v='ab\c'; echo ${v/\\b/_\\_\z_}
6311 * The result is a_\_z_c (not a\_\_z_c)!
6312 *
6313 * Enable debug prints in this function and you'll see:
6314 * ash: arg:'\\b/_\\_z_' varflags:d
6315 * ash: pattern:'\\b' repl:'_\_z_'
6316 * That is, \\b is interpreted as \\b, but \\_ as \_!
6317 * IOW: search pattern and replace string treat backslashes
6318 * differently! That is the reason why we check repl below:
6319 */
6320 if (c == '\\' && *arg == '\\' && repl && !(varflags & VSQUOTE))
6321 arg++; /* skip both '\', not just first one */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006322 }
Denis Vlasenko29038c02008-06-14 06:14:02 +00006323 *idx = c; /* NUL */
Denys Vlasenko16149002010-08-06 22:06:21 +02006324 //bb_error_msg("pattern:'%s' repl:'%s'", org_arg, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006325
6326 return repl;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006327}
6328#endif /* ENABLE_ASH_BASH_COMPAT */
6329
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006330static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006331subevalvar(char *p, char *varname, int strloc, int subtype,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006332 int startloc, int varflags, int quotes, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006333{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006334 struct nodelist *saveargbackq = argbackq;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006335 char *startp;
6336 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006337 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006338 char *str;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006339 IF_ASH_BASH_COMPAT(const char *repl = NULL;)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006340 IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006341 int saveherefd = herefd;
Tanguy Pruvot823694d2012-11-18 13:20:29 +01006342 int amount, resetloc;
6343 IF_ASH_BASH_COMPAT(int workloc;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006344 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006345 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006346
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006347 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6348 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006349
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006350 herefd = -1;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006351 argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
6352 var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006353 STPUTC('\0', expdest);
6354 herefd = saveherefd;
6355 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006356 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006357
6358 switch (subtype) {
6359 case VSASSIGN:
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006360 setvar(varname, startp, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006361 amount = startp - expdest;
6362 STADJUST(amount, expdest);
6363 return startp;
6364
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006365 case VSQUESTION:
6366 varunset(p, varname, startp, varflags);
6367 /* NOTREACHED */
6368
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006369#if ENABLE_ASH_BASH_COMPAT
6370 case VSSUBSTR:
Tanguy Pruvot6fef6a32012-05-05 15:26:43 +02006371 loc = str = (char*) ((uint32_t) stackblock() + strloc);
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006372 /* Read POS in ${var:POS:LEN} */
6373 pos = atoi(loc); /* number(loc) errors out on "1:4" */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006374 len = str - startp - 1;
6375
6376 /* *loc != '\0', guaranteed by parser */
6377 if (quotes) {
6378 char *ptr;
6379
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006380 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006381 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006382 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006383 len--;
6384 ptr++;
6385 }
6386 }
6387 }
6388 orig_len = len;
6389
6390 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006391 /* ${var::LEN} */
6392 len = number(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006393 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006394 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006395 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006396 while (*loc && *loc != ':') {
6397 /* TODO?
6398 * bash complains on: var=qwe; echo ${var:1a:123}
6399 if (!isdigit(*loc))
6400 ash_msg_and_raise_error(msg_illnum, str);
6401 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006402 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006403 }
6404 if (*loc++ == ':') {
6405 len = number(loc);
6406 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006407 }
6408 if (pos >= orig_len) {
6409 pos = 0;
6410 len = 0;
6411 }
6412 if (len > (orig_len - pos))
6413 len = orig_len - pos;
6414
6415 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006416 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006417 str++;
6418 }
6419 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006420 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006421 *loc++ = *str++;
6422 *loc++ = *str++;
6423 }
6424 *loc = '\0';
6425 amount = loc - expdest;
6426 STADJUST(amount, expdest);
6427 return loc;
6428#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006429 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006430
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006431 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006432
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006433 /* We'll comeback here if we grow the stack while handling
6434 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6435 * stack will need rebasing, and we'll need to remove our work
6436 * areas each time
6437 */
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006438 IF_ASH_BASH_COMPAT(restart:)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006439
6440 amount = expdest - ((char *)stackblock() + resetloc);
6441 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006442 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006443
6444 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006445 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006446 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006447 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006448 if (rmesc != startp) {
6449 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006450 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006451 }
6452 }
6453 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006454 str = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006455 preglob(str, varflags & VSQUOTE, 0);
6456
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006457#if ENABLE_ASH_BASH_COMPAT
Tanguy Pruvot823694d2012-11-18 13:20:29 +01006458 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006459 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006460 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006461
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006462 if (!repl) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006463 repl = parse_sub_pattern(str, varflags);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006464 //bb_error_msg("repl:'%s'", repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006465 if (!repl)
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006466 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006467 }
6468
6469 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006470 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006471 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006472
6473 len = 0;
6474 idx = startp;
6475 end = str - 1;
6476 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006477 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006478 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006479 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006480 if (!loc) {
6481 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006482 char *restart_detect = stackblock();
6483 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006484 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006485 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006486 idx++;
6487 len++;
6488 STPUTC(*idx, expdest);
6489 }
6490 if (stackblock() != restart_detect)
6491 goto restart;
6492 idx++;
6493 len++;
6494 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006495 /* continue; - prone to quadratic behavior, smarter code: */
6496 if (idx >= end)
6497 break;
6498 if (str[0] == '*') {
6499 /* Pattern is "*foo". If "*foo" does not match "long_string",
6500 * it would never match "ong_string" etc, no point in trying.
6501 */
6502 goto skip_matching;
6503 }
6504 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006505 }
6506
6507 if (subtype == VSREPLACEALL) {
6508 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006509 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006510 idx++;
6511 idx++;
6512 rmesc++;
6513 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006514 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006515 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006516 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006517
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006518 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006519 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006520 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006521 if (quotes && *loc == '\\') {
6522 STPUTC(CTLESC, expdest);
6523 len++;
6524 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006525 STPUTC(*loc, expdest);
6526 if (stackblock() != restart_detect)
6527 goto restart;
6528 len++;
6529 }
6530
6531 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006532 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006533 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006534 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006535 STPUTC(*idx, expdest);
6536 if (stackblock() != restart_detect)
6537 goto restart;
6538 len++;
6539 idx++;
6540 }
6541 break;
6542 }
6543 }
6544
6545 /* We've put the replaced text into a buffer at workloc, now
6546 * move it to the right place and adjust the stack.
6547 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006548 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006549 startp = (char *)stackblock() + startloc;
6550 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006551 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006552 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006553 STADJUST(-amount, expdest);
6554 return startp;
6555 }
6556#endif /* ENABLE_ASH_BASH_COMPAT */
6557
6558 subtype -= VSTRIMRIGHT;
6559#if DEBUG
6560 if (subtype < 0 || subtype > 7)
6561 abort();
6562#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006563 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006564 zero = subtype >> 1;
6565 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6566 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6567
6568 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6569 if (loc) {
6570 if (zero) {
6571 memmove(startp, loc, str - loc);
6572 loc = startp + (str - loc) - 1;
6573 }
6574 *loc = '\0';
6575 amount = loc - expdest;
6576 STADJUST(amount, expdest);
6577 }
6578 return loc;
6579}
6580
6581/*
6582 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006583 * name parameter (examples):
6584 * ash -c 'echo $1' name:'1='
6585 * ash -c 'echo $qwe' name:'qwe='
6586 * ash -c 'echo $$' name:'$='
6587 * ash -c 'echo ${$}' name:'$='
6588 * ash -c 'echo ${$##q}' name:'$=q'
6589 * ash -c 'echo ${#$}' name:'$='
6590 * note: examples with bad shell syntax:
6591 * ash -c 'echo ${#$1}' name:'$=1'
6592 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006593 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02006594static NOINLINE ssize_t
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006595varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006596{
Mike Frysinger98c52642009-04-02 10:02:37 +00006597 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006598 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006599 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006600 int sepq = 0;
6601 ssize_t len = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006602 int subtype = varflags & VSTYPE;
Denys Vlasenko1166d7b2009-09-16 16:20:31 +02006603 int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR);
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006604 int quoted = varflags & VSQUOTE;
6605 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006606
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006607 switch (*name) {
6608 case '$':
6609 num = rootpid;
6610 goto numvar;
6611 case '?':
6612 num = exitstatus;
6613 goto numvar;
6614 case '#':
6615 num = shellparam.nparam;
6616 goto numvar;
6617 case '!':
6618 num = backgndpid;
6619 if (num == 0)
6620 return -1;
6621 numvar:
6622 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006623 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006624 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00006625 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006626 for (i = NOPTS - 1; i >= 0; i--) {
6627 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00006628 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006629 len++;
6630 }
6631 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006632 check_1char_name:
6633#if 0
6634 /* handles cases similar to ${#$1} */
6635 if (name[2] != '\0')
6636 raise_error_syntax("bad substitution");
6637#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006638 break;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006639 case '@': {
6640 char **ap;
6641 int sep;
6642
6643 if (quoted && (flags & EXP_FULL)) {
6644 /* note: this is not meant as PEOF value */
6645 sep = 1 << CHAR_BIT;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006646 goto param;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006647 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006648 /* fall through */
6649 case '*':
Denys Vlasenkocd716832009-11-28 22:14:02 +01006650 sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' ';
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006651 i = SIT(sep, syntax);
6652 if (quotes && (i == CCTL || i == CBACK))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006653 sepq = 1;
6654 param:
6655 ap = shellparam.p;
6656 if (!ap)
6657 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006658 while ((p = *ap++) != NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006659 size_t partlen;
6660
6661 partlen = strlen(p);
6662 len += partlen;
6663
6664 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6665 memtodest(p, partlen, syntax, quotes);
6666
6667 if (*ap && sep) {
6668 char *q;
6669
6670 len++;
6671 if (subtype == VSPLUS || subtype == VSLENGTH) {
6672 continue;
6673 }
6674 q = expdest;
6675 if (sepq)
6676 STPUTC(CTLESC, q);
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006677 /* note: may put NUL despite sep != 0
6678 * (see sep = 1 << CHAR_BIT above) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006679 STPUTC(sep, q);
6680 expdest = q;
6681 }
6682 }
6683 return len;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006684 } /* case '@' and '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006685 case '0':
6686 case '1':
6687 case '2':
6688 case '3':
6689 case '4':
6690 case '5':
6691 case '6':
6692 case '7':
6693 case '8':
6694 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02006695 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006696 if (num < 0 || num > shellparam.nparam)
6697 return -1;
6698 p = num ? shellparam.p[num - 1] : arg0;
6699 goto value;
6700 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006701 /* NB: name has form "VAR=..." */
6702
6703 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6704 * which should be considered before we check variables. */
6705 if (var_str_list) {
6706 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6707 p = NULL;
6708 do {
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00006709 char *str, *eq;
6710 str = var_str_list->text;
6711 eq = strchr(str, '=');
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006712 if (!eq) /* stop at first non-assignment */
6713 break;
6714 eq++;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00006715 if (name_len == (unsigned)(eq - str)
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006716 && strncmp(str, name, name_len) == 0
6717 ) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006718 p = eq;
6719 /* goto value; - WRONG! */
6720 /* think "A=1 A=2 B=$A" */
6721 }
6722 var_str_list = var_str_list->next;
6723 } while (var_str_list);
6724 if (p)
6725 goto value;
6726 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006727 p = lookupvar(name);
6728 value:
6729 if (!p)
6730 return -1;
6731
6732 len = strlen(p);
6733 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6734 memtodest(p, len, syntax, quotes);
6735 return len;
6736 }
6737
6738 if (subtype == VSPLUS || subtype == VSLENGTH)
6739 STADJUST(-len, expdest);
6740 return len;
6741}
6742
6743/*
6744 * Expand a variable, and return a pointer to the next character in the
6745 * input string.
6746 */
6747static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006748evalvar(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006749{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006750 char varflags;
6751 char subtype;
6752 char quoted;
6753 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006754 char *var;
6755 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006756 int startloc;
6757 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006758
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006759 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006760 subtype = varflags & VSTYPE;
6761 quoted = varflags & VSQUOTE;
6762 var = p;
6763 easy = (!quoted || (*var == '@' && shellparam.nparam));
6764 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02006765 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006766
6767 again:
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006768 varlen = varvalue(var, varflags, flags, var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006769 if (varflags & VSNUL)
6770 varlen--;
6771
6772 if (subtype == VSPLUS) {
6773 varlen = -1 - varlen;
6774 goto vsplus;
6775 }
6776
6777 if (subtype == VSMINUS) {
6778 vsplus:
6779 if (varlen < 0) {
6780 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006781 p,
6782 flags | (quoted ? EXP_TILDE|EXP_QWORD : EXP_TILDE|EXP_WORD),
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006783 var_str_list
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006784 );
6785 goto end;
6786 }
6787 if (easy)
6788 goto record;
6789 goto end;
6790 }
6791
6792 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6793 if (varlen < 0) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006794 if (subevalvar(p, var, /* strloc: */ 0,
6795 subtype, startloc, varflags,
6796 /* quotes: */ 0,
6797 var_str_list)
6798 ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006799 varflags &= ~VSNUL;
6800 /*
6801 * Remove any recorded regions beyond
6802 * start of variable
6803 */
6804 removerecordregions(startloc);
6805 goto again;
6806 }
6807 goto end;
6808 }
6809 if (easy)
6810 goto record;
6811 goto end;
6812 }
6813
6814 if (varlen < 0 && uflag)
6815 varunset(p, var, 0, 0);
6816
6817 if (subtype == VSLENGTH) {
6818 cvtnum(varlen > 0 ? varlen : 0);
6819 goto record;
6820 }
6821
6822 if (subtype == VSNORMAL) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006823 if (easy)
6824 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006825 goto end;
6826 }
6827
6828#if DEBUG
6829 switch (subtype) {
6830 case VSTRIMLEFT:
6831 case VSTRIMLEFTMAX:
6832 case VSTRIMRIGHT:
6833 case VSTRIMRIGHTMAX:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006834#if ENABLE_ASH_BASH_COMPAT
6835 case VSSUBSTR:
6836 case VSREPLACE:
6837 case VSREPLACEALL:
6838#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006839 break;
6840 default:
6841 abort();
6842 }
6843#endif
6844
6845 if (varlen >= 0) {
6846 /*
6847 * Terminate the string and start recording the pattern
6848 * right after it
6849 */
6850 STPUTC('\0', expdest);
6851 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006852 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006853 startloc, varflags,
Denys Vlasenko6e73af52012-07-14 01:07:39 +02006854 /* quotes: */ flags & (EXP_FULL | EXP_CASE | EXP_REDIR),
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006855 var_str_list)
6856 ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006857 int amount = expdest - (
6858 (char *)stackblock() + patloc - 1
6859 );
6860 STADJUST(-amount, expdest);
6861 }
6862 /* Remove any recorded regions beyond start of variable */
6863 removerecordregions(startloc);
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006864 record:
6865 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006866 }
6867
6868 end:
6869 if (subtype != VSNORMAL) { /* skip to end of alternative */
6870 int nesting = 1;
6871 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006872 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006873 if (c == CTLESC)
6874 p++;
6875 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
6876 if (varlen >= 0)
6877 argbackq = argbackq->next;
6878 } else if (c == CTLVAR) {
6879 if ((*p++ & VSTYPE) != VSNORMAL)
6880 nesting++;
6881 } else if (c == CTLENDVAR) {
6882 if (--nesting == 0)
6883 break;
6884 }
6885 }
6886 }
6887 return p;
6888}
6889
6890/*
6891 * Break the argument string into pieces based upon IFS and add the
6892 * strings to the argument list. The regions of the string to be
6893 * searched for IFS characters have been stored by recordregion.
6894 */
6895static void
6896ifsbreakup(char *string, struct arglist *arglist)
6897{
6898 struct ifsregion *ifsp;
6899 struct strlist *sp;
6900 char *start;
6901 char *p;
6902 char *q;
6903 const char *ifs, *realifs;
6904 int ifsspc;
6905 int nulonly;
6906
6907 start = string;
6908 if (ifslastp != NULL) {
6909 ifsspc = 0;
6910 nulonly = 0;
6911 realifs = ifsset() ? ifsval() : defifs;
6912 ifsp = &ifsfirst;
6913 do {
6914 p = string + ifsp->begoff;
6915 nulonly = ifsp->nulonly;
6916 ifs = nulonly ? nullstr : realifs;
6917 ifsspc = 0;
6918 while (p < string + ifsp->endoff) {
6919 q = p;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006920 if ((unsigned char)*p == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006921 p++;
6922 if (!strchr(ifs, *p)) {
6923 p++;
6924 continue;
6925 }
6926 if (!nulonly)
6927 ifsspc = (strchr(defifs, *p) != NULL);
6928 /* Ignore IFS whitespace at start */
6929 if (q == start && ifsspc) {
6930 p++;
6931 start = p;
6932 continue;
6933 }
6934 *q = '\0';
Denis Vlasenko597906c2008-02-20 16:38:54 +00006935 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006936 sp->text = start;
6937 *arglist->lastp = sp;
6938 arglist->lastp = &sp->next;
6939 p++;
6940 if (!nulonly) {
6941 for (;;) {
6942 if (p >= string + ifsp->endoff) {
6943 break;
6944 }
6945 q = p;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006946 if ((unsigned char)*p == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006947 p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00006948 if (strchr(ifs, *p) == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006949 p = q;
6950 break;
Denis Vlasenko597906c2008-02-20 16:38:54 +00006951 }
6952 if (strchr(defifs, *p) == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006953 if (ifsspc) {
6954 p++;
6955 ifsspc = 0;
6956 } else {
6957 p = q;
6958 break;
6959 }
6960 } else
6961 p++;
6962 }
6963 }
6964 start = p;
6965 } /* while */
6966 ifsp = ifsp->next;
6967 } while (ifsp != NULL);
6968 if (nulonly)
6969 goto add;
6970 }
6971
6972 if (!*start)
6973 return;
6974
6975 add:
Denis Vlasenko597906c2008-02-20 16:38:54 +00006976 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006977 sp->text = start;
6978 *arglist->lastp = sp;
6979 arglist->lastp = &sp->next;
6980}
6981
6982static void
6983ifsfree(void)
6984{
6985 struct ifsregion *p;
6986
6987 INT_OFF;
6988 p = ifsfirst.next;
6989 do {
6990 struct ifsregion *ifsp;
6991 ifsp = p->next;
6992 free(p);
6993 p = ifsp;
6994 } while (p);
6995 ifslastp = NULL;
6996 ifsfirst.next = NULL;
6997 INT_ON;
6998}
6999
7000/*
7001 * Add a file name to the list.
7002 */
7003static void
7004addfname(const char *name)
7005{
7006 struct strlist *sp;
7007
Denis Vlasenko597906c2008-02-20 16:38:54 +00007008 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007009 sp->text = ststrdup(name);
7010 *exparg.lastp = sp;
7011 exparg.lastp = &sp->next;
7012}
7013
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007014/*
7015 * Do metacharacter (i.e. *, ?, [...]) expansion.
7016 */
7017static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007018expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007019{
7020 char *p;
7021 const char *cp;
7022 char *start;
7023 char *endname;
7024 int metaflag;
7025 struct stat statb;
7026 DIR *dirp;
7027 struct dirent *dp;
7028 int atend;
7029 int matchdot;
7030
7031 metaflag = 0;
7032 start = name;
7033 for (p = name; *p; p++) {
7034 if (*p == '*' || *p == '?')
7035 metaflag = 1;
7036 else if (*p == '[') {
7037 char *q = p + 1;
7038 if (*q == '!')
7039 q++;
7040 for (;;) {
7041 if (*q == '\\')
7042 q++;
7043 if (*q == '/' || *q == '\0')
7044 break;
7045 if (*++q == ']') {
7046 metaflag = 1;
7047 break;
7048 }
7049 }
7050 } else if (*p == '\\')
7051 p++;
7052 else if (*p == '/') {
7053 if (metaflag)
7054 goto out;
7055 start = p + 1;
7056 }
7057 }
7058 out:
7059 if (metaflag == 0) { /* we've reached the end of the file name */
7060 if (enddir != expdir)
7061 metaflag++;
7062 p = name;
7063 do {
7064 if (*p == '\\')
7065 p++;
7066 *enddir++ = *p;
7067 } while (*p++);
7068 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7069 addfname(expdir);
7070 return;
7071 }
7072 endname = p;
7073 if (name < start) {
7074 p = name;
7075 do {
7076 if (*p == '\\')
7077 p++;
7078 *enddir++ = *p++;
7079 } while (p < start);
7080 }
7081 if (enddir == expdir) {
7082 cp = ".";
7083 } else if (enddir == expdir + 1 && *expdir == '/') {
7084 cp = "/";
7085 } else {
7086 cp = expdir;
7087 enddir[-1] = '\0';
7088 }
7089 dirp = opendir(cp);
7090 if (dirp == NULL)
7091 return;
7092 if (enddir != expdir)
7093 enddir[-1] = '/';
7094 if (*endname == 0) {
7095 atend = 1;
7096 } else {
7097 atend = 0;
7098 *endname++ = '\0';
7099 }
7100 matchdot = 0;
7101 p = start;
7102 if (*p == '\\')
7103 p++;
7104 if (*p == '.')
7105 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007106 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007107 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007108 continue;
7109 if (pmatch(start, dp->d_name)) {
7110 if (atend) {
7111 strcpy(enddir, dp->d_name);
7112 addfname(expdir);
7113 } else {
7114 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7115 continue;
7116 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007117 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007118 }
7119 }
7120 }
7121 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007122 if (!atend)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007123 endname[-1] = '/';
7124}
7125
7126static struct strlist *
7127msort(struct strlist *list, int len)
7128{
7129 struct strlist *p, *q = NULL;
7130 struct strlist **lpp;
7131 int half;
7132 int n;
7133
7134 if (len <= 1)
7135 return list;
7136 half = len >> 1;
7137 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007138 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007139 q = p;
7140 p = p->next;
7141 }
7142 q->next = NULL; /* terminate first half of list */
7143 q = msort(list, half); /* sort first half of list */
7144 p = msort(p, len - half); /* sort second half */
7145 lpp = &list;
7146 for (;;) {
7147#if ENABLE_LOCALE_SUPPORT
7148 if (strcoll(p->text, q->text) < 0)
7149#else
7150 if (strcmp(p->text, q->text) < 0)
7151#endif
7152 {
7153 *lpp = p;
7154 lpp = &p->next;
7155 p = *lpp;
7156 if (p == NULL) {
7157 *lpp = q;
7158 break;
7159 }
7160 } else {
7161 *lpp = q;
7162 lpp = &q->next;
7163 q = *lpp;
7164 if (q == NULL) {
7165 *lpp = p;
7166 break;
7167 }
7168 }
7169 }
7170 return list;
7171}
7172
7173/*
7174 * Sort the results of file name expansion. It calculates the number of
7175 * strings to sort and then calls msort (short for merge sort) to do the
7176 * work.
7177 */
7178static struct strlist *
7179expsort(struct strlist *str)
7180{
7181 int len;
7182 struct strlist *sp;
7183
7184 len = 0;
7185 for (sp = str; sp; sp = sp->next)
7186 len++;
7187 return msort(str, len);
7188}
7189
7190static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007191expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007192{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00007193 static const char metachars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007194 '*', '?', '[', 0
7195 };
7196 /* TODO - EXP_REDIR */
7197
7198 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007199 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007200 struct strlist **savelastp;
7201 struct strlist *sp;
7202 char *p;
7203
7204 if (fflag)
7205 goto nometa;
7206 if (!strpbrk(str->text, metachars))
7207 goto nometa;
7208 savelastp = exparg.lastp;
7209
7210 INT_OFF;
7211 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7212 {
7213 int i = strlen(str->text);
7214 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
7215 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007216 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007217 free(expdir);
7218 if (p != str->text)
7219 free(p);
7220 INT_ON;
7221 if (exparg.lastp == savelastp) {
7222 /*
7223 * no matches
7224 */
7225 nometa:
7226 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007227 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007228 exparg.lastp = &str->next;
7229 } else {
7230 *exparg.lastp = NULL;
7231 *savelastp = sp = expsort(*savelastp);
7232 while (sp->next != NULL)
7233 sp = sp->next;
7234 exparg.lastp = &sp->next;
7235 }
7236 str = str->next;
7237 }
7238}
7239
7240/*
7241 * Perform variable substitution and command substitution on an argument,
7242 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7243 * perform splitting and file name expansion. When arglist is NULL, perform
7244 * here document expansion.
7245 */
7246static void
7247expandarg(union node *arg, struct arglist *arglist, int flag)
7248{
7249 struct strlist *sp;
7250 char *p;
7251
7252 argbackq = arg->narg.backquote;
7253 STARTSTACKSTR(expdest);
7254 ifsfirst.next = NULL;
7255 ifslastp = NULL;
Tanguy Pruvot823694d2012-11-18 13:20:29 +01007256 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007257 argstr(arg->narg.text, flag,
7258 /* var_str_list: */ arglist ? arglist->list : NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007259 p = _STPUTC('\0', expdest);
7260 expdest = p - 1;
7261 if (arglist == NULL) {
7262 return; /* here document expanded */
7263 }
7264 p = grabstackstr(p);
Tanguy Pruvot823694d2012-11-18 13:20:29 +01007265 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007266 exparg.lastp = &exparg.list;
7267 /*
7268 * TODO - EXP_REDIR
7269 */
7270 if (flag & EXP_FULL) {
7271 ifsbreakup(p, &exparg);
7272 *exparg.lastp = NULL;
7273 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007274 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007275 } else {
Tanguy Pruvot823694d2012-11-18 13:20:29 +01007276 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007277 rmescapes(p, 0);
Tanguy Pruvot823694d2012-11-18 13:20:29 +01007278 TRACE(("expandarg: rmescapes:'%s'\n", p));
7279 }
Denis Vlasenko597906c2008-02-20 16:38:54 +00007280 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007281 sp->text = p;
7282 *exparg.lastp = sp;
7283 exparg.lastp = &sp->next;
7284 }
7285 if (ifsfirst.next)
7286 ifsfree();
7287 *exparg.lastp = NULL;
7288 if (exparg.list) {
7289 *arglist->lastp = exparg.list;
7290 arglist->lastp = exparg.lastp;
7291 }
7292}
7293
7294/*
7295 * Expand shell variables and backquotes inside a here document.
7296 */
7297static void
7298expandhere(union node *arg, int fd)
7299{
7300 herefd = fd;
7301 expandarg(arg, (struct arglist *)NULL, 0);
7302 full_write(fd, stackblock(), expdest - (char *)stackblock());
7303}
7304
7305/*
7306 * Returns true if the pattern matches the string.
7307 */
7308static int
7309patmatch(char *pattern, const char *string)
7310{
7311 return pmatch(preglob(pattern, 0, 0), string);
7312}
7313
7314/*
7315 * See if a pattern matches in a case statement.
7316 */
7317static int
7318casematch(union node *pattern, char *val)
7319{
7320 struct stackmark smark;
7321 int result;
7322
7323 setstackmark(&smark);
7324 argbackq = pattern->narg.backquote;
7325 STARTSTACKSTR(expdest);
7326 ifslastp = NULL;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007327 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7328 /* var_str_list: */ NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007329 STACKSTRNUL(expdest);
7330 result = patmatch(stackblock(), val);
7331 popstackmark(&smark);
7332 return result;
7333}
7334
7335
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007336/* ============ find_command */
7337
7338struct builtincmd {
7339 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007340 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007341 /* unsigned flags; */
7342};
7343#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007344/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007345 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007346#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007347#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007348
7349struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007350 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007351 union param {
7352 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007353 /* index >= 0 for commands without path (slashes) */
7354 /* (TODO: what exactly does the value mean? PATH position?) */
7355 /* index == -1 for commands with slashes */
7356 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007357 const struct builtincmd *cmd;
7358 struct funcnode *func;
7359 } u;
7360};
7361/* values of cmdtype */
7362#define CMDUNKNOWN -1 /* no entry in table for command */
7363#define CMDNORMAL 0 /* command is an executable program */
7364#define CMDFUNCTION 1 /* command is a shell function */
7365#define CMDBUILTIN 2 /* command is a shell builtin */
7366
7367/* action to find_command() */
7368#define DO_ERR 0x01 /* prints errors */
7369#define DO_ABS 0x02 /* checks absolute paths */
7370#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7371#define DO_ALTPATH 0x08 /* using alternate path */
7372#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7373
7374static void find_command(char *, struct cmdentry *, int, const char *);
7375
7376
7377/* ============ Hashing commands */
7378
7379/*
7380 * When commands are first encountered, they are entered in a hash table.
7381 * This ensures that a full path search will not have to be done for them
7382 * on each invocation.
7383 *
7384 * We should investigate converting to a linear search, even though that
7385 * would make the command name "hash" a misnomer.
7386 */
7387
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007388struct tblentry {
7389 struct tblentry *next; /* next entry in hash chain */
7390 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007391 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007392 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007393 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007394};
7395
Denis Vlasenko01631112007-12-16 17:20:38 +00007396static struct tblentry **cmdtable;
7397#define INIT_G_cmdtable() do { \
7398 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7399} while (0)
7400
7401static int builtinloc = -1; /* index in path of %builtin, or -1 */
7402
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007403
7404static void
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007405tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007406{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007407#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007408 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007409 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007410 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007411 while (*envp)
7412 putenv(*envp++);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007413 run_applet_no_and_exit(applet_no, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007414 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007415 /* re-exec ourselves with the new arguments */
7416 execve(bb_busybox_exec_path, argv, envp);
7417 /* If they called chroot or otherwise made the binary no longer
7418 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007419 }
7420#endif
7421
7422 repeat:
7423#ifdef SYSV
7424 do {
7425 execve(cmd, argv, envp);
7426 } while (errno == EINTR);
7427#else
7428 execve(cmd, argv, envp);
7429#endif
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007430 if (cmd == (char*) bb_busybox_exec_path) {
7431 /* We already visited ENOEXEC branch below, don't do it again */
7432//TODO: try execve(initial_argv0_of_shell, argv, envp) before giving up?
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007433 free(argv);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007434 return;
7435 }
7436 if (errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007437 /* Run "cmd" as a shell script:
7438 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7439 * "If the execve() function fails with ENOEXEC, the shell
7440 * shall execute a command equivalent to having a shell invoked
7441 * with the command name as its first operand,
7442 * with any remaining arguments passed to the new shell"
7443 *
7444 * That is, do not use $SHELL, user's shell, or /bin/sh;
7445 * just call ourselves.
Tanguy Pruvot8a6c2c22012-04-28 00:24:09 +02007446 *
7447 * Note that bash reads ~80 chars of the file, and if it sees
7448 * a zero byte before it sees newline, it doesn't try to
7449 * interpret it, but fails with "cannot execute binary file"
7450 * message and exit code 126. For one, this prevents attempts
7451 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007452 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007453 char **ap;
7454 char **new;
7455
7456 for (ap = argv; *ap; ap++)
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007457 continue;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007458 new = ckmalloc((ap - argv + 2) * sizeof(new[0]));
7459 new[0] = (char*) "ash";
7460 new[1] = cmd;
7461 ap = new + 2;
7462 while ((*ap++ = *++argv) != NULL)
Denis Vlasenko597906c2008-02-20 16:38:54 +00007463 continue;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007464 cmd = (char*) bb_busybox_exec_path;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007465 argv = new;
7466 goto repeat;
7467 }
7468}
7469
7470/*
7471 * Exec a program. Never returns. If you change this routine, you may
7472 * have to change the find_command routine as well.
7473 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007474static void shellexec(char **, const char *, int) NORETURN;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007475static void
7476shellexec(char **argv, const char *path, int idx)
7477{
7478 char *cmdname;
7479 int e;
7480 char **envp;
7481 int exerrno;
Tanguy Pruvot8a6c2c22012-04-28 00:24:09 +02007482 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007483
Denis Vlasenko34c73c42008-08-16 11:48:02 +00007484 clearredir(/*drop:*/ 1);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007485 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007486 if (strchr(argv[0], '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007487#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007488 || (applet_no = find_applet_by_name(argv[0])) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007489#endif
7490 ) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007491 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
Tanguy Pruvot8a6c2c22012-04-28 00:24:09 +02007492 if (applet_no >= 0) {
7493 /* We tried execing ourself, but it didn't work.
7494 * Maybe /proc/self/exe doesn't exist?
7495 * Try $PATH search.
7496 */
7497 goto try_PATH;
7498 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007499 e = errno;
7500 } else {
Tanguy Pruvot8a6c2c22012-04-28 00:24:09 +02007501 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007502 e = ENOENT;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007503 while ((cmdname = path_advance(&path, argv[0])) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007504 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007505 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007506 if (errno != ENOENT && errno != ENOTDIR)
7507 e = errno;
7508 }
7509 stunalloc(cmdname);
7510 }
7511 }
7512
7513 /* Map to POSIX errors */
7514 switch (e) {
7515 case EACCES:
7516 exerrno = 126;
7517 break;
7518 case ENOENT:
7519 exerrno = 127;
7520 break;
7521 default:
7522 exerrno = 2;
7523 break;
7524 }
7525 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007526 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7527 argv[0], e, suppress_int));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007528 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
7529 /* NOTREACHED */
7530}
7531
7532static void
7533printentry(struct tblentry *cmdp)
7534{
7535 int idx;
7536 const char *path;
7537 char *name;
7538
7539 idx = cmdp->param.index;
7540 path = pathval();
7541 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007542 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007543 stunalloc(name);
7544 } while (--idx >= 0);
7545 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7546}
7547
7548/*
7549 * Clear out command entries. The argument specifies the first entry in
7550 * PATH which has changed.
7551 */
7552static void
7553clearcmdentry(int firstchange)
7554{
7555 struct tblentry **tblp;
7556 struct tblentry **pp;
7557 struct tblentry *cmdp;
7558
7559 INT_OFF;
7560 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7561 pp = tblp;
7562 while ((cmdp = *pp) != NULL) {
7563 if ((cmdp->cmdtype == CMDNORMAL &&
7564 cmdp->param.index >= firstchange)
7565 || (cmdp->cmdtype == CMDBUILTIN &&
7566 builtinloc >= firstchange)
7567 ) {
7568 *pp = cmdp->next;
7569 free(cmdp);
7570 } else {
7571 pp = &cmdp->next;
7572 }
7573 }
7574 }
7575 INT_ON;
7576}
7577
7578/*
7579 * Locate a command in the command hash table. If "add" is nonzero,
7580 * add the command to the table if it is not already present. The
7581 * variable "lastcmdentry" is set to point to the address of the link
7582 * pointing to the entry, so that delete_cmd_entry can delete the
7583 * entry.
7584 *
7585 * Interrupts must be off if called with add != 0.
7586 */
7587static struct tblentry **lastcmdentry;
7588
7589static struct tblentry *
7590cmdlookup(const char *name, int add)
7591{
7592 unsigned int hashval;
7593 const char *p;
7594 struct tblentry *cmdp;
7595 struct tblentry **pp;
7596
7597 p = name;
7598 hashval = (unsigned char)*p << 4;
7599 while (*p)
7600 hashval += (unsigned char)*p++;
7601 hashval &= 0x7FFF;
7602 pp = &cmdtable[hashval % CMDTABLESIZE];
7603 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7604 if (strcmp(cmdp->cmdname, name) == 0)
7605 break;
7606 pp = &cmdp->next;
7607 }
7608 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007609 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7610 + strlen(name)
7611 /* + 1 - already done because
7612 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007613 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007614 cmdp->cmdtype = CMDUNKNOWN;
7615 strcpy(cmdp->cmdname, name);
7616 }
7617 lastcmdentry = pp;
7618 return cmdp;
7619}
7620
7621/*
7622 * Delete the command entry returned on the last lookup.
7623 */
7624static void
7625delete_cmd_entry(void)
7626{
7627 struct tblentry *cmdp;
7628
7629 INT_OFF;
7630 cmdp = *lastcmdentry;
7631 *lastcmdentry = cmdp->next;
7632 if (cmdp->cmdtype == CMDFUNCTION)
7633 freefunc(cmdp->param.func);
7634 free(cmdp);
7635 INT_ON;
7636}
7637
7638/*
7639 * Add a new command entry, replacing any existing command entry for
7640 * the same name - except special builtins.
7641 */
7642static void
7643addcmdentry(char *name, struct cmdentry *entry)
7644{
7645 struct tblentry *cmdp;
7646
7647 cmdp = cmdlookup(name, 1);
7648 if (cmdp->cmdtype == CMDFUNCTION) {
7649 freefunc(cmdp->param.func);
7650 }
7651 cmdp->cmdtype = entry->cmdtype;
7652 cmdp->param = entry->u;
7653 cmdp->rehash = 0;
7654}
7655
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007656static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007657hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007658{
7659 struct tblentry **pp;
7660 struct tblentry *cmdp;
7661 int c;
7662 struct cmdentry entry;
7663 char *name;
7664
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007665 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007666 clearcmdentry(0);
7667 return 0;
7668 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007669
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007670 if (*argptr == NULL) {
7671 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7672 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7673 if (cmdp->cmdtype == CMDNORMAL)
7674 printentry(cmdp);
7675 }
7676 }
7677 return 0;
7678 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007679
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007680 c = 0;
7681 while ((name = *argptr) != NULL) {
7682 cmdp = cmdlookup(name, 0);
7683 if (cmdp != NULL
7684 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007685 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7686 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007687 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007688 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007689 find_command(name, &entry, DO_ERR, pathval());
7690 if (entry.cmdtype == CMDUNKNOWN)
7691 c = 1;
7692 argptr++;
7693 }
7694 return c;
7695}
7696
7697/*
7698 * Called when a cd is done. Marks all commands so the next time they
7699 * are executed they will be rehashed.
7700 */
7701static void
7702hashcd(void)
7703{
7704 struct tblentry **pp;
7705 struct tblentry *cmdp;
7706
7707 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7708 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007709 if (cmdp->cmdtype == CMDNORMAL
7710 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02007711 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007712 && builtinloc > 0)
7713 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007714 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007715 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007716 }
7717 }
7718}
7719
7720/*
7721 * Fix command hash table when PATH changed.
7722 * Called before PATH is changed. The argument is the new value of PATH;
7723 * pathval() still returns the old value at this point.
7724 * Called with interrupts off.
7725 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007726static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007727changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007728{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007729 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007730 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007731 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007732 int idx_bltin;
7733
7734 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007735 firstchange = 9999; /* assume no change */
7736 idx = 0;
7737 idx_bltin = -1;
7738 for (;;) {
7739 if (*old != *new) {
7740 firstchange = idx;
7741 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007742 || (*old == ':' && *new == '\0')
7743 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007744 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007745 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007746 old = new; /* ignore subsequent differences */
7747 }
7748 if (*new == '\0')
7749 break;
7750 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7751 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007752 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007753 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007754 new++;
7755 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007756 }
7757 if (builtinloc < 0 && idx_bltin >= 0)
7758 builtinloc = idx_bltin; /* zap builtins */
7759 if (builtinloc >= 0 && idx_bltin < 0)
7760 firstchange = 0;
7761 clearcmdentry(firstchange);
7762 builtinloc = idx_bltin;
7763}
7764
7765#define TEOF 0
7766#define TNL 1
7767#define TREDIR 2
7768#define TWORD 3
7769#define TSEMI 4
7770#define TBACKGND 5
7771#define TAND 6
7772#define TOR 7
7773#define TPIPE 8
7774#define TLP 9
7775#define TRP 10
7776#define TENDCASE 11
7777#define TENDBQUOTE 12
7778#define TNOT 13
7779#define TCASE 14
7780#define TDO 15
7781#define TDONE 16
7782#define TELIF 17
7783#define TELSE 18
7784#define TESAC 19
7785#define TFI 20
7786#define TFOR 21
7787#define TIF 22
7788#define TIN 23
7789#define TTHEN 24
7790#define TUNTIL 25
7791#define TWHILE 26
7792#define TBEGIN 27
7793#define TEND 28
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007794typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007795
7796/* first char is indicating which tokens mark the end of a list */
7797static const char *const tokname_array[] = {
7798 "\1end of file",
7799 "\0newline",
7800 "\0redirection",
7801 "\0word",
7802 "\0;",
7803 "\0&",
7804 "\0&&",
7805 "\0||",
7806 "\0|",
7807 "\0(",
7808 "\1)",
7809 "\1;;",
7810 "\1`",
7811#define KWDOFFSET 13
7812 /* the following are keywords */
7813 "\0!",
7814 "\0case",
7815 "\1do",
7816 "\1done",
7817 "\1elif",
7818 "\1else",
7819 "\1esac",
7820 "\1fi",
7821 "\0for",
7822 "\0if",
7823 "\0in",
7824 "\1then",
7825 "\0until",
7826 "\0while",
7827 "\0{",
7828 "\1}",
7829};
7830
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007831/* Wrapper around strcmp for qsort/bsearch/... */
7832static int
7833pstrcmp(const void *a, const void *b)
7834{
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00007835 return strcmp((char*) a, (*(char**) b) + 1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007836}
7837
7838static const char *const *
7839findkwd(const char *s)
7840{
7841 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00007842 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7843 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007844}
7845
7846/*
7847 * Locate and print what a word is...
7848 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007849static int
7850describe_command(char *command, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007851{
7852 struct cmdentry entry;
7853 struct tblentry *cmdp;
7854#if ENABLE_ASH_ALIAS
7855 const struct alias *ap;
7856#endif
7857 const char *path = pathval();
7858
7859 if (describe_command_verbose) {
7860 out1str(command);
7861 }
7862
7863 /* First look at the keywords */
7864 if (findkwd(command)) {
7865 out1str(describe_command_verbose ? " is a shell keyword" : command);
7866 goto out;
7867 }
7868
7869#if ENABLE_ASH_ALIAS
7870 /* Then look at the aliases */
7871 ap = lookupalias(command, 0);
7872 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00007873 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007874 out1str("alias ");
7875 printalias(ap);
7876 return 0;
7877 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00007878 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007879 goto out;
7880 }
7881#endif
7882 /* Then check if it is a tracked alias */
7883 cmdp = cmdlookup(command, 0);
7884 if (cmdp != NULL) {
7885 entry.cmdtype = cmdp->cmdtype;
7886 entry.u = cmdp->param;
7887 } else {
7888 /* Finally use brute force */
7889 find_command(command, &entry, DO_ABS, path);
7890 }
7891
7892 switch (entry.cmdtype) {
7893 case CMDNORMAL: {
7894 int j = entry.u.index;
7895 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007896 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007897 p = command;
7898 } else {
7899 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007900 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007901 stunalloc(p);
7902 } while (--j >= 0);
7903 }
7904 if (describe_command_verbose) {
7905 out1fmt(" is%s %s",
7906 (cmdp ? " a tracked alias for" : nullstr), p
7907 );
7908 } else {
7909 out1str(p);
7910 }
7911 break;
7912 }
7913
7914 case CMDFUNCTION:
7915 if (describe_command_verbose) {
7916 out1str(" is a shell function");
7917 } else {
7918 out1str(command);
7919 }
7920 break;
7921
7922 case CMDBUILTIN:
7923 if (describe_command_verbose) {
7924 out1fmt(" is a %sshell builtin",
7925 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7926 "special " : nullstr
7927 );
7928 } else {
7929 out1str(command);
7930 }
7931 break;
7932
7933 default:
7934 if (describe_command_verbose) {
7935 out1str(": not found\n");
7936 }
7937 return 127;
7938 }
7939 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01007940 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007941 return 0;
7942}
7943
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007944static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007945typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007946{
Denis Vlasenko46846e22007-05-20 13:08:31 +00007947 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007948 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00007949 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007950
Denis Vlasenko46846e22007-05-20 13:08:31 +00007951 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00007952 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00007953 i++;
7954 verbose = 0;
7955 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00007956 while (argv[i]) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00007957 err |= describe_command(argv[i++], verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007958 }
7959 return err;
7960}
7961
7962#if ENABLE_ASH_CMDCMD
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007963static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007964commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007965{
7966 int c;
7967 enum {
7968 VERIFY_BRIEF = 1,
7969 VERIFY_VERBOSE = 2,
7970 } verify = 0;
7971
7972 while ((c = nextopt("pvV")) != '\0')
7973 if (c == 'V')
7974 verify |= VERIFY_VERBOSE;
7975 else if (c == 'v')
7976 verify |= VERIFY_BRIEF;
7977#if DEBUG
7978 else if (c != 'p')
7979 abort();
7980#endif
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00007981 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
7982 if (verify && (*argptr != NULL)) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007983 return describe_command(*argptr, verify - VERIFY_BRIEF);
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00007984 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007985
7986 return 0;
7987}
7988#endif
7989
7990
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007991/* ============ eval.c */
Eric Andersencb57d552001-06-28 07:25:16 +00007992
Denis Vlasenko340299a2008-11-21 10:36:36 +00007993static int funcblocksize; /* size of structures in function */
7994static int funcstringsize; /* size of strings in node */
7995static void *funcblock; /* block to allocate function from */
7996static char *funcstring; /* block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007997
Eric Andersencb57d552001-06-28 07:25:16 +00007998/* flags in argument to evaltree */
Denis Vlasenko340299a2008-11-21 10:36:36 +00007999#define EV_EXIT 01 /* exit after evaluating tree */
8000#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Eric Andersenc470f442003-07-28 09:56:35 +00008001#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00008002
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02008003static const uint8_t nodesize[N_NUMBER] = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008004 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8005 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8006 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8007 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8008 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8009 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8010 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8011 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8012 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8013 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8014 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8015 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8016 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8017 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8018 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8019 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8020 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008021#if ENABLE_ASH_BASH_COMPAT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008022 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008023#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008024 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8025 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8026 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8027 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8028 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8029 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8030 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8031 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8032 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008033};
8034
8035static void calcsize(union node *n);
8036
8037static void
8038sizenodelist(struct nodelist *lp)
8039{
8040 while (lp) {
8041 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8042 calcsize(lp->n);
8043 lp = lp->next;
8044 }
8045}
8046
8047static void
8048calcsize(union node *n)
8049{
8050 if (n == NULL)
8051 return;
8052 funcblocksize += nodesize[n->type];
8053 switch (n->type) {
8054 case NCMD:
8055 calcsize(n->ncmd.redirect);
8056 calcsize(n->ncmd.args);
8057 calcsize(n->ncmd.assign);
8058 break;
8059 case NPIPE:
8060 sizenodelist(n->npipe.cmdlist);
8061 break;
8062 case NREDIR:
8063 case NBACKGND:
8064 case NSUBSHELL:
8065 calcsize(n->nredir.redirect);
8066 calcsize(n->nredir.n);
8067 break;
8068 case NAND:
8069 case NOR:
8070 case NSEMI:
8071 case NWHILE:
8072 case NUNTIL:
8073 calcsize(n->nbinary.ch2);
8074 calcsize(n->nbinary.ch1);
8075 break;
8076 case NIF:
8077 calcsize(n->nif.elsepart);
8078 calcsize(n->nif.ifpart);
8079 calcsize(n->nif.test);
8080 break;
8081 case NFOR:
8082 funcstringsize += strlen(n->nfor.var) + 1;
8083 calcsize(n->nfor.body);
8084 calcsize(n->nfor.args);
8085 break;
8086 case NCASE:
8087 calcsize(n->ncase.cases);
8088 calcsize(n->ncase.expr);
8089 break;
8090 case NCLIST:
8091 calcsize(n->nclist.body);
8092 calcsize(n->nclist.pattern);
8093 calcsize(n->nclist.next);
8094 break;
8095 case NDEFUN:
8096 case NARG:
8097 sizenodelist(n->narg.backquote);
8098 funcstringsize += strlen(n->narg.text) + 1;
8099 calcsize(n->narg.next);
8100 break;
8101 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008102#if ENABLE_ASH_BASH_COMPAT
8103 case NTO2:
8104#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008105 case NCLOBBER:
8106 case NFROM:
8107 case NFROMTO:
8108 case NAPPEND:
8109 calcsize(n->nfile.fname);
8110 calcsize(n->nfile.next);
8111 break;
8112 case NTOFD:
8113 case NFROMFD:
8114 calcsize(n->ndup.vname);
8115 calcsize(n->ndup.next);
8116 break;
8117 case NHERE:
8118 case NXHERE:
8119 calcsize(n->nhere.doc);
8120 calcsize(n->nhere.next);
8121 break;
8122 case NNOT:
8123 calcsize(n->nnot.com);
8124 break;
8125 };
8126}
8127
8128static char *
8129nodeckstrdup(char *s)
8130{
8131 char *rtn = funcstring;
8132
8133 strcpy(funcstring, s);
8134 funcstring += strlen(s) + 1;
8135 return rtn;
8136}
8137
8138static union node *copynode(union node *);
8139
8140static struct nodelist *
8141copynodelist(struct nodelist *lp)
8142{
8143 struct nodelist *start;
8144 struct nodelist **lpp;
8145
8146 lpp = &start;
8147 while (lp) {
8148 *lpp = funcblock;
8149 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8150 (*lpp)->n = copynode(lp->n);
8151 lp = lp->next;
8152 lpp = &(*lpp)->next;
8153 }
8154 *lpp = NULL;
8155 return start;
8156}
8157
8158static union node *
8159copynode(union node *n)
8160{
8161 union node *new;
8162
8163 if (n == NULL)
8164 return NULL;
8165 new = funcblock;
8166 funcblock = (char *) funcblock + nodesize[n->type];
8167
8168 switch (n->type) {
8169 case NCMD:
8170 new->ncmd.redirect = copynode(n->ncmd.redirect);
8171 new->ncmd.args = copynode(n->ncmd.args);
8172 new->ncmd.assign = copynode(n->ncmd.assign);
8173 break;
8174 case NPIPE:
8175 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008176 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008177 break;
8178 case NREDIR:
8179 case NBACKGND:
8180 case NSUBSHELL:
8181 new->nredir.redirect = copynode(n->nredir.redirect);
8182 new->nredir.n = copynode(n->nredir.n);
8183 break;
8184 case NAND:
8185 case NOR:
8186 case NSEMI:
8187 case NWHILE:
8188 case NUNTIL:
8189 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8190 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8191 break;
8192 case NIF:
8193 new->nif.elsepart = copynode(n->nif.elsepart);
8194 new->nif.ifpart = copynode(n->nif.ifpart);
8195 new->nif.test = copynode(n->nif.test);
8196 break;
8197 case NFOR:
8198 new->nfor.var = nodeckstrdup(n->nfor.var);
8199 new->nfor.body = copynode(n->nfor.body);
8200 new->nfor.args = copynode(n->nfor.args);
8201 break;
8202 case NCASE:
8203 new->ncase.cases = copynode(n->ncase.cases);
8204 new->ncase.expr = copynode(n->ncase.expr);
8205 break;
8206 case NCLIST:
8207 new->nclist.body = copynode(n->nclist.body);
8208 new->nclist.pattern = copynode(n->nclist.pattern);
8209 new->nclist.next = copynode(n->nclist.next);
8210 break;
8211 case NDEFUN:
8212 case NARG:
8213 new->narg.backquote = copynodelist(n->narg.backquote);
8214 new->narg.text = nodeckstrdup(n->narg.text);
8215 new->narg.next = copynode(n->narg.next);
8216 break;
8217 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008218#if ENABLE_ASH_BASH_COMPAT
8219 case NTO2:
8220#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008221 case NCLOBBER:
8222 case NFROM:
8223 case NFROMTO:
8224 case NAPPEND:
8225 new->nfile.fname = copynode(n->nfile.fname);
8226 new->nfile.fd = n->nfile.fd;
8227 new->nfile.next = copynode(n->nfile.next);
8228 break;
8229 case NTOFD:
8230 case NFROMFD:
8231 new->ndup.vname = copynode(n->ndup.vname);
8232 new->ndup.dupfd = n->ndup.dupfd;
8233 new->ndup.fd = n->ndup.fd;
8234 new->ndup.next = copynode(n->ndup.next);
8235 break;
8236 case NHERE:
8237 case NXHERE:
8238 new->nhere.doc = copynode(n->nhere.doc);
8239 new->nhere.fd = n->nhere.fd;
8240 new->nhere.next = copynode(n->nhere.next);
8241 break;
8242 case NNOT:
8243 new->nnot.com = copynode(n->nnot.com);
8244 break;
8245 };
8246 new->type = n->type;
8247 return new;
8248}
8249
8250/*
8251 * Make a copy of a parse tree.
8252 */
8253static struct funcnode *
8254copyfunc(union node *n)
8255{
8256 struct funcnode *f;
8257 size_t blocksize;
8258
8259 funcblocksize = offsetof(struct funcnode, n);
8260 funcstringsize = 0;
8261 calcsize(n);
8262 blocksize = funcblocksize;
8263 f = ckmalloc(blocksize + funcstringsize);
8264 funcblock = (char *) f + offsetof(struct funcnode, n);
8265 funcstring = (char *) f + blocksize;
8266 copynode(n);
8267 f->count = 0;
8268 return f;
8269}
8270
8271/*
8272 * Define a shell function.
8273 */
8274static void
8275defun(char *name, union node *func)
8276{
8277 struct cmdentry entry;
8278
8279 INT_OFF;
8280 entry.cmdtype = CMDFUNCTION;
8281 entry.u.func = copyfunc(func);
8282 addcmdentry(name, &entry);
8283 INT_ON;
8284}
8285
Denis Vlasenko4b875702009-03-19 13:30:04 +00008286/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008287#define SKIPBREAK (1 << 0)
8288#define SKIPCONT (1 << 1)
8289#define SKIPFUNC (1 << 2)
8290#define SKIPFILE (1 << 3)
8291#define SKIPEVAL (1 << 4)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008292static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008293static int skipcount; /* number of levels to skip */
8294static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008295static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008296
Denis Vlasenko4b875702009-03-19 13:30:04 +00008297/* Forward decl way out to parsing code - dotrap needs it */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008298static int evalstring(char *s, int mask);
8299
Denis Vlasenko4b875702009-03-19 13:30:04 +00008300/* Called to execute a trap.
8301 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008302 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008303 *
8304 * Perhaps we should avoid entering new trap handlers
8305 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008306 */
8307static int
8308dotrap(void)
8309{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008310 uint8_t *g;
8311 int sig;
8312 uint8_t savestatus;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008313
8314 savestatus = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008315 pending_sig = 0;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008316 xbarrier();
8317
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008318 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008319 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
8320 int want_exexit;
8321 char *t;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008322
Denis Vlasenko4b875702009-03-19 13:30:04 +00008323 if (*g == 0)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008324 continue;
Denis Vlasenko4b875702009-03-19 13:30:04 +00008325 t = trap[sig];
8326 /* non-trapped SIGINT is handled separately by raise_interrupt,
8327 * don't upset it by resetting gotsig[SIGINT-1] */
8328 if (sig == SIGINT && !t)
8329 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008330
8331 TRACE(("sig %d is active, will run handler '%s'\n", sig, t));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008332 *g = 0;
8333 if (!t)
8334 continue;
8335 want_exexit = evalstring(t, SKIPEVAL);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008336 exitstatus = savestatus;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008337 if (want_exexit) {
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008338 TRACE(("dotrap returns %d\n", want_exexit));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008339 return want_exexit;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008340 }
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008341 }
8342
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008343 TRACE(("dotrap returns 0\n"));
Denis Vlasenko991a1da2008-02-10 19:02:53 +00008344 return 0;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008345}
8346
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008347/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008348static void evalloop(union node *, int);
8349static void evalfor(union node *, int);
8350static void evalcase(union node *, int);
8351static void evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008352static void expredir(union node *);
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008353static void evalpipe(union node *, int);
8354static void evalcommand(union node *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008355static int evalbltin(const struct builtincmd *, int, char **);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008356static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008357
Eric Andersen62483552001-07-10 06:09:16 +00008358/*
Eric Andersenc470f442003-07-28 09:56:35 +00008359 * Evaluate a parse tree. The value is left in the global variable
8360 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008361 */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008362static void
Eric Andersenc470f442003-07-28 09:56:35 +00008363evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008364{
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008365 struct jmploc *volatile savehandler = exception_handler;
8366 struct jmploc jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00008367 int checkexit = 0;
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008368 void (*evalfn)(union node *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008369 int status;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008370 int int_level;
8371
8372 SAVE_INT(int_level);
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008373
Eric Andersenc470f442003-07-28 09:56:35 +00008374 if (n == NULL) {
8375 TRACE(("evaltree(NULL) called\n"));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008376 goto out1;
Eric Andersen62483552001-07-10 06:09:16 +00008377 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008378 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008379
8380 exception_handler = &jmploc;
8381 {
8382 int err = setjmp(jmploc.loc);
8383 if (err) {
8384 /* if it was a signal, check for trap handlers */
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008385 if (exception_type == EXSIG) {
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008386 TRACE(("exception %d (EXSIG) in evaltree, err=%d\n",
8387 exception_type, err));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008388 goto out;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008389 }
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008390 /* continue on the way out */
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008391 TRACE(("exception %d in evaltree, propagating err=%d\n",
8392 exception_type, err));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008393 exception_handler = savehandler;
8394 longjmp(exception_handler->loc, err);
8395 }
8396 }
8397
Eric Andersenc470f442003-07-28 09:56:35 +00008398 switch (n->type) {
8399 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008400#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008401 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008402 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008403 break;
8404#endif
8405 case NNOT:
8406 evaltree(n->nnot.com, EV_TESTED);
8407 status = !exitstatus;
8408 goto setstatus;
8409 case NREDIR:
8410 expredir(n->nredir.redirect);
8411 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8412 if (!status) {
8413 evaltree(n->nredir.n, flags & EV_TESTED);
8414 status = exitstatus;
8415 }
Denis Vlasenko34c73c42008-08-16 11:48:02 +00008416 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
Eric Andersenc470f442003-07-28 09:56:35 +00008417 goto setstatus;
8418 case NCMD:
8419 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008420 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008421 if (eflag && !(flags & EV_TESTED))
8422 checkexit = ~0;
8423 goto calleval;
8424 case NFOR:
8425 evalfn = evalfor;
8426 goto calleval;
8427 case NWHILE:
8428 case NUNTIL:
8429 evalfn = evalloop;
8430 goto calleval;
8431 case NSUBSHELL:
8432 case NBACKGND:
8433 evalfn = evalsubshell;
8434 goto calleval;
8435 case NPIPE:
8436 evalfn = evalpipe;
8437 goto checkexit;
8438 case NCASE:
8439 evalfn = evalcase;
8440 goto calleval;
8441 case NAND:
8442 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008443 case NSEMI: {
8444
Eric Andersenc470f442003-07-28 09:56:35 +00008445#if NAND + 1 != NOR
8446#error NAND + 1 != NOR
8447#endif
8448#if NOR + 1 != NSEMI
8449#error NOR + 1 != NSEMI
8450#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008451 unsigned is_or = n->type - NAND;
Eric Andersenc470f442003-07-28 09:56:35 +00008452 evaltree(
8453 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008454 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008455 );
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008456 if (!exitstatus == is_or)
Eric Andersenc470f442003-07-28 09:56:35 +00008457 break;
8458 if (!evalskip) {
8459 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008460 evaln:
Eric Andersenc470f442003-07-28 09:56:35 +00008461 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008462 calleval:
Eric Andersenc470f442003-07-28 09:56:35 +00008463 evalfn(n, flags);
8464 break;
8465 }
8466 break;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008467 }
Eric Andersenc470f442003-07-28 09:56:35 +00008468 case NIF:
8469 evaltree(n->nif.test, EV_TESTED);
8470 if (evalskip)
8471 break;
8472 if (exitstatus == 0) {
8473 n = n->nif.ifpart;
8474 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008475 }
8476 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008477 n = n->nif.elsepart;
8478 goto evaln;
8479 }
8480 goto success;
8481 case NDEFUN:
8482 defun(n->narg.text, n->narg.next);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008483 success:
Eric Andersenc470f442003-07-28 09:56:35 +00008484 status = 0;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008485 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00008486 exitstatus = status;
8487 break;
8488 }
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008489
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008490 out:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008491 exception_handler = savehandler;
Denys Vlasenkob563f622010-09-25 17:15:13 +02008492
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008493 out1:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008494 /* Order of checks below is important:
8495 * signal handlers trigger before exit caused by "set -e".
8496 */
8497 if (pending_sig && dotrap())
8498 goto exexit;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008499 if (checkexit & exitstatus)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008500 evalskip |= SKIPEVAL;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008501
8502 if (flags & EV_EXIT) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008503 exexit:
Denis Vlasenkob012b102007-02-19 22:43:01 +00008504 raise_exception(EXEXIT);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008505 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008506
8507 RESTORE_INT(int_level);
8508 TRACE(("leaving evaltree (no interrupts)\n"));
Eric Andersen62483552001-07-10 06:09:16 +00008509}
8510
Eric Andersenc470f442003-07-28 09:56:35 +00008511#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8512static
8513#endif
8514void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
8515
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008516static void
Eric Andersenc470f442003-07-28 09:56:35 +00008517evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008518{
8519 int status;
8520
8521 loopnest++;
8522 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008523 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00008524 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00008525 int i;
8526
Eric Andersencb57d552001-06-28 07:25:16 +00008527 evaltree(n->nbinary.ch1, EV_TESTED);
8528 if (evalskip) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008529 skipping:
8530 if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00008531 evalskip = 0;
8532 continue;
8533 }
8534 if (evalskip == SKIPBREAK && --skipcount <= 0)
8535 evalskip = 0;
8536 break;
8537 }
Eric Andersenc470f442003-07-28 09:56:35 +00008538 i = exitstatus;
8539 if (n->type != NWHILE)
8540 i = !i;
8541 if (i != 0)
8542 break;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008543 evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008544 status = exitstatus;
8545 if (evalskip)
8546 goto skipping;
8547 }
8548 loopnest--;
8549 exitstatus = status;
8550}
8551
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008552static void
Eric Andersenc470f442003-07-28 09:56:35 +00008553evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008554{
8555 struct arglist arglist;
8556 union node *argp;
8557 struct strlist *sp;
8558 struct stackmark smark;
8559
8560 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008561 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008562 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008563 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008564 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
Eric Andersenc470f442003-07-28 09:56:35 +00008565 /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00008566 if (evalskip)
8567 goto out;
8568 }
8569 *arglist.lastp = NULL;
8570
8571 exitstatus = 0;
8572 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008573 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008574 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008575 setvar(n->nfor.var, sp->text, 0);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008576 evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008577 if (evalskip) {
8578 if (evalskip == SKIPCONT && --skipcount <= 0) {
8579 evalskip = 0;
8580 continue;
8581 }
8582 if (evalskip == SKIPBREAK && --skipcount <= 0)
8583 evalskip = 0;
8584 break;
8585 }
8586 }
8587 loopnest--;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008588 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008589 popstackmark(&smark);
8590}
8591
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008592static void
Eric Andersenc470f442003-07-28 09:56:35 +00008593evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008594{
8595 union node *cp;
8596 union node *patp;
8597 struct arglist arglist;
8598 struct stackmark smark;
8599
8600 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008601 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008602 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00008603 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00008604 exitstatus = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008605 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8606 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008607 if (casematch(patp, arglist.list->text)) {
8608 if (evalskip == 0) {
8609 evaltree(cp->nclist.body, flags);
8610 }
8611 goto out;
8612 }
8613 }
8614 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008615 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008616 popstackmark(&smark);
8617}
8618
Eric Andersenc470f442003-07-28 09:56:35 +00008619/*
8620 * Kick off a subshell to evaluate a tree.
8621 */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008622static void
Eric Andersenc470f442003-07-28 09:56:35 +00008623evalsubshell(union node *n, int flags)
8624{
8625 struct job *jp;
8626 int backgnd = (n->type == NBACKGND);
8627 int status;
8628
8629 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02008630 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00008631 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008632 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008633 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008634 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02008635 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008636 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008637 flags |= EV_EXIT;
8638 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02008639 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00008640 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00008641 redirect(n->nredir.redirect, 0);
8642 evaltreenr(n->nredir.n, flags);
8643 /* never returns */
8644 }
8645 status = 0;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008646 if (!backgnd)
Eric Andersenc470f442003-07-28 09:56:35 +00008647 status = waitforjob(jp);
8648 exitstatus = status;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008649 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008650}
8651
Eric Andersenc470f442003-07-28 09:56:35 +00008652/*
8653 * Compute the names of the files in a redirection list.
8654 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00008655static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008656static void
8657expredir(union node *n)
8658{
8659 union node *redir;
8660
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008661 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00008662 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008663
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008664 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008665 fn.lastp = &fn.list;
8666 switch (redir->type) {
8667 case NFROMTO:
8668 case NFROM:
8669 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008670#if ENABLE_ASH_BASH_COMPAT
8671 case NTO2:
8672#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008673 case NCLOBBER:
8674 case NAPPEND:
8675 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Tanguy Pruvot823694d2012-11-18 13:20:29 +01008676 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denis Vlasenko559691a2008-10-05 18:39:31 +00008677#if ENABLE_ASH_BASH_COMPAT
8678 store_expfname:
8679#endif
Tanguy Pruvot823694d2012-11-18 13:20:29 +01008680#if 0
8681// By the design of stack allocator, the loop of this kind:
8682// while true; do while true; do break; done </dev/null; done
8683// will look like a memory leak: ash plans to free expfname's
8684// of "/dev/null" as soon as it finishes running the loop
8685// (in this case, never).
8686// This "fix" is wrong:
8687 if (redir->nfile.expfname)
8688 stunalloc(redir->nfile.expfname);
8689// It results in corrupted state of stacked allocations.
8690#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008691 redir->nfile.expfname = fn.list->text;
8692 break;
8693 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008694 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00008695 if (redir->ndup.vname) {
8696 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008697 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008698 ash_msg_and_raise_error("redir error");
Denis Vlasenko559691a2008-10-05 18:39:31 +00008699#if ENABLE_ASH_BASH_COMPAT
8700//FIXME: we used expandarg with different args!
8701 if (!isdigit_str9(fn.list->text)) {
8702 /* >&file, not >&fd */
8703 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8704 ash_msg_and_raise_error("redir error");
8705 redir->type = NTO2;
8706 goto store_expfname;
8707 }
8708#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008709 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008710 }
8711 break;
8712 }
8713 }
8714}
8715
Eric Andersencb57d552001-06-28 07:25:16 +00008716/*
Eric Andersencb57d552001-06-28 07:25:16 +00008717 * Evaluate a pipeline. All the processes in the pipeline are children
8718 * of the process creating the pipeline. (This differs from some versions
8719 * of the shell, which make the last process in a pipeline the parent
8720 * of all the rest.)
8721 */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008722static void
Eric Andersenc470f442003-07-28 09:56:35 +00008723evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008724{
8725 struct job *jp;
8726 struct nodelist *lp;
8727 int pipelen;
8728 int prevfd;
8729 int pip[2];
8730
Eric Andersenc470f442003-07-28 09:56:35 +00008731 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00008732 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008733 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00008734 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008735 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008736 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008737 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00008738 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008739 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008740 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00008741 pip[1] = -1;
8742 if (lp->next) {
8743 if (pipe(pip) < 0) {
8744 close(prevfd);
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00008745 ash_msg_and_raise_error("pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00008746 }
8747 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008748 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00008749 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00008750 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008751 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00008752 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008753 if (prevfd > 0) {
8754 dup2(prevfd, 0);
8755 close(prevfd);
8756 }
8757 if (pip[1] > 1) {
8758 dup2(pip[1], 1);
8759 close(pip[1]);
8760 }
Eric Andersenc470f442003-07-28 09:56:35 +00008761 evaltreenr(lp->n, flags);
8762 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00008763 }
8764 if (prevfd >= 0)
8765 close(prevfd);
8766 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00008767 /* Don't want to trigger debugging */
8768 if (pip[1] != -1)
8769 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00008770 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008771 if (n->npipe.pipe_backgnd == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00008772 exitstatus = waitforjob(jp);
8773 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
Eric Andersencb57d552001-06-28 07:25:16 +00008774 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00008775 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00008776}
8777
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008778/*
8779 * Controls whether the shell is interactive or not.
8780 */
8781static void
8782setinteractive(int on)
8783{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008784 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008785
8786 if (++on == is_interactive)
8787 return;
8788 is_interactive = on;
8789 setsignal(SIGINT);
8790 setsignal(SIGQUIT);
8791 setsignal(SIGTERM);
8792#if !ENABLE_FEATURE_SH_EXTRA_QUIET
8793 if (is_interactive > 1) {
8794 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008795 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008796
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008797 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008798 /* note: ash and hush share this string */
8799 out1fmt("\n\n%s %s\n"
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008800 "Enter 'help' for a list of built-in commands."
8801 "\n\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008802 bb_banner,
8803 "built-in shell (ash)"
8804 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008805 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008806 }
8807 }
8808#endif
8809}
8810
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008811static void
8812optschanged(void)
8813{
8814#if DEBUG
8815 opentrace();
8816#endif
8817 setinteractive(iflag);
8818 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008819#if ENABLE_FEATURE_EDITING_VI
8820 if (viflag)
8821 line_input_state->flags |= VI_MODE;
8822 else
8823 line_input_state->flags &= ~VI_MODE;
8824#else
8825 viflag = 0; /* forcibly keep the option off */
8826#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008827}
8828
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008829static struct localvar *localvars;
8830
8831/*
8832 * Called after a function returns.
8833 * Interrupts must be off.
8834 */
8835static void
8836poplocalvars(void)
8837{
8838 struct localvar *lvp;
8839 struct var *vp;
8840
8841 while ((lvp = localvars) != NULL) {
8842 localvars = lvp->next;
8843 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02008844 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008845 if (vp == NULL) { /* $- saved */
8846 memcpy(optlist, lvp->text, sizeof(optlist));
8847 free((char*)lvp->text);
8848 optschanged();
8849 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008850 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008851 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008852 if (vp->var_func)
8853 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008854 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008855 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008856 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008857 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008858 }
8859 free(lvp);
8860 }
8861}
8862
8863static int
8864evalfun(struct funcnode *func, int argc, char **argv, int flags)
8865{
8866 volatile struct shparam saveparam;
8867 struct localvar *volatile savelocalvars;
8868 struct jmploc *volatile savehandler;
8869 struct jmploc jmploc;
8870 int e;
8871
8872 saveparam = shellparam;
8873 savelocalvars = localvars;
8874 e = setjmp(jmploc.loc);
8875 if (e) {
8876 goto funcdone;
8877 }
8878 INT_OFF;
8879 savehandler = exception_handler;
8880 exception_handler = &jmploc;
8881 localvars = NULL;
Denis Vlasenko01631112007-12-16 17:20:38 +00008882 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008883 func->count++;
8884 funcnest++;
8885 INT_ON;
8886 shellparam.nparam = argc - 1;
8887 shellparam.p = argv + 1;
8888#if ENABLE_ASH_GETOPTS
8889 shellparam.optind = 1;
8890 shellparam.optoff = -1;
8891#endif
8892 evaltree(&func->n, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00008893 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008894 INT_OFF;
8895 funcnest--;
8896 freefunc(func);
8897 poplocalvars();
8898 localvars = savelocalvars;
8899 freeparam(&shellparam);
8900 shellparam = saveparam;
8901 exception_handler = savehandler;
8902 INT_ON;
8903 evalskip &= ~SKIPFUNC;
8904 return e;
8905}
8906
Denis Vlasenko131ae172007-02-18 13:00:19 +00008907#if ENABLE_ASH_CMDCMD
Denis Vlasenkoaa744452007-02-23 01:04:22 +00008908static char **
8909parse_command_args(char **argv, const char **path)
Eric Andersenc470f442003-07-28 09:56:35 +00008910{
8911 char *cp, c;
8912
8913 for (;;) {
8914 cp = *++argv;
8915 if (!cp)
8916 return 0;
8917 if (*cp++ != '-')
8918 break;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008919 c = *cp++;
8920 if (!c)
Eric Andersenc470f442003-07-28 09:56:35 +00008921 break;
8922 if (c == '-' && !*cp) {
8923 argv++;
8924 break;
8925 }
8926 do {
8927 switch (c) {
8928 case 'p':
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00008929 *path = bb_default_path;
Eric Andersenc470f442003-07-28 09:56:35 +00008930 break;
8931 default:
8932 /* run 'typecmd' for other options */
8933 return 0;
8934 }
Denis Vlasenko9650f362007-02-23 01:04:37 +00008935 c = *cp++;
8936 } while (c);
Eric Andersenc470f442003-07-28 09:56:35 +00008937 }
8938 return argv;
8939}
8940#endif
8941
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008942/*
8943 * Make a variable a local variable. When a variable is made local, it's
8944 * value and flags are saved in a localvar structure. The saved values
8945 * will be restored when the shell function returns. We handle the name
8946 * "-" as a special case.
8947 */
8948static void
8949mklocal(char *name)
8950{
8951 struct localvar *lvp;
8952 struct var **vpp;
8953 struct var *vp;
8954
8955 INT_OFF;
Denis Vlasenko838ffd52008-02-21 04:32:08 +00008956 lvp = ckzalloc(sizeof(struct localvar));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008957 if (LONE_DASH(name)) {
8958 char *p;
8959 p = ckmalloc(sizeof(optlist));
8960 lvp->text = memcpy(p, optlist, sizeof(optlist));
8961 vp = NULL;
8962 } else {
8963 char *eq;
8964
8965 vpp = hashvar(name);
8966 vp = *findvar(vpp, name);
8967 eq = strchr(name, '=');
8968 if (vp == NULL) {
8969 if (eq)
8970 setvareq(name, VSTRFIXED);
8971 else
8972 setvar(name, NULL, VSTRFIXED);
8973 vp = *vpp; /* the new variable */
8974 lvp->flags = VUNSET;
8975 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008976 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008977 lvp->flags = vp->flags;
8978 vp->flags |= VSTRFIXED|VTEXTFIXED;
8979 if (eq)
8980 setvareq(name, 0);
8981 }
8982 }
8983 lvp->vp = vp;
8984 lvp->next = localvars;
8985 localvars = lvp;
8986 INT_ON;
8987}
8988
8989/*
8990 * The "local" command.
8991 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008992static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008993localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008994{
8995 char *name;
8996
8997 argv = argptr;
8998 while ((name = *argv++) != NULL) {
8999 mklocal(name);
9000 }
9001 return 0;
9002}
9003
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009004static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009005falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009006{
9007 return 1;
9008}
9009
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009010static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009011truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009012{
9013 return 0;
9014}
9015
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009016static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009017execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009018{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009019 if (argv[1]) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009020 iflag = 0; /* exit on error */
9021 mflag = 0;
9022 optschanged();
9023 shellexec(argv + 1, pathval(), 0);
9024 }
9025 return 0;
9026}
9027
9028/*
9029 * The return command.
9030 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009031static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009032returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009033{
9034 /*
9035 * If called outside a function, do what ksh does;
9036 * skip the rest of the file.
9037 */
9038 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
9039 return argv[1] ? number(argv[1]) : exitstatus;
9040}
9041
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009042/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009043static int breakcmd(int, char **) FAST_FUNC;
9044static int dotcmd(int, char **) FAST_FUNC;
9045static int evalcmd(int, char **) FAST_FUNC;
9046static int exitcmd(int, char **) FAST_FUNC;
9047static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009048#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009049static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009050#endif
Denis Vlasenko52764022007-02-24 13:42:56 +00009051#if !ENABLE_FEATURE_SH_EXTRA_QUIET
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009052static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009053#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009054#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009055static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009056#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009057static int readcmd(int, char **) FAST_FUNC;
9058static int setcmd(int, char **) FAST_FUNC;
9059static int shiftcmd(int, char **) FAST_FUNC;
9060static int timescmd(int, char **) FAST_FUNC;
9061static int trapcmd(int, char **) FAST_FUNC;
9062static int umaskcmd(int, char **) FAST_FUNC;
9063static int unsetcmd(int, char **) FAST_FUNC;
9064static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009065
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009066#define BUILTIN_NOSPEC "0"
9067#define BUILTIN_SPECIAL "1"
9068#define BUILTIN_REGULAR "2"
9069#define BUILTIN_SPEC_REG "3"
9070#define BUILTIN_ASSIGN "4"
9071#define BUILTIN_SPEC_ASSG "5"
9072#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009073#define BUILTIN_SPEC_REG_ASSG "7"
9074
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009075/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009076#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009077static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009078#endif
9079#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009080static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009081#endif
9082#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009083static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009084#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009085
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009086/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009087static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009088 { BUILTIN_SPEC_REG "." , dotcmd },
9089 { BUILTIN_SPEC_REG ":" , truecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009090#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009091 { BUILTIN_REGULAR "[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009092#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009093 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009094#endif
Denis Vlasenko80591b02008-03-25 07:49:43 +00009095#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009096#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009097 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009098#endif
9099#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009100 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009101#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009102 { BUILTIN_SPEC_REG "break" , breakcmd },
9103 { BUILTIN_REGULAR "cd" , cdcmd },
9104 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009105#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009106 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009107#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009108 { BUILTIN_SPEC_REG "continue", breakcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009109#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009110 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009111#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009112 { BUILTIN_SPEC_REG "eval" , evalcmd },
9113 { BUILTIN_SPEC_REG "exec" , execcmd },
9114 { BUILTIN_SPEC_REG "exit" , exitcmd },
9115 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9116 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009117#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009118 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009119#endif
9120#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009121 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009122#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009123 { BUILTIN_NOSPEC "hash" , hashcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009124#if !ENABLE_FEATURE_SH_EXTRA_QUIET
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009125 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009126#endif
9127#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009128 { BUILTIN_REGULAR "jobs" , jobscmd },
9129 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009130#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009131#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009132 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009133#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009134 { BUILTIN_ASSIGN "local" , localcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009135#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009136 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009137#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009138 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9139 { BUILTIN_REGULAR "read" , readcmd },
9140 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9141 { BUILTIN_SPEC_REG "return" , returncmd },
9142 { BUILTIN_SPEC_REG "set" , setcmd },
9143 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009144#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009145 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009146#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009147#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009148 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009149#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009150 { BUILTIN_SPEC_REG "times" , timescmd },
9151 { BUILTIN_SPEC_REG "trap" , trapcmd },
9152 { BUILTIN_REGULAR "true" , truecmd },
9153 { BUILTIN_NOSPEC "type" , typecmd },
9154 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9155 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009156#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009157 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009158#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009159 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9160 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009161};
9162
Denis Vlasenko80591b02008-03-25 07:49:43 +00009163/* Should match the above table! */
9164#define COMMANDCMD (builtintab + \
9165 2 + \
9166 1 * ENABLE_ASH_BUILTIN_TEST + \
9167 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9168 1 * ENABLE_ASH_ALIAS + \
9169 1 * ENABLE_ASH_JOB_CONTROL + \
9170 3)
9171#define EXECCMD (builtintab + \
9172 2 + \
9173 1 * ENABLE_ASH_BUILTIN_TEST + \
9174 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9175 1 * ENABLE_ASH_ALIAS + \
9176 1 * ENABLE_ASH_JOB_CONTROL + \
9177 3 + \
9178 1 * ENABLE_ASH_CMDCMD + \
9179 1 + \
9180 ENABLE_ASH_BUILTIN_ECHO + \
9181 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009182
9183/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009184 * Search the table of builtin commands.
9185 */
9186static struct builtincmd *
9187find_builtin(const char *name)
9188{
9189 struct builtincmd *bp;
9190
9191 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009192 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009193 pstrcmp
9194 );
9195 return bp;
9196}
9197
9198/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009199 * Execute a simple command.
9200 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009201static int
9202isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009203{
9204 const char *q = endofname(p);
9205 if (p == q)
9206 return 0;
9207 return *q == '=';
9208}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009209static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009210bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009211{
9212 /* Preserve exitstatus of a previous possible redirection
9213 * as POSIX mandates */
9214 return back_exitstatus;
9215}
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02009216static void
Eric Andersenc470f442003-07-28 09:56:35 +00009217evalcommand(union node *cmd, int flags)
9218{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009219 static const struct builtincmd null_bltin = {
9220 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009221 };
Eric Andersenc470f442003-07-28 09:56:35 +00009222 struct stackmark smark;
9223 union node *argp;
9224 struct arglist arglist;
9225 struct arglist varlist;
9226 char **argv;
9227 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009228 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009229 struct cmdentry cmdentry;
9230 struct job *jp;
9231 char *lastarg;
9232 const char *path;
9233 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009234 int status;
9235 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00009236 struct builtincmd *bcmd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009237 smallint cmd_is_exec;
9238 smallint pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009239
9240 /* First expand the arguments. */
9241 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9242 setstackmark(&smark);
9243 back_exitstatus = 0;
9244
9245 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009246 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009247 varlist.lastp = &varlist.list;
9248 *varlist.lastp = NULL;
9249 arglist.lastp = &arglist.list;
9250 *arglist.lastp = NULL;
9251
9252 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009253 if (cmd->ncmd.args) {
Paul Foxc3850c82005-07-20 18:23:39 +00009254 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9255 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9256 }
9257
Eric Andersenc470f442003-07-28 09:56:35 +00009258 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9259 struct strlist **spp;
9260
9261 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00009262 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00009263 expandarg(argp, &arglist, EXP_VARTILDE);
9264 else
9265 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9266
Eric Andersenc470f442003-07-28 09:56:35 +00009267 for (sp = *spp; sp; sp = sp->next)
9268 argc++;
9269 }
9270
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009271 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009272 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009273 TRACE(("evalcommand arg: %s\n", sp->text));
9274 *nargv++ = sp->text;
9275 }
9276 *nargv = NULL;
9277
9278 lastarg = NULL;
9279 if (iflag && funcnest == 0 && argc > 0)
9280 lastarg = nargv[-1];
9281
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009282 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009283 expredir(cmd->ncmd.redirect);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009284 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009285
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009286 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009287 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9288 struct strlist **spp;
9289 char *p;
9290
9291 spp = varlist.lastp;
9292 expandarg(argp, &varlist, EXP_VARTILDE);
9293
9294 /*
9295 * Modify the command lookup path, if a PATH= assignment
9296 * is present
9297 */
9298 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009299 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009300 path = p;
9301 }
9302
9303 /* Print the command if xflag is set. */
9304 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009305 int n;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009306 const char *p = " %s" + 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009307
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009308 fdprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009309 sp = varlist.list;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009310 for (n = 0; n < 2; n++) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009311 while (sp) {
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009312 fdprintf(preverrout_fd, p, sp->text);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009313 sp = sp->next;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009314 p = " %s";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009315 }
9316 sp = arglist.list;
9317 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009318 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009319 }
9320
9321 cmd_is_exec = 0;
9322 spclbltin = -1;
9323
9324 /* Now locate the command. */
9325 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009326 int cmd_flag = DO_ERR;
Tanguy Pruvot823694d2012-11-18 13:20:29 +01009327#if ENABLE_ASH_CMDCMD
9328 const char *oldpath = path + 5;
9329#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009330 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009331 for (;;) {
9332 find_command(argv[0], &cmdentry, cmd_flag, path);
9333 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009334 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009335 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009336 goto bail;
9337 }
9338
9339 /* implement bltin and command here */
9340 if (cmdentry.cmdtype != CMDBUILTIN)
9341 break;
9342 if (spclbltin < 0)
9343 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9344 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009345 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009346#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009347 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009348 path = oldpath;
9349 nargv = parse_command_args(argv, &path);
9350 if (!nargv)
9351 break;
9352 argc -= nargv - argv;
9353 argv = nargv;
9354 cmd_flag |= DO_NOFUNC;
9355 } else
9356#endif
9357 break;
9358 }
9359 }
9360
9361 if (status) {
9362 /* We have a redirection error. */
9363 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009364 raise_exception(EXERROR);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009365 bail:
Eric Andersenc470f442003-07-28 09:56:35 +00009366 exitstatus = status;
9367 goto out;
9368 }
9369
9370 /* Execute the command. */
9371 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009372 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009373
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009374#if ENABLE_FEATURE_SH_NOFORK
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009375/* (1) BUG: if variables are set, we need to fork, or save/restore them
9376 * around run_nofork_applet() call.
9377 * (2) Should this check also be done in forkshell()?
9378 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9379 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009380 /* find_command() encodes applet_no as (-2 - applet_no) */
9381 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009382 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009383 listsetvar(varlist.list, VEXPORT|VSTACK);
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009384 /* run <applet>_main() */
9385 exitstatus = run_nofork_applet(applet_no, argv);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009386 break;
9387 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009388#endif
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009389 /* Can we avoid forking off? For example, very last command
9390 * in a script or a subshell does not need forking,
9391 * we can just exec it.
9392 */
Denys Vlasenko238bf182010-05-18 15:49:07 +02009393 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009394 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009395 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00009396 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009397 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009398 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00009399 exitstatus = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009400 INT_ON;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009401 TRACE(("forked child exited with %d\n", exitstatus));
Eric Andersenc470f442003-07-28 09:56:35 +00009402 break;
9403 }
Denys Vlasenko238bf182010-05-18 15:49:07 +02009404 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009405 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +02009406 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +00009407 }
9408 listsetvar(varlist.list, VEXPORT|VSTACK);
9409 shellexec(argv, path, cmdentry.u.index);
9410 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009411 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +00009412 case CMDBUILTIN:
9413 cmdenviron = varlist.list;
9414 if (cmdenviron) {
9415 struct strlist *list = cmdenviron;
9416 int i = VNOSET;
9417 if (spclbltin > 0 || argc == 0) {
9418 i = 0;
9419 if (cmd_is_exec && argc > 1)
9420 i = VEXPORT;
9421 }
9422 listsetvar(list, i);
9423 }
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009424 /* Tight loop with builtins only:
9425 * "while kill -0 $child; do true; done"
9426 * will never exit even if $child died, unless we do this
9427 * to reap the zombie and make kill detect that it's gone: */
9428 dowait(DOWAIT_NONBLOCK, NULL);
9429
Eric Andersenc470f442003-07-28 09:56:35 +00009430 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
9431 int exit_status;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00009432 int i = exception_type;
Eric Andersenc470f442003-07-28 09:56:35 +00009433 if (i == EXEXIT)
9434 goto raise;
Eric Andersenc470f442003-07-28 09:56:35 +00009435 exit_status = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009436 if (i == EXINT)
Denis Vlasenko991a1da2008-02-10 19:02:53 +00009437 exit_status = 128 + SIGINT;
Eric Andersenc470f442003-07-28 09:56:35 +00009438 if (i == EXSIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009439 exit_status = 128 + pending_sig;
Eric Andersenc470f442003-07-28 09:56:35 +00009440 exitstatus = exit_status;
Eric Andersenc470f442003-07-28 09:56:35 +00009441 if (i == EXINT || spclbltin > 0) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009442 raise:
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009443 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009444 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009445 FORCE_INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009446 }
9447 break;
9448
9449 case CMDFUNCTION:
9450 listsetvar(varlist.list, 0);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009451 /* See above for the rationale */
9452 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009453 if (evalfun(cmdentry.u.func, argc, argv, flags))
9454 goto raise;
9455 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009456
9457 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +00009458
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009459 out:
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009460 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009461 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +00009462 /* dsl: I think this is intended to be used to support
9463 * '_' in 'vi' command mode during line editing...
9464 * However I implemented that within libedit itself.
9465 */
9466 setvar("_", lastarg, 0);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009467 }
Eric Andersenc470f442003-07-28 09:56:35 +00009468 popstackmark(&smark);
9469}
9470
9471static int
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009472evalbltin(const struct builtincmd *cmd, int argc, char **argv)
9473{
Eric Andersenc470f442003-07-28 09:56:35 +00009474 char *volatile savecmdname;
9475 struct jmploc *volatile savehandler;
9476 struct jmploc jmploc;
9477 int i;
9478
9479 savecmdname = commandname;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009480 i = setjmp(jmploc.loc);
9481 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +00009482 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009483 savehandler = exception_handler;
9484 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00009485 commandname = argv[0];
9486 argptr = argv + 1;
9487 optptr = NULL; /* initialize nextopt */
9488 exitstatus = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009489 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009490 cmddone:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009491 exitstatus |= ferror(stdout);
Rob Landleyf296f0b2006-07-06 01:09:21 +00009492 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009493 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009494 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +00009495
9496 return i;
9497}
9498
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009499static int
9500goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009501{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02009502 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009503}
9504
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009505
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009506/*
9507 * Search for a command. This is called before we fork so that the
9508 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009509 * the child. The check for "goodname" is an overly conservative
9510 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009511 */
Eric Andersenc470f442003-07-28 09:56:35 +00009512static void
9513prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009514{
9515 struct cmdentry entry;
9516
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009517 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9518 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009519}
9520
Eric Andersencb57d552001-06-28 07:25:16 +00009521
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009522/* ============ Builtin commands
9523 *
9524 * Builtin commands whose functions are closely tied to evaluation
9525 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +00009526 */
9527
9528/*
Eric Andersencb57d552001-06-28 07:25:16 +00009529 * Handle break and continue commands. Break, continue, and return are
9530 * all handled by setting the evalskip flag. The evaluation routines
9531 * above all check this flag, and if it is set they start skipping
9532 * commands rather than executing them. The variable skipcount is
9533 * the number of loops to break/continue, or the number of function
9534 * levels to return. (The latter is always 1.) It should probably
9535 * be an error to break out of more loops than exist, but it isn't
9536 * in the standard shell so we don't make it one here.
9537 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009538static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009539breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009540{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009541 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009542
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00009543 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009544 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009545 if (n > loopnest)
9546 n = loopnest;
9547 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009548 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00009549 skipcount = n;
9550 }
9551 return 0;
9552}
9553
Eric Andersenc470f442003-07-28 09:56:35 +00009554
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009555/* ============ input.c
9556 *
Eric Andersen90898442003-08-06 11:20:52 +00009557 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00009558 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009559
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009560enum {
9561 INPUT_PUSH_FILE = 1,
9562 INPUT_NOFILE_OK = 2,
9563};
Eric Andersencb57d552001-06-28 07:25:16 +00009564
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009565static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009566/* values of checkkwd variable */
9567#define CHKALIAS 0x1
9568#define CHKKWD 0x2
9569#define CHKNL 0x4
9570
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009571/*
9572 * Push a string back onto the input at this current parsefile level.
9573 * We handle aliases this way.
9574 */
9575#if !ENABLE_ASH_ALIAS
9576#define pushstring(s, ap) pushstring(s)
9577#endif
9578static void
9579pushstring(char *s, struct alias *ap)
9580{
9581 struct strpush *sp;
9582 int len;
9583
9584 len = strlen(s);
9585 INT_OFF;
9586 if (g_parsefile->strpush) {
9587 sp = ckzalloc(sizeof(*sp));
9588 sp->prev = g_parsefile->strpush;
9589 } else {
9590 sp = &(g_parsefile->basestrpush);
9591 }
9592 g_parsefile->strpush = sp;
9593 sp->prev_string = g_parsefile->next_to_pgetc;
9594 sp->prev_left_in_line = g_parsefile->left_in_line;
9595#if ENABLE_ASH_ALIAS
9596 sp->ap = ap;
9597 if (ap) {
9598 ap->flag |= ALIASINUSE;
9599 sp->string = s;
9600 }
9601#endif
9602 g_parsefile->next_to_pgetc = s;
9603 g_parsefile->left_in_line = len;
9604 INT_ON;
9605}
9606
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009607static void
9608popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009609{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009610 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +00009611
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009612 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009613#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009614 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009615 if (g_parsefile->next_to_pgetc[-1] == ' '
9616 || g_parsefile->next_to_pgetc[-1] == '\t'
9617 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009618 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009619 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009620 if (sp->string != sp->ap->val) {
9621 free(sp->string);
9622 }
9623 sp->ap->flag &= ~ALIASINUSE;
9624 if (sp->ap->flag & ALIASDEAD) {
9625 unalias(sp->ap->name);
9626 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009627 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009628#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009629 g_parsefile->next_to_pgetc = sp->prev_string;
9630 g_parsefile->left_in_line = sp->prev_left_in_line;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009631 g_parsefile->strpush = sp->prev;
9632 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009633 free(sp);
9634 INT_ON;
9635}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009636
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009637//FIXME: BASH_COMPAT with "...&" does TWO pungetc():
9638//it peeks whether it is &>, and then pushes back both chars.
9639//This function needs to save last *next_to_pgetc to buf[0]
9640//to make two pungetc() reliable. Currently,
9641// pgetc (out of buf: does preadfd), pgetc, pungetc, pungetc won't work...
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009642static int
9643preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009644{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009645 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00009646 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009647
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009648 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +00009649#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +00009650 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009651 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Denys Vlasenko80542ba2011-05-08 21:23:43 +02009652 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009653 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009654 int timeout = -1;
9655# if ENABLE_ASH_IDLE_TIMEOUT
9656 if (iflag) {
9657 const char *tmout_var = lookupvar("TMOUT");
9658 if (tmout_var) {
9659 timeout = atoi(tmout_var) * 1000;
9660 if (timeout <= 0)
9661 timeout = -1;
9662 }
9663 }
9664# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009665# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009666 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009667# endif
Denys Vlasenko20704f02011-03-23 17:59:27 +01009668 /* Unicode support should be activated even if LANG is set
9669 * _during_ shell execution, not only if it was set when
9670 * shell was started. Therefore, re-check LANG every time:
9671 */
9672 reinit_unicode(lookupvar("LANG"));
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009673 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009674 if (nr == 0) {
9675 /* Ctrl+C pressed */
9676 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009677 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009678 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009679 raise(SIGINT);
9680 return 1;
9681 }
Eric Andersenc470f442003-07-28 09:56:35 +00009682 goto retry;
9683 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009684 if (nr < 0) {
9685 if (errno == 0) {
9686 /* Ctrl+D pressed */
9687 nr = 0;
9688 }
9689# if ENABLE_ASH_IDLE_TIMEOUT
9690 else if (errno == EAGAIN && timeout > 0) {
9691 printf("\007timed out waiting for input: auto-logout\n");
9692 exitshell();
9693 }
9694# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009695 }
Eric Andersencb57d552001-06-28 07:25:16 +00009696 }
9697#else
Denys Vlasenko80542ba2011-05-08 21:23:43 +02009698 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1);
Eric Andersencb57d552001-06-28 07:25:16 +00009699#endif
9700
Denys Vlasenko80c5b682011-05-08 21:21:10 +02009701#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +00009702 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00009703 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +00009704 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +00009705 if (flags >= 0 && (flags & O_NONBLOCK)) {
9706 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00009707 if (fcntl(0, F_SETFL, flags) >= 0) {
9708 out2str("sh: turning off NDELAY mode\n");
9709 goto retry;
9710 }
9711 }
9712 }
9713 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +00009714#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009715 return nr;
9716}
9717
9718/*
9719 * Refill the input buffer and return the next input character:
9720 *
9721 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009722 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9723 * or we are reading from a string so we can't refill the buffer,
9724 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +02009725 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +00009726 * 4) Process input up to the next newline, deleting nul characters.
9727 */
Denis Vlasenko727752d2008-11-28 03:41:47 +00009728//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9729#define pgetc_debug(...) ((void)0)
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009730static int
Eric Andersenc470f442003-07-28 09:56:35 +00009731preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009732{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009733 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +00009734 int more;
Eric Andersencb57d552001-06-28 07:25:16 +00009735
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009736 while (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +00009737#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009738 if (g_parsefile->left_in_line == -1
9739 && g_parsefile->strpush->ap
9740 && g_parsefile->next_to_pgetc[-1] != ' '
9741 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +00009742 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009743 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +00009744 return PEOA;
9745 }
Eric Andersen2870d962001-07-02 17:27:21 +00009746#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009747 popstring();
Denis Vlasenko727752d2008-11-28 03:41:47 +00009748 /* try "pgetc" now: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009749 pgetc_debug("preadbuffer internal pgetc at %d:%p'%s'",
9750 g_parsefile->left_in_line,
9751 g_parsefile->next_to_pgetc,
9752 g_parsefile->next_to_pgetc);
9753 if (--g_parsefile->left_in_line >= 0)
9754 return (unsigned char)(*g_parsefile->next_to_pgetc++);
Eric Andersencb57d552001-06-28 07:25:16 +00009755 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009756 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009757 * "pgetc" needs refilling.
9758 */
9759
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009760 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009761 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009762 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009763 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009764 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009765 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009766 /* even in failure keep left_in_line and next_to_pgetc
9767 * in lock step, for correct multi-layer pungetc.
9768 * left_in_line was decremented before preadbuffer(),
9769 * must inc next_to_pgetc: */
9770 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009771 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009772 }
Eric Andersencb57d552001-06-28 07:25:16 +00009773
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009774 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009775 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009776 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009777 again:
9778 more = preadfd();
9779 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009780 /* don't try reading again */
9781 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009782 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009783 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009784 return PEOF;
9785 }
9786 }
9787
Denis Vlasenko727752d2008-11-28 03:41:47 +00009788 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009789 * Set g_parsefile->left_in_line
9790 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009791 * NUL chars are deleted.
9792 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009793 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009794 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009795 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00009796
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009797 more--;
Eric Andersenc470f442003-07-28 09:56:35 +00009798
Denis Vlasenko727752d2008-11-28 03:41:47 +00009799 c = *q;
9800 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009801 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009802 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009803 q++;
9804 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009805 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009806 break;
9807 }
Eric Andersencb57d552001-06-28 07:25:16 +00009808 }
9809
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009810 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009811 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9812 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00009813 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009814 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009815 }
9816 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009817 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +00009818
Eric Andersencb57d552001-06-28 07:25:16 +00009819 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009820 char save = *q;
9821 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009822 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009823 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +00009824 }
9825
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009826 pgetc_debug("preadbuffer at %d:%p'%s'",
9827 g_parsefile->left_in_line,
9828 g_parsefile->next_to_pgetc,
9829 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +01009830 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009831}
9832
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009833#define pgetc_as_macro() \
9834 (--g_parsefile->left_in_line >= 0 \
Denys Vlasenkocd716832009-11-28 22:14:02 +01009835 ? (unsigned char)*g_parsefile->next_to_pgetc++ \
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009836 : preadbuffer() \
9837 )
Denis Vlasenko727752d2008-11-28 03:41:47 +00009838
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009839static int
9840pgetc(void)
9841{
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009842 pgetc_debug("pgetc_fast at %d:%p'%s'",
9843 g_parsefile->left_in_line,
9844 g_parsefile->next_to_pgetc,
9845 g_parsefile->next_to_pgetc);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009846 return pgetc_as_macro();
9847}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00009848
9849#if ENABLE_ASH_OPTIMIZE_FOR_SIZE
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009850# define pgetc_fast() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009851#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009852# define pgetc_fast() pgetc_as_macro()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009853#endif
9854
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009855#if ENABLE_ASH_ALIAS
9856static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009857pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009858{
9859 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009860 do {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009861 pgetc_debug("pgetc_fast at %d:%p'%s'",
9862 g_parsefile->left_in_line,
9863 g_parsefile->next_to_pgetc,
9864 g_parsefile->next_to_pgetc);
Denis Vlasenko834dee72008-10-07 09:18:30 +00009865 c = pgetc_fast();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009866 } while (c == PEOA);
9867 return c;
9868}
9869#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009870# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009871#endif
9872
9873/*
9874 * Read a line from the script.
9875 */
9876static char *
9877pfgets(char *line, int len)
9878{
9879 char *p = line;
9880 int nleft = len;
9881 int c;
9882
9883 while (--nleft > 0) {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009884 c = pgetc_without_PEOA();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009885 if (c == PEOF) {
9886 if (p == line)
9887 return NULL;
9888 break;
9889 }
9890 *p++ = c;
9891 if (c == '\n')
9892 break;
9893 }
9894 *p = '\0';
9895 return line;
9896}
9897
Eric Andersenc470f442003-07-28 09:56:35 +00009898/*
9899 * Undo the last call to pgetc. Only one character may be pushed back.
9900 * PEOF may be pushed back.
9901 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009902static void
Eric Andersenc470f442003-07-28 09:56:35 +00009903pungetc(void)
9904{
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009905 g_parsefile->left_in_line++;
9906 g_parsefile->next_to_pgetc--;
9907 pgetc_debug("pushed back to %d:%p'%s'",
9908 g_parsefile->left_in_line,
9909 g_parsefile->next_to_pgetc,
9910 g_parsefile->next_to_pgetc);
Eric Andersencb57d552001-06-28 07:25:16 +00009911}
9912
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009913/*
9914 * To handle the "." command, a stack of input files is used. Pushfile
9915 * adds a new entry to the stack and popfile restores the previous level.
9916 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009917static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009918pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009919{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009920 struct parsefile *pf;
9921
Denis Vlasenko597906c2008-02-20 16:38:54 +00009922 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009923 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009924 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +00009925 /*pf->strpush = NULL; - ckzalloc did it */
9926 /*pf->basestrpush.prev = NULL;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009927 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009928}
9929
9930static void
9931popfile(void)
9932{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009933 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +00009934
Denis Vlasenkob012b102007-02-19 22:43:01 +00009935 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009936 if (pf->pf_fd >= 0)
9937 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +00009938 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009939 while (pf->strpush)
9940 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009941 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009942 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009943 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009944}
9945
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009946/*
9947 * Return to top level.
9948 */
9949static void
9950popallfiles(void)
9951{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009952 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009953 popfile();
9954}
9955
9956/*
9957 * Close the file(s) that the shell is reading commands from. Called
9958 * after a fork is done.
9959 */
9960static void
9961closescript(void)
9962{
9963 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009964 if (g_parsefile->pf_fd > 0) {
9965 close(g_parsefile->pf_fd);
9966 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009967 }
9968}
9969
9970/*
9971 * Like setinputfile, but takes an open file descriptor. Call this with
9972 * interrupts off.
9973 */
9974static void
9975setinputfd(int fd, int push)
9976{
Denis Vlasenko96e1b382007-09-30 23:50:48 +00009977 close_on_exec_on(fd);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009978 if (push) {
9979 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +00009980 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009981 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009982 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009983 if (g_parsefile->buf == NULL)
9984 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009985 g_parsefile->left_in_buffer = 0;
9986 g_parsefile->left_in_line = 0;
9987 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009988}
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009989
Eric Andersenc470f442003-07-28 09:56:35 +00009990/*
9991 * Set the input to take input from a file. If push is set, push the
9992 * old input onto the stack first.
9993 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009994static int
9995setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +00009996{
9997 int fd;
9998 int fd2;
9999
Denis Vlasenkob012b102007-02-19 22:43:01 +000010000 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010001 fd = open(fname, O_RDONLY);
10002 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010003 if (flags & INPUT_NOFILE_OK)
10004 goto out;
Denis Vlasenko9604e1b2009-03-03 18:47:56 +000010005 ash_msg_and_raise_error("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010006 }
Eric Andersenc470f442003-07-28 09:56:35 +000010007 if (fd < 10) {
10008 fd2 = copyfd(fd, 10);
10009 close(fd);
10010 if (fd2 < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010011 ash_msg_and_raise_error("out of file descriptors");
Eric Andersenc470f442003-07-28 09:56:35 +000010012 fd = fd2;
10013 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010014 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010015 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010016 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010017 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010018}
10019
Eric Andersencb57d552001-06-28 07:25:16 +000010020/*
10021 * Like setinputfile, but takes input from a string.
10022 */
Eric Andersenc470f442003-07-28 09:56:35 +000010023static void
10024setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010025{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010026 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010027 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010028 g_parsefile->next_to_pgetc = string;
10029 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010030 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010031 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010032 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010033}
10034
10035
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010036/* ============ mail.c
10037 *
10038 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010039 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010040
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010041#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010042
Eric Andersencb57d552001-06-28 07:25:16 +000010043#define MAXMBOXES 10
10044
Eric Andersenc470f442003-07-28 09:56:35 +000010045/* times of mailboxes */
10046static time_t mailtime[MAXMBOXES];
10047/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010048static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010049
Eric Andersencb57d552001-06-28 07:25:16 +000010050/*
Eric Andersenc470f442003-07-28 09:56:35 +000010051 * Print appropriate message(s) if mail has arrived.
10052 * If mail_var_path_changed is set,
10053 * then the value of MAIL has mail_var_path_changed,
10054 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010055 */
Eric Andersenc470f442003-07-28 09:56:35 +000010056static void
10057chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010058{
Eric Andersencb57d552001-06-28 07:25:16 +000010059 const char *mpath;
10060 char *p;
10061 char *q;
Eric Andersenc470f442003-07-28 09:56:35 +000010062 time_t *mtp;
Eric Andersencb57d552001-06-28 07:25:16 +000010063 struct stackmark smark;
10064 struct stat statb;
10065
Eric Andersencb57d552001-06-28 07:25:16 +000010066 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010067 mpath = mpathset() ? mpathval() : mailval();
10068 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010069 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010070 if (p == NULL)
10071 break;
10072 if (*p == '\0')
10073 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010074 for (q = p; *q; q++)
10075 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010076#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010077 if (q[-1] != '/')
10078 abort();
10079#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010080 q[-1] = '\0'; /* delete trailing '/' */
10081 if (stat(p, &statb) < 0) {
10082 *mtp = 0;
10083 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010084 }
Eric Andersenc470f442003-07-28 09:56:35 +000010085 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
10086 fprintf(
Denys Vlasenkoea8b2522010-06-02 12:57:26 +020010087 stderr, "%s\n",
Eric Andersenc470f442003-07-28 09:56:35 +000010088 pathopt ? pathopt : "you have mail"
10089 );
10090 }
10091 *mtp = statb.st_mtime;
Eric Andersencb57d552001-06-28 07:25:16 +000010092 }
Eric Andersenc470f442003-07-28 09:56:35 +000010093 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010094 popstackmark(&smark);
10095}
Eric Andersencb57d552001-06-28 07:25:16 +000010096
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010097static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010098changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010099{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010100 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010101}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010102
Denis Vlasenko131ae172007-02-18 13:00:19 +000010103#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010104
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010105
10106/* ============ ??? */
10107
Eric Andersencb57d552001-06-28 07:25:16 +000010108/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010109 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010110 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010111static void
10112setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010113{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010114 char **newparam;
10115 char **ap;
10116 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010117
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010118 for (nparam = 0; argv[nparam]; nparam++)
10119 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010120 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10121 while (*argv) {
10122 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010123 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010124 *ap = NULL;
10125 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010126 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010127 shellparam.nparam = nparam;
10128 shellparam.p = newparam;
10129#if ENABLE_ASH_GETOPTS
10130 shellparam.optind = 1;
10131 shellparam.optoff = -1;
10132#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010133}
10134
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010135/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010136 * Process shell options. The global variable argptr contains a pointer
10137 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010138 *
10139 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10140 * For a non-interactive shell, an error condition encountered
10141 * by a special built-in ... shall cause the shell to write a diagnostic message
10142 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010143 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010144 * ...
10145 * Utility syntax error (option or operand error) Shall exit
10146 * ...
10147 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10148 * we see that bash does not do that (set "finishes" with error code 1 instead,
10149 * and shell continues), and people rely on this behavior!
10150 * Testcase:
10151 * set -o barfoo 2>/dev/null
10152 * echo $?
10153 *
10154 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010155 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010156static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010157plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010158{
10159 int i;
10160
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010161 if (name) {
10162 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010163 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010164 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010165 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010166 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010167 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010168 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010169 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010170 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010171 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010172 if (val) {
10173 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10174 } else {
10175 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10176 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010177 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010178 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010179}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010180static void
10181setoption(int flag, int val)
10182{
10183 int i;
10184
10185 for (i = 0; i < NOPTS; i++) {
10186 if (optletters(i) == flag) {
10187 optlist[i] = val;
10188 return;
10189 }
10190 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010191 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010192 /* NOTREACHED */
10193}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010194static int
Eric Andersenc470f442003-07-28 09:56:35 +000010195options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +000010196{
10197 char *p;
10198 int val;
10199 int c;
10200
10201 if (cmdline)
10202 minusc = NULL;
10203 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010204 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010205 if (c != '-' && c != '+')
10206 break;
10207 argptr++;
10208 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010209 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010210 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010211 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010212 if (!cmdline) {
10213 /* "-" means turn off -x and -v */
10214 if (p[0] == '\0')
10215 xflag = vflag = 0;
10216 /* "--" means reset params */
10217 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010218 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010219 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010220 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010221 }
Eric Andersencb57d552001-06-28 07:25:16 +000010222 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010223 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010224 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010225 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010226 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010227 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010228 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010229 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010230 /* it already printed err message */
10231 return 1; /* error */
10232 }
Eric Andersencb57d552001-06-28 07:25:16 +000010233 if (*argptr)
10234 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010235 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10236 isloginsh = 1;
10237 /* bash does not accept +-login, we also won't */
10238 } else if (cmdline && val && (c == '-')) { /* long options */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010239 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +000010240 isloginsh = 1;
10241 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010242 } else {
10243 setoption(c, val);
10244 }
10245 }
10246 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010247 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010248}
10249
Eric Andersencb57d552001-06-28 07:25:16 +000010250/*
Eric Andersencb57d552001-06-28 07:25:16 +000010251 * The shift builtin command.
10252 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010253static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010254shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010255{
10256 int n;
10257 char **ap1, **ap2;
10258
10259 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010260 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010261 n = number(argv[1]);
10262 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010263 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010264 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010265 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010266 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010267 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010268 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010269 }
10270 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010271 while ((*ap2++ = *ap1++) != NULL)
10272 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010273#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010274 shellparam.optind = 1;
10275 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010276#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010277 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010278 return 0;
10279}
10280
Eric Andersencb57d552001-06-28 07:25:16 +000010281/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010282 * POSIX requires that 'set' (but not export or readonly) output the
10283 * variables in lexicographic order - by the locale's collating order (sigh).
10284 * Maybe we could keep them in an ordered balanced binary tree
10285 * instead of hashed lists.
10286 * For now just roll 'em through qsort for printing...
10287 */
10288static int
10289showvars(const char *sep_prefix, int on, int off)
10290{
10291 const char *sep;
10292 char **ep, **epend;
10293
10294 ep = listvars(on, off, &epend);
10295 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10296
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010297 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010298
10299 for (; ep < epend; ep++) {
10300 const char *p;
10301 const char *q;
10302
10303 p = strchrnul(*ep, '=');
10304 q = nullstr;
10305 if (*p)
10306 q = single_quote(++p);
10307 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10308 }
10309 return 0;
10310}
10311
10312/*
Eric Andersencb57d552001-06-28 07:25:16 +000010313 * The set command builtin.
10314 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010315static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010316setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010317{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010318 int retval;
10319
Denis Vlasenko68404f12008-03-17 09:00:54 +000010320 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010321 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010322
Denis Vlasenkob012b102007-02-19 22:43:01 +000010323 INT_OFF;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010324 retval = options(/*cmdline:*/ 0);
10325 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010326 optschanged();
10327 if (*argptr != NULL) {
10328 setparam(argptr);
10329 }
Eric Andersencb57d552001-06-28 07:25:16 +000010330 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010331 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010332 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010333}
10334
Denis Vlasenko131ae172007-02-18 13:00:19 +000010335#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010336static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010337change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010338{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010339 uint32_t t;
10340
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010341 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010342 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010343 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010344 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010345 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010346 vrandom.flags &= ~VNOFUNC;
10347 } else {
10348 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010349 t = strtoul(value, NULL, 10);
10350 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010351 }
Eric Andersenef02f822004-03-11 13:34:24 +000010352}
Eric Andersen16767e22004-03-16 05:14:10 +000010353#endif
10354
Denis Vlasenko131ae172007-02-18 13:00:19 +000010355#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010356static int
Eric Andersenc470f442003-07-28 09:56:35 +000010357getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +000010358{
10359 char *p, *q;
10360 char c = '?';
10361 int done = 0;
10362 int err = 0;
Eric Andersena48b0a32003-10-22 10:56:47 +000010363 char s[12];
10364 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +000010365
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010366 if (*param_optind < 1)
Eric Andersena48b0a32003-10-22 10:56:47 +000010367 return 1;
10368 optnext = optfirst + *param_optind - 1;
10369
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010370 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +000010371 p = NULL;
10372 else
Eric Andersena48b0a32003-10-22 10:56:47 +000010373 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010374 if (p == NULL || *p == '\0') {
10375 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010376 p = *optnext;
10377 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010378 atend:
Eric Andersencb57d552001-06-28 07:25:16 +000010379 p = NULL;
10380 done = 1;
10381 goto out;
10382 }
10383 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010384 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010385 goto atend;
10386 }
10387
10388 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010389 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010390 if (*q == '\0') {
10391 if (optstr[0] == ':') {
10392 s[0] = c;
10393 s[1] = '\0';
10394 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010395 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010396 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010397 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010398 }
10399 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010400 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010401 }
10402 if (*++q == ':')
10403 q++;
10404 }
10405
10406 if (*++q == ':') {
10407 if (*p == '\0' && (p = *optnext) == NULL) {
10408 if (optstr[0] == ':') {
10409 s[0] = c;
10410 s[1] = '\0';
10411 err |= setvarsafe("OPTARG", s, 0);
10412 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010413 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010414 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010415 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010416 c = '?';
10417 }
Eric Andersenc470f442003-07-28 09:56:35 +000010418 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010419 }
10420
10421 if (p == *optnext)
10422 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +000010423 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010424 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010425 } else
Eric Andersenc470f442003-07-28 09:56:35 +000010426 err |= setvarsafe("OPTARG", nullstr, 0);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010427 out:
Eric Andersencb57d552001-06-28 07:25:16 +000010428 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010429 *param_optind = optnext - optfirst + 1;
10430 fmtstr(s, sizeof(s), "%d", *param_optind);
Eric Andersencb57d552001-06-28 07:25:16 +000010431 err |= setvarsafe("OPTIND", s, VNOFUNC);
10432 s[0] = c;
10433 s[1] = '\0';
10434 err |= setvarsafe(optvar, s, 0);
10435 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +000010436 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010437 *optoff = -1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010438 flush_stdout_stderr();
10439 raise_exception(EXERROR);
Eric Andersencb57d552001-06-28 07:25:16 +000010440 }
10441 return done;
10442}
Eric Andersenc470f442003-07-28 09:56:35 +000010443
10444/*
10445 * The getopts builtin. Shellparam.optnext points to the next argument
10446 * to be processed. Shellparam.optptr points to the next character to
10447 * be processed in the current argument. If shellparam.optnext is NULL,
10448 * then it's the first time getopts has been called.
10449 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010450static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000010451getoptscmd(int argc, char **argv)
10452{
10453 char **optbase;
10454
10455 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010456 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010457 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000010458 optbase = shellparam.p;
10459 if (shellparam.optind > shellparam.nparam + 1) {
10460 shellparam.optind = 1;
10461 shellparam.optoff = -1;
10462 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010463 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010464 optbase = &argv[3];
10465 if (shellparam.optind > argc - 2) {
10466 shellparam.optind = 1;
10467 shellparam.optoff = -1;
10468 }
10469 }
10470
10471 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010472 &shellparam.optoff);
Eric Andersenc470f442003-07-28 09:56:35 +000010473}
Denis Vlasenko131ae172007-02-18 13:00:19 +000010474#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000010475
Eric Andersencb57d552001-06-28 07:25:16 +000010476
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010477/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000010478
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010479struct heredoc {
10480 struct heredoc *next; /* next here document in list */
10481 union node *here; /* redirection node */
10482 char *eofmark; /* string indicating end of input */
10483 smallint striptabs; /* if set, strip leading tabs */
10484};
10485
10486static smallint tokpushback; /* last token pushed back */
10487static smallint parsebackquote; /* nonzero if we are inside backquotes */
10488static smallint quoteflag; /* set if (part of) last token was quoted */
10489static token_id_t lasttoken; /* last token read (integer id Txxx) */
10490static struct heredoc *heredoclist; /* list of here documents to read */
10491static char *wordtext; /* text of last word returned by readtoken */
10492static struct nodelist *backquotelist;
10493static union node *redirnode;
10494static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010495
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010496static const char *
10497tokname(char *buf, int tok)
10498{
10499 if (tok < TSEMI)
10500 return tokname_array[tok] + 1;
10501 sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
10502 return buf;
10503}
10504
10505/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010506 * Called when an unexpected token is read during the parse. The argument
10507 * is the token that is expected, or -1 if more than one type of token can
10508 * occur at this point.
10509 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010510static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010511static void
10512raise_error_unexpected_syntax(int token)
10513{
10514 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010515 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010516 int l;
10517
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010518 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010519 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010520 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010521 raise_error_syntax(msg);
10522 /* NOTREACHED */
10523}
Eric Andersencb57d552001-06-28 07:25:16 +000010524
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010525#define EOFMARKLEN 79
Eric Andersencb57d552001-06-28 07:25:16 +000010526
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010527/* parsing is heavily cross-recursive, need these forward decls */
10528static union node *andor(void);
10529static union node *pipeline(void);
10530static union node *parse_command(void);
10531static void parseheredoc(void);
10532static char peektoken(void);
10533static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000010534
Eric Andersenc470f442003-07-28 09:56:35 +000010535static union node *
10536list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000010537{
10538 union node *n1, *n2, *n3;
10539 int tok;
10540
Eric Andersenc470f442003-07-28 09:56:35 +000010541 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10542 if (nlflag == 2 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +000010543 return NULL;
10544 n1 = NULL;
10545 for (;;) {
10546 n2 = andor();
10547 tok = readtoken();
10548 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000010549 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010550 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010551 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010552 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010553 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000010554 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010555 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010556 n2 = n3;
10557 }
10558 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000010559 }
10560 }
10561 if (n1 == NULL) {
10562 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010563 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010564 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010565 n3->type = NSEMI;
10566 n3->nbinary.ch1 = n1;
10567 n3->nbinary.ch2 = n2;
10568 n1 = n3;
10569 }
10570 switch (tok) {
10571 case TBACKGND:
10572 case TSEMI:
10573 tok = readtoken();
10574 /* fall through */
10575 case TNL:
10576 if (tok == TNL) {
10577 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +000010578 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +000010579 return n1;
10580 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010581 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010582 }
Eric Andersenc470f442003-07-28 09:56:35 +000010583 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010584 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +000010585 return n1;
10586 break;
10587 case TEOF:
10588 if (heredoclist)
10589 parseheredoc();
10590 else
Eric Andersenc470f442003-07-28 09:56:35 +000010591 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +000010592 return n1;
10593 default:
Eric Andersenc470f442003-07-28 09:56:35 +000010594 if (nlflag == 1)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010595 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010596 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010597 return n1;
10598 }
10599 }
10600}
10601
Eric Andersenc470f442003-07-28 09:56:35 +000010602static union node *
10603andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010604{
Eric Andersencb57d552001-06-28 07:25:16 +000010605 union node *n1, *n2, *n3;
10606 int t;
10607
Eric Andersencb57d552001-06-28 07:25:16 +000010608 n1 = pipeline();
10609 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010610 t = readtoken();
10611 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000010612 t = NAND;
10613 } else if (t == TOR) {
10614 t = NOR;
10615 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010616 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010617 return n1;
10618 }
Eric Andersenc470f442003-07-28 09:56:35 +000010619 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010620 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010621 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010622 n3->type = t;
10623 n3->nbinary.ch1 = n1;
10624 n3->nbinary.ch2 = n2;
10625 n1 = n3;
10626 }
10627}
10628
Eric Andersenc470f442003-07-28 09:56:35 +000010629static union node *
10630pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010631{
Eric Andersencb57d552001-06-28 07:25:16 +000010632 union node *n1, *n2, *pipenode;
10633 struct nodelist *lp, *prev;
10634 int negate;
10635
10636 negate = 0;
10637 TRACE(("pipeline: entered\n"));
10638 if (readtoken() == TNOT) {
10639 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000010640 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010641 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010642 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010643 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010644 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010645 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000010646 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010647 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010648 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000010649 pipenode->npipe.cmdlist = lp;
10650 lp->n = n1;
10651 do {
10652 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010653 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000010654 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010655 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010656 prev->next = lp;
10657 } while (readtoken() == TPIPE);
10658 lp->next = NULL;
10659 n1 = pipenode;
10660 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010661 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010662 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010663 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000010664 n2->type = NNOT;
10665 n2->nnot.com = n1;
10666 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010667 }
10668 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000010669}
10670
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010671static union node *
10672makename(void)
10673{
10674 union node *n;
10675
Denis Vlasenko597906c2008-02-20 16:38:54 +000010676 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010677 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010678 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010679 n->narg.text = wordtext;
10680 n->narg.backquote = backquotelist;
10681 return n;
10682}
10683
10684static void
10685fixredir(union node *n, const char *text, int err)
10686{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010687 int fd;
10688
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010689 TRACE(("Fix redir %s %d\n", text, err));
10690 if (!err)
10691 n->ndup.vname = NULL;
10692
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010693 fd = bb_strtou(text, NULL, 10);
10694 if (!errno && fd >= 0)
10695 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010696 else if (LONE_DASH(text))
10697 n->ndup.dupfd = -1;
10698 else {
10699 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010700 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010701 n->ndup.vname = makename();
10702 }
10703}
10704
10705/*
10706 * Returns true if the text contains nothing to expand (no dollar signs
10707 * or backquotes).
10708 */
10709static int
Denis Vlasenko68819d12008-12-15 11:26:36 +000010710noexpand(const char *text)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010711{
Denys Vlasenkocd716832009-11-28 22:14:02 +010010712 unsigned char c;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010713
Denys Vlasenkocd716832009-11-28 22:14:02 +010010714 while ((c = *text++) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010715 if (c == CTLQUOTEMARK)
10716 continue;
10717 if (c == CTLESC)
Denys Vlasenkocd716832009-11-28 22:14:02 +010010718 text++;
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010010719 else if (SIT(c, BASESYNTAX) == CCTL)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010720 return 0;
10721 }
10722 return 1;
10723}
10724
10725static void
10726parsefname(void)
10727{
10728 union node *n = redirnode;
10729
10730 if (readtoken() != TWORD)
10731 raise_error_unexpected_syntax(-1);
10732 if (n->type == NHERE) {
10733 struct heredoc *here = heredoc;
10734 struct heredoc *p;
10735 int i;
10736
10737 if (quoteflag == 0)
10738 n->type = NXHERE;
10739 TRACE(("Here document %d\n", n->type));
10740 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010741 raise_error_syntax("illegal eof marker for << redirection");
Denys Vlasenkob6c84342009-08-29 20:23:20 +020010742 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010743 here->eofmark = wordtext;
10744 here->next = NULL;
10745 if (heredoclist == NULL)
10746 heredoclist = here;
10747 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010748 for (p = heredoclist; p->next; p = p->next)
10749 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010750 p->next = here;
10751 }
10752 } else if (n->type == NTOFD || n->type == NFROMFD) {
10753 fixredir(n, wordtext, 0);
10754 } else {
10755 n->nfile.fname = makename();
10756 }
10757}
Eric Andersencb57d552001-06-28 07:25:16 +000010758
Eric Andersenc470f442003-07-28 09:56:35 +000010759static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010760simplecmd(void)
10761{
10762 union node *args, **app;
10763 union node *n = NULL;
10764 union node *vars, **vpp;
10765 union node **rpp, *redir;
10766 int savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010767#if ENABLE_ASH_BASH_COMPAT
10768 smallint double_brackets_flag = 0;
10769#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010770
10771 args = NULL;
10772 app = &args;
10773 vars = NULL;
10774 vpp = &vars;
10775 redir = NULL;
10776 rpp = &redir;
10777
10778 savecheckkwd = CHKALIAS;
10779 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000010780 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010781 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010782 t = readtoken();
10783 switch (t) {
10784#if ENABLE_ASH_BASH_COMPAT
10785 case TAND: /* "&&" */
10786 case TOR: /* "||" */
10787 if (!double_brackets_flag) {
10788 tokpushback = 1;
10789 goto out;
10790 }
10791 wordtext = (char *) (t == TAND ? "-a" : "-o");
10792#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010793 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000010794 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010795 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010796 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010797 n->narg.text = wordtext;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010798#if ENABLE_ASH_BASH_COMPAT
10799 if (strcmp("[[", wordtext) == 0)
10800 double_brackets_flag = 1;
10801 else if (strcmp("]]", wordtext) == 0)
10802 double_brackets_flag = 0;
10803#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010804 n->narg.backquote = backquotelist;
10805 if (savecheckkwd && isassignment(wordtext)) {
10806 *vpp = n;
10807 vpp = &n->narg.next;
10808 } else {
10809 *app = n;
10810 app = &n->narg.next;
10811 savecheckkwd = 0;
10812 }
10813 break;
10814 case TREDIR:
10815 *rpp = n = redirnode;
10816 rpp = &n->nfile.next;
10817 parsefname(); /* read name of redirection file */
10818 break;
10819 case TLP:
10820 if (args && app == &args->narg.next
10821 && !vars && !redir
10822 ) {
10823 struct builtincmd *bcmd;
10824 const char *name;
10825
10826 /* We have a function */
10827 if (readtoken() != TRP)
10828 raise_error_unexpected_syntax(TRP);
10829 name = n->narg.text;
10830 if (!goodname(name)
10831 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10832 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000010833 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010834 }
10835 n->type = NDEFUN;
10836 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10837 n->narg.next = parse_command();
10838 return n;
10839 }
10840 /* fall through */
10841 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010842 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010843 goto out;
10844 }
10845 }
10846 out:
10847 *app = NULL;
10848 *vpp = NULL;
10849 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010850 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010851 n->type = NCMD;
10852 n->ncmd.args = args;
10853 n->ncmd.assign = vars;
10854 n->ncmd.redirect = redir;
10855 return n;
10856}
10857
10858static union node *
10859parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010860{
Eric Andersencb57d552001-06-28 07:25:16 +000010861 union node *n1, *n2;
10862 union node *ap, **app;
10863 union node *cp, **cpp;
10864 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000010865 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000010866 int t;
10867
10868 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000010869 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000010870
Eric Andersencb57d552001-06-28 07:25:16 +000010871 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000010872 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010873 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000010874 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000010875 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010876 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000010877 n1->type = NIF;
10878 n1->nif.test = list(0);
10879 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010880 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000010881 n1->nif.ifpart = list(0);
10882 n2 = n1;
10883 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010884 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000010885 n2 = n2->nif.elsepart;
10886 n2->type = NIF;
10887 n2->nif.test = list(0);
10888 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010889 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000010890 n2->nif.ifpart = list(0);
10891 }
10892 if (lasttoken == TELSE)
10893 n2->nif.elsepart = list(0);
10894 else {
10895 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010896 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010897 }
Eric Andersenc470f442003-07-28 09:56:35 +000010898 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000010899 break;
10900 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010901 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000010902 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010903 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010904 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000010905 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010906 got = readtoken();
10907 if (got != TDO) {
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010908 TRACE(("expecting DO got '%s' %s\n", tokname_array[got] + 1,
Denis Vlasenko131ae172007-02-18 13:00:19 +000010909 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010910 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000010911 }
10912 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000010913 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000010914 break;
10915 }
10916 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010917 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000010918 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010919 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000010920 n1->type = NFOR;
10921 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +000010922 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010923 if (readtoken() == TIN) {
10924 app = &ap;
10925 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010926 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000010927 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010928 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000010929 n2->narg.text = wordtext;
10930 n2->narg.backquote = backquotelist;
10931 *app = n2;
10932 app = &n2->narg.next;
10933 }
10934 *app = NULL;
10935 n1->nfor.args = ap;
10936 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010937 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000010938 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010939 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000010940 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010941 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010942 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010943 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000010944 n1->nfor.args = n2;
10945 /*
10946 * Newline or semicolon here is optional (but note
10947 * that the original Bourne shell only allowed NL).
10948 */
10949 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010950 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010951 }
Eric Andersenc470f442003-07-28 09:56:35 +000010952 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010953 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010954 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000010955 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000010956 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000010957 break;
10958 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010959 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000010960 n1->type = NCASE;
10961 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010962 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000010963 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000010964 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010965 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000010966 n2->narg.text = wordtext;
10967 n2->narg.backquote = backquotelist;
Eric Andersencb57d552001-06-28 07:25:16 +000010968 do {
Eric Andersenc470f442003-07-28 09:56:35 +000010969 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010970 } while (readtoken() == TNL);
10971 if (lasttoken != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010972 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000010973 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010974 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000010975 checkkwd = CHKNL | CHKKWD;
10976 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010977 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000010978 if (lasttoken == TLP)
10979 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010980 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000010981 cp->type = NCLIST;
10982 app = &cp->nclist.pattern;
10983 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010984 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000010985 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010986 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000010987 ap->narg.text = wordtext;
10988 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000010989 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000010990 break;
10991 app = &ap->narg.next;
10992 readtoken();
10993 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000010994 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000010995 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010996 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000010997 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010998
Eric Andersenc470f442003-07-28 09:56:35 +000010999 cpp = &cp->nclist.next;
11000
11001 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011002 t = readtoken();
11003 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011004 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011005 raise_error_unexpected_syntax(TENDCASE);
11006 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011007 }
Eric Andersenc470f442003-07-28 09:56:35 +000011008 }
Eric Andersencb57d552001-06-28 07:25:16 +000011009 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011010 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011011 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011012 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011013 n1->type = NSUBSHELL;
11014 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011015 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011016 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011017 break;
11018 case TBEGIN:
11019 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011020 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011021 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011022 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011023 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011024 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011025 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011026 }
11027
Eric Andersenc470f442003-07-28 09:56:35 +000011028 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011029 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011030
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011031 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011032 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011033 checkkwd = CHKKWD | CHKALIAS;
11034 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011035 while (readtoken() == TREDIR) {
11036 *rpp = n2 = redirnode;
11037 rpp = &n2->nfile.next;
11038 parsefname();
11039 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011040 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011041 *rpp = NULL;
11042 if (redir) {
11043 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011044 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011045 n2->type = NREDIR;
11046 n2->nredir.n = n1;
11047 n1 = n2;
11048 }
11049 n1->nredir.redirect = redir;
11050 }
Eric Andersencb57d552001-06-28 07:25:16 +000011051 return n1;
11052}
11053
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011054#if ENABLE_ASH_BASH_COMPAT
11055static int decode_dollar_squote(void)
11056{
11057 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11058 int c, cnt;
11059 char *p;
11060 char buf[4];
11061
11062 c = pgetc();
11063 p = strchr(C_escapes, c);
11064 if (p) {
11065 buf[0] = c;
11066 p = buf;
11067 cnt = 3;
11068 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11069 do {
11070 c = pgetc();
11071 *++p = c;
11072 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11073 pungetc();
11074 } else if (c == 'x') { /* \xHH */
11075 do {
11076 c = pgetc();
11077 *++p = c;
11078 } while (isxdigit(c) && --cnt);
11079 pungetc();
11080 if (cnt == 3) { /* \x but next char is "bad" */
11081 c = 'x';
11082 goto unrecognized;
11083 }
11084 } else { /* simple seq like \\ or \t */
11085 p++;
11086 }
11087 *p = '\0';
11088 p = buf;
11089 c = bb_process_escape_sequence((void*)&p);
11090 } else { /* unrecognized "\z": print both chars unless ' or " */
11091 if (c != '\'' && c != '"') {
11092 unrecognized:
11093 c |= 0x100; /* "please encode \, then me" */
11094 }
11095 }
11096 return c;
11097}
11098#endif
11099
Eric Andersencb57d552001-06-28 07:25:16 +000011100/*
11101 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11102 * is not NULL, read a here document. In the latter case, eofmark is the
11103 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011104 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011105 * is the first character of the input token or document.
11106 *
11107 * Because C does not have internal subroutines, I have simulated them
11108 * using goto's to implement the subroutine linkage. The following macros
11109 * will run code that appears at the end of readtoken1.
11110 */
Eric Andersen2870d962001-07-02 17:27:21 +000011111#define CHECKEND() {goto checkend; checkend_return:;}
11112#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11113#define PARSESUB() {goto parsesub; parsesub_return:;}
11114#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11115#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11116#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011117static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011118readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011119{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011120 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011121 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011122 char *out;
11123 int len;
11124 char line[EOFMARKLEN + 1];
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011125 struct nodelist *bqlist;
11126 smallint quotef;
11127 smallint dblquote;
11128 smallint oldstyle;
11129 smallint prevsyntax; /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011130#if ENABLE_ASH_EXPAND_PRMT
11131 smallint pssyntax; /* we are expanding a prompt string */
11132#endif
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011133 int varnest; /* levels of variables expansion */
11134 int arinest; /* levels of arithmetic expansion */
11135 int parenlevel; /* levels of parens in arithmetic */
11136 int dqvarnest; /* levels of variables expansion within double quotes */
11137
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011138 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011139
Eric Andersencb57d552001-06-28 07:25:16 +000011140#if __GNUC__
11141 /* Avoid longjmp clobbering */
11142 (void) &out;
11143 (void) &quotef;
11144 (void) &dblquote;
11145 (void) &varnest;
11146 (void) &arinest;
11147 (void) &parenlevel;
11148 (void) &dqvarnest;
11149 (void) &oldstyle;
11150 (void) &prevsyntax;
11151 (void) &syntax;
11152#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011153 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011154 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011155 quotef = 0;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011156 prevsyntax = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000011157#if ENABLE_ASH_EXPAND_PRMT
11158 pssyntax = (syntax == PSSYNTAX);
11159 if (pssyntax)
11160 syntax = DQSYNTAX;
11161#endif
11162 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011163 varnest = 0;
11164 arinest = 0;
11165 parenlevel = 0;
11166 dqvarnest = 0;
11167
11168 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011169 loop:
11170 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011171 CHECKEND(); /* set c to PEOF if at end of here document */
11172 for (;;) { /* until end of line or end of word */
11173 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11174 switch (SIT(c, syntax)) {
11175 case CNL: /* '\n' */
11176 if (syntax == BASESYNTAX)
11177 goto endword; /* exit outer loop */
11178 USTPUTC(c, out);
11179 g_parsefile->linno++;
11180 setprompt_if(doprompt, 2);
11181 c = pgetc();
11182 goto loop; /* continue outer loop */
11183 case CWORD:
11184 USTPUTC(c, out);
11185 break;
11186 case CCTL:
11187 if (eofmark == NULL || dblquote)
11188 USTPUTC(CTLESC, out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011189#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011190 if (c == '\\' && bash_dollar_squote) {
11191 c = decode_dollar_squote();
11192 if (c & 0x100) {
11193 USTPUTC('\\', out);
11194 c = (unsigned char)c;
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011195 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011196 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011197#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011198 USTPUTC(c, out);
11199 break;
11200 case CBACK: /* backslash */
11201 c = pgetc_without_PEOA();
11202 if (c == PEOF) {
11203 USTPUTC(CTLESC, out);
11204 USTPUTC('\\', out);
11205 pungetc();
11206 } else if (c == '\n') {
11207 setprompt_if(doprompt, 2);
11208 } else {
11209#if ENABLE_ASH_EXPAND_PRMT
11210 if (c == '$' && pssyntax) {
Eric Andersenc470f442003-07-28 09:56:35 +000011211 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011212 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011213 }
Denis Vlasenko46a53062007-09-24 18:30:02 +000011214#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011215 /* Backslash is retained if we are in "str" and next char isn't special */
11216 if (dblquote
11217 && c != '\\'
11218 && c != '`'
11219 && c != '$'
11220 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011221 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011222 USTPUTC(CTLESC, out);
11223 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011224 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011225 if (SIT(c, SQSYNTAX) == CCTL)
11226 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011227 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011228 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011229 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011230 break;
11231 case CSQUOTE:
11232 syntax = SQSYNTAX;
11233 quotemark:
11234 if (eofmark == NULL) {
11235 USTPUTC(CTLQUOTEMARK, out);
11236 }
11237 break;
11238 case CDQUOTE:
11239 syntax = DQSYNTAX;
11240 dblquote = 1;
11241 goto quotemark;
11242 case CENDQUOTE:
11243 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
11244 if (eofmark != NULL && arinest == 0
11245 && varnest == 0
11246 ) {
11247 USTPUTC(c, out);
11248 } else {
11249 if (dqvarnest == 0) {
11250 syntax = BASESYNTAX;
11251 dblquote = 0;
11252 }
11253 quotef = 1;
11254 goto quotemark;
11255 }
11256 break;
11257 case CVAR: /* '$' */
11258 PARSESUB(); /* parse substitution */
11259 break;
11260 case CENDVAR: /* '}' */
11261 if (varnest > 0) {
11262 varnest--;
11263 if (dqvarnest > 0) {
11264 dqvarnest--;
11265 }
11266 c = CTLENDVAR;
11267 }
11268 USTPUTC(c, out);
11269 break;
11270#if ENABLE_SH_MATH_SUPPORT
11271 case CLP: /* '(' in arithmetic */
11272 parenlevel++;
11273 USTPUTC(c, out);
11274 break;
11275 case CRP: /* ')' in arithmetic */
11276 if (parenlevel > 0) {
11277 parenlevel--;
11278 } else {
11279 if (pgetc() == ')') {
11280 if (--arinest == 0) {
11281 syntax = prevsyntax;
11282 dblquote = (syntax == DQSYNTAX);
11283 c = CTLENDARI;
11284 }
11285 } else {
11286 /*
11287 * unbalanced parens
11288 * (don't 2nd guess - no error)
11289 */
11290 pungetc();
11291 }
11292 }
11293 USTPUTC(c, out);
11294 break;
11295#endif
11296 case CBQUOTE: /* '`' */
11297 PARSEBACKQOLD();
11298 break;
11299 case CENDFILE:
11300 goto endword; /* exit outer loop */
11301 case CIGN:
11302 break;
11303 default:
11304 if (varnest == 0) {
11305#if ENABLE_ASH_BASH_COMPAT
11306 if (c == '&') {
11307 if (pgetc() == '>')
11308 c = 0x100 + '>'; /* flag &> */
11309 pungetc();
11310 }
11311#endif
11312 goto endword; /* exit outer loop */
11313 }
11314 IF_ASH_ALIAS(if (c != PEOA))
11315 USTPUTC(c, out);
11316 }
11317 c = pgetc_fast();
11318 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011319 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011320
Mike Frysinger98c52642009-04-02 10:02:37 +000011321#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011322 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011323 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011324#endif
Denis Vlasenko99eb8502007-02-23 21:09:49 +000011325 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011326 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011327 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011328 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011329 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011330 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011331 }
11332 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011333 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011334 out = stackblock();
11335 if (eofmark == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011336 if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011337 && quotef == 0
11338 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011339 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011340 PARSEREDIR(); /* passed as params: out, c */
11341 lasttoken = TREDIR;
11342 return lasttoken;
11343 }
11344 /* else: non-number X seen, interpret it
11345 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011346 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011347 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011348 }
11349 quoteflag = quotef;
11350 backquotelist = bqlist;
11351 grabstackblock(len);
11352 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011353 lasttoken = TWORD;
11354 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011355/* end of readtoken routine */
11356
Eric Andersencb57d552001-06-28 07:25:16 +000011357/*
11358 * Check to see whether we are at the end of the here document. When this
11359 * is called, c is set to the first character of the next input line. If
11360 * we are at the end of the here document, this routine sets the c to PEOF.
11361 */
Eric Andersenc470f442003-07-28 09:56:35 +000011362checkend: {
11363 if (eofmark) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000011364#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011365 if (c == PEOA)
11366 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011367#endif
11368 if (striptabs) {
11369 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011370 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011371 }
Eric Andersenc470f442003-07-28 09:56:35 +000011372 }
11373 if (c == *eofmark) {
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011374 if (pfgets(line, sizeof(line)) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000011375 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000011376
Eric Andersenc470f442003-07-28 09:56:35 +000011377 p = line;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011378 for (q = eofmark + 1; *q && *p == *q; p++, q++)
11379 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000011380 if (*p == '\n' && *q == '\0') {
11381 c = PEOF;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011382 g_parsefile->linno++;
Eric Andersenc470f442003-07-28 09:56:35 +000011383 needprompt = doprompt;
11384 } else {
11385 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011386 }
11387 }
11388 }
11389 }
Eric Andersenc470f442003-07-28 09:56:35 +000011390 goto checkend_return;
11391}
Eric Andersencb57d552001-06-28 07:25:16 +000011392
Eric Andersencb57d552001-06-28 07:25:16 +000011393/*
11394 * Parse a redirection operator. The variable "out" points to a string
11395 * specifying the fd to be redirected. The variable "c" contains the
11396 * first character of the redirection operator.
11397 */
Eric Andersenc470f442003-07-28 09:56:35 +000011398parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011399 /* out is already checked to be a valid number or "" */
11400 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000011401 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000011402
Denis Vlasenko597906c2008-02-20 16:38:54 +000011403 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000011404 if (c == '>') {
11405 np->nfile.fd = 1;
11406 c = pgetc();
11407 if (c == '>')
11408 np->type = NAPPEND;
11409 else if (c == '|')
11410 np->type = NCLOBBER;
11411 else if (c == '&')
11412 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011413 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000011414 else {
11415 np->type = NTO;
11416 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011417 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000011418 }
11419#if ENABLE_ASH_BASH_COMPAT
11420 else if (c == 0x100 + '>') { /* this flags &> redirection */
11421 np->nfile.fd = 1;
11422 pgetc(); /* this is '>', no need to check */
11423 np->type = NTO2;
11424 }
11425#endif
11426 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000011427 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011428 c = pgetc();
11429 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000011430 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011431 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011432 np = stzalloc(sizeof(struct nhere));
11433 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011434 }
11435 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011436 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000011437 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011438 c = pgetc();
11439 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000011440 heredoc->striptabs = 1;
11441 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011442 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011443 pungetc();
11444 }
11445 break;
11446
11447 case '&':
11448 np->type = NFROMFD;
11449 break;
11450
11451 case '>':
11452 np->type = NFROMTO;
11453 break;
11454
11455 default:
11456 np->type = NFROM;
11457 pungetc();
11458 break;
11459 }
Eric Andersencb57d552001-06-28 07:25:16 +000011460 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011461 if (fd >= 0)
11462 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011463 redirnode = np;
11464 goto parseredir_return;
11465}
Eric Andersencb57d552001-06-28 07:25:16 +000011466
Eric Andersencb57d552001-06-28 07:25:16 +000011467/*
11468 * Parse a substitution. At this point, we have read the dollar sign
11469 * and nothing else.
11470 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000011471
11472/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11473 * (assuming ascii char codes, as the original implementation did) */
11474#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011475 (((unsigned)(c) - 33 < 32) \
11476 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000011477parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010011478 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011479 int typeloc;
11480 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +000011481
Eric Andersenc470f442003-07-28 09:56:35 +000011482 c = pgetc();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011483 if (c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011484 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000011485 ) {
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011486#if ENABLE_ASH_BASH_COMPAT
11487 if (c == '\'')
11488 bash_dollar_squote = 1;
11489 else
11490#endif
11491 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011492 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011493 } else if (c == '(') {
11494 /* $(command) or $((arith)) */
Eric Andersenc470f442003-07-28 09:56:35 +000011495 if (pgetc() == '(') {
Mike Frysinger98c52642009-04-02 10:02:37 +000011496#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000011497 PARSEARITH();
11498#else
Mike Frysinger98a6f562008-06-09 09:38:45 +000011499 raise_error_syntax("you disabled math support for $((arith)) syntax");
Eric Andersenc470f442003-07-28 09:56:35 +000011500#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011501 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011502 pungetc();
11503 PARSEBACKQNEW();
11504 }
11505 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011506 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000011507 USTPUTC(CTLVAR, out);
11508 typeloc = out - (char *)stackblock();
11509 USTPUTC(VSNORMAL, out);
11510 subtype = VSNORMAL;
11511 if (c == '{') {
11512 c = pgetc();
11513 if (c == '#') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011514 c = pgetc();
11515 if (c == '}')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011516 c = '#'; /* ${#} - same as $# */
Eric Andersenc470f442003-07-28 09:56:35 +000011517 else
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011518 subtype = VSLENGTH; /* ${#VAR} */
11519 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011520 subtype = 0;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011521 }
Eric Andersenc470f442003-07-28 09:56:35 +000011522 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011523 if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011524 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011525 do {
11526 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011527 c = pgetc();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011528 } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011529 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011530 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011531 do {
11532 STPUTC(c, out);
11533 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011534 } while (isdigit(c));
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011535 } else if (is_special(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011536 /* $[{[#]]<specialchar>[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011537 USTPUTC(c, out);
11538 c = pgetc();
Denis Vlasenko559691a2008-10-05 18:39:31 +000011539 } else {
11540 badsub:
11541 raise_error_syntax("bad substitution");
11542 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011543 if (c != '}' && subtype == VSLENGTH) {
11544 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020011545 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011546 }
Eric Andersencb57d552001-06-28 07:25:16 +000011547
Eric Andersenc470f442003-07-28 09:56:35 +000011548 STPUTC('=', out);
11549 flags = 0;
11550 if (subtype == 0) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011551 /* ${VAR...} but not $VAR or ${#VAR} */
11552 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000011553 switch (c) {
11554 case ':':
Eric Andersenc470f442003-07-28 09:56:35 +000011555 c = pgetc();
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011556#if ENABLE_ASH_BASH_COMPAT
11557 if (c == ':' || c == '$' || isdigit(c)) {
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011558//TODO: support more general format ${v:EXPR:EXPR},
11559// where EXPR follows $(()) rules
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011560 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011561 pungetc();
11562 break; /* "goto do_pungetc" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011563 }
11564#endif
11565 flags = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000011566 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011567 default: {
11568 static const char types[] ALIGN1 = "}-+?=";
11569 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000011570 if (p == NULL)
11571 goto badsub;
11572 subtype = p - types + VSNORMAL;
11573 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011574 }
Eric Andersenc470f442003-07-28 09:56:35 +000011575 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011576 case '#': {
11577 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011578 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011579 c = pgetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011580 if (c != cc)
11581 goto do_pungetc;
11582 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011583 break;
11584 }
11585#if ENABLE_ASH_BASH_COMPAT
11586 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011587 /* ${v/[/]pattern/repl} */
11588//TODO: encode pattern and repl separately.
11589// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011590 subtype = VSREPLACE;
11591 c = pgetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011592 if (c != '/')
11593 goto do_pungetc;
11594 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011595 break;
11596#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011597 }
Eric Andersenc470f442003-07-28 09:56:35 +000011598 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011599 do_pungetc:
Eric Andersenc470f442003-07-28 09:56:35 +000011600 pungetc();
11601 }
11602 if (dblquote || arinest)
11603 flags |= VSQUOTE;
Denys Vlasenkocd716832009-11-28 22:14:02 +010011604 ((unsigned char *)stackblock())[typeloc] = subtype | flags;
Eric Andersenc470f442003-07-28 09:56:35 +000011605 if (subtype != VSNORMAL) {
11606 varnest++;
11607 if (dblquote || arinest) {
11608 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000011609 }
11610 }
11611 }
Eric Andersenc470f442003-07-28 09:56:35 +000011612 goto parsesub_return;
11613}
Eric Andersencb57d552001-06-28 07:25:16 +000011614
Eric Andersencb57d552001-06-28 07:25:16 +000011615/*
11616 * Called to parse command substitutions. Newstyle is set if the command
11617 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11618 * list of commands (passed by reference), and savelen is the number of
11619 * characters on the top of the stack which must be preserved.
11620 */
Eric Andersenc470f442003-07-28 09:56:35 +000011621parsebackq: {
11622 struct nodelist **nlpp;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011623 smallint savepbq;
Eric Andersenc470f442003-07-28 09:56:35 +000011624 union node *n;
11625 char *volatile str;
11626 struct jmploc jmploc;
11627 struct jmploc *volatile savehandler;
11628 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011629 smallint saveprompt = 0;
11630
Eric Andersencb57d552001-06-28 07:25:16 +000011631#ifdef __GNUC__
Eric Andersenc470f442003-07-28 09:56:35 +000011632 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000011633#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011634 savepbq = parsebackquote;
11635 if (setjmp(jmploc.loc)) {
Denis Vlasenko60818682007-09-28 22:07:23 +000011636 free(str);
Eric Andersenc470f442003-07-28 09:56:35 +000011637 parsebackquote = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011638 exception_handler = savehandler;
11639 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +000011640 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000011641 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011642 str = NULL;
11643 savelen = out - (char *)stackblock();
11644 if (savelen > 0) {
11645 str = ckmalloc(savelen);
11646 memcpy(str, stackblock(), savelen);
11647 }
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011648 savehandler = exception_handler;
11649 exception_handler = &jmploc;
Denis Vlasenkob012b102007-02-19 22:43:01 +000011650 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000011651 if (oldstyle) {
11652 /* We must read until the closing backquote, giving special
Tanguy Pruvot823694d2012-11-18 13:20:29 +010011653 * treatment to some slashes, and then push the string and
11654 * reread it as input, interpreting it normally.
11655 */
Eric Andersenc470f442003-07-28 09:56:35 +000011656 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000011657 size_t psavelen;
11658 char *pstr;
11659
Eric Andersenc470f442003-07-28 09:56:35 +000011660 STARTSTACKSTR(pout);
11661 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011662 int pc;
11663
11664 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011665 pc = pgetc();
11666 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000011667 case '`':
11668 goto done;
11669
11670 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011671 pc = pgetc();
11672 if (pc == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011673 g_parsefile->linno++;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011674 setprompt_if(doprompt, 2);
Eric Andersenc470f442003-07-28 09:56:35 +000011675 /*
11676 * If eating a newline, avoid putting
11677 * the newline into the new character
11678 * stream (via the STPUTC after the
11679 * switch).
11680 */
11681 continue;
11682 }
11683 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011684 && (!dblquote || pc != '"')
11685 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000011686 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011687 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011688 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000011689 break;
11690 }
11691 /* fall through */
11692
11693 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011694 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011695 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011696 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000011697
11698 case '\n':
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011699 g_parsefile->linno++;
Eric Andersenc470f442003-07-28 09:56:35 +000011700 needprompt = doprompt;
11701 break;
11702
11703 default:
11704 break;
11705 }
11706 STPUTC(pc, pout);
11707 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011708 done:
Eric Andersenc470f442003-07-28 09:56:35 +000011709 STPUTC('\0', pout);
11710 psavelen = pout - (char *)stackblock();
11711 if (psavelen > 0) {
11712 pstr = grabstackstr(pout);
11713 setinputstring(pstr);
11714 }
11715 }
11716 nlpp = &bqlist;
11717 while (*nlpp)
11718 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011719 *nlpp = stzalloc(sizeof(**nlpp));
11720 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011721 parsebackquote = oldstyle;
11722
11723 if (oldstyle) {
11724 saveprompt = doprompt;
11725 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011726 }
11727
Eric Andersenc470f442003-07-28 09:56:35 +000011728 n = list(2);
11729
11730 if (oldstyle)
11731 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011732 else if (readtoken() != TRP)
11733 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011734
11735 (*nlpp)->n = n;
11736 if (oldstyle) {
11737 /*
11738 * Start reading from old file again, ignoring any pushed back
11739 * tokens left from the backquote parsing
11740 */
11741 popfile();
11742 tokpushback = 0;
11743 }
11744 while (stackblocksize() <= savelen)
11745 growstackblock();
11746 STARTSTACKSTR(out);
11747 if (str) {
11748 memcpy(out, str, savelen);
11749 STADJUST(savelen, out);
Denis Vlasenkob012b102007-02-19 22:43:01 +000011750 INT_OFF;
11751 free(str);
Eric Andersenc470f442003-07-28 09:56:35 +000011752 str = NULL;
Denis Vlasenkob012b102007-02-19 22:43:01 +000011753 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000011754 }
11755 parsebackquote = savepbq;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011756 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000011757 if (arinest || dblquote)
11758 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11759 else
11760 USTPUTC(CTLBACKQ, out);
11761 if (oldstyle)
11762 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011763 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000011764}
11765
Mike Frysinger98c52642009-04-02 10:02:37 +000011766#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011767/*
11768 * Parse an arithmetic expansion (indicate start of one and set state)
11769 */
Eric Andersenc470f442003-07-28 09:56:35 +000011770parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000011771 if (++arinest == 1) {
11772 prevsyntax = syntax;
11773 syntax = ARISYNTAX;
11774 USTPUTC(CTLARI, out);
11775 if (dblquote)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011776 USTPUTC('"', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011777 else
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011778 USTPUTC(' ', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011779 } else {
11780 /*
11781 * we collapse embedded arithmetic expansion to
11782 * parenthesis, which should be equivalent
11783 */
11784 USTPUTC('(', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011785 }
Eric Andersenc470f442003-07-28 09:56:35 +000011786 goto parsearith_return;
11787}
11788#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011789
Eric Andersenc470f442003-07-28 09:56:35 +000011790} /* end of readtoken */
11791
Eric Andersencb57d552001-06-28 07:25:16 +000011792/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011793 * Read the next input token.
11794 * If the token is a word, we set backquotelist to the list of cmds in
11795 * backquotes. We set quoteflag to true if any part of the word was
11796 * quoted.
11797 * If the token is TREDIR, then we set redirnode to a structure containing
11798 * the redirection.
11799 * In all cases, the variable startlinno is set to the number of the line
11800 * on which the token starts.
11801 *
11802 * [Change comment: here documents and internal procedures]
11803 * [Readtoken shouldn't have any arguments. Perhaps we should make the
11804 * word parsing code into a separate routine. In this case, readtoken
11805 * doesn't need to have any internal procedures, but parseword does.
11806 * We could also make parseoperator in essence the main routine, and
11807 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000011808 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011809#define NEW_xxreadtoken
11810#ifdef NEW_xxreadtoken
11811/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011812static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000011813 '\n', '(', ')', /* singles */
11814 '&', '|', ';', /* doubles */
11815 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011816};
Eric Andersencb57d552001-06-28 07:25:16 +000011817
Denis Vlasenko834dee72008-10-07 09:18:30 +000011818#define xxreadtoken_singles 3
11819#define xxreadtoken_doubles 3
11820
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011821static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011822 TNL, TLP, TRP, /* only single occurrence allowed */
11823 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11824 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011825 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011826};
11827
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011828static int
11829xxreadtoken(void)
11830{
11831 int c;
11832
11833 if (tokpushback) {
11834 tokpushback = 0;
11835 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011836 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011837 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011838 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011839 for (;;) { /* until token or start of word found */
Denis Vlasenko834dee72008-10-07 09:18:30 +000011840 c = pgetc_fast();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011841 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011842 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011843
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011844 if (c == '#') {
11845 while ((c = pgetc()) != '\n' && c != PEOF)
11846 continue;
11847 pungetc();
11848 } else if (c == '\\') {
11849 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011850 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000011851 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011852 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011853 startlinno = ++g_parsefile->linno;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011854 setprompt_if(doprompt, 2);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011855 } else {
11856 const char *p;
11857
11858 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11859 if (c != PEOF) {
11860 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011861 g_parsefile->linno++;
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011862 needprompt = doprompt;
11863 }
11864
11865 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000011866 if (p == NULL)
11867 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011868
Denis Vlasenko834dee72008-10-07 09:18:30 +000011869 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
11870 int cc = pgetc();
11871 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011872 p += xxreadtoken_doubles + 1;
11873 } else {
11874 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000011875#if ENABLE_ASH_BASH_COMPAT
11876 if (c == '&' && cc == '>') /* &> */
11877 break; /* return readtoken1(...) */
11878#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011879 }
11880 }
11881 }
11882 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
11883 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011884 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011885 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000011886
11887 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011888}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011889#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011890#define RETURN(token) return lasttoken = token
11891static int
11892xxreadtoken(void)
11893{
11894 int c;
11895
11896 if (tokpushback) {
11897 tokpushback = 0;
11898 return lasttoken;
11899 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011900 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011901 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011902 for (;;) { /* until token or start of word found */
Denis Vlasenko834dee72008-10-07 09:18:30 +000011903 c = pgetc_fast();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011904 switch (c) {
11905 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011906 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011907 continue;
11908 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011909 while ((c = pgetc()) != '\n' && c != PEOF)
11910 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011911 pungetc();
11912 continue;
11913 case '\\':
11914 if (pgetc() == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011915 startlinno = ++g_parsefile->linno;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011916 setprompt_if(doprompt, 2);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011917 continue;
11918 }
11919 pungetc();
11920 goto breakloop;
11921 case '\n':
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011922 g_parsefile->linno++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011923 needprompt = doprompt;
11924 RETURN(TNL);
11925 case PEOF:
11926 RETURN(TEOF);
11927 case '&':
11928 if (pgetc() == '&')
11929 RETURN(TAND);
11930 pungetc();
11931 RETURN(TBACKGND);
11932 case '|':
11933 if (pgetc() == '|')
11934 RETURN(TOR);
11935 pungetc();
11936 RETURN(TPIPE);
11937 case ';':
11938 if (pgetc() == ';')
11939 RETURN(TENDCASE);
11940 pungetc();
11941 RETURN(TSEMI);
11942 case '(':
11943 RETURN(TLP);
11944 case ')':
11945 RETURN(TRP);
11946 default:
11947 goto breakloop;
11948 }
11949 }
11950 breakloop:
11951 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
11952#undef RETURN
11953}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011954#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011955
11956static int
11957readtoken(void)
11958{
11959 int t;
11960#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011961 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011962#endif
11963
11964#if ENABLE_ASH_ALIAS
11965 top:
11966#endif
11967
11968 t = xxreadtoken();
11969
11970 /*
11971 * eat newlines
11972 */
11973 if (checkkwd & CHKNL) {
11974 while (t == TNL) {
11975 parseheredoc();
11976 t = xxreadtoken();
11977 }
11978 }
11979
11980 if (t != TWORD || quoteflag) {
11981 goto out;
11982 }
11983
11984 /*
11985 * check for keywords
11986 */
11987 if (checkkwd & CHKKWD) {
11988 const char *const *pp;
11989
11990 pp = findkwd(wordtext);
11991 if (pp) {
11992 lasttoken = t = pp - tokname_array;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011993 TRACE(("keyword '%s' recognized\n", tokname_array[t] + 1));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011994 goto out;
11995 }
11996 }
11997
11998 if (checkkwd & CHKALIAS) {
11999#if ENABLE_ASH_ALIAS
12000 struct alias *ap;
12001 ap = lookupalias(wordtext, 1);
12002 if (ap != NULL) {
12003 if (*ap->val) {
12004 pushstring(ap->val, ap);
12005 }
12006 goto top;
12007 }
12008#endif
12009 }
12010 out:
12011 checkkwd = 0;
12012#if DEBUG
12013 if (!alreadyseen)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020012014 TRACE(("token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012015 else
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020012016 TRACE(("reread token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012017#endif
12018 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012019}
12020
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012021static char
12022peektoken(void)
12023{
12024 int t;
12025
12026 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012027 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012028 return tokname_array[t][0];
12029}
Eric Andersencb57d552001-06-28 07:25:16 +000012030
12031/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012032 * Read and parse a command. Returns NODE_EOF on end of file.
12033 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012034 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012035static union node *
12036parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012037{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012038 int t;
Eric Andersencb57d552001-06-28 07:25:16 +000012039
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012040 tokpushback = 0;
12041 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012042 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012043 needprompt = 0;
12044 t = readtoken();
12045 if (t == TEOF)
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012046 return NODE_EOF;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012047 if (t == TNL)
12048 return NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012049 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012050 return list(1);
12051}
12052
12053/*
12054 * Input any here documents.
12055 */
12056static void
12057parseheredoc(void)
12058{
12059 struct heredoc *here;
12060 union node *n;
12061
12062 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012063 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012064
12065 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012066 setprompt_if(needprompt, 2);
12067 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012068 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012069 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012070 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012071 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012072 n->narg.text = wordtext;
12073 n->narg.backquote = backquotelist;
12074 here->here->nhere.doc = n;
12075 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012076 }
Eric Andersencb57d552001-06-28 07:25:16 +000012077}
12078
12079
12080/*
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012081 * called by editline -- any expansions to the prompt should be added here.
Eric Andersencb57d552001-06-28 07:25:16 +000012082 */
Denis Vlasenko131ae172007-02-18 13:00:19 +000012083#if ENABLE_ASH_EXPAND_PRMT
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012084static const char *
12085expandstr(const char *ps)
12086{
12087 union node n;
12088
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000012089 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12090 * and token processing _can_ alter it (delete NULs etc). */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012091 setinputstring((char *)ps);
Denis Vlasenko46a53062007-09-24 18:30:02 +000012092 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012093 popfile();
12094
12095 n.narg.type = NARG;
12096 n.narg.next = NULL;
12097 n.narg.text = wordtext;
12098 n.narg.backquote = backquotelist;
12099
12100 expandarg(&n, NULL, 0);
12101 return stackblock();
12102}
12103#endif
12104
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012105/*
12106 * Execute a command or commands contained in a string.
12107 */
12108static int
12109evalstring(char *s, int mask)
Eric Andersenc470f442003-07-28 09:56:35 +000012110{
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012111 union node *n;
12112 struct stackmark smark;
12113 int skip;
12114
12115 setinputstring(s);
12116 setstackmark(&smark);
12117
12118 skip = 0;
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012119 while ((n = parsecmd(0)) != NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012120 evaltree(n, 0);
12121 popstackmark(&smark);
12122 skip = evalskip;
12123 if (skip)
12124 break;
12125 }
12126 popfile();
12127
12128 skip &= mask;
12129 evalskip = skip;
12130 return skip;
Eric Andersenc470f442003-07-28 09:56:35 +000012131}
12132
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012133/*
12134 * The eval command.
12135 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012136static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012137evalcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012138{
12139 char *p;
12140 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012141
Denis Vlasenko68404f12008-03-17 09:00:54 +000012142 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012143 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012144 argv += 2;
12145 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012146 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012147 for (;;) {
12148 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012149 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012150 if (p == NULL)
12151 break;
12152 STPUTC(' ', concat);
12153 }
12154 STPUTC('\0', concat);
12155 p = grabstackstr(concat);
12156 }
12157 evalstring(p, ~SKIPEVAL);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012158 }
12159 return exitstatus;
12160}
12161
12162/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012163 * Read and execute commands.
12164 * "Top" is nonzero for the top level command loop;
12165 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012166 */
12167static int
12168cmdloop(int top)
12169{
12170 union node *n;
12171 struct stackmark smark;
12172 int inter;
12173 int numeof = 0;
12174
12175 TRACE(("cmdloop(%d) called\n", top));
12176 for (;;) {
12177 int skip;
12178
12179 setstackmark(&smark);
12180#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012181 if (doing_jobctl)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012182 showjobs(stderr, SHOW_CHANGED);
12183#endif
12184 inter = 0;
12185 if (iflag && top) {
12186 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012187 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012188 }
12189 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012190#if DEBUG
12191 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012192 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012193#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012194 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012195 if (!top || numeof >= 50)
12196 break;
12197 if (!stoppedjobs()) {
12198 if (!Iflag)
12199 break;
12200 out2str("\nUse \"exit\" to leave shell.\n");
12201 }
12202 numeof++;
12203 } else if (nflag == 0) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012204 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12205 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012206 numeof = 0;
12207 evaltree(n, 0);
12208 }
12209 popstackmark(&smark);
12210 skip = evalskip;
12211
12212 if (skip) {
12213 evalskip = 0;
12214 return skip & SKIPEVAL;
12215 }
12216 }
12217 return 0;
12218}
12219
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012220/*
12221 * Take commands from a file. To be compatible we should do a path
12222 * search for the file, which is necessary to find sub-commands.
12223 */
12224static char *
12225find_dot_file(char *name)
12226{
12227 char *fullname;
12228 const char *path = pathval();
12229 struct stat statb;
12230
12231 /* don't try this for absolute or relative paths */
12232 if (strchr(name, '/'))
12233 return name;
12234
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012235 /* IIRC standards do not say whether . is to be searched.
12236 * And it is even smaller this way, making it unconditional for now:
12237 */
12238 if (1) { /* ENABLE_ASH_BASH_COMPAT */
12239 fullname = name;
12240 goto try_cur_dir;
12241 }
12242
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012243 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012244 try_cur_dir:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012245 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12246 /*
12247 * Don't bother freeing here, since it will
12248 * be freed by the caller.
12249 */
12250 return fullname;
12251 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012252 if (fullname != name)
12253 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012254 }
12255
12256 /* not found in the PATH */
12257 ash_msg_and_raise_error("%s: not found", name);
12258 /* NOTREACHED */
12259}
12260
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012261static int FAST_FUNC
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012262dotcmd(int argc, char **argv)
12263{
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012264 char *fullname;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012265 struct strlist *sp;
12266 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012267
12268 for (sp = cmdenviron; sp; sp = sp->next)
Denis Vlasenko4222ae42007-02-25 02:37:49 +000012269 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012270
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012271 if (!argv[1]) {
12272 /* bash says: "bash: .: filename argument required" */
12273 return 2; /* bash compat */
12274 }
12275
Denys Vlasenkocd10dc42010-05-17 17:10:46 +020012276 /* "false; . empty_file; echo $?" should print 0, not 1: */
12277 exitstatus = 0;
12278
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012279 fullname = find_dot_file(argv[1]);
Denys Vlasenkocd10dc42010-05-17 17:10:46 +020012280
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012281 argv += 2;
12282 argc -= 2;
12283 if (argc) { /* argc > 0, argv[0] != NULL */
12284 saveparam = shellparam;
12285 shellparam.malloced = 0;
12286 shellparam.nparam = argc;
12287 shellparam.p = argv;
12288 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012289
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012290 setinputfile(fullname, INPUT_PUSH_FILE);
12291 commandname = fullname;
12292 cmdloop(0);
12293 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012294
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012295 if (argc) {
12296 freeparam(&shellparam);
12297 shellparam = saveparam;
12298 };
12299
Denys Vlasenkocd10dc42010-05-17 17:10:46 +020012300 return exitstatus;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012301}
12302
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012303static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012304exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012305{
12306 if (stoppedjobs())
12307 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012308 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012309 exitstatus = number(argv[1]);
12310 raise_exception(EXEXIT);
12311 /* NOTREACHED */
12312}
12313
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012314/*
12315 * Read a file containing shell functions.
12316 */
12317static void
12318readcmdfile(char *name)
12319{
12320 setinputfile(name, INPUT_PUSH_FILE);
12321 cmdloop(0);
12322 popfile();
12323}
12324
12325
Denis Vlasenkocc571512007-02-23 21:10:35 +000012326/* ============ find_command inplementation */
12327
12328/*
12329 * Resolve a command name. If you change this routine, you may have to
12330 * change the shellexec routine as well.
12331 */
12332static void
12333find_command(char *name, struct cmdentry *entry, int act, const char *path)
12334{
12335 struct tblentry *cmdp;
12336 int idx;
12337 int prev;
12338 char *fullname;
12339 struct stat statb;
12340 int e;
12341 int updatetbl;
12342 struct builtincmd *bcmd;
12343
12344 /* If name contains a slash, don't use PATH or hash table */
12345 if (strchr(name, '/') != NULL) {
12346 entry->u.index = -1;
12347 if (act & DO_ABS) {
12348 while (stat(name, &statb) < 0) {
12349#ifdef SYSV
12350 if (errno == EINTR)
12351 continue;
12352#endif
12353 entry->cmdtype = CMDUNKNOWN;
12354 return;
12355 }
12356 }
12357 entry->cmdtype = CMDNORMAL;
12358 return;
12359 }
12360
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012361/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012362
12363 updatetbl = (path == pathval());
12364 if (!updatetbl) {
12365 act |= DO_ALTPATH;
12366 if (strstr(path, "%builtin") != NULL)
12367 act |= DO_ALTBLTIN;
12368 }
12369
12370 /* If name is in the table, check answer will be ok */
12371 cmdp = cmdlookup(name, 0);
12372 if (cmdp != NULL) {
12373 int bit;
12374
12375 switch (cmdp->cmdtype) {
12376 default:
12377#if DEBUG
12378 abort();
12379#endif
12380 case CMDNORMAL:
12381 bit = DO_ALTPATH;
12382 break;
12383 case CMDFUNCTION:
12384 bit = DO_NOFUNC;
12385 break;
12386 case CMDBUILTIN:
12387 bit = DO_ALTBLTIN;
12388 break;
12389 }
12390 if (act & bit) {
12391 updatetbl = 0;
12392 cmdp = NULL;
12393 } else if (cmdp->rehash == 0)
12394 /* if not invalidated by cd, we're done */
12395 goto success;
12396 }
12397
12398 /* If %builtin not in path, check for builtin next */
12399 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012400 if (bcmd) {
12401 if (IS_BUILTIN_REGULAR(bcmd))
12402 goto builtin_success;
12403 if (act & DO_ALTPATH) {
12404 if (!(act & DO_ALTBLTIN))
12405 goto builtin_success;
12406 } else if (builtinloc <= 0) {
12407 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000012408 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012409 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000012410
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012411#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000012412 {
12413 int applet_no = find_applet_by_name(name);
12414 if (applet_no >= 0) {
12415 entry->cmdtype = CMDNORMAL;
12416 entry->u.index = -2 - applet_no;
12417 return;
12418 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012419 }
12420#endif
12421
Denis Vlasenkocc571512007-02-23 21:10:35 +000012422 /* We have to search path. */
12423 prev = -1; /* where to start */
12424 if (cmdp && cmdp->rehash) { /* doing a rehash */
12425 if (cmdp->cmdtype == CMDBUILTIN)
12426 prev = builtinloc;
12427 else
12428 prev = cmdp->param.index;
12429 }
12430
12431 e = ENOENT;
12432 idx = -1;
12433 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012434 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000012435 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012436 /* NB: code below will still use fullname
12437 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012438 idx++;
12439 if (pathopt) {
12440 if (prefix(pathopt, "builtin")) {
12441 if (bcmd)
12442 goto builtin_success;
12443 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000012444 }
12445 if ((act & DO_NOFUNC)
12446 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020012447 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012448 continue;
12449 }
12450 }
12451 /* if rehash, don't redo absolute path names */
12452 if (fullname[0] == '/' && idx <= prev) {
12453 if (idx < prev)
12454 continue;
12455 TRACE(("searchexec \"%s\": no change\n", name));
12456 goto success;
12457 }
12458 while (stat(fullname, &statb) < 0) {
12459#ifdef SYSV
12460 if (errno == EINTR)
12461 continue;
12462#endif
12463 if (errno != ENOENT && errno != ENOTDIR)
12464 e = errno;
12465 goto loop;
12466 }
12467 e = EACCES; /* if we fail, this will be the error */
12468 if (!S_ISREG(statb.st_mode))
12469 continue;
12470 if (pathopt) { /* this is a %func directory */
12471 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012472 /* NB: stalloc will return space pointed by fullname
12473 * (because we don't have any intervening allocations
12474 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012475 readcmdfile(fullname);
12476 cmdp = cmdlookup(name, 0);
12477 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12478 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12479 stunalloc(fullname);
12480 goto success;
12481 }
12482 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12483 if (!updatetbl) {
12484 entry->cmdtype = CMDNORMAL;
12485 entry->u.index = idx;
12486 return;
12487 }
12488 INT_OFF;
12489 cmdp = cmdlookup(name, 1);
12490 cmdp->cmdtype = CMDNORMAL;
12491 cmdp->param.index = idx;
12492 INT_ON;
12493 goto success;
12494 }
12495
12496 /* We failed. If there was an entry for this command, delete it */
12497 if (cmdp && updatetbl)
12498 delete_cmd_entry();
12499 if (act & DO_ERR)
12500 ash_msg("%s: %s", name, errmsg(e, "not found"));
12501 entry->cmdtype = CMDUNKNOWN;
12502 return;
12503
12504 builtin_success:
12505 if (!updatetbl) {
12506 entry->cmdtype = CMDBUILTIN;
12507 entry->u.cmd = bcmd;
12508 return;
12509 }
12510 INT_OFF;
12511 cmdp = cmdlookup(name, 1);
12512 cmdp->cmdtype = CMDBUILTIN;
12513 cmdp->param.cmd = bcmd;
12514 INT_ON;
12515 success:
12516 cmdp->rehash = 0;
12517 entry->cmdtype = cmdp->cmdtype;
12518 entry->u = cmdp->param;
12519}
12520
12521
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012522/* ============ trap.c */
Eric Andersenc470f442003-07-28 09:56:35 +000012523
Eric Andersencb57d552001-06-28 07:25:16 +000012524/*
Eric Andersencb57d552001-06-28 07:25:16 +000012525 * The trap builtin.
12526 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012527static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012528trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012529{
12530 char *action;
12531 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012532 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012533
Eric Andersenc470f442003-07-28 09:56:35 +000012534 nextopt(nullstr);
12535 ap = argptr;
12536 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012537 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012538 char *tr = trap_ptr[signo];
12539 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012540 /* note: bash adds "SIG", but only if invoked
12541 * as "bash". If called as "sh", or if set -o posix,
12542 * then it prints short signal names.
12543 * We are printing short names: */
12544 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012545 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012546 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012547 /* trap_ptr != trap only if we are in special-cased `trap` code.
12548 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012549 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012550 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000012551 }
12552 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012553 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012554 if (trap_ptr != trap) {
12555 free(trap_ptr);
12556 trap_ptr = trap;
12557 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012558 */
Eric Andersencb57d552001-06-28 07:25:16 +000012559 return 0;
12560 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012561
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012562 action = NULL;
12563 if (ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000012564 action = *ap++;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012565 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012566 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012567 signo = get_signum(*ap);
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012568 if (signo < 0) {
12569 /* Mimic bash message exactly */
12570 ash_msg("%s: invalid signal specification", *ap);
12571 exitcode = 1;
12572 goto next;
12573 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000012574 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000012575 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000012576 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000012577 action = NULL;
12578 else
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012579 action = ckstrdup(action);
Eric Andersencb57d552001-06-28 07:25:16 +000012580 }
Denis Vlasenko60818682007-09-28 22:07:23 +000012581 free(trap[signo]);
Denys Vlasenko238bf182010-05-18 15:49:07 +020012582 if (action)
12583 may_have_traps = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012584 trap[signo] = action;
12585 if (signo != 0)
12586 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012587 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012588 next:
Eric Andersencb57d552001-06-28 07:25:16 +000012589 ap++;
12590 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012591 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012592}
12593
Eric Andersenc470f442003-07-28 09:56:35 +000012594
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012595/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000012596
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000012597#if !ENABLE_FEATURE_SH_EXTRA_QUIET
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000012598/*
12599 * Lists available builtins
12600 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012601static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012602helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012603{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000012604 unsigned col;
12605 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000012606
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020012607 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000012608 "Built-in commands:\n"
12609 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000012610 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012611 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000012612 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000012613 if (col > 60) {
12614 out1fmt("\n");
12615 col = 0;
12616 }
12617 }
Denis Vlasenko80d14be2007-04-10 23:03:30 +000012618#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000012619 {
12620 const char *a = applet_names;
12621 while (*a) {
12622 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12623 if (col > 60) {
12624 out1fmt("\n");
12625 col = 0;
12626 }
12627 a += strlen(a) + 1;
Eric Andersenc470f442003-07-28 09:56:35 +000012628 }
12629 }
12630#endif
12631 out1fmt("\n\n");
12632 return EXIT_SUCCESS;
12633}
Denis Vlasenko131ae172007-02-18 13:00:19 +000012634#endif /* FEATURE_SH_EXTRA_QUIET */
Eric Andersenc470f442003-07-28 09:56:35 +000012635
Eric Andersencb57d552001-06-28 07:25:16 +000012636/*
Eric Andersencb57d552001-06-28 07:25:16 +000012637 * The export and readonly commands.
12638 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012639static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012640exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012641{
12642 struct var *vp;
12643 char *name;
12644 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012645 char **aptr;
Tanguy Pruvot823694d2012-11-18 13:20:29 +010012646 char opt;
12647 int flag;
12648 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000012649
Tanguy Pruvot823694d2012-11-18 13:20:29 +010012650 /* "readonly" in bash accepts, but ignores -n.
12651 * We do the same: it saves a conditional in nextopt's param.
12652 */
12653 flag_off = 0;
12654 while ((opt = nextopt("np")) != '\0') {
12655 if (opt == 'n')
12656 flag_off = VEXPORT;
12657 }
12658 flag = VEXPORT;
12659 if (argv[0][0] == 'r') {
12660 flag = VREADONLY;
12661 flag_off = 0; /* readonly ignores -n */
12662 }
12663 flag_off = ~flag_off;
12664
12665 /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */
12666 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012667 aptr = argptr;
12668 name = *aptr;
12669 if (name) {
12670 do {
12671 p = strchr(name, '=');
12672 if (p != NULL) {
12673 p++;
12674 } else {
12675 vp = *findvar(hashvar(name), name);
12676 if (vp) {
Tanguy Pruvot823694d2012-11-18 13:20:29 +010012677 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012678 continue;
12679 }
Eric Andersencb57d552001-06-28 07:25:16 +000012680 }
Tanguy Pruvot823694d2012-11-18 13:20:29 +010012681 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012682 } while ((name = *++aptr) != NULL);
12683 return 0;
12684 }
Eric Andersencb57d552001-06-28 07:25:16 +000012685 }
Tanguy Pruvot823694d2012-11-18 13:20:29 +010012686
12687 /* No arguments. Show the list of exported or readonly vars.
12688 * -n is ignored.
12689 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012690 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012691 return 0;
12692}
12693
Eric Andersencb57d552001-06-28 07:25:16 +000012694/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012695 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000012696 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000012697static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012698unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012699{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012700 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000012701
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012702 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012703 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012704 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000012705}
12706
Eric Andersencb57d552001-06-28 07:25:16 +000012707/*
Eric Andersencb57d552001-06-28 07:25:16 +000012708 * The unset builtin command. We unset the function before we unset the
12709 * variable to allow a function to be unset when there is a readonly variable
12710 * with the same name.
12711 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012712static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012713unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012714{
12715 char **ap;
12716 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012717 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012718 int ret = 0;
12719
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012720 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000012721 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012722 }
Eric Andersencb57d552001-06-28 07:25:16 +000012723
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012724 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012725 if (flag != 'f') {
12726 i = unsetvar(*ap);
12727 ret |= i;
12728 if (!(i & 2))
12729 continue;
12730 }
12731 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012732 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012733 }
Eric Andersenc470f442003-07-28 09:56:35 +000012734 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012735}
12736
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012737static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012738 ' ', offsetof(struct tms, tms_utime),
12739 '\n', offsetof(struct tms, tms_stime),
12740 ' ', offsetof(struct tms, tms_cutime),
12741 '\n', offsetof(struct tms, tms_cstime),
12742 0
12743};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012744static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012745timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012746{
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012747 unsigned long clk_tck, s, t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012748 const unsigned char *p;
12749 struct tms buf;
12750
12751 clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersencb57d552001-06-28 07:25:16 +000012752 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012753
12754 p = timescmd_str;
12755 do {
12756 t = *(clock_t *)(((char *) &buf) + p[1]);
12757 s = t / clk_tck;
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012758 t = t % clk_tck;
12759 out1fmt("%lum%lu.%03lus%c",
12760 s / 60, s % 60,
12761 (t * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012762 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012763 p += 2;
12764 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012765
Eric Andersencb57d552001-06-28 07:25:16 +000012766 return 0;
12767}
12768
Mike Frysinger98c52642009-04-02 10:02:37 +000012769#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000012770/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012771 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012772 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000012773 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012774 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012775 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012776static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012777letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012778{
Denis Vlasenko68404f12008-03-17 09:00:54 +000012779 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000012780
Denis Vlasenko68404f12008-03-17 09:00:54 +000012781 argv++;
12782 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000012783 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000012784 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012785 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012786 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000012787
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000012788 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000012789}
Eric Andersenc470f442003-07-28 09:56:35 +000012790#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012791
Eric Andersenc470f442003-07-28 09:56:35 +000012792/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012793 * The read builtin. Options:
12794 * -r Do not interpret '\' specially
12795 * -s Turn off echo (tty only)
12796 * -n NCHARS Read NCHARS max
12797 * -p PROMPT Display PROMPT on stderr (if input is from tty)
12798 * -t SECONDS Timeout after SECONDS (tty or pipe only)
12799 * -u FD Read from given FD instead of fd 0
Eric Andersenc470f442003-07-28 09:56:35 +000012800 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012801 * TODO: bash also has:
12802 * -a ARRAY Read into array[0],[1],etc
12803 * -d DELIM End on DELIM char, not newline
12804 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000012805 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012806static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012807readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012808{
Denys Vlasenko73067272010-01-12 22:11:24 +010012809 char *opt_n = NULL;
12810 char *opt_p = NULL;
12811 char *opt_t = NULL;
12812 char *opt_u = NULL;
12813 int read_flags = 0;
12814 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000012815 int i;
12816
Denys Vlasenko73067272010-01-12 22:11:24 +010012817 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000012818 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000012819 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010012820 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012821 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012822 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010012823 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012824 break;
12825 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010012826 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000012827 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012828 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010012829 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012830 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012831 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010012832 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000012833 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012834 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010012835 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012836 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012837 default:
12838 break;
12839 }
Eric Andersenc470f442003-07-28 09:56:35 +000012840 }
Paul Fox02eb9342005-09-07 16:56:02 +000012841
Tanguy Pruvot823694d2012-11-18 13:20:29 +010012842 /* "read -s" needs to save/restore termios, can't allow ^C
12843 * to jump out of it.
12844 */
12845 INT_OFF;
Denys Vlasenko03dad222010-01-12 23:29:57 +010012846 r = shell_builtin_read(setvar2,
Denys Vlasenko73067272010-01-12 22:11:24 +010012847 argptr,
12848 bltinlookup("IFS"), /* can be NULL */
12849 read_flags,
12850 opt_n,
12851 opt_p,
12852 opt_t,
12853 opt_u
12854 );
Tanguy Pruvot823694d2012-11-18 13:20:29 +010012855 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000012856
Denys Vlasenko73067272010-01-12 22:11:24 +010012857 if ((uintptr_t)r > 1)
12858 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000012859
Denys Vlasenko73067272010-01-12 22:11:24 +010012860 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000012861}
12862
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012863static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012864umaskcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012865{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012866 static const char permuser[3] ALIGN1 = "ugo";
12867 static const char permmode[3] ALIGN1 = "rwx";
12868 static const short permmask[] ALIGN2 = {
Eric Andersenc470f442003-07-28 09:56:35 +000012869 S_IRUSR, S_IWUSR, S_IXUSR,
12870 S_IRGRP, S_IWGRP, S_IXGRP,
12871 S_IROTH, S_IWOTH, S_IXOTH
12872 };
12873
Denis Vlasenkoeb858492009-04-18 02:06:54 +000012874 /* TODO: use bb_parse_mode() instead */
12875
Eric Andersenc470f442003-07-28 09:56:35 +000012876 char *ap;
12877 mode_t mask;
12878 int i;
12879 int symbolic_mode = 0;
12880
12881 while (nextopt("S") != '\0') {
12882 symbolic_mode = 1;
12883 }
12884
Denis Vlasenkob012b102007-02-19 22:43:01 +000012885 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012886 mask = umask(0);
12887 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012888 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000012889
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012890 ap = *argptr;
12891 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012892 if (symbolic_mode) {
12893 char buf[18];
12894 char *p = buf;
12895
12896 for (i = 0; i < 3; i++) {
12897 int j;
12898
12899 *p++ = permuser[i];
12900 *p++ = '=';
12901 for (j = 0; j < 3; j++) {
12902 if ((mask & permmask[3 * i + j]) == 0) {
12903 *p++ = permmode[j];
12904 }
12905 }
12906 *p++ = ',';
12907 }
12908 *--p = 0;
12909 puts(buf);
12910 } else {
12911 out1fmt("%.4o\n", mask);
12912 }
12913 } else {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012914 if (isdigit((unsigned char) *ap)) {
Eric Andersenc470f442003-07-28 09:56:35 +000012915 mask = 0;
12916 do {
12917 if (*ap >= '8' || *ap < '0')
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +020012918 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +000012919 mask = (mask << 3) + (*ap - '0');
12920 } while (*++ap != '\0');
12921 umask(mask);
12922 } else {
12923 mask = ~mask & 0777;
12924 if (!bb_parse_mode(ap, &mask)) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000012925 ash_msg_and_raise_error("illegal mode: %s", ap);
Eric Andersenc470f442003-07-28 09:56:35 +000012926 }
12927 umask(~mask & 0777);
12928 }
12929 }
12930 return 0;
12931}
12932
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012933static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010012934ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012935{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010012936 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000012937}
12938
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012939/* ============ main() and helpers */
12940
12941/*
12942 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012943 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012944static void
12945exitshell(void)
12946{
12947 struct jmploc loc;
12948 char *p;
12949 int status;
12950
Tanguy Pruvot8a6c2c22012-04-28 00:24:09 +020012951#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
12952 save_history(line_input_state);
12953#endif
12954
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012955 status = exitstatus;
12956 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
12957 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000012958 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012959/* dash bug: it just does _exit(exitstatus) here
12960 * but we have to do setjobctl(0) first!
12961 * (bug is still not fixed in dash-0.5.3 - if you run dash
12962 * under Midnight Commander, on exit from dash MC is backgrounded) */
12963 status = exitstatus;
12964 goto out;
12965 }
12966 exception_handler = &loc;
12967 p = trap[0];
12968 if (p) {
12969 trap[0] = NULL;
12970 evalstring(p, 0);
Denys Vlasenko0800e3a2009-09-24 03:09:26 +020012971 free(p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012972 }
12973 flush_stdout_stderr();
12974 out:
12975 setjobctl(0);
12976 _exit(status);
12977 /* NOTREACHED */
12978}
12979
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000012980static void
12981init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012982{
12983 /* from input.c: */
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020012984 /* we will never free this */
12985 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012986
12987 /* from trap.c: */
12988 signal(SIGCHLD, SIG_DFL);
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010012989 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
12990 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
12991 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020012992 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012993
12994 /* from var.c: */
12995 {
12996 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012997 const char *p;
12998 struct stat st1, st2;
12999
13000 initvar();
13001 for (envp = environ; envp && *envp; envp++) {
13002 if (strchr(*envp, '=')) {
13003 setvareq(*envp, VEXPORT|VTEXTFIXED);
13004 }
13005 }
13006
Denys Vlasenko7bb346f2009-10-06 22:09:50 +020013007 setvar("PPID", utoa(getppid()), 0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013008
13009 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013010 if (p) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013011 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013012 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13013 ) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013014 p = '\0';
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013015 }
13016 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013017 setpwd(p, 0);
13018 }
13019}
13020
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013021
13022//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013023//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013024//usage:#define ash_full_usage "\n\n"
13025//usage: "Unix shell interpreter"
13026
13027//usage:#if ENABLE_FEATURE_SH_IS_ASH
13028//usage:# define sh_trivial_usage ash_trivial_usage
13029//usage:# define sh_full_usage ash_full_usage
13030//usage:#endif
13031//usage:#if ENABLE_FEATURE_BASH_IS_ASH
13032//usage:# define bash_trivial_usage ash_trivial_usage
13033//usage:# define bash_full_usage ash_full_usage
13034//usage:#endif
13035
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013036/*
13037 * Process the shell command line arguments.
13038 */
13039static void
Denis Vlasenko68404f12008-03-17 09:00:54 +000013040procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013041{
13042 int i;
13043 const char *xminusc;
13044 char **xargv;
13045
13046 xargv = argv;
13047 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013048 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013049 xargv++;
13050 for (i = 0; i < NOPTS; i++)
13051 optlist[i] = 2;
13052 argptr = xargv;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013053 if (options(/*cmdline:*/ 1)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013054 /* it already printed err message */
13055 raise_exception(EXERROR);
13056 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013057 xargv = argptr;
13058 xminusc = minusc;
13059 if (*xargv == NULL) {
13060 if (xminusc)
13061 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13062 sflag = 1;
13063 }
13064 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13065 iflag = 1;
13066 if (mflag == 2)
13067 mflag = iflag;
13068 for (i = 0; i < NOPTS; i++)
13069 if (optlist[i] == 2)
13070 optlist[i] = 0;
13071#if DEBUG == 2
13072 debug = 1;
13073#endif
13074 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13075 if (xminusc) {
13076 minusc = *xargv++;
13077 if (*xargv)
13078 goto setarg0;
13079 } else if (!sflag) {
13080 setinputfile(*xargv, 0);
13081 setarg0:
13082 arg0 = *xargv++;
13083 commandname = arg0;
13084 }
13085
13086 shellparam.p = xargv;
13087#if ENABLE_ASH_GETOPTS
13088 shellparam.optind = 1;
13089 shellparam.optoff = -1;
13090#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013091 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013092 while (*xargv) {
13093 shellparam.nparam++;
13094 xargv++;
13095 }
13096 optschanged();
13097}
13098
13099/*
13100 * Read /etc/profile or .profile.
13101 */
13102static void
13103read_profile(const char *name)
13104{
13105 int skip;
13106
13107 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13108 return;
13109 skip = cmdloop(0);
13110 popfile();
13111 if (skip)
13112 exitshell();
13113}
13114
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013115/*
13116 * This routine is called when an error or an interrupt occurs in an
13117 * interactive shell and control is returned to the main command loop.
13118 */
13119static void
13120reset(void)
13121{
13122 /* from eval.c: */
13123 evalskip = 0;
13124 loopnest = 0;
13125 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013126 g_parsefile->left_in_buffer = 0;
13127 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013128 popallfiles();
13129 /* from parser.c: */
13130 tokpushback = 0;
13131 checkkwd = 0;
13132 /* from redir.c: */
Denis Vlasenko34c73c42008-08-16 11:48:02 +000013133 clearredir(/*drop:*/ 0);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013134}
13135
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013136#if PROFILE
13137static short profile_buf[16384];
13138extern int etext();
13139#endif
13140
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013141/*
13142 * Main routine. We initialize things, parse the arguments, execute
13143 * profiles if we're a login shell, and then call cmdloop to execute
13144 * commands. The setjmp call sets up the location to jump to when an
13145 * exception occurs. When an exception occurs the variable "state"
13146 * is used to figure out how far we had gotten.
13147 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013148int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013149int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013150{
Mike Frysinger98c52642009-04-02 10:02:37 +000013151 const char *shinit;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013152 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013153 struct jmploc jmploc;
13154 struct stackmark smark;
13155
Denis Vlasenko01631112007-12-16 17:20:38 +000013156 /* Initialize global data */
13157 INIT_G_misc();
13158 INIT_G_memstack();
13159 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013160#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013161 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013162#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013163 INIT_G_cmdtable();
13164
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013165#if PROFILE
13166 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13167#endif
13168
13169#if ENABLE_FEATURE_EDITING
13170 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13171#endif
13172 state = 0;
13173 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013174 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013175 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013176
13177 reset();
13178
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013179 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013180 if (e == EXERROR)
13181 exitstatus = 2;
13182 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013183 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013184 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013185 }
13186 if (e == EXINT) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013187 outcslow('\n', stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013188 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013189
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013190 popstackmark(&smark);
13191 FORCE_INT_ON; /* enable interrupts */
13192 if (s == 1)
13193 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013194 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013195 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013196 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013197 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013198 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013199 }
13200 exception_handler = &jmploc;
13201#if DEBUG
13202 opentrace();
Denis Vlasenko653d8e72009-03-19 21:59:35 +000013203 TRACE(("Shell args: "));
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013204 trace_puts_args(argv);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013205#endif
13206 rootpid = getpid();
13207
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013208 init();
13209 setstackmark(&smark);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013210 procargs(argv);
13211
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013212#if ENABLE_FEATURE_EDITING_SAVEHISTORY
13213 if (iflag) {
13214 const char *hp = lookupvar("HISTFILE");
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013215 if (!hp) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013216 hp = lookupvar("HOME");
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013217 if (hp) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013218 char *defhp = concat_path_file(hp, ".ash_history");
13219 setvar("HISTFILE", defhp, 0);
13220 free(defhp);
13221 }
13222 }
13223 }
13224#endif
Denys Vlasenko6088e132010-12-25 23:58:42 +010013225 if (argv[0] && argv[0][0] == '-')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013226 isloginsh = 1;
13227 if (isloginsh) {
13228 state = 1;
13229 read_profile("/etc/profile");
13230 state1:
13231 state = 2;
13232 read_profile(".profile");
13233 }
13234 state2:
13235 state = 3;
13236 if (
13237#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013238 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013239#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013240 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013241 ) {
13242 shinit = lookupvar("ENV");
13243 if (shinit != NULL && *shinit != '\0') {
13244 read_profile(shinit);
13245 }
13246 }
13247 state3:
13248 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013249 if (minusc) {
13250 /* evalstring pushes parsefile stack.
13251 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013252 * is one of stacked source fds.
13253 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013254 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013255 // ^^ not necessary since now we special-case fd 0
13256 // in is_hidden_fd() to not be considered "hidden fd"
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013257 evalstring(minusc, 0);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013258 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013259
13260 if (sflag || minusc == NULL) {
Tanguy Pruvot8a6c2c22012-04-28 00:24:09 +020013261#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013262 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013263 const char *hp = lookupvar("HISTFILE");
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013264 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013265 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013266# if ENABLE_FEATURE_SH_HISTFILESIZE
13267 hp = lookupvar("HISTFILESIZE");
13268 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13269# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013270 }
13271#endif
13272 state4: /* XXX ??? - why isn't this before the "if" statement */
13273 cmdloop(1);
13274 }
13275#if PROFILE
13276 monitor(0);
13277#endif
13278#ifdef GPROF
13279 {
13280 extern void _mcleanup(void);
13281 _mcleanup();
13282 }
13283#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013284 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013285 exitshell();
13286 /* NOTREACHED */
13287}
13288
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013289
Eric Andersendf82f612001-06-28 07:46:40 +000013290/*-
13291 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013292 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013293 *
13294 * This code is derived from software contributed to Berkeley by
13295 * Kenneth Almquist.
13296 *
13297 * Redistribution and use in source and binary forms, with or without
13298 * modification, are permitted provided that the following conditions
13299 * are met:
13300 * 1. Redistributions of source code must retain the above copyright
13301 * notice, this list of conditions and the following disclaimer.
13302 * 2. Redistributions in binary form must reproduce the above copyright
13303 * notice, this list of conditions and the following disclaimer in the
13304 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013305 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013306 * may be used to endorse or promote products derived from this software
13307 * without specific prior written permission.
13308 *
13309 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13310 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13311 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13312 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13313 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13314 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13315 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13316 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13317 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13318 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13319 * SUCH DAMAGE.
13320 */