blob: e8d24d40bf5ac5b29f1c46796571d54d439ec7a8 [file] [log] [blame]
Eric Andersen25f27032001-04-26 23:22:31 +00001/* vi: set sw=4 ts=4: */
2/*
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003 * A prototype Bourne shell grammar parser.
4 * Intended to follow the original Thompson and Ritchie
5 * "small and simple is beautiful" philosophy, which
6 * incidentally is a good match to today's BusyBox.
Eric Andersen25f27032001-04-26 23:22:31 +00007 *
Denis Vlasenkoce4acbb2009-04-10 23:23:41 +00008 * Copyright (C) 2000,2001 Larry Doolittle <larry@doolittle.boa.org>
Denis Vlasenkoc8d27332009-04-06 10:47:21 +00009 * Copyright (C) 2008,2009 Denys Vlasenko <vda.linux@googlemail.com>
Eric Andersen25f27032001-04-26 23:22:31 +000010 *
Denys Vlasenkobbecd742010-10-03 17:22:52 +020011 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
12 *
Eric Andersen25f27032001-04-26 23:22:31 +000013 * Credits:
14 * The parser routines proper are all original material, first
Eric Andersencb81e642003-07-14 21:21:08 +000015 * written Dec 2000 and Jan 2001 by Larry Doolittle. The
16 * execution engine, the builtins, and much of the underlying
17 * support has been adapted from busybox-0.49pre's lash, which is
Eric Andersenc7bda1c2004-03-15 08:29:22 +000018 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
Eric Andersencb81e642003-07-14 21:21:08 +000019 * written by Erik Andersen <andersen@codepoet.org>. That, in turn,
20 * is based in part on ladsh.c, by Michael K. Johnson and Erik W.
21 * Troan, which they placed in the public domain. I don't know
22 * how much of the Johnson/Troan code has survived the repeated
23 * rewrites.
24 *
Eric Andersen25f27032001-04-26 23:22:31 +000025 * Other credits:
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +000026 * o_addchr derived from similar w_addchar function in glibc-2.2.
Denis Vlasenko50f3aa42009-04-07 10:52:40 +000027 * parse_redirect, redirect_opt_num, and big chunks of main
Denis Vlasenko424f79b2009-03-22 14:23:34 +000028 * and many builtins derived from contributions by Erik Andersen.
29 * Miscellaneous bugfixes from Matt Kraai.
Eric Andersen25f27032001-04-26 23:22:31 +000030 *
31 * There are two big (and related) architecture differences between
32 * this parser and the lash parser. One is that this version is
33 * actually designed from the ground up to understand nearly all
34 * of the Bourne grammar. The second, consequential change is that
35 * the parser and input reader have been turned inside out. Now,
36 * the parser is in control, and asks for input as needed. The old
37 * way had the input reader in control, and it asked for parsing to
38 * take place as needed. The new way makes it much easier to properly
39 * handle the recursion implicit in the various substitutions, especially
40 * across continuation lines.
41 *
Denys Vlasenko349ef962010-05-21 15:46:24 +020042 * TODOs:
43 * grep for "TODO" and fix (some of them are easy)
Denys Vlasenkoa6ad3972010-05-22 00:26:06 +020044 * make complex ${var%...} constructs support optional
45 * make here documents optional
Denys Vlasenko203fd7b2017-07-17 16:13:35 +020046 * special variables (done: PWD, PPID, RANDOM)
47 * follow IFS rules more precisely, including update semantics
48 * tilde expansion
49 * aliases
Denys Vlasenko57000292018-01-12 14:41:45 +010050 * "command" missing features:
51 * command -p CMD: run CMD using default $PATH
52 * (can use this to override standalone shell as well?)
Denys Vlasenko1e660422017-07-17 21:10:50 +020053 * command BLTIN: disables special-ness (e.g. errors do not abort)
Denys Vlasenko57000292018-01-12 14:41:45 +010054 * command -V CMD1 CMD2 CMD3 (multiple args) (not in standard)
55 * builtins mandated by standards we don't support:
56 * [un]alias, fc:
Denys Vlasenko203fd7b2017-07-17 16:13:35 +020057 * fc -l[nr] [BEG] [END]: list range of commands in history
58 * fc [-e EDITOR] [BEG] [END]: edit/rerun range of commands
59 * fc -s [PAT=REP] [CMD]: rerun CMD, replacing PAT with REP
Mike Frysinger25a6ca02009-03-28 13:59:26 +000060 *
Denys Vlasenkoadc0e202010-05-17 18:56:58 +020061 * Bash compat TODO:
62 * redirection of stdout+stderr: &> and >&
Denys Vlasenkoadc0e202010-05-17 18:56:58 +020063 * reserved words: function select
64 * advanced test: [[ ]]
Denys Vlasenkoadc0e202010-05-17 18:56:58 +020065 * process substitution: <(list) and >(list)
Denys Vlasenko9ca656b2009-06-10 13:39:35 +020066 * let EXPR [EXPR...]
Denys Vlasenko349ef962010-05-21 15:46:24 +020067 * Each EXPR is an arithmetic expression (ARITHMETIC EVALUATION)
68 * If the last arg evaluates to 0, let returns 1; 0 otherwise.
69 * NB: let `echo 'a=a + 1'` - error (IOW: multi-word expansion is used)
Denys Vlasenko9ca656b2009-06-10 13:39:35 +020070 * ((EXPR))
Denys Vlasenko349ef962010-05-21 15:46:24 +020071 * The EXPR is evaluated according to ARITHMETIC EVALUATION.
72 * This is exactly equivalent to let "EXPR".
Denys Vlasenkoadc0e202010-05-17 18:56:58 +020073 * $[EXPR]: synonym for $((EXPR))
Denys Vlasenko203fd7b2017-07-17 16:13:35 +020074 * indirect expansion: ${!VAR}
75 * substring op on @: ${@:n:m}
Denys Vlasenkobbecd742010-10-03 17:22:52 +020076 *
77 * Won't do:
Denys Vlasenko203fd7b2017-07-17 16:13:35 +020078 * Some builtins mandated by standards:
79 * newgrp [GRP]: not a builtin in bash but a suid binary
80 * which spawns a new shell with new group ID
Denys Vlasenko3632cb12018-04-10 15:25:41 +020081 *
82 * Status of [[ support:
83 * [[ args ]] are CMD_SINGLEWORD_NOGLOB:
84 * v='a b'; [[ $v = 'a b' ]]; echo 0:$?
Denys Vlasenko89e9d552018-04-11 01:15:33 +020085 * [[ /bin/n* ]]; echo 0:$?
Denys Vlasenkod2241f52020-10-31 03:34:07 +010086 * = is glob match operator, not equality operator: STR = GLOB
Denys Vlasenkod2241f52020-10-31 03:34:07 +010087 * == same as =
88 * =~ is regex match operator: STR =~ REGEX
Denys Vlasenko3632cb12018-04-10 15:25:41 +020089 * TODO:
Denys Vlasenko3632cb12018-04-10 15:25:41 +020090 * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc)
Denys Vlasenkoa7c06532020-10-31 04:32:34 +010091 * in word = GLOB, quoting should be significant on char-by-char basis: a*cd"*"
Eric Andersen25f27032001-04-26 23:22:31 +000092 */
Denys Vlasenko202a2d12010-07-16 12:36:14 +020093//config:config HUSH
Denys Vlasenkob097a842018-12-28 03:20:17 +010094//config: bool "hush (68 kb)"
Denys Vlasenko202a2d12010-07-16 12:36:14 +020095//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +020096//config: select SHELL_HUSH
Denys Vlasenko202a2d12010-07-16 12:36:14 +020097//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020098//config: hush is a small shell. It handles the normal flow control
99//config: constructs such as if/then/elif/else/fi, for/in/do/done, while loops,
100//config: case/esac. Redirections, here documents, $((arithmetic))
101//config: and functions are supported.
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200102//config:
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200103//config: It will compile and work on no-mmu systems.
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200104//config:
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200105//config: It does not handle select, aliases, tilde expansion,
106//config: &>file and >&file redirection of stdout+stderr.
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200107//config:
Denys Vlasenko67e15292020-06-24 13:39:13 +0200108// This option is visible (has a description) to make it possible to select
109// a "scripted" applet (such as NOLOGIN) but avoid selecting any shells:
110//config:config SHELL_HUSH
111//config: bool "Internal shell for embedded script support"
112//config: default n
113//config:
114//config:# hush options
115//config:# It's only needed to get "nice" menuconfig indenting.
116//config:if SHELL_HUSH || HUSH || SH_IS_HUSH || BASH_IS_HUSH
117//config:
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200118//config:config HUSH_BASH_COMPAT
119//config: bool "bash-compatible extensions"
120//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200121//config: depends on SHELL_HUSH
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200122//config:
Denys Vlasenko9e800222010-10-03 14:28:04 +0200123//config:config HUSH_BRACE_EXPANSION
124//config: bool "Brace expansion"
125//config: default y
126//config: depends on HUSH_BASH_COMPAT
127//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200128//config: Enable {abc,def} extension.
Denys Vlasenko9e800222010-10-03 14:28:04 +0200129//config:
Denys Vlasenko54c21112018-01-27 20:46:45 +0100130//config:config HUSH_BASH_SOURCE_CURDIR
131//config: bool "'source' and '.' builtins search current directory after $PATH"
132//config: default n # do not encourage non-standard behavior
133//config: depends on HUSH_BASH_COMPAT
134//config: help
135//config: This is not compliant with standards. Avoid if possible.
136//config:
Denys Vlasenkocbfdeba2021-03-10 16:31:05 +0100137//config:config HUSH_LINENO_VAR
138//config: bool "$LINENO variable (bashism)"
139//config: default y
140//config: depends on SHELL_HUSH
141//config:
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200142//config:config HUSH_INTERACTIVE
143//config: bool "Interactive mode"
144//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200145//config: depends on SHELL_HUSH
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200146//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200147//config: Enable interactive mode (prompt and command editing).
148//config: Without this, hush simply reads and executes commands
149//config: from stdin just like a shell script from a file.
150//config: No prompt, no PS1/PS2 magic shell variables.
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200151//config:
Denys Vlasenko99862cb2010-09-12 17:34:13 +0200152//config:config HUSH_SAVEHISTORY
153//config: bool "Save command history to .hush_history"
154//config: default y
155//config: depends on HUSH_INTERACTIVE && FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko99862cb2010-09-12 17:34:13 +0200156//config:
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200157//config:config HUSH_JOB
158//config: bool "Job control"
159//config: default y
160//config: depends on HUSH_INTERACTIVE
161//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200162//config: Enable job control: Ctrl-Z backgrounds, Ctrl-C interrupts current
163//config: command (not entire shell), fg/bg builtins work. Without this option,
164//config: "cmd &" still works by simply spawning a process and immediately
165//config: prompting for next command (or executing next command in a script),
166//config: but no separate process group is formed.
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200167//config:
168//config:config HUSH_TICK
Ron Yorston060f0a02018-11-09 12:00:39 +0000169//config: bool "Support command substitution"
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200170//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200171//config: depends on SHELL_HUSH
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200172//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200173//config: Enable `command` and $(command).
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200174//config:
175//config:config HUSH_IF
176//config: bool "Support if/then/elif/else/fi"
177//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200178//config: depends on SHELL_HUSH
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200179//config:
180//config:config HUSH_LOOPS
181//config: bool "Support for, while and until loops"
182//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200183//config: depends on SHELL_HUSH
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200184//config:
185//config:config HUSH_CASE
186//config: bool "Support case ... esac statement"
187//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200188//config: depends on SHELL_HUSH
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200189//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200190//config: Enable case ... esac statement. +400 bytes.
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200191//config:
192//config:config HUSH_FUNCTIONS
193//config: bool "Support funcname() { commands; } syntax"
194//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200195//config: depends on SHELL_HUSH
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200196//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200197//config: Enable support for shell functions. +800 bytes.
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200198//config:
199//config:config HUSH_LOCAL
Denys Vlasenko7a85c602017-01-08 17:40:18 +0100200//config: bool "local builtin"
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200201//config: default y
202//config: depends on HUSH_FUNCTIONS
203//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200204//config: Enable support for local variables in functions.
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200205//config:
206//config:config HUSH_RANDOM_SUPPORT
207//config: bool "Pseudorandom generator and $RANDOM variable"
208//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200209//config: depends on SHELL_HUSH
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200210//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200211//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
212//config: Each read of "$RANDOM" will generate a new pseudorandom value.
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200213//config:
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200214//config:config HUSH_MODE_X
215//config: bool "Support 'hush -x' option and 'set -x' command"
216//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200217//config: depends on SHELL_HUSH
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200218//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200219//config: This instructs hush to print commands before execution.
220//config: Adds ~300 bytes.
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200221//config:
Denys Vlasenko1cc68042017-01-09 17:10:04 +0100222//config:config HUSH_ECHO
223//config: bool "echo builtin"
224//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200225//config: depends on SHELL_HUSH
Denys Vlasenko1cc68042017-01-09 17:10:04 +0100226//config:
227//config:config HUSH_PRINTF
228//config: bool "printf builtin"
229//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200230//config: depends on SHELL_HUSH
Denys Vlasenkof5604222017-01-10 14:58:54 +0100231//config:
Denys Vlasenko265062d2017-01-10 15:13:30 +0100232//config:config HUSH_TEST
233//config: bool "test builtin"
234//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200235//config: depends on SHELL_HUSH
Denys Vlasenko265062d2017-01-10 15:13:30 +0100236//config:
Denys Vlasenkof5604222017-01-10 14:58:54 +0100237//config:config HUSH_HELP
238//config: bool "help builtin"
239//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200240//config: depends on SHELL_HUSH
Denys Vlasenko1cc68042017-01-09 17:10:04 +0100241//config:
Denys Vlasenko6ec76d82017-01-08 18:40:41 +0100242//config:config HUSH_EXPORT
243//config: bool "export builtin"
244//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200245//config: depends on SHELL_HUSH
Denys Vlasenko6ec76d82017-01-08 18:40:41 +0100246//config:
247//config:config HUSH_EXPORT_N
248//config: bool "Support 'export -n' option"
249//config: default y
250//config: depends on HUSH_EXPORT
251//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200252//config: export -n unexports variables. It is a bash extension.
Denys Vlasenko6ec76d82017-01-08 18:40:41 +0100253//config:
Denys Vlasenko1e660422017-07-17 21:10:50 +0200254//config:config HUSH_READONLY
255//config: bool "readonly builtin"
256//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200257//config: depends on SHELL_HUSH
Denys Vlasenko1e660422017-07-17 21:10:50 +0200258//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200259//config: Enable support for read-only variables.
Denys Vlasenko1e660422017-07-17 21:10:50 +0200260//config:
Denys Vlasenko7a85c602017-01-08 17:40:18 +0100261//config:config HUSH_KILL
Denys Vlasenkof5604222017-01-10 14:58:54 +0100262//config: bool "kill builtin (supports kill %jobspec)"
Denys Vlasenko7a85c602017-01-08 17:40:18 +0100263//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200264//config: depends on SHELL_HUSH
Denys Vlasenko7a85c602017-01-08 17:40:18 +0100265//config:
266//config:config HUSH_WAIT
267//config: bool "wait builtin"
268//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200269//config: depends on SHELL_HUSH
Denys Vlasenko7a85c602017-01-08 17:40:18 +0100270//config:
Denys Vlasenko3bb3e1d2018-01-11 18:05:05 +0100271//config:config HUSH_COMMAND
272//config: bool "command builtin"
273//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200274//config: depends on SHELL_HUSH
Denys Vlasenko3bb3e1d2018-01-11 18:05:05 +0100275//config:
Denys Vlasenko7a85c602017-01-08 17:40:18 +0100276//config:config HUSH_TRAP
277//config: bool "trap builtin"
278//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200279//config: depends on SHELL_HUSH
Denys Vlasenko7a85c602017-01-08 17:40:18 +0100280//config:
281//config:config HUSH_TYPE
282//config: bool "type builtin"
283//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200284//config: depends on SHELL_HUSH
Denys Vlasenko7a85c602017-01-08 17:40:18 +0100285//config:
Denys Vlasenko11f2e992017-08-10 16:34:03 +0200286//config:config HUSH_TIMES
287//config: bool "times builtin"
288//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200289//config: depends on SHELL_HUSH
Denys Vlasenko11f2e992017-08-10 16:34:03 +0200290//config:
Denys Vlasenko7a85c602017-01-08 17:40:18 +0100291//config:config HUSH_READ
292//config: bool "read builtin"
293//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200294//config: depends on SHELL_HUSH
Denys Vlasenko7a85c602017-01-08 17:40:18 +0100295//config:
Denys Vlasenko10d5ece2017-01-08 18:28:43 +0100296//config:config HUSH_SET
297//config: bool "set builtin"
298//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200299//config: depends on SHELL_HUSH
Denys Vlasenko10d5ece2017-01-08 18:28:43 +0100300//config:
301//config:config HUSH_UNSET
302//config: bool "unset builtin"
303//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200304//config: depends on SHELL_HUSH
Denys Vlasenkof5604222017-01-10 14:58:54 +0100305//config:
306//config:config HUSH_ULIMIT
307//config: bool "ulimit builtin"
308//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200309//config: depends on SHELL_HUSH
Denys Vlasenko10d5ece2017-01-08 18:28:43 +0100310//config:
Denys Vlasenkod5933b12017-01-08 18:31:39 +0100311//config:config HUSH_UMASK
312//config: bool "umask builtin"
313//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200314//config: depends on SHELL_HUSH
Denys Vlasenkod5933b12017-01-08 18:31:39 +0100315//config:
Denys Vlasenko74d40582017-08-11 01:32:46 +0200316//config:config HUSH_GETOPTS
317//config: bool "getopts builtin"
318//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200319//config: depends on SHELL_HUSH
Denys Vlasenko74d40582017-08-11 01:32:46 +0200320//config:
Denys Vlasenko44719692017-01-08 18:44:41 +0100321//config:config HUSH_MEMLEAK
322//config: bool "memleak builtin (debugging)"
323//config: default n
Denys Vlasenko67e15292020-06-24 13:39:13 +0200324//config: depends on SHELL_HUSH
325//config:
326//config:endif # hush options
Denys Vlasenko202a2d12010-07-16 12:36:14 +0200327
Denys Vlasenko20704f02011-03-23 17:59:27 +0100328//applet:IF_HUSH(APPLET(hush, BB_DIR_BIN, BB_SUID_DROP))
Denys Vlasenko205d48e2017-01-29 14:57:33 +0100329// APPLET_ODDNAME:name main location suid_type help
Denys Vlasenko205d48e2017-01-29 14:57:33 +0100330//applet:IF_SH_IS_HUSH( APPLET_ODDNAME(sh, hush, BB_DIR_BIN, BB_SUID_DROP, hush))
Denys Vlasenko0b883582016-12-23 16:49:07 +0100331//applet:IF_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, BB_DIR_BIN, BB_SUID_DROP, hush))
Denys Vlasenko20704f02011-03-23 17:59:27 +0100332
Denys Vlasenko67e15292020-06-24 13:39:13 +0200333//kbuild:lib-$(CONFIG_SHELL_HUSH) += hush.o match.o shell_common.o
Denys Vlasenko20704f02011-03-23 17:59:27 +0100334//kbuild:lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o
335
Denys Vlasenkof2ed39b2018-04-05 16:46:49 +0200336/* -i (interactive) is also accepted,
337 * but does nothing, therefore not shown in help.
Dan Fandrich89ca2f92010-11-28 01:54:39 +0100338 * NOMMU-specific options are not meant to be used by users,
339 * therefore we don't show them either.
340 */
341//usage:#define hush_trivial_usage
Denys Vlasenko1f60d882021-06-15 10:00:18 +0200342//usage: "[-enxl] [-c 'SCRIPT' [ARG0 ARGS] | FILE [ARGS] | -s [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +0100343//usage:#define hush_full_usage "\n\n"
344//usage: "Unix shell interpreter"
345
Denys Vlasenko67047462016-12-22 15:21:58 +0100346#if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
347 || defined(__APPLE__) \
348 )
349# include <malloc.h> /* for malloc_trim */
350#endif
351#include <glob.h>
352/* #include <dmalloc.h> */
353#if ENABLE_HUSH_CASE
354# include <fnmatch.h>
355#endif
Denys Vlasenko11f2e992017-08-10 16:34:03 +0200356#include <sys/times.h>
Denys Vlasenko67047462016-12-22 15:21:58 +0100357#include <sys/utsname.h> /* for setting $HOSTNAME */
358
359#include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */
360#include "unicode.h"
361#include "shell_common.h"
362#include "math.h"
363#include "match.h"
364#if ENABLE_HUSH_RANDOM_SUPPORT
365# include "random.h"
366#else
367# define CLEAR_RANDOM_T(rnd) ((void)0)
368#endif
Denys Vlasenko41ef41b2018-07-24 16:54:41 +0200369#ifndef O_CLOEXEC
370# define O_CLOEXEC 0
371#endif
Denys Vlasenko67047462016-12-22 15:21:58 +0100372#ifndef F_DUPFD_CLOEXEC
373# define F_DUPFD_CLOEXEC F_DUPFD
374#endif
Denys Vlasenko67047462016-12-22 15:21:58 +0100375
Ron Yorston71df2d32018-11-27 14:34:25 +0000376#if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS && !(ENABLE_ASH || ENABLE_SH_IS_ASH || ENABLE_BASH_IS_ASH)
377# include "embedded_scripts.h"
378#else
379# define NUM_SCRIPTS 0
380#endif
Denis Vlasenko1943aec2009-04-09 14:15:57 +0000381
Kang-Che Sung027d3ab2017-01-11 14:18:15 +0100382/* So far, all bash compat is controlled by one config option */
383/* Separate defines document which part of code implements what */
384#define BASH_PATTERN_SUBST ENABLE_HUSH_BASH_COMPAT
385#define BASH_SUBSTR ENABLE_HUSH_BASH_COMPAT
Kang-Che Sung027d3ab2017-01-11 14:18:15 +0100386#define BASH_SOURCE ENABLE_HUSH_BASH_COMPAT
387#define BASH_HOSTNAME_VAR ENABLE_HUSH_BASH_COMPAT
Ron Yorstona81700b2019-04-15 10:48:29 +0100388#define BASH_EPOCH_VARS ENABLE_HUSH_BASH_COMPAT
Denys Vlasenko4ee824f2017-07-03 01:22:13 +0200389#define BASH_TEST2 (ENABLE_HUSH_BASH_COMPAT && ENABLE_HUSH_TEST)
Denys Vlasenko1f41c882017-08-09 13:52:36 +0200390#define BASH_READ_D ENABLE_HUSH_BASH_COMPAT
Kang-Che Sung027d3ab2017-01-11 14:18:15 +0100391
392
Denys Vlasenko8d7be232009-05-25 16:38:32 +0200393/* Build knobs */
Denis Vlasenko05d3b7c2009-04-09 19:16:15 +0000394#define LEAK_HUNTING 0
395#define BUILD_AS_NOMMU 0
396/* Enable/disable sanity checks. Ok to enable in production,
397 * only adds a bit of bloat. Set to >1 to get non-production level verbosity.
398 * Keeping 1 for now even in released versions.
399 */
400#define HUSH_DEBUG 1
Denys Vlasenko8d7be232009-05-25 16:38:32 +0200401/* Slightly bigger (+200 bytes), but faster hush.
402 * So far it only enables a trick with counting SIGCHLDs and forks,
403 * which allows us to do fewer waitpid's.
404 * (we can detect a case where neither forks were done nor SIGCHLDs happened
405 * and therefore waitpid will return the same result as last time)
406 */
407#define ENABLE_HUSH_FAST 0
Denys Vlasenko9297dbc2010-07-05 21:37:12 +0200408/* TODO: implement simplified code for users which do not need ${var%...} ops
409 * So far ${var%...} ops are always enabled:
410 */
411#define ENABLE_HUSH_DOLLAR_OPS 1
Denis Vlasenko1943aec2009-04-09 14:15:57 +0000412
413
Denis Vlasenko05d3b7c2009-04-09 19:16:15 +0000414#if BUILD_AS_NOMMU
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +0000415# undef BB_MMU
416# undef USE_FOR_NOMMU
417# undef USE_FOR_MMU
418# define BB_MMU 0
419# define USE_FOR_NOMMU(...) __VA_ARGS__
420# define USE_FOR_MMU(...)
421#endif
422
Denys Vlasenko1fcbff22010-06-26 02:40:08 +0200423#include "NUM_APPLETS.h"
Denys Vlasenko14974842010-03-23 01:08:26 +0100424#if NUM_APPLETS == 1
Denis Vlasenko61befda2008-11-25 01:36:03 +0000425/* STANDALONE does not make sense, and won't compile */
Denis Vlasenkoce4acbb2009-04-10 23:23:41 +0000426# undef CONFIG_FEATURE_SH_STANDALONE
427# undef ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000428# undef IF_FEATURE_SH_STANDALONE
Denys Vlasenko14974842010-03-23 01:08:26 +0100429# undef IF_NOT_FEATURE_SH_STANDALONE
430# define ENABLE_FEATURE_SH_STANDALONE 0
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000431# define IF_FEATURE_SH_STANDALONE(...)
432# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
Denis Vlasenko61befda2008-11-25 01:36:03 +0000433#endif
434
Denis Vlasenko05743d72008-02-10 12:10:08 +0000435#if !ENABLE_HUSH_INTERACTIVE
Denis Vlasenkoce4acbb2009-04-10 23:23:41 +0000436# undef ENABLE_FEATURE_EDITING
437# define ENABLE_FEATURE_EDITING 0
438# undef ENABLE_FEATURE_EDITING_FANCY_PROMPT
439# define ENABLE_FEATURE_EDITING_FANCY_PROMPT 0
Denys Vlasenko8cab6672012-04-20 14:48:00 +0200440# undef ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
441# define ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 0
Denis Vlasenko8412d792007-10-01 09:59:47 +0000442#endif
443
Denis Vlasenko424f79b2009-03-22 14:23:34 +0000444/* Do we support ANY keywords? */
445#if ENABLE_HUSH_IF || ENABLE_HUSH_LOOPS || ENABLE_HUSH_CASE
Denis Vlasenkoce4acbb2009-04-10 23:23:41 +0000446# define HAS_KEYWORDS 1
447# define IF_HAS_KEYWORDS(...) __VA_ARGS__
448# define IF_HAS_NO_KEYWORDS(...)
Denis Vlasenko424f79b2009-03-22 14:23:34 +0000449#else
Denis Vlasenkoce4acbb2009-04-10 23:23:41 +0000450# define HAS_KEYWORDS 0
451# define IF_HAS_KEYWORDS(...)
452# define IF_HAS_NO_KEYWORDS(...) __VA_ARGS__
Denis Vlasenko424f79b2009-03-22 14:23:34 +0000453#endif
Denis Vlasenko8412d792007-10-01 09:59:47 +0000454
Denis Vlasenkod01ff132007-05-02 21:40:23 +0000455/* If you comment out one of these below, it will be #defined later
456 * to perform debug printfs to stderr: */
Denys Vlasenko3675c372018-07-23 16:31:21 +0200457#define debug_printf(...) do {} while (0)
Denis Vlasenko400c5b62007-05-04 13:07:27 +0000458/* Finer-grained debug switches */
Denys Vlasenko3675c372018-07-23 16:31:21 +0200459#define debug_printf_parse(...) do {} while (0)
460#define debug_printf_heredoc(...) do {} while (0)
461#define debug_print_tree(a, b) do {} while (0)
462#define debug_printf_exec(...) do {} while (0)
463#define debug_printf_env(...) do {} while (0)
464#define debug_printf_jobs(...) do {} while (0)
465#define debug_printf_expand(...) do {} while (0)
466#define debug_printf_varexp(...) do {} while (0)
467#define debug_printf_glob(...) do {} while (0)
468#define debug_printf_redir(...) do {} while (0)
469#define debug_printf_list(...) do {} while (0)
470#define debug_printf_subst(...) do {} while (0)
471#define debug_printf_prompt(...) do {} while (0)
472#define debug_printf_clean(...) do {} while (0)
Denis Vlasenkod01ff132007-05-02 21:40:23 +0000473
Denis Vlasenkob6e65562009-04-03 16:49:04 +0000474#define ERR_PTR ((void*)(long)1)
475
Denys Vlasenkod5b5c2f2017-01-08 15:46:04 +0100476#define JOB_STATUS_FORMAT "[%u] %-22s %.40s\n"
Denis Vlasenko5ec61322008-06-24 00:50:07 +0000477
Denys Vlasenkoef8985c2019-05-19 16:29:09 +0200478#define _SPECIAL_VARS_STR "_*@$!?#-"
479#define SPECIAL_VARS_STR ("_*@$!?#-" + 1)
480#define NUMERIC_SPECVARS_STR ("_*@$!?#-" + 3)
Kang-Che Sung027d3ab2017-01-11 14:18:15 +0100481#if BASH_PATTERN_SUBST
Denys Vlasenko36f774a2010-09-05 14:45:38 +0200482/* Support / and // replace ops */
483/* Note that // is stored as \ in "encoded" string representation */
484# define VAR_ENCODED_SUBST_OPS "\\/%#:-=+?"
485# define VAR_SUBST_OPS ("\\/%#:-=+?" + 1)
486# define MINUS_PLUS_EQUAL_QUESTION ("\\/%#:-=+?" + 5)
487#else
488# define VAR_ENCODED_SUBST_OPS "%#:-=+?"
489# define VAR_SUBST_OPS "%#:-=+?"
490# define MINUS_PLUS_EQUAL_QUESTION ("%#:-=+?" + 3)
491#endif
Denys Vlasenkoe85248a2010-05-22 06:20:26 +0200492
Denys Vlasenko932b9972018-01-11 12:39:48 +0100493#define SPECIAL_VAR_SYMBOL_STR "\3"
494#define SPECIAL_VAR_SYMBOL 3
495/* The "variable" with name "\1" emits string "\3". Testcase: "echo ^C" */
496#define SPECIAL_VAR_QUOTED_SVS 1
Eric Andersen25f27032001-04-26 23:22:31 +0000497
Denys Vlasenkocb6ff252009-05-04 00:14:30 +0200498struct variable;
499
Denis Vlasenkocc90f442009-04-08 16:40:34 +0000500static const char hush_version_str[] ALIGN1 = "HUSH_VERSION="BB_VER;
501
502/* This supports saving pointers malloced in vfork child,
Denis Vlasenkoc376db32009-04-15 21:49:48 +0000503 * to be freed in the parent.
Denis Vlasenkocc90f442009-04-08 16:40:34 +0000504 */
505#if !BB_MMU
506typedef struct nommu_save_t {
Denys Vlasenkocb6ff252009-05-04 00:14:30 +0200507 struct variable *old_vars;
Denis Vlasenkocc90f442009-04-08 16:40:34 +0000508 char **argv;
Denis Vlasenko27014ed2009-04-15 21:48:23 +0000509 char **argv_from_re_execing;
Denis Vlasenkocc90f442009-04-08 16:40:34 +0000510} nommu_save_t;
511#endif
512
Denys Vlasenko9b782552010-09-08 13:33:26 +0200513enum {
Eric Andersen25f27032001-04-26 23:22:31 +0000514 RES_NONE = 0,
Denis Vlasenko06810332007-05-21 23:30:54 +0000515#if ENABLE_HUSH_IF
Denis Vlasenko17f02e72008-07-14 04:32:29 +0000516 RES_IF ,
517 RES_THEN ,
518 RES_ELIF ,
519 RES_ELSE ,
520 RES_FI ,
Denis Vlasenko06810332007-05-21 23:30:54 +0000521#endif
522#if ENABLE_HUSH_LOOPS
Denis Vlasenko17f02e72008-07-14 04:32:29 +0000523 RES_FOR ,
524 RES_WHILE ,
525 RES_UNTIL ,
526 RES_DO ,
527 RES_DONE ,
Denis Vlasenkod91afa32008-07-29 11:10:01 +0000528#endif
529#if ENABLE_HUSH_LOOPS || ENABLE_HUSH_CASE
Denis Vlasenko17f02e72008-07-14 04:32:29 +0000530 RES_IN ,
Denis Vlasenko06810332007-05-21 23:30:54 +0000531#endif
Denis Vlasenko17f02e72008-07-14 04:32:29 +0000532#if ENABLE_HUSH_CASE
533 RES_CASE ,
Denys Vlasenkoe9bda902009-05-23 16:50:07 +0200534 /* three pseudo-keywords support contrived "case" syntax: */
535 RES_CASE_IN, /* "case ... IN", turns into RES_MATCH when IN is observed */
536 RES_MATCH , /* "word)" */
537 RES_CASE_BODY, /* "this command is inside CASE" */
Denis Vlasenko17f02e72008-07-14 04:32:29 +0000538 RES_ESAC ,
539#endif
540 RES_XXXX ,
541 RES_SNTX
Denys Vlasenko9b782552010-09-08 13:33:26 +0200542};
Denis Vlasenkoc7985b72008-06-17 05:43:38 +0000543
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +0000544typedef struct o_string {
545 char *data;
546 int length; /* position where data is appended */
547 int maxlen;
Denys Vlasenko5b686cb2010-09-08 13:44:34 +0200548 int o_expflags;
Denis Vlasenko02d6f1a2009-04-07 19:56:55 +0000549 /* At least some part of the string was inside '' or "",
550 * possibly empty one: word"", wo''rd etc. */
Denys Vlasenko38292b62010-09-05 14:49:40 +0200551 smallint has_quoted_part;
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +0000552 smallint has_empty_slot;
Denys Vlasenko168579a2018-07-19 13:45:54 +0200553 smallint ended_in_ifs;
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +0000554} o_string;
555enum {
Denys Vlasenko0e13b402010-09-21 12:35:39 +0200556 EXP_FLAG_SINGLEWORD = 0x80, /* must be 0x80 */
557 EXP_FLAG_GLOB = 0x2,
558 /* Protect newly added chars against globbing
559 * by prepending \ to *, ?, [, \ */
560 EXP_FLAG_ESC_GLOB_CHARS = 0x1,
561};
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +0000562/* Used for initialization: o_string foo = NULL_O_STRING; */
563#define NULL_O_STRING { NULL }
564
Denys Vlasenko29f9b722011-05-14 11:27:36 +0200565#ifndef debug_printf_parse
566static const char *const assignment_flag[] = {
567 "MAYBE_ASSIGNMENT",
568 "DEFINITELY_ASSIGNMENT",
569 "NOT_ASSIGNMENT",
570 "WORD_IS_KEYWORD",
571};
572#endif
573
Denys Vlasenko41ef41b2018-07-24 16:54:41 +0200574/* We almost can use standard FILE api, but we need an ability to move
575 * its fd when redirects coincide with it. No api exists for that
576 * (RFE for it at https://sourceware.org/bugzilla/show_bug.cgi?id=21902).
577 * HFILE is our internal alternative. Only supports reading.
578 * Since we now can, we incorporate linked list of all opened HFILEs
579 * into the struct (used to be a separate mini-list).
580 */
581typedef struct HFILE {
582 char *cur;
583 char *end;
584 struct HFILE *next_hfile;
Denys Vlasenko41ef41b2018-07-24 16:54:41 +0200585 int fd;
586 char buf[1024];
587} HFILE;
588
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +0000589typedef struct in_str {
590 const char *p;
Denys Vlasenkod17a91d2016-09-29 18:02:37 +0200591 int peek_buf[2];
Denys Vlasenkocecbc982011-03-30 18:54:52 +0200592 int last_char;
Denys Vlasenko41ef41b2018-07-24 16:54:41 +0200593 HFILE *file;
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +0000594} in_str;
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +0000595
Denys Vlasenko764b2f02009-06-07 16:05:04 +0200596/* The descrip member of this structure is only used to make
597 * debugging output pretty */
598static const struct {
Denys Vlasenko965b7952020-11-30 13:03:03 +0100599 int32_t mode;
Denys Vlasenko764b2f02009-06-07 16:05:04 +0200600 signed char default_fd;
601 char descrip[3];
Denys Vlasenko965b7952020-11-30 13:03:03 +0100602} redir_table[] ALIGN4 = {
Denys Vlasenko764b2f02009-06-07 16:05:04 +0200603 { O_RDONLY, 0, "<" },
604 { O_CREAT|O_TRUNC|O_WRONLY, 1, ">" },
605 { O_CREAT|O_APPEND|O_WRONLY, 1, ">>" },
606 { O_CREAT|O_RDWR, 1, "<>" },
607 { O_RDONLY, 0, "<<" },
608/* Should not be needed. Bogus default_fd helps in debugging */
609/* { O_RDONLY, 77, "<<" }, */
610};
611
Eric Andersen25f27032001-04-26 23:22:31 +0000612struct redir_struct {
Denis Vlasenko55789c62008-06-18 16:30:42 +0000613 struct redir_struct *next;
Denis Vlasenko5ec61322008-06-24 00:50:07 +0000614 char *rd_filename; /* filename */
Denis Vlasenko02d6f1a2009-04-07 19:56:55 +0000615 int rd_fd; /* fd to redirect */
616 /* fd to redirect to, or -3 if rd_fd is to be closed (n>&-) */
617 int rd_dup;
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +0000618 smallint rd_type; /* (enum redir_type) */
619 /* note: for heredocs, rd_filename contains heredoc delimiter,
Denis Vlasenko02d6f1a2009-04-07 19:56:55 +0000620 * and subsequently heredoc itself; and rd_dup is a bitmask:
Denys Vlasenko764b2f02009-06-07 16:05:04 +0200621 * bit 0: do we need to trim leading tabs?
622 * bit 1: is heredoc quoted (<<'delim' syntax) ?
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +0000623 */
Eric Andersen25f27032001-04-26 23:22:31 +0000624};
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +0000625typedef enum redir_type {
Denys Vlasenko764b2f02009-06-07 16:05:04 +0200626 REDIRECT_INPUT = 0,
627 REDIRECT_OVERWRITE = 1,
628 REDIRECT_APPEND = 2,
629 REDIRECT_IO = 3,
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +0000630 REDIRECT_HEREDOC = 4,
Denys Vlasenko764b2f02009-06-07 16:05:04 +0200631 REDIRECT_HEREDOC2 = 5, /* REDIRECT_HEREDOC after heredoc is loaded */
Denis Vlasenkoc96865f2009-04-10 00:20:58 +0000632
633 REDIRFD_CLOSE = -3,
634 REDIRFD_SYNTAX_ERR = -2,
Denis Vlasenko835fcfd2009-04-10 13:51:56 +0000635 REDIRFD_TO_FILE = -1,
636 /* otherwise, rd_fd is redirected to rd_dup */
Denis Vlasenkoc96865f2009-04-10 00:20:58 +0000637
Denis Vlasenko02d6f1a2009-04-07 19:56:55 +0000638 HEREDOC_SKIPTABS = 1,
639 HEREDOC_QUOTED = 2,
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +0000640} redir_type;
641
Eric Andersen25f27032001-04-26 23:22:31 +0000642
Denis Vlasenko9af22c72008-10-09 12:54:58 +0000643struct command {
Denis Vlasenko0c886c62007-01-30 22:30:09 +0000644 pid_t pid; /* 0 if exited */
Denys Vlasenko21b7f1b2018-04-05 15:15:53 +0200645 unsigned assignment_cnt; /* how many argv[i] are assignments? */
Denys Vlasenko5807e182018-02-08 19:19:04 +0100646#if ENABLE_HUSH_LINENO_VAR
Denys Vlasenko6aad1dd2018-01-19 15:37:04 +0100647 unsigned lineno;
648#endif
Denys Vlasenko9d617c42009-06-09 18:40:52 +0200649 smallint cmd_type; /* CMD_xxx */
650#define CMD_NORMAL 0
651#define CMD_SUBSHELL 1
Denys Vlasenkod2241f52020-10-31 03:34:07 +0100652#if BASH_TEST2
653/* used for "[[ EXPR ]]" */
654# define CMD_TEST2_SINGLEWORD_NOGLOB 2
655#endif
Denys Vlasenko77a51a22020-12-29 16:53:11 +0100656#if BASH_TEST2 || ENABLE_HUSH_LOCAL || ENABLE_HUSH_EXPORT || ENABLE_HUSH_READONLY
Denys Vlasenkod2241f52020-10-31 03:34:07 +0100657/* used to prevent word splitting and globbing in "export v=t*" */
658# define CMD_SINGLEWORD_NOGLOB 3
Denis Vlasenkoed055212009-04-11 10:37:10 +0000659#endif
Denys Vlasenko9ca656b2009-06-10 13:39:35 +0200660#if ENABLE_HUSH_FUNCTIONS
Denys Vlasenkod2241f52020-10-31 03:34:07 +0100661# define CMD_FUNCDEF 4
Denys Vlasenko9ca656b2009-06-10 13:39:35 +0200662#endif
663
Denys Vlasenko6696eac2010-11-14 02:01:50 +0100664 smalluint cmd_exitcode;
Denys Vlasenkocb6ff252009-05-04 00:14:30 +0200665 /* if non-NULL, this "command" is { list }, ( list ), or a compound statement */
666 struct pipe *group;
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +0000667#if !BB_MMU
668 char *group_as_string;
669#endif
Denis Vlasenkoed055212009-04-11 10:37:10 +0000670#if ENABLE_HUSH_FUNCTIONS
671 struct function *child_func;
672/* This field is used to prevent a bug here:
Denys Vlasenko9d617c42009-06-09 18:40:52 +0200673 * while...do f1() {a;}; f1; f1() {b;}; f1; done
Denis Vlasenkoed055212009-04-11 10:37:10 +0000674 * When we execute "f1() {a;}" cmd, we create new function and clear
675 * cmd->group, cmd->group_as_string, cmd->argv[0].
Denys Vlasenko9d617c42009-06-09 18:40:52 +0200676 * When we execute "f1() {b;}", we notice that f1 exists,
677 * and that its "parent cmd" struct is still "alive",
Denis Vlasenkoed055212009-04-11 10:37:10 +0000678 * we put those fields back into cmd->xxx
679 * (struct function has ->parent_cmd ptr to facilitate that).
680 * When we loop back, we can execute "f1() {a;}" again and set f1 correctly.
681 * Without this trick, loop would execute a;b;b;b;...
682 * instead of correct sequence a;b;a;b;...
683 * When command is freed, it severs the link
684 * (sets ->child_func->parent_cmd to NULL).
685 */
686#endif
Denis Vlasenko9af22c72008-10-09 12:54:58 +0000687 char **argv; /* command name and arguments */
Denis Vlasenko03eb8bf2007-05-14 16:19:34 +0000688/* argv vector may contain variable references (^Cvar^C, ^C0^C etc)
689 * and on execution these are substituted with their values.
690 * Substitution can make _several_ words out of one argv[n]!
691 * Example: argv[0]=='.^C*^C.' here: echo .$*.
Denis Vlasenkoc7985b72008-06-17 05:43:38 +0000692 * References of the form ^C`cmd arg^C are `cmd arg` substitutions.
Denis Vlasenko03eb8bf2007-05-14 16:19:34 +0000693 */
Denis Vlasenkoed055212009-04-11 10:37:10 +0000694 struct redir_struct *redirects; /* I/O redirections */
695};
Denis Vlasenkof8c1f022009-04-17 11:55:42 +0000696/* Is there anything in this command at all? */
697#define IS_NULL_CMD(cmd) \
698 (!(cmd)->group && !(cmd)->argv && !(cmd)->redirects)
699
Eric Andersen25f27032001-04-26 23:22:31 +0000700struct pipe {
Denis Vlasenkob81b3df2007-04-28 16:48:04 +0000701 struct pipe *next;
Denis Vlasenkob7d8c0d2009-04-10 19:05:43 +0000702 int num_cmds; /* total number of commands in pipe */
Denis Vlasenko9af22c72008-10-09 12:54:58 +0000703 int alive_cmds; /* number of commands running (not exited) */
704 int stopped_cmds; /* number of commands alive, but stopped */
Denis Vlasenkoe3f2f892007-04-28 16:48:27 +0000705#if ENABLE_HUSH_JOB
Denys Vlasenkod5b5c2f2017-01-08 15:46:04 +0100706 unsigned jobid; /* job number */
Denis Vlasenko0c886c62007-01-30 22:30:09 +0000707 pid_t pgrp; /* process group ID for the job */
Denis Vlasenko219e88d2007-05-21 10:18:23 +0000708 char *cmdtext; /* name of job */
Denis Vlasenkob81b3df2007-04-28 16:48:04 +0000709#endif
Denis Vlasenko9af22c72008-10-09 12:54:58 +0000710 struct command *cmds; /* array of commands in pipe */
Denis Vlasenko219e88d2007-05-21 10:18:23 +0000711 smallint followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */
Denis Vlasenko5ec61322008-06-24 00:50:07 +0000712 IF_HAS_KEYWORDS(smallint pi_inverted;) /* "! cmd | cmd" */
713 IF_HAS_KEYWORDS(smallint res_word;) /* needed for if, for, while, until... */
Eric Andersen25f27032001-04-26 23:22:31 +0000714};
Denis Vlasenkoa2b11e32009-04-06 14:11:13 +0000715typedef enum pipe_style {
Denys Vlasenko00a06b92016-11-08 20:35:53 +0100716 PIPE_SEQ = 0,
717 PIPE_AND = 1,
718 PIPE_OR = 2,
719 PIPE_BG = 3,
Denis Vlasenkoa2b11e32009-04-06 14:11:13 +0000720} pipe_style;
Denis Vlasenkof8c1f022009-04-17 11:55:42 +0000721/* Is there anything in this pipe at all? */
722#define IS_NULL_PIPE(pi) \
723 ((pi)->num_cmds == 0 IF_HAS_KEYWORDS( && (pi)->res_word == RES_NONE))
Eric Andersen25f27032001-04-26 23:22:31 +0000724
Denis Vlasenko9af22c72008-10-09 12:54:58 +0000725/* This holds pointers to the various results of parsing */
726struct parse_context {
Denis Vlasenkof9f74292009-04-03 00:07:05 +0000727 /* linked list of pipes */
Denis Vlasenko9af22c72008-10-09 12:54:58 +0000728 struct pipe *list_head;
Denis Vlasenkof9f74292009-04-03 00:07:05 +0000729 /* last pipe (being constructed right now) */
Denis Vlasenko9af22c72008-10-09 12:54:58 +0000730 struct pipe *pipe;
Denis Vlasenkof9f74292009-04-03 00:07:05 +0000731 /* last command in pipe (being constructed right now) */
732 struct command *command;
733 /* last redirect in command->redirects list */
Denis Vlasenko9af22c72008-10-09 12:54:58 +0000734 struct redir_struct *pending_redirect;
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +0200735 o_string word;
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +0000736#if !BB_MMU
737 o_string as_string;
738#endif
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +0200739 smallint is_assignment; /* 0:maybe, 1:yes, 2:no, 3:keyword */
Denis Vlasenko9af22c72008-10-09 12:54:58 +0000740#if HAS_KEYWORDS
741 smallint ctx_res_w;
742 smallint ctx_inverted; /* "! cmd | cmd" */
743#if ENABLE_HUSH_CASE
744 smallint ctx_dsemicolon; /* ";;" seen */
745#endif
Denis Vlasenkof9f74292009-04-03 00:07:05 +0000746 /* bitmask of FLAG_xxx, for figuring out valid reserved words */
747 int old_flag;
748 /* group we are enclosed in:
Denis Vlasenko34d4d892009-04-04 20:24:37 +0000749 * example: "if pipe1; pipe2; then pipe3; fi"
750 * when we see "if" or "then", we malloc and copy current context,
751 * and make ->stack point to it. then we parse pipeN.
752 * when closing "then" / fi" / whatever is found,
753 * we move list_head into ->stack->command->group,
754 * copy ->stack into current context, and delete ->stack.
755 * (parsing of { list } and ( list ) doesn't use this method)
Denis Vlasenkof9f74292009-04-03 00:07:05 +0000756 */
Denis Vlasenko9af22c72008-10-09 12:54:58 +0000757 struct parse_context *stack;
758#endif
759};
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +0200760enum {
761 MAYBE_ASSIGNMENT = 0,
762 DEFINITELY_ASSIGNMENT = 1,
763 NOT_ASSIGNMENT = 2,
764 /* Not an assignment, but next word may be: "if v=xyz cmd;" */
765 WORD_IS_KEYWORD = 3,
766};
Denis Vlasenko9af22c72008-10-09 12:54:58 +0000767
Denis Vlasenkod76c0492007-05-25 02:16:25 +0000768/* On program start, environ points to initial environment.
769 * putenv adds new pointers into it, unsetenv removes them.
770 * Neither of these (de)allocates the strings.
771 * setenv allocates new strings in malloc space and does putenv,
772 * and thus setenv is unusable (leaky) for shell's purposes */
773#define setenv(...) setenv_is_leaky_dont_use()
774struct variable {
775 struct variable *next;
Denis Vlasenko28c0f0f2007-05-25 02:46:01 +0000776 char *varstr; /* points to "name=" portion */
Denis Vlasenkod76c0492007-05-25 02:16:25 +0000777 int max_len; /* if > 0, name is part of initial env; else name is malloced */
Denys Vlasenko332e4112018-04-04 22:32:59 +0200778 uint16_t var_nest_level;
Denis Vlasenkod76c0492007-05-25 02:16:25 +0000779 smallint flg_export; /* putenv should be done on this var */
Denis Vlasenko219e88d2007-05-21 10:18:23 +0000780 smallint flg_read_only;
Eric Andersen9ffb7dd2001-05-19 03:00:46 +0000781};
782
Denis Vlasenkoc8be5ee2007-05-17 15:38:46 +0000783enum {
Denis Vlasenkobcb25532008-07-28 23:04:34 +0000784 BC_BREAK = 1,
785 BC_CONTINUE = 2,
786};
787
Denis Vlasenkoc0ea3292009-04-10 21:22:02 +0000788#if ENABLE_HUSH_FUNCTIONS
Denis Vlasenkob7d8c0d2009-04-10 19:05:43 +0000789struct function {
790 struct function *next;
791 char *name;
Denis Vlasenkoed055212009-04-11 10:37:10 +0000792 struct command *parent_cmd;
Denis Vlasenkob7d8c0d2009-04-10 19:05:43 +0000793 struct pipe *body;
Denys Vlasenkoc1947f12009-10-23 01:30:26 +0200794# if !BB_MMU
Denis Vlasenkoc0ea3292009-04-10 21:22:02 +0000795 char *body_as_string;
Denys Vlasenkoc1947f12009-10-23 01:30:26 +0200796# endif
Denis Vlasenkob7d8c0d2009-04-10 19:05:43 +0000797};
Denis Vlasenkoc0ea3292009-04-10 21:22:02 +0000798#endif
Denis Vlasenkob7d8c0d2009-04-10 19:05:43 +0000799
Denis Vlasenkod76c0492007-05-25 02:16:25 +0000800
Denys Vlasenko6696eac2010-11-14 02:01:50 +0100801/* set -/+o OPT support. (TODO: make it optional)
802 * bash supports the following opts:
803 * allexport off
804 * braceexpand on
805 * emacs on
806 * errexit off
807 * errtrace off
808 * functrace off
809 * hashall on
810 * histexpand off
811 * history on
812 * ignoreeof off
813 * interactive-comments on
814 * keyword off
815 * monitor on
816 * noclobber off
817 * noexec off
818 * noglob off
819 * nolog off
820 * notify off
821 * nounset off
822 * onecmd off
823 * physical off
824 * pipefail off
825 * posix off
826 * privileged off
827 * verbose off
828 * vi off
829 * xtrace off
830 */
Dan Fandrich85c62472010-11-20 13:05:17 -0800831static const char o_opt_strings[] ALIGN1 =
832 "pipefail\0"
833 "noexec\0"
Denys Vlasenko9fda6092017-07-14 13:36:48 +0200834 "errexit\0"
Dan Fandrich85c62472010-11-20 13:05:17 -0800835#if ENABLE_HUSH_MODE_X
836 "xtrace\0"
837#endif
838 ;
Denys Vlasenko6696eac2010-11-14 02:01:50 +0100839enum {
840 OPT_O_PIPEFAIL,
Dan Fandrich85c62472010-11-20 13:05:17 -0800841 OPT_O_NOEXEC,
Denys Vlasenko9fda6092017-07-14 13:36:48 +0200842 OPT_O_ERREXIT,
Dan Fandrich85c62472010-11-20 13:05:17 -0800843#if ENABLE_HUSH_MODE_X
844 OPT_O_XTRACE,
845#endif
Denys Vlasenko6696eac2010-11-14 02:01:50 +0100846 NUM_OPT_O
847};
848
Denis Vlasenkoc8be5ee2007-05-17 15:38:46 +0000849/* "Globals" within this file */
Denis Vlasenkoc8be5ee2007-05-17 15:38:46 +0000850/* Sorted roughly by size (smaller offsets == smaller code) */
851struct globals {
Denis Vlasenkoc8653f62009-04-27 23:29:14 +0000852 /* interactive_fd != 0 means we are an interactive shell.
853 * If we are, then saved_tty_pgrp can also be != 0, meaning
854 * that controlling tty is available. With saved_tty_pgrp == 0,
855 * job control still works, but terminal signals
856 * (^C, ^Z, ^Y, ^\) won't work at all, and background
857 * process groups can only be created with "cmd &".
858 * With saved_tty_pgrp != 0, hush will use tcsetpgrp()
859 * to give tty to the foreground process group,
860 * and will take it back when the group is stopped (^Z)
861 * or killed (^C).
862 */
Denis Vlasenkoc8be5ee2007-05-17 15:38:46 +0000863#if ENABLE_HUSH_INTERACTIVE
864 /* 'interactive_fd' is a fd# open to ctty, if we have one
865 * _AND_ if we decided to act interactively */
866 int interactive_fd;
Denys Vlasenko4ebcdf72019-05-16 15:39:19 +0200867 IF_NOT_FEATURE_EDITING_FANCY_PROMPT(char *PS1;)
Denis Vlasenkoc8653f62009-04-27 23:29:14 +0000868# define G_interactive_fd (G.interactive_fd)
Denis Vlasenko60b392f2009-04-03 19:14:32 +0000869#else
Denis Vlasenkoc8653f62009-04-27 23:29:14 +0000870# define G_interactive_fd 0
Denis Vlasenkoc8be5ee2007-05-17 15:38:46 +0000871#endif
872#if ENABLE_FEATURE_EDITING
873 line_input_t *line_input_state;
874#endif
Denis Vlasenkocc3f20b2008-06-23 22:31:52 +0000875 pid_t root_pid;
Denys Vlasenkodea47882009-10-09 15:40:49 +0200876 pid_t root_ppid;
Denis Vlasenko87a86552008-07-29 19:43:10 +0000877 pid_t last_bg_pid;
Denys Vlasenko20b3d142009-10-09 20:59:39 +0200878#if ENABLE_HUSH_RANDOM_SUPPORT
879 random_t random_gen;
880#endif
Denis Vlasenkoc8be5ee2007-05-17 15:38:46 +0000881#if ENABLE_HUSH_JOB
882 int run_list_level;
Denys Vlasenkod5b5c2f2017-01-08 15:46:04 +0100883 unsigned last_jobid;
Denis Vlasenkoc8653f62009-04-27 23:29:14 +0000884 pid_t saved_tty_pgrp;
Denis Vlasenkoc8be5ee2007-05-17 15:38:46 +0000885 struct pipe *job_list;
Mike Frysinger38478a62009-05-20 04:48:06 -0400886# define G_saved_tty_pgrp (G.saved_tty_pgrp)
887#else
888# define G_saved_tty_pgrp 0
Denis Vlasenkoc8be5ee2007-05-17 15:38:46 +0000889#endif
Denys Vlasenko9fda6092017-07-14 13:36:48 +0200890 /* How deeply are we in context where "set -e" is ignored */
891 int errexit_depth;
892 /* "set -e" rules (do we follow them correctly?):
893 * Exit if pipe, list, or compound command exits with a non-zero status.
894 * Shell does not exit if failed command is part of condition in
895 * if/while, part of && or || list except the last command, any command
896 * in a pipe but the last, or if the command's return value is being
897 * inverted with !. If a compound command other than a subshell returns a
898 * non-zero status because a command failed while -e was being ignored, the
899 * shell does not exit. A trap on ERR, if set, is executed before the shell
900 * exits [ERR is a bashism].
901 *
902 * If a compound command or function executes in a context where -e is
903 * ignored, none of the commands executed within are affected by the -e
904 * setting. If a compound command or function sets -e while executing in a
905 * context where -e is ignored, that setting does not have any effect until
906 * the compound command or the command containing the function call completes.
907 */
908
Denys Vlasenko26777aa2010-11-22 23:49:10 +0100909 char o_opt[NUM_OPT_O];
Denys Vlasenko57542eb2010-11-28 03:59:30 +0100910#if ENABLE_HUSH_MODE_X
911# define G_x_mode (G.o_opt[OPT_O_XTRACE])
912#else
913# define G_x_mode 0
914#endif
Denys Vlasenkod8740b22019-05-19 19:11:21 +0200915 char opt_s;
Denys Vlasenkof3634582019-06-03 12:21:04 +0200916 char opt_c;
Denys Vlasenko8d6eab32018-04-07 17:01:31 +0200917#if ENABLE_HUSH_INTERACTIVE
918 smallint promptmode; /* 0: PS1, 1: PS2 */
919#endif
Denis Vlasenko422cd7c2009-03-31 12:41:52 +0000920 smallint flag_SIGINT;
Denis Vlasenkodadfb492008-07-29 10:16:05 +0000921#if ENABLE_HUSH_LOOPS
Denis Vlasenkobcb25532008-07-28 23:04:34 +0000922 smallint flag_break_continue;
Denis Vlasenkodadfb492008-07-29 10:16:05 +0000923#endif
Denis Vlasenko3d40d8e2009-04-17 23:44:18 +0000924#if ENABLE_HUSH_FUNCTIONS
925 /* 0: outside of a function (or sourced file)
926 * -1: inside of a function, ok to use return builtin
Denis Vlasenkoc8653f62009-04-27 23:29:14 +0000927 * 1: return is invoked, skip all till end of func
Denis Vlasenko3d40d8e2009-04-17 23:44:18 +0000928 */
929 smallint flag_return_in_progress;
Denys Vlasenko04b46bc2016-10-01 22:28:03 +0200930# define G_flag_return_in_progress (G.flag_return_in_progress)
931#else
932# define G_flag_return_in_progress 0
Denis Vlasenko3d40d8e2009-04-17 23:44:18 +0000933#endif
Denis Vlasenkoefea9d22009-04-09 13:43:11 +0000934 smallint exiting; /* used to prevent EXIT trap recursion */
Denys Vlasenkoe6f51ac2019-03-27 18:34:10 +0100935 /* These support $? */
Denis Vlasenkoab2b0642009-04-06 18:42:11 +0000936 smalluint last_exitcode;
Denys Vlasenko5fa05052018-04-03 11:21:13 +0200937 smalluint expand_exitcode;
Denys Vlasenko840a4352017-07-07 22:56:02 +0200938 smalluint last_bg_pid_exitcode;
Denys Vlasenko4e4f88e2017-01-09 07:57:38 +0100939#if ENABLE_HUSH_SET
Denis Vlasenkocc4c6932009-04-05 07:38:48 +0000940 /* are global_argv and global_argv[1..n] malloced? (note: not [0]) */
Denis Vlasenko11fb7cf2009-03-20 10:13:08 +0000941 smalluint global_args_malloced;
Denys Vlasenko4e4f88e2017-01-09 07:57:38 +0100942# define G_global_args_malloced (G.global_args_malloced)
943#else
944# define G_global_args_malloced 0
945#endif
Denys Vlasenkoe6f51ac2019-03-27 18:34:10 +0100946#if ENABLE_HUSH_BASH_COMPAT
947 int dead_job_exitcode; /* for "wait -n" */
948#endif
Denis Vlasenkoe1300f62009-03-22 11:41:18 +0000949 /* how many non-NULL argv's we have. NB: $# + 1 */
950 int global_argc;
Denis Vlasenkoc8be5ee2007-05-17 15:38:46 +0000951 char **global_argv;
Denis Vlasenkocc4c6932009-04-05 07:38:48 +0000952#if !BB_MMU
Denis Vlasenko46f9b6d2009-04-05 10:39:03 +0000953 char *argv0_for_re_execing;
Denis Vlasenkocc4c6932009-04-05 07:38:48 +0000954#endif
Denis Vlasenkodadfb492008-07-29 10:16:05 +0000955#if ENABLE_HUSH_LOOPS
Denis Vlasenko6a2d40f2008-07-28 23:07:06 +0000956 unsigned depth_break_continue;
Denis Vlasenkofcf37c32008-07-29 11:37:15 +0000957 unsigned depth_of_loop;
Denis Vlasenkodadfb492008-07-29 10:16:05 +0000958#endif
Denys Vlasenko238ff982017-08-29 13:38:30 +0200959#if ENABLE_HUSH_GETOPTS
960 unsigned getopt_count;
961#endif
Denis Vlasenkoc8be5ee2007-05-17 15:38:46 +0000962 const char *ifs;
Denys Vlasenko96786362018-04-11 16:02:58 +0200963 char *ifs_whitespace; /* = G.ifs or malloced */
Denis Vlasenkoc8be5ee2007-05-17 15:38:46 +0000964 const char *cwd;
Denys Vlasenko52e460b2010-09-16 16:12:00 +0200965 struct variable *top_var;
Denys Vlasenko29082232010-07-16 13:52:32 +0200966 char **expanded_assignments;
Denys Vlasenko295fef82009-06-03 12:47:26 +0200967 struct variable **shadowed_vars_pp;
Denys Vlasenko332e4112018-04-04 22:32:59 +0200968 unsigned var_nest_level;
969#if ENABLE_HUSH_FUNCTIONS
970# if ENABLE_HUSH_LOCAL
971 unsigned func_nest_level; /* solely to prevent "local v" in non-functions */
Denys Vlasenko295fef82009-06-03 12:47:26 +0200972# endif
Denys Vlasenko332e4112018-04-04 22:32:59 +0200973 struct function *top_func;
Denis Vlasenkoc0ea3292009-04-10 21:22:02 +0000974#endif
Denis Vlasenkod5762932009-03-31 11:22:57 +0000975 /* Signal and trap handling */
Denys Vlasenko8d7be232009-05-25 16:38:32 +0200976#if ENABLE_HUSH_FAST
977 unsigned count_SIGCHLD;
978 unsigned handled_SIGCHLD;
Denys Vlasenkoe2df5f42009-05-26 14:34:10 +0200979 smallint we_have_children;
Denys Vlasenko8d7be232009-05-25 16:38:32 +0200980#endif
Denys Vlasenko5807e182018-02-08 19:19:04 +0100981#if ENABLE_HUSH_LINENO_VAR
Denys Vlasenko08fb82c2019-05-19 15:26:05 +0200982 unsigned parse_lineno;
983 unsigned execute_lineno;
Denys Vlasenko6aad1dd2018-01-19 15:37:04 +0100984#endif
Denys Vlasenko41ef41b2018-07-24 16:54:41 +0200985 HFILE *HFILE_list;
Denys Vlasenko21806562019-11-01 14:16:07 +0100986 HFILE *HFILE_stdin;
Denys Vlasenko10c01312011-05-11 11:49:21 +0200987 /* Which signals have non-DFL handler (even with no traps set)?
988 * Set at the start to:
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +0200989 * (SIGQUIT + maybe SPECIAL_INTERACTIVE_SIGS + maybe SPECIAL_JOBSTOP_SIGS)
Denys Vlasenko10c01312011-05-11 11:49:21 +0200990 * SPECIAL_INTERACTIVE_SIGS are cleared after fork.
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +0200991 * The rest is cleared right before execv syscalls.
Denys Vlasenko10c01312011-05-11 11:49:21 +0200992 * Other than these two times, never modified.
993 */
994 unsigned special_sig_mask;
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +0200995#if ENABLE_HUSH_JOB
996 unsigned fatal_sig_mask;
Denys Vlasenko4e4f88e2017-01-09 07:57:38 +0100997# define G_fatal_sig_mask (G.fatal_sig_mask)
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +0200998#else
Denys Vlasenko75e77de2011-05-12 13:12:47 +0200999# define G_fatal_sig_mask 0
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02001000#endif
Denys Vlasenko7a85c602017-01-08 17:40:18 +01001001#if ENABLE_HUSH_TRAP
Denys Vlasenkocc9ecd92020-02-21 02:18:06 +01001002 int pre_trap_exitcode;
Denys Vlasenkobb095f42020-02-20 16:37:59 +01001003# if ENABLE_HUSH_FUNCTIONS
1004 int return_exitcode;
1005# endif
Denis Vlasenko7566bae2009-03-31 17:24:49 +00001006 char **traps; /* char *traps[NSIG] */
Denys Vlasenko7a85c602017-01-08 17:40:18 +01001007# define G_traps G.traps
1008#else
1009# define G_traps ((char**)NULL)
1010#endif
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02001011 sigset_t pending_set;
Denys Vlasenko44719692017-01-08 18:44:41 +01001012#if ENABLE_HUSH_MEMLEAK
Denis Vlasenkoc73b70c2009-04-08 11:48:57 +00001013 unsigned long memleak_value;
Denys Vlasenko44719692017-01-08 18:44:41 +01001014#endif
Denys Vlasenkoaa449c92018-07-28 12:13:58 +02001015#if ENABLE_HUSH_MODE_X
1016 unsigned x_mode_depth;
1017 /* "set -x" output should not be redirectable with subsequent 2>FILE.
1018 * We dup fd#2 to x_mode_fd when "set -x" is executed, and use it
1019 * for all subsequent output.
1020 */
1021 int x_mode_fd;
1022 o_string x_mode_buf;
1023#endif
Denys Vlasenkoa8e74412018-07-28 12:16:30 +02001024#if HUSH_DEBUG >= 2
Denis Vlasenko0701dca2009-04-11 10:38:47 +00001025 int debug_indent;
Denis Vlasenkoc73b70c2009-04-08 11:48:57 +00001026#endif
Denys Vlasenko0806e402011-05-12 23:06:20 +02001027 struct sigaction sa;
Denys Vlasenkof3634582019-06-03 12:21:04 +02001028 char optstring_buf[sizeof("eixcs")];
Ron Yorstona81700b2019-04-15 10:48:29 +01001029#if BASH_EPOCH_VARS
Denys Vlasenko3c13da32020-12-30 23:48:01 +01001030 char epoch_buf[sizeof("%llu.nnnnnn") + sizeof(long long)*3];
Ron Yorstona81700b2019-04-15 10:48:29 +01001031#endif
Denys Vlasenko0448c552016-09-29 20:25:44 +02001032#if ENABLE_FEATURE_EDITING
1033 char user_input_buf[CONFIG_FEATURE_EDITING_MAX_LEN];
1034#endif
Denis Vlasenkoc8be5ee2007-05-17 15:38:46 +00001035};
Denis Vlasenkoc8be5ee2007-05-17 15:38:46 +00001036#define G (*ptr_to_globals)
Denis Vlasenko87a86552008-07-29 19:43:10 +00001037/* Not #defining name to G.name - this quickly gets unwieldy
1038 * (too many defines). Also, I actually prefer to see when a variable
1039 * is global, thus "G." prefix is a useful hint */
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001040#define INIT_G() do { \
1041 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
Denys Vlasenko0806e402011-05-12 23:06:20 +02001042 /* memset(&G.sa, 0, sizeof(G.sa)); */ \
1043 sigfillset(&G.sa.sa_mask); \
1044 G.sa.sa_flags = SA_RESTART; \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001045} while (0)
Denis Vlasenkoc8be5ee2007-05-17 15:38:46 +00001046
1047
Denis Vlasenko424f79b2009-03-22 14:23:34 +00001048/* Function prototypes for builtins */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001049static int builtin_cd(char **argv) FAST_FUNC;
Denys Vlasenko1cc68042017-01-09 17:10:04 +01001050#if ENABLE_HUSH_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001051static int builtin_echo(char **argv) FAST_FUNC;
Denys Vlasenko1cc68042017-01-09 17:10:04 +01001052#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001053static int builtin_eval(char **argv) FAST_FUNC;
1054static int builtin_exec(char **argv) FAST_FUNC;
1055static int builtin_exit(char **argv) FAST_FUNC;
Denys Vlasenko6ec76d82017-01-08 18:40:41 +01001056#if ENABLE_HUSH_EXPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001057static int builtin_export(char **argv) FAST_FUNC;
Denys Vlasenko6ec76d82017-01-08 18:40:41 +01001058#endif
Denys Vlasenko1e660422017-07-17 21:10:50 +02001059#if ENABLE_HUSH_READONLY
1060static int builtin_readonly(char **argv) FAST_FUNC;
1061#endif
Denis Vlasenko424f79b2009-03-22 14:23:34 +00001062#if ENABLE_HUSH_JOB
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001063static int builtin_fg_bg(char **argv) FAST_FUNC;
1064static int builtin_jobs(char **argv) FAST_FUNC;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00001065#endif
Denys Vlasenko74d40582017-08-11 01:32:46 +02001066#if ENABLE_HUSH_GETOPTS
1067static int builtin_getopts(char **argv) FAST_FUNC;
1068#endif
Denis Vlasenko424f79b2009-03-22 14:23:34 +00001069#if ENABLE_HUSH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001070static int builtin_help(char **argv) FAST_FUNC;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00001071#endif
Denys Vlasenkoff463a82013-05-12 02:45:23 +02001072#if MAX_HISTORY && ENABLE_FEATURE_EDITING
Flemming Madsend96ffda2013-04-07 18:47:24 +02001073static int builtin_history(char **argv) FAST_FUNC;
1074#endif
Denys Vlasenko295fef82009-06-03 12:47:26 +02001075#if ENABLE_HUSH_LOCAL
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001076static int builtin_local(char **argv) FAST_FUNC;
Denys Vlasenko295fef82009-06-03 12:47:26 +02001077#endif
Denys Vlasenko44719692017-01-08 18:44:41 +01001078#if ENABLE_HUSH_MEMLEAK
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001079static int builtin_memleak(char **argv) FAST_FUNC;
Denis Vlasenkoc73b70c2009-04-08 11:48:57 +00001080#endif
Denys Vlasenko1125d7d2017-01-08 17:19:38 +01001081#if ENABLE_HUSH_PRINTF
Mike Frysinger4ebc76c2009-10-15 03:32:39 -04001082static int builtin_printf(char **argv) FAST_FUNC;
1083#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001084static int builtin_pwd(char **argv) FAST_FUNC;
Denys Vlasenko7a85c602017-01-08 17:40:18 +01001085#if ENABLE_HUSH_READ
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001086static int builtin_read(char **argv) FAST_FUNC;
Denys Vlasenko7a85c602017-01-08 17:40:18 +01001087#endif
Denys Vlasenko10d5ece2017-01-08 18:28:43 +01001088#if ENABLE_HUSH_SET
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001089static int builtin_set(char **argv) FAST_FUNC;
Denys Vlasenko10d5ece2017-01-08 18:28:43 +01001090#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001091static int builtin_shift(char **argv) FAST_FUNC;
1092static int builtin_source(char **argv) FAST_FUNC;
Kang-Che Sung027d3ab2017-01-11 14:18:15 +01001093#if ENABLE_HUSH_TEST || BASH_TEST2
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001094static int builtin_test(char **argv) FAST_FUNC;
Denys Vlasenko265062d2017-01-10 15:13:30 +01001095#endif
Denys Vlasenko7a85c602017-01-08 17:40:18 +01001096#if ENABLE_HUSH_TRAP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001097static int builtin_trap(char **argv) FAST_FUNC;
Denys Vlasenko7a85c602017-01-08 17:40:18 +01001098#endif
Denys Vlasenko1125d7d2017-01-08 17:19:38 +01001099#if ENABLE_HUSH_TYPE
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001100static int builtin_type(char **argv) FAST_FUNC;
Denys Vlasenko1125d7d2017-01-08 17:19:38 +01001101#endif
Denys Vlasenko11f2e992017-08-10 16:34:03 +02001102#if ENABLE_HUSH_TIMES
1103static int builtin_times(char **argv) FAST_FUNC;
1104#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001105static int builtin_true(char **argv) FAST_FUNC;
Denys Vlasenkod5933b12017-01-08 18:31:39 +01001106#if ENABLE_HUSH_UMASK
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001107static int builtin_umask(char **argv) FAST_FUNC;
Denys Vlasenkod5933b12017-01-08 18:31:39 +01001108#endif
Denys Vlasenko10d5ece2017-01-08 18:28:43 +01001109#if ENABLE_HUSH_UNSET
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001110static int builtin_unset(char **argv) FAST_FUNC;
Denys Vlasenko10d5ece2017-01-08 18:28:43 +01001111#endif
Denys Vlasenko1125d7d2017-01-08 17:19:38 +01001112#if ENABLE_HUSH_KILL
1113static int builtin_kill(char **argv) FAST_FUNC;
1114#endif
1115#if ENABLE_HUSH_WAIT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001116static int builtin_wait(char **argv) FAST_FUNC;
Denys Vlasenko1125d7d2017-01-08 17:19:38 +01001117#endif
Denis Vlasenko424f79b2009-03-22 14:23:34 +00001118#if ENABLE_HUSH_LOOPS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001119static int builtin_break(char **argv) FAST_FUNC;
1120static int builtin_continue(char **argv) FAST_FUNC;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00001121#endif
Denis Vlasenko3d40d8e2009-04-17 23:44:18 +00001122#if ENABLE_HUSH_FUNCTIONS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001123static int builtin_return(char **argv) FAST_FUNC;
Denis Vlasenko3d40d8e2009-04-17 23:44:18 +00001124#endif
Denis Vlasenko424f79b2009-03-22 14:23:34 +00001125
1126/* Table of built-in functions. They can be forked or not, depending on
1127 * context: within pipes, they fork. As simple commands, they do not.
1128 * When used in non-forking context, they can change global variables
1129 * in the parent shell process. If forked, of course they cannot.
1130 * For example, 'unset foo | whatever' will parse and run, but foo will
1131 * still be set at the end. */
1132struct built_in_command {
Denys Vlasenko17323a62010-01-28 01:57:05 +01001133 const char *b_cmd;
1134 int (*b_function)(char **argv) FAST_FUNC;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00001135#if ENABLE_HUSH_HELP
Denys Vlasenko17323a62010-01-28 01:57:05 +01001136 const char *b_descr;
Denys Vlasenko28a105d2009-06-01 11:26:30 +02001137# define BLTIN(cmd, func, help) { cmd, func, help }
Denis Vlasenko424f79b2009-03-22 14:23:34 +00001138#else
Denys Vlasenko28a105d2009-06-01 11:26:30 +02001139# define BLTIN(cmd, func, help) { cmd, func }
Denis Vlasenko424f79b2009-03-22 14:23:34 +00001140#endif
1141};
1142
Denys Vlasenko965b7952020-11-30 13:03:03 +01001143static const struct built_in_command bltins1[] ALIGN_PTR = {
Denys Vlasenko80f806c2017-01-10 16:51:10 +01001144 BLTIN("." , builtin_source , "Run commands in file"),
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +02001145 BLTIN(":" , builtin_true , NULL),
Denis Vlasenko424f79b2009-03-22 14:23:34 +00001146#if ENABLE_HUSH_JOB
Denys Vlasenko80f806c2017-01-10 16:51:10 +01001147 BLTIN("bg" , builtin_fg_bg , "Resume job in background"),
Denis Vlasenko424f79b2009-03-22 14:23:34 +00001148#endif
1149#if ENABLE_HUSH_LOOPS
Denys Vlasenko80f806c2017-01-10 16:51:10 +01001150 BLTIN("break" , builtin_break , "Exit loop"),
Denis Vlasenko424f79b2009-03-22 14:23:34 +00001151#endif
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +02001152 BLTIN("cd" , builtin_cd , "Change directory"),
Denis Vlasenko424f79b2009-03-22 14:23:34 +00001153#if ENABLE_HUSH_LOOPS
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +02001154 BLTIN("continue" , builtin_continue, "Start new loop iteration"),
Denis Vlasenko424f79b2009-03-22 14:23:34 +00001155#endif
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +02001156 BLTIN("eval" , builtin_eval , "Construct and run shell command"),
1157 BLTIN("exec" , builtin_exec , "Execute command, don't return to shell"),
Denys Vlasenko80f806c2017-01-10 16:51:10 +01001158 BLTIN("exit" , builtin_exit , NULL),
Denys Vlasenko6ec76d82017-01-08 18:40:41 +01001159#if ENABLE_HUSH_EXPORT
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +02001160 BLTIN("export" , builtin_export , "Set environment variables"),
Denys Vlasenko6ec76d82017-01-08 18:40:41 +01001161#endif
Denis Vlasenko424f79b2009-03-22 14:23:34 +00001162#if ENABLE_HUSH_JOB
Denys Vlasenkod2c15bc2017-07-18 18:14:42 +02001163 BLTIN("fg" , builtin_fg_bg , "Bring job to foreground"),
Denis Vlasenko424f79b2009-03-22 14:23:34 +00001164#endif
Denys Vlasenko74d40582017-08-11 01:32:46 +02001165#if ENABLE_HUSH_GETOPTS
1166 BLTIN("getopts" , builtin_getopts , NULL),
1167#endif
Denis Vlasenko424f79b2009-03-22 14:23:34 +00001168#if ENABLE_HUSH_HELP
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +02001169 BLTIN("help" , builtin_help , NULL),
Denis Vlasenko424f79b2009-03-22 14:23:34 +00001170#endif
Denys Vlasenkoff463a82013-05-12 02:45:23 +02001171#if MAX_HISTORY && ENABLE_FEATURE_EDITING
Denys Vlasenko80f806c2017-01-10 16:51:10 +01001172 BLTIN("history" , builtin_history , "Show history"),
Flemming Madsend96ffda2013-04-07 18:47:24 +02001173#endif
Denis Vlasenko34d4d892009-04-04 20:24:37 +00001174#if ENABLE_HUSH_JOB
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +02001175 BLTIN("jobs" , builtin_jobs , "List jobs"),
Denis Vlasenko34d4d892009-04-04 20:24:37 +00001176#endif
Denys Vlasenko1125d7d2017-01-08 17:19:38 +01001177#if ENABLE_HUSH_KILL
1178 BLTIN("kill" , builtin_kill , "Send signals to processes"),
1179#endif
Denys Vlasenko295fef82009-06-03 12:47:26 +02001180#if ENABLE_HUSH_LOCAL
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +02001181 BLTIN("local" , builtin_local , "Set local variables"),
Denys Vlasenko295fef82009-06-03 12:47:26 +02001182#endif
Denys Vlasenko44719692017-01-08 18:44:41 +01001183#if ENABLE_HUSH_MEMLEAK
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +02001184 BLTIN("memleak" , builtin_memleak , NULL),
Denis Vlasenkoc73b70c2009-04-08 11:48:57 +00001185#endif
Denys Vlasenko7a85c602017-01-08 17:40:18 +01001186#if ENABLE_HUSH_READ
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +02001187 BLTIN("read" , builtin_read , "Input into variable"),
Denys Vlasenko7a85c602017-01-08 17:40:18 +01001188#endif
Denys Vlasenko1e660422017-07-17 21:10:50 +02001189#if ENABLE_HUSH_READONLY
1190 BLTIN("readonly" , builtin_readonly, "Make variables read-only"),
1191#endif
Denis Vlasenko3d40d8e2009-04-17 23:44:18 +00001192#if ENABLE_HUSH_FUNCTIONS
Denys Vlasenko80f806c2017-01-10 16:51:10 +01001193 BLTIN("return" , builtin_return , "Return from function"),
Denis Vlasenko3d40d8e2009-04-17 23:44:18 +00001194#endif
Denys Vlasenko10d5ece2017-01-08 18:28:43 +01001195#if ENABLE_HUSH_SET
Denys Vlasenko80f806c2017-01-10 16:51:10 +01001196 BLTIN("set" , builtin_set , "Set positional parameters"),
Denys Vlasenko10d5ece2017-01-08 18:28:43 +01001197#endif
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +02001198 BLTIN("shift" , builtin_shift , "Shift positional parameters"),
Kang-Che Sung027d3ab2017-01-11 14:18:15 +01001199#if BASH_SOURCE
Denys Vlasenko80f806c2017-01-10 16:51:10 +01001200 BLTIN("source" , builtin_source , NULL),
Denys Vlasenko82731b42010-05-17 17:49:52 +02001201#endif
Denys Vlasenko11f2e992017-08-10 16:34:03 +02001202#if ENABLE_HUSH_TIMES
1203 BLTIN("times" , builtin_times , NULL),
1204#endif
Denys Vlasenko7a85c602017-01-08 17:40:18 +01001205#if ENABLE_HUSH_TRAP
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +02001206 BLTIN("trap" , builtin_trap , "Trap signals"),
Denys Vlasenko7a85c602017-01-08 17:40:18 +01001207#endif
Denys Vlasenko2bba5912014-03-14 12:43:57 +01001208 BLTIN("true" , builtin_true , NULL),
Denys Vlasenko1125d7d2017-01-08 17:19:38 +01001209#if ENABLE_HUSH_TYPE
Denys Vlasenko651a2692010-03-23 16:25:17 +01001210 BLTIN("type" , builtin_type , "Show command type"),
Denys Vlasenko1125d7d2017-01-08 17:19:38 +01001211#endif
Denys Vlasenko7a85c602017-01-08 17:40:18 +01001212#if ENABLE_HUSH_ULIMIT
Denys Vlasenko10d5ece2017-01-08 18:28:43 +01001213 BLTIN("ulimit" , shell_builtin_ulimit, "Control resource limits"),
Denys Vlasenko7a85c602017-01-08 17:40:18 +01001214#endif
Denys Vlasenkod5933b12017-01-08 18:31:39 +01001215#if ENABLE_HUSH_UMASK
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +02001216 BLTIN("umask" , builtin_umask , "Set file creation mask"),
Denys Vlasenkod5933b12017-01-08 18:31:39 +01001217#endif
Denys Vlasenko10d5ece2017-01-08 18:28:43 +01001218#if ENABLE_HUSH_UNSET
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +02001219 BLTIN("unset" , builtin_unset , "Unset variables"),
Denys Vlasenko10d5ece2017-01-08 18:28:43 +01001220#endif
Denys Vlasenko1125d7d2017-01-08 17:19:38 +01001221#if ENABLE_HUSH_WAIT
Denys Vlasenkod2c15bc2017-07-18 18:14:42 +02001222 BLTIN("wait" , builtin_wait , "Wait for process to finish"),
Denys Vlasenko1125d7d2017-01-08 17:19:38 +01001223#endif
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +02001224};
Denys Vlasenko80f806c2017-01-10 16:51:10 +01001225/* These builtins won't be used if we are on NOMMU and need to re-exec
1226 * (it's cheaper to run an external program in this case):
1227 */
Denys Vlasenko965b7952020-11-30 13:03:03 +01001228static const struct built_in_command bltins2[] ALIGN_PTR = {
Denys Vlasenko265062d2017-01-10 15:13:30 +01001229#if ENABLE_HUSH_TEST
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +02001230 BLTIN("[" , builtin_test , NULL),
Denys Vlasenko265062d2017-01-10 15:13:30 +01001231#endif
Denys Vlasenko8944c672017-01-11 14:22:00 +01001232#if BASH_TEST2
1233 BLTIN("[[" , builtin_test , NULL),
1234#endif
Denys Vlasenko1cc68042017-01-09 17:10:04 +01001235#if ENABLE_HUSH_ECHO
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +02001236 BLTIN("echo" , builtin_echo , NULL),
Denys Vlasenko1cc68042017-01-09 17:10:04 +01001237#endif
Denys Vlasenko1125d7d2017-01-08 17:19:38 +01001238#if ENABLE_HUSH_PRINTF
Mike Frysinger4ebc76c2009-10-15 03:32:39 -04001239 BLTIN("printf" , builtin_printf , NULL),
1240#endif
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +02001241 BLTIN("pwd" , builtin_pwd , NULL),
Denys Vlasenko265062d2017-01-10 15:13:30 +01001242#if ENABLE_HUSH_TEST
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +02001243 BLTIN("test" , builtin_test , NULL),
Denys Vlasenko265062d2017-01-10 15:13:30 +01001244#endif
Denis Vlasenko424f79b2009-03-22 14:23:34 +00001245};
1246
Denis Vlasenkoc8be5ee2007-05-17 15:38:46 +00001247
Denis Vlasenko0701dca2009-04-11 10:38:47 +00001248/* Debug printouts.
1249 */
Denys Vlasenkoa8e74412018-07-28 12:16:30 +02001250#if HUSH_DEBUG >= 2
Denis Vlasenko0701dca2009-04-11 10:38:47 +00001251/* prevent disasters with G.debug_indent < 0 */
Denys Vlasenko75eb9d22010-12-21 21:18:12 +01001252# define indent() fdprintf(2, "%*s", (G.debug_indent * 2) & 0xff, "")
Denis Vlasenko0701dca2009-04-11 10:38:47 +00001253# define debug_enter() (G.debug_indent++)
1254# define debug_leave() (G.debug_indent--)
1255#else
Denys Vlasenko28a105d2009-06-01 11:26:30 +02001256# define indent() ((void)0)
Denis Vlasenko0701dca2009-04-11 10:38:47 +00001257# define debug_enter() ((void)0)
1258# define debug_leave() ((void)0)
1259#endif
1260
1261#ifndef debug_printf
Denys Vlasenko75eb9d22010-12-21 21:18:12 +01001262# define debug_printf(...) (indent(), fdprintf(2, __VA_ARGS__))
Denis Vlasenko0701dca2009-04-11 10:38:47 +00001263#endif
1264
1265#ifndef debug_printf_parse
Denys Vlasenko75eb9d22010-12-21 21:18:12 +01001266# define debug_printf_parse(...) (indent(), fdprintf(2, __VA_ARGS__))
Denis Vlasenko0701dca2009-04-11 10:38:47 +00001267#endif
1268
Denys Vlasenko3675c372018-07-23 16:31:21 +02001269#ifndef debug_printf_heredoc
1270# define debug_printf_heredoc(...) (indent(), fdprintf(2, __VA_ARGS__))
1271#endif
1272
Denis Vlasenko0701dca2009-04-11 10:38:47 +00001273#ifndef debug_printf_exec
Denys Vlasenko75eb9d22010-12-21 21:18:12 +01001274#define debug_printf_exec(...) (indent(), fdprintf(2, __VA_ARGS__))
Denis Vlasenko0701dca2009-04-11 10:38:47 +00001275#endif
1276
1277#ifndef debug_printf_env
Denys Vlasenko75eb9d22010-12-21 21:18:12 +01001278# define debug_printf_env(...) (indent(), fdprintf(2, __VA_ARGS__))
Denis Vlasenko0701dca2009-04-11 10:38:47 +00001279#endif
1280
1281#ifndef debug_printf_jobs
Denys Vlasenko75eb9d22010-12-21 21:18:12 +01001282# define debug_printf_jobs(...) (indent(), fdprintf(2, __VA_ARGS__))
Denis Vlasenko0701dca2009-04-11 10:38:47 +00001283# define DEBUG_JOBS 1
1284#else
1285# define DEBUG_JOBS 0
1286#endif
1287
1288#ifndef debug_printf_expand
Denys Vlasenko75eb9d22010-12-21 21:18:12 +01001289# define debug_printf_expand(...) (indent(), fdprintf(2, __VA_ARGS__))
Denis Vlasenko0701dca2009-04-11 10:38:47 +00001290# define DEBUG_EXPAND 1
1291#else
1292# define DEBUG_EXPAND 0
1293#endif
1294
Denys Vlasenko1e811b12010-05-22 03:12:29 +02001295#ifndef debug_printf_varexp
Denys Vlasenko75eb9d22010-12-21 21:18:12 +01001296# define debug_printf_varexp(...) (indent(), fdprintf(2, __VA_ARGS__))
Denys Vlasenko1e811b12010-05-22 03:12:29 +02001297#endif
1298
Denis Vlasenko0701dca2009-04-11 10:38:47 +00001299#ifndef debug_printf_glob
Denys Vlasenko75eb9d22010-12-21 21:18:12 +01001300# define debug_printf_glob(...) (indent(), fdprintf(2, __VA_ARGS__))
Denis Vlasenko0701dca2009-04-11 10:38:47 +00001301# define DEBUG_GLOB 1
1302#else
1303# define DEBUG_GLOB 0
1304#endif
1305
Denys Vlasenko2db74612017-07-07 22:07:28 +02001306#ifndef debug_printf_redir
1307# define debug_printf_redir(...) (indent(), fdprintf(2, __VA_ARGS__))
1308#endif
1309
Denis Vlasenko0701dca2009-04-11 10:38:47 +00001310#ifndef debug_printf_list
Denys Vlasenko75eb9d22010-12-21 21:18:12 +01001311# define debug_printf_list(...) (indent(), fdprintf(2, __VA_ARGS__))
Denis Vlasenko0701dca2009-04-11 10:38:47 +00001312#endif
1313
1314#ifndef debug_printf_subst
Denys Vlasenko75eb9d22010-12-21 21:18:12 +01001315# define debug_printf_subst(...) (indent(), fdprintf(2, __VA_ARGS__))
Denis Vlasenko0701dca2009-04-11 10:38:47 +00001316#endif
1317
Denys Vlasenko8d6eab32018-04-07 17:01:31 +02001318#ifndef debug_printf_prompt
1319# define debug_printf_prompt(...) (indent(), fdprintf(2, __VA_ARGS__))
1320#endif
1321
Denis Vlasenko0701dca2009-04-11 10:38:47 +00001322#ifndef debug_printf_clean
Denys Vlasenko75eb9d22010-12-21 21:18:12 +01001323# define debug_printf_clean(...) (indent(), fdprintf(2, __VA_ARGS__))
Denis Vlasenko0701dca2009-04-11 10:38:47 +00001324# define DEBUG_CLEAN 1
1325#else
1326# define DEBUG_CLEAN 0
1327#endif
1328
1329#if DEBUG_EXPAND
1330static void debug_print_strings(const char *prefix, char **vv)
1331{
1332 indent();
Denys Vlasenko75eb9d22010-12-21 21:18:12 +01001333 fdprintf(2, "%s:\n", prefix);
Denis Vlasenko0701dca2009-04-11 10:38:47 +00001334 while (*vv)
Denys Vlasenko75eb9d22010-12-21 21:18:12 +01001335 fdprintf(2, " '%s'\n", *vv++);
Denis Vlasenko0701dca2009-04-11 10:38:47 +00001336}
1337#else
Denys Vlasenko28a105d2009-06-01 11:26:30 +02001338# define debug_print_strings(prefix, vv) ((void)0)
Denis Vlasenko0701dca2009-04-11 10:38:47 +00001339#endif
1340
1341
Denis Vlasenko05d3b7c2009-04-09 19:16:15 +00001342/* Leak hunting. Use hush_leaktool.sh for post-processing.
1343 */
1344#if LEAK_HUNTING
1345static void *xxmalloc(int lineno, size_t size)
Denis Vlasenko90e485c2007-05-23 15:22:50 +00001346{
Denis Vlasenko05d3b7c2009-04-09 19:16:15 +00001347 void *ptr = xmalloc((size + 0xff) & ~0xff);
1348 fdprintf(2, "line %d: malloc %p\n", lineno, ptr);
1349 return ptr;
1350}
1351static void *xxrealloc(int lineno, void *ptr, size_t size)
1352{
1353 ptr = xrealloc(ptr, (size + 0xff) & ~0xff);
1354 fdprintf(2, "line %d: realloc %p\n", lineno, ptr);
1355 return ptr;
1356}
1357static char *xxstrdup(int lineno, const char *str)
1358{
1359 char *ptr = xstrdup(str);
1360 fdprintf(2, "line %d: strdup %p\n", lineno, ptr);
1361 return ptr;
1362}
1363static void xxfree(void *ptr)
1364{
1365 fdprintf(2, "free %p\n", ptr);
1366 free(ptr);
1367}
Denys Vlasenko8391c482010-05-22 17:50:43 +02001368# define xmalloc(s) xxmalloc(__LINE__, s)
1369# define xrealloc(p, s) xxrealloc(__LINE__, p, s)
1370# define xstrdup(s) xxstrdup(__LINE__, s)
1371# define free(p) xxfree(p)
Denis Vlasenko05d3b7c2009-04-09 19:16:15 +00001372#endif
1373
1374
1375/* Syntax and runtime errors. They always abort scripts.
1376 * In interactive use they usually discard unparsed and/or unexecuted commands
1377 * and return to the prompt.
1378 * HUSH_DEBUG >= 2 prints line number in this file where it was detected.
1379 */
1380#if HUSH_DEBUG < 2
Denys Vlasenko39701202017-08-02 19:44:05 +02001381# define msg_and_die_if_script(lineno, ...) msg_and_die_if_script(__VA_ARGS__)
Denis Vlasenkoc0ea3292009-04-10 21:22:02 +00001382# define syntax_error(lineno, msg) syntax_error(msg)
1383# define syntax_error_at(lineno, msg) syntax_error_at(msg)
1384# define syntax_error_unterm_ch(lineno, ch) syntax_error_unterm_ch(ch)
1385# define syntax_error_unterm_str(lineno, s) syntax_error_unterm_str(s)
1386# define syntax_error_unexpected_ch(lineno, ch) syntax_error_unexpected_ch(ch)
Denis Vlasenko05d3b7c2009-04-09 19:16:15 +00001387#endif
1388
Denys Vlasenko39701202017-08-02 19:44:05 +02001389static void die_if_script(void)
1390{
1391 if (!G_interactive_fd) {
1392 if (G.last_exitcode) /* sometines it's 2, not 1 (bash compat) */
1393 xfunc_error_retval = G.last_exitcode;
1394 xfunc_die();
1395 }
1396}
1397
1398static void msg_and_die_if_script(unsigned lineno, const char *fmt, ...)
Denis Vlasenko05d3b7c2009-04-09 19:16:15 +00001399{
Denis Vlasenkod68ae082009-04-09 20:41:34 +00001400 va_list p;
1401
Denis Vlasenko05d3b7c2009-04-09 19:16:15 +00001402#if HUSH_DEBUG >= 2
1403 bb_error_msg("hush.c:%u", lineno);
1404#endif
Denis Vlasenkod68ae082009-04-09 20:41:34 +00001405 va_start(p, fmt);
1406 bb_verror_msg(fmt, p, NULL);
1407 va_end(p);
Denys Vlasenko39701202017-08-02 19:44:05 +02001408 die_if_script();
Mike Frysinger6379bb42009-03-28 18:55:03 +00001409}
Denis Vlasenko05d3b7c2009-04-09 19:16:15 +00001410
Denys Vlasenkocecbc982011-03-30 18:54:52 +02001411static void syntax_error(unsigned lineno UNUSED_PARAM, const char *msg)
Denis Vlasenko05d3b7c2009-04-09 19:16:15 +00001412{
1413 if (msg)
Denys Vlasenkocecbc982011-03-30 18:54:52 +02001414 bb_error_msg("syntax error: %s", msg);
Denis Vlasenko05d3b7c2009-04-09 19:16:15 +00001415 else
James Byrne69374872019-07-02 11:35:03 +02001416 bb_simple_error_msg("syntax error");
Denys Vlasenko39701202017-08-02 19:44:05 +02001417 die_if_script();
Denis Vlasenko05d3b7c2009-04-09 19:16:15 +00001418}
1419
Denys Vlasenkocecbc982011-03-30 18:54:52 +02001420static void syntax_error_at(unsigned lineno UNUSED_PARAM, const char *msg)
Denis Vlasenko05d3b7c2009-04-09 19:16:15 +00001421{
Denys Vlasenkocecbc982011-03-30 18:54:52 +02001422 bb_error_msg("syntax error at '%s'", msg);
Denys Vlasenko39701202017-08-02 19:44:05 +02001423 die_if_script();
Denis Vlasenko05d3b7c2009-04-09 19:16:15 +00001424}
1425
Denys Vlasenkocecbc982011-03-30 18:54:52 +02001426static void syntax_error_unterm_str(unsigned lineno UNUSED_PARAM, const char *s)
Mike Frysinger6a46ab82009-06-01 14:14:36 -04001427{
Denys Vlasenko18bcaf32020-12-23 23:01:18 +01001428 bb_error_msg("syntax error: unterminated %s", s);
Denys Vlasenko39701202017-08-02 19:44:05 +02001429//? source4.tests fails: in bash, echo ${^} in script does not terminate the script
1430// die_if_script();
Mike Frysinger6a46ab82009-06-01 14:14:36 -04001431}
1432
Denis Vlasenkod68ae082009-04-09 20:41:34 +00001433static void syntax_error_unterm_ch(unsigned lineno, char ch)
Denis Vlasenko05d3b7c2009-04-09 19:16:15 +00001434{
Mike Frysinger6a46ab82009-06-01 14:14:36 -04001435 char msg[2] = { ch, '\0' };
1436 syntax_error_unterm_str(lineno, msg);
Denis Vlasenko05d3b7c2009-04-09 19:16:15 +00001437}
1438
Denys Vlasenkocecbc982011-03-30 18:54:52 +02001439static void syntax_error_unexpected_ch(unsigned lineno UNUSED_PARAM, int ch)
Denis Vlasenkoc0ea3292009-04-10 21:22:02 +00001440{
1441 char msg[2];
1442 msg[0] = ch;
1443 msg[1] = '\0';
Denys Vlasenkob05bcaf2017-01-03 11:47:50 +01001444#if HUSH_DEBUG >= 2
1445 bb_error_msg("hush.c:%u", lineno);
1446#endif
Denys Vlasenkocecbc982011-03-30 18:54:52 +02001447 bb_error_msg("syntax error: unexpected %s", ch == EOF ? "EOF" : msg);
Denys Vlasenko39701202017-08-02 19:44:05 +02001448 die_if_script();
Denis Vlasenkoc0ea3292009-04-10 21:22:02 +00001449}
1450
Denis Vlasenko05d3b7c2009-04-09 19:16:15 +00001451#if HUSH_DEBUG < 2
Denys Vlasenko39701202017-08-02 19:44:05 +02001452# undef msg_and_die_if_script
Denis Vlasenko05d3b7c2009-04-09 19:16:15 +00001453# undef syntax_error
1454# undef syntax_error_at
Denis Vlasenkod68ae082009-04-09 20:41:34 +00001455# undef syntax_error_unterm_ch
1456# undef syntax_error_unterm_str
Denis Vlasenkoc0ea3292009-04-10 21:22:02 +00001457# undef syntax_error_unexpected_ch
Denis Vlasenko90e485c2007-05-23 15:22:50 +00001458#else
Denys Vlasenko39701202017-08-02 19:44:05 +02001459# define msg_and_die_if_script(...) msg_and_die_if_script(__LINE__, __VA_ARGS__)
Denis Vlasenkoc0ea3292009-04-10 21:22:02 +00001460# define syntax_error(msg) syntax_error(__LINE__, msg)
1461# define syntax_error_at(msg) syntax_error_at(__LINE__, msg)
1462# define syntax_error_unterm_ch(ch) syntax_error_unterm_ch(__LINE__, ch)
1463# define syntax_error_unterm_str(s) syntax_error_unterm_str(__LINE__, s)
1464# define syntax_error_unexpected_ch(ch) syntax_error_unexpected_ch(__LINE__, ch)
Denis Vlasenko90e485c2007-05-23 15:22:50 +00001465#endif
Eric Andersen25f27032001-04-26 23:22:31 +00001466
Denis Vlasenko552433b2009-04-04 19:29:21 +00001467
Denis Vlasenko05d3b7c2009-04-09 19:16:15 +00001468/* Utility functions
1469 */
Denis Vlasenko55789c62008-06-18 16:30:42 +00001470/* Replace each \x with x in place, return ptr past NUL. */
1471static char *unbackslash(char *src)
1472{
Denys Vlasenko71885402009-09-24 01:44:13 +02001473 char *dst = src = strchrnul(src, '\\');
Denis Vlasenko55789c62008-06-18 16:30:42 +00001474 while (1) {
Denys Vlasenko89e9d552018-04-11 01:15:33 +02001475 if (*src == '\\') {
Denis Vlasenko55789c62008-06-18 16:30:42 +00001476 src++;
Denys Vlasenko89e9d552018-04-11 01:15:33 +02001477 if (*src != '\0') {
1478 /* \x -> x */
1479 *dst++ = *src++;
1480 continue;
1481 }
1482 /* else: "\<nul>". Do not delete this backslash.
1483 * Testcase: eval 'echo ok\'
1484 */
1485 *dst++ = '\\';
1486 /* fallthrough */
1487 }
Denis Vlasenko55789c62008-06-18 16:30:42 +00001488 if ((*dst++ = *src++) == '\0')
1489 break;
1490 }
1491 return dst;
1492}
1493
Denis Vlasenko11fb7cf2009-03-20 10:13:08 +00001494static char **add_strings_to_strings(char **strings, char **add, int need_to_dup)
Denis Vlasenkod65ea392007-10-01 10:02:25 +00001495{
1496 int i;
1497 unsigned count1;
1498 unsigned count2;
1499 char **v;
1500
1501 v = strings;
1502 count1 = 0;
1503 if (v) {
1504 while (*v) {
1505 count1++;
1506 v++;
1507 }
1508 }
1509 count2 = 0;
1510 v = add;
1511 while (*v) {
1512 count2++;
1513 v++;
1514 }
1515 v = xrealloc(strings, (count1 + count2 + 1) * sizeof(char*));
1516 v[count1 + count2] = NULL;
1517 i = count2;
1518 while (--i >= 0)
Denis Vlasenko11fb7cf2009-03-20 10:13:08 +00001519 v[count1 + i] = (need_to_dup ? xstrdup(add[i]) : add[i]);
Denis Vlasenkod65ea392007-10-01 10:02:25 +00001520 return v;
1521}
Denis Vlasenko05d3b7c2009-04-09 19:16:15 +00001522#if LEAK_HUNTING
Denis Vlasenkocc90f442009-04-08 16:40:34 +00001523static char **xx_add_strings_to_strings(int lineno, char **strings, char **add, int need_to_dup)
1524{
1525 char **ptr = add_strings_to_strings(strings, add, need_to_dup);
1526 fdprintf(2, "line %d: add_strings_to_strings %p\n", lineno, ptr);
1527 return ptr;
1528}
1529#define add_strings_to_strings(strings, add, need_to_dup) \
1530 xx_add_strings_to_strings(__LINE__, strings, add, need_to_dup)
1531#endif
Denis Vlasenkod65ea392007-10-01 10:02:25 +00001532
Denys Vlasenkocb6ff252009-05-04 00:14:30 +02001533/* Note: takes ownership of "add" ptr (it is not strdup'ed) */
Denis Vlasenko22d10a02008-10-13 08:53:43 +00001534static char **add_string_to_strings(char **strings, char *add)
Denis Vlasenkod65ea392007-10-01 10:02:25 +00001535{
1536 char *v[2];
Denis Vlasenkod65ea392007-10-01 10:02:25 +00001537 v[0] = add;
1538 v[1] = NULL;
Denis Vlasenko11fb7cf2009-03-20 10:13:08 +00001539 return add_strings_to_strings(strings, v, /*dup:*/ 0);
Denis Vlasenko22d10a02008-10-13 08:53:43 +00001540}
Denis Vlasenko05d3b7c2009-04-09 19:16:15 +00001541#if LEAK_HUNTING
Denis Vlasenkocc90f442009-04-08 16:40:34 +00001542static char **xx_add_string_to_strings(int lineno, char **strings, char *add)
1543{
1544 char **ptr = add_string_to_strings(strings, add);
1545 fdprintf(2, "line %d: add_string_to_strings %p\n", lineno, ptr);
1546 return ptr;
1547}
1548#define add_string_to_strings(strings, add) \
1549 xx_add_string_to_strings(__LINE__, strings, add)
1550#endif
Denis Vlasenkod65ea392007-10-01 10:02:25 +00001551
Denys Vlasenkoacdc49c2009-05-04 01:58:10 +02001552static void free_strings(char **strings)
Denis Vlasenkod65ea392007-10-01 10:02:25 +00001553{
Denis Vlasenkoafd7a8d2008-10-09 16:29:44 +00001554 char **v;
1555
1556 if (!strings)
1557 return;
Denis Vlasenkoafd7a8d2008-10-09 16:29:44 +00001558 v = strings;
1559 while (*v) {
Denys Vlasenkoacdc49c2009-05-04 01:58:10 +02001560 free(*v);
1561 v++;
Denis Vlasenkod65ea392007-10-01 10:02:25 +00001562 }
Denis Vlasenkoafd7a8d2008-10-09 16:29:44 +00001563 free(strings);
Denis Vlasenkod65ea392007-10-01 10:02:25 +00001564}
1565
Denys Vlasenko9acd63c2018-03-28 18:35:07 +02001566static int dup_CLOEXEC(int fd, int avoid_fd)
Denys Vlasenkoaa3576a2016-08-22 19:54:12 +02001567{
Denys Vlasenko2db74612017-07-07 22:07:28 +02001568 int newfd;
1569 repeat:
Denys Vlasenko9acd63c2018-03-28 18:35:07 +02001570 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
1571 if (newfd >= 0) {
1572 if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
1573 fcntl(newfd, F_SETFD, FD_CLOEXEC);
1574 } else { /* newfd < 0 */
Denys Vlasenko2db74612017-07-07 22:07:28 +02001575 if (errno == EBUSY)
1576 goto repeat;
1577 if (errno == EINTR)
1578 goto repeat;
1579 }
1580 return newfd;
1581}
1582
Denys Vlasenko657e9002017-07-30 23:34:04 +02001583static int xdup_CLOEXEC_and_close(int fd, int avoid_fd)
Denys Vlasenko2db74612017-07-07 22:07:28 +02001584{
1585 int newfd;
1586 repeat:
Denys Vlasenko657e9002017-07-30 23:34:04 +02001587 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
Denys Vlasenko2db74612017-07-07 22:07:28 +02001588 if (newfd < 0) {
1589 if (errno == EBUSY)
1590 goto repeat;
1591 if (errno == EINTR)
1592 goto repeat;
Denys Vlasenkoaa3576a2016-08-22 19:54:12 +02001593 /* fd was not open? */
1594 if (errno == EBADF)
1595 return fd;
1596 xfunc_die();
1597 }
Denys Vlasenko657e9002017-07-30 23:34:04 +02001598 if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
1599 fcntl(newfd, F_SETFD, FD_CLOEXEC);
Denys Vlasenkoaa3576a2016-08-22 19:54:12 +02001600 close(fd);
1601 return newfd;
1602}
1603
1604
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02001605/* Manipulating HFILEs */
1606static HFILE *hfopen(const char *name)
Denys Vlasenko7b25b1c2016-08-20 15:58:34 +02001607{
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02001608 HFILE *fp;
1609 int fd;
1610
1611 fd = STDIN_FILENO;
1612 if (name) {
1613 fd = open(name, O_RDONLY | O_CLOEXEC);
1614 if (fd < 0)
1615 return NULL;
1616 if (O_CLOEXEC == 0) /* ancient libc */
1617 close_on_exec_on(fd);
Denys Vlasenko7b25b1c2016-08-20 15:58:34 +02001618 }
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02001619
1620 fp = xmalloc(sizeof(*fp));
Denys Vlasenko21806562019-11-01 14:16:07 +01001621 if (name == NULL)
1622 G.HFILE_stdin = fp;
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02001623 fp->fd = fd;
1624 fp->cur = fp->end = fp->buf;
1625 fp->next_hfile = G.HFILE_list;
1626 G.HFILE_list = fp;
Denys Vlasenko7b25b1c2016-08-20 15:58:34 +02001627 return fp;
1628}
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02001629static void hfclose(HFILE *fp)
Denys Vlasenko7b25b1c2016-08-20 15:58:34 +02001630{
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02001631 HFILE **pp = &G.HFILE_list;
Denys Vlasenko7b25b1c2016-08-20 15:58:34 +02001632 while (*pp) {
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02001633 HFILE *cur = *pp;
1634 if (cur == fp) {
1635 *pp = cur->next_hfile;
Denys Vlasenko7b25b1c2016-08-20 15:58:34 +02001636 break;
1637 }
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02001638 pp = &cur->next_hfile;
Denys Vlasenko7b25b1c2016-08-20 15:58:34 +02001639 }
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02001640 if (fp->fd >= 0)
1641 close(fp->fd);
1642 free(fp);
Denys Vlasenko7b25b1c2016-08-20 15:58:34 +02001643}
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02001644static int refill_HFILE_and_getc(HFILE *fp)
Denys Vlasenkoaa3576a2016-08-22 19:54:12 +02001645{
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02001646 int n;
1647
1648 if (fp->fd < 0) {
1649 /* Already saw EOF */
1650 return EOF;
1651 }
Denys Vlasenko521220e2020-12-23 23:44:55 +01001652#if ENABLE_HUSH_INTERACTIVE && !ENABLE_FEATURE_EDITING
1653 /* If user presses ^C, read() restarts after SIGINT (we use SA_RESTART).
1654 * IOW: ^C will not immediately stop line input.
1655 * But poll() is different: it does NOT restart after signals.
1656 */
1657 if (fp == G.HFILE_stdin) {
1658 struct pollfd pfd[1];
1659 pfd[0].fd = fp->fd;
1660 pfd[0].events = POLLIN;
1661 n = poll(pfd, 1, -1);
1662 if (n < 0
1663 /*&& errno == EINTR - assumed true */
1664 && sigismember(&G.pending_set, SIGINT)
1665 ) {
1666 return '\0';
1667 }
1668 }
1669#else
1670/* if FEATURE_EDITING=y, we do not use this routine for interactive input */
1671#endif
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02001672 /* Try to buffer more input */
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02001673 n = safe_read(fp->fd, fp->buf, sizeof(fp->buf));
1674 if (n < 0) {
James Byrne69374872019-07-02 11:35:03 +02001675 bb_simple_perror_msg("read error");
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02001676 n = 0;
1677 }
Denys Vlasenko93e2a222020-12-23 12:23:21 +01001678 fp->cur = fp->buf;
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02001679 fp->end = fp->buf + n;
1680 if (n == 0) {
1681 /* EOF/error */
1682 close(fp->fd);
1683 fp->fd = -1;
1684 return EOF;
1685 }
1686 return (unsigned char)(*fp->cur++);
1687}
1688/* Inlined for common case of non-empty buffer.
1689 */
1690static ALWAYS_INLINE int hfgetc(HFILE *fp)
1691{
1692 if (fp->cur < fp->end)
1693 return (unsigned char)(*fp->cur++);
1694 /* Buffer empty */
1695 return refill_HFILE_and_getc(fp);
1696}
1697static int move_HFILEs_on_redirect(int fd, int avoid_fd)
1698{
1699 HFILE *fl = G.HFILE_list;
Denys Vlasenkoaa3576a2016-08-22 19:54:12 +02001700 while (fl) {
1701 if (fd == fl->fd) {
1702 /* We use it only on script files, they are all CLOEXEC */
Denys Vlasenko657e9002017-07-30 23:34:04 +02001703 fl->fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
Denys Vlasenko2db74612017-07-07 22:07:28 +02001704 debug_printf_redir("redirect_fd %d: matches a script fd, moving it to %d\n", fd, fl->fd);
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02001705 return 1; /* "found and moved" */
Denys Vlasenkoaa3576a2016-08-22 19:54:12 +02001706 }
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02001707 fl = fl->next_hfile;
Denys Vlasenkoaa3576a2016-08-22 19:54:12 +02001708 }
Denys Vlasenkoaa449c92018-07-28 12:13:58 +02001709#if ENABLE_HUSH_MODE_X
1710 if (G.x_mode_fd > 0 && fd == G.x_mode_fd) {
1711 G.x_mode_fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
1712 return 1; /* "found and moved" */
1713 }
1714#endif
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02001715 return 0; /* "not in the list" */
Denys Vlasenkoaa3576a2016-08-22 19:54:12 +02001716}
Denys Vlasenko4ee824f2017-07-03 01:22:13 +02001717#if ENABLE_FEATURE_SH_STANDALONE && BB_MMU
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02001718static void close_all_HFILE_list(void)
Denys Vlasenkoaa3576a2016-08-22 19:54:12 +02001719{
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02001720 HFILE *fl = G.HFILE_list;
Denys Vlasenkoaa3576a2016-08-22 19:54:12 +02001721 while (fl) {
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02001722 /* hfclose would also free HFILE object.
Denys Vlasenkoaa3576a2016-08-22 19:54:12 +02001723 * It is disastrous if we share memory with a vforked parent.
1724 * I'm not sure we never come here after vfork.
1725 * Therefore just close fd, nothing more.
Denys Vlasenkoe9dccab2018-08-05 14:55:01 +02001726 *
1727 * ">" instead of ">=": we don't close fd#0,
1728 * interactive shell uses hfopen(NULL) as stdin input
1729 * which has fl->fd == 0, but fd#0 gets redirected in pipes.
1730 * If we'd close it here, then e.g. interactive "set | sort"
1731 * with NOFORKed sort, would have sort's input fd closed.
Denys Vlasenkoaa3576a2016-08-22 19:54:12 +02001732 */
Denys Vlasenkoe9dccab2018-08-05 14:55:01 +02001733 if (fl->fd > 0)
1734 /*hfclose(fl); - unsafe */
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02001735 close(fl->fd);
1736 fl = fl->next_hfile;
Denys Vlasenkoaa3576a2016-08-22 19:54:12 +02001737 }
1738}
Denys Vlasenko7b25b1c2016-08-20 15:58:34 +02001739#endif
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02001740static int fd_in_HFILEs(int fd)
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02001741{
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02001742 HFILE *fl = G.HFILE_list;
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02001743 while (fl) {
1744 if (fl->fd == fd)
1745 return 1;
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02001746 fl = fl->next_hfile;
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02001747 }
1748 return 0;
1749}
Denys Vlasenko7b25b1c2016-08-20 15:58:34 +02001750
1751
Denis Vlasenko270b1c32009-04-17 18:54:50 +00001752/* Helpers for setting new $n and restoring them back
1753 */
1754typedef struct save_arg_t {
1755 char *sv_argv0;
1756 char **sv_g_argv;
1757 int sv_g_argc;
Denys Vlasenko4e4f88e2017-01-09 07:57:38 +01001758 IF_HUSH_SET(smallint sv_g_malloced;)
Denis Vlasenko270b1c32009-04-17 18:54:50 +00001759} save_arg_t;
1760
1761static void save_and_replace_G_args(save_arg_t *sv, char **argv)
1762{
Denis Vlasenko270b1c32009-04-17 18:54:50 +00001763 sv->sv_argv0 = argv[0];
1764 sv->sv_g_argv = G.global_argv;
1765 sv->sv_g_argc = G.global_argc;
Denys Vlasenko4e4f88e2017-01-09 07:57:38 +01001766 IF_HUSH_SET(sv->sv_g_malloced = G.global_args_malloced;)
Denis Vlasenko270b1c32009-04-17 18:54:50 +00001767
1768 argv[0] = G.global_argv[0]; /* retain $0 */
1769 G.global_argv = argv;
Denys Vlasenko4e4f88e2017-01-09 07:57:38 +01001770 IF_HUSH_SET(G.global_args_malloced = 0;)
Denis Vlasenko270b1c32009-04-17 18:54:50 +00001771
Denys Vlasenkod4e4fdb2017-07-03 21:31:16 +02001772 G.global_argc = 1 + string_array_len(argv + 1);
Denis Vlasenko270b1c32009-04-17 18:54:50 +00001773}
1774
1775static void restore_G_args(save_arg_t *sv, char **argv)
1776{
Denys Vlasenko4e4f88e2017-01-09 07:57:38 +01001777#if ENABLE_HUSH_SET
Denis Vlasenko270b1c32009-04-17 18:54:50 +00001778 if (G.global_args_malloced) {
1779 /* someone ran "set -- arg1 arg2 ...", undo */
Denys Vlasenko4e4f88e2017-01-09 07:57:38 +01001780 char **pp = G.global_argv;
Denis Vlasenko270b1c32009-04-17 18:54:50 +00001781 while (*++pp) /* note: does not free $0 */
1782 free(*pp);
1783 free(G.global_argv);
1784 }
Denys Vlasenko4e4f88e2017-01-09 07:57:38 +01001785#endif
Denis Vlasenko270b1c32009-04-17 18:54:50 +00001786 argv[0] = sv->sv_argv0;
1787 G.global_argv = sv->sv_g_argv;
1788 G.global_argc = sv->sv_g_argc;
Denys Vlasenko4e4f88e2017-01-09 07:57:38 +01001789 IF_HUSH_SET(G.global_args_malloced = sv->sv_g_malloced;)
Denis Vlasenko270b1c32009-04-17 18:54:50 +00001790}
1791
1792
Denis Vlasenkod5762932009-03-31 11:22:57 +00001793/* Basic theory of signal handling in shell
1794 * ========================================
Denis Vlasenko7b830e72009-03-31 13:05:32 +00001795 * This does not describe what hush does, rather, it is current understanding
1796 * what it _should_ do. If it doesn't, it's a bug.
Denis Vlasenkod5762932009-03-31 11:22:57 +00001797 * http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#trap
1798 *
1799 * Signals are handled only after each pipe ("cmd | cmd | cmd" thing)
1800 * is finished or backgrounded. It is the same in interactive and
1801 * non-interactive shells, and is the same regardless of whether
Denis Vlasenko7b830e72009-03-31 13:05:32 +00001802 * a user trap handler is installed or a shell special one is in effect.
Denys Vlasenko69b1cef2009-09-21 10:21:44 +02001803 * ^C or ^Z from keyboard seems to execute "at once" because it usually
Denis Vlasenkod5762932009-03-31 11:22:57 +00001804 * backgrounds (i.e. stops) or kills all members of currently running
1805 * pipe.
1806 *
Denys Vlasenko8bd810b2013-11-28 01:50:01 +01001807 * Wait builtin is interruptible by signals for which user trap is set
Denis Vlasenkod5762932009-03-31 11:22:57 +00001808 * or by SIGINT in interactive shell.
1809 *
1810 * Trap handlers will execute even within trap handlers. (right?)
1811 *
Denys Vlasenkoe89a2412010-01-12 15:19:31 +01001812 * User trap handlers are forgotten when subshell ("(cmd)") is entered,
1813 * except for handlers set to '' (empty string).
Denis Vlasenkod5762932009-03-31 11:22:57 +00001814 *
1815 * If job control is off, backgrounded commands ("cmd &")
Denis Vlasenko7b830e72009-03-31 13:05:32 +00001816 * have SIGINT, SIGQUIT set to SIG_IGN.
Denis Vlasenkod5762932009-03-31 11:22:57 +00001817 *
Denys Vlasenko28a105d2009-06-01 11:26:30 +02001818 * Commands which are run in command substitution ("`cmd`")
Denis Vlasenko7b830e72009-03-31 13:05:32 +00001819 * have SIGTTIN, SIGTTOU, SIGTSTP set to SIG_IGN.
Denis Vlasenkod5762932009-03-31 11:22:57 +00001820 *
Denys Vlasenko4b7db4f2009-05-29 10:39:06 +02001821 * Ordinary commands have signals set to SIG_IGN/DFL as inherited
Denis Vlasenko7b830e72009-03-31 13:05:32 +00001822 * by the shell from its parent.
Denis Vlasenkod5762932009-03-31 11:22:57 +00001823 *
Denys Vlasenko28a105d2009-06-01 11:26:30 +02001824 * Signals which differ from SIG_DFL action
Denis Vlasenko7b830e72009-03-31 13:05:32 +00001825 * (note: child (i.e., [v]forked) shell is not an interactive shell):
Denis Vlasenkod5762932009-03-31 11:22:57 +00001826 *
1827 * SIGQUIT: ignore
1828 * SIGTERM (interactive): ignore
Denis Vlasenko7b830e72009-03-31 13:05:32 +00001829 * SIGHUP (interactive):
1830 * send SIGCONT to stopped jobs, send SIGHUP to all jobs and exit
Denis Vlasenkod5762932009-03-31 11:22:57 +00001831 * SIGTTIN, SIGTTOU, SIGTSTP (if job control is on): ignore
Denis Vlasenkoc4ada792009-04-15 23:29:00 +00001832 * Note that ^Z is handled not by trapping SIGTSTP, but by seeing
1833 * that all pipe members are stopped. Try this in bash:
1834 * while :; do :; done - ^Z does not background it
1835 * (while :; do :; done) - ^Z backgrounds it
Denis Vlasenkod5762932009-03-31 11:22:57 +00001836 * SIGINT (interactive): wait for last pipe, ignore the rest
Denis Vlasenko7b830e72009-03-31 13:05:32 +00001837 * of the command line, show prompt. NB: ^C does not send SIGINT
1838 * to interactive shell while shell is waiting for a pipe,
1839 * since shell is bg'ed (is not in foreground process group).
Denis Vlasenko7b830e72009-03-31 13:05:32 +00001840 * Example 1: this waits 5 sec, but does not execute ls:
1841 * "echo $$; sleep 5; ls -l" + "kill -INT <pid>"
1842 * Example 2: this does not wait and does not execute ls:
1843 * "echo $$; sleep 5 & wait; ls -l" + "kill -INT <pid>"
1844 * Example 3: this does not wait 5 sec, but executes ls:
1845 * "sleep 5; ls -l" + press ^C
Denys Vlasenkob8709032011-05-08 21:20:01 +02001846 * Example 4: this does not wait and does not execute ls:
1847 * "sleep 5 & wait; ls -l" + press ^C
Denis Vlasenkod5762932009-03-31 11:22:57 +00001848 *
1849 * (What happens to signals which are IGN on shell start?)
1850 * (What happens with signal mask on shell start?)
1851 *
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02001852 * Old implementation
1853 * ==================
Denis Vlasenkod5762932009-03-31 11:22:57 +00001854 * We use in-kernel pending signal mask to determine which signals were sent.
1855 * We block all signals which we don't want to take action immediately,
1856 * i.e. we block all signals which need to have special handling as described
1857 * above, and all signals which have traps set.
1858 * After each pipe execution, we extract any pending signals via sigtimedwait()
1859 * and act on them.
1860 *
Denys Vlasenko10c01312011-05-11 11:49:21 +02001861 * unsigned special_sig_mask: a mask of such "special" signals
Denis Vlasenkod5762932009-03-31 11:22:57 +00001862 * sigset_t blocked_set: current blocked signal set
1863 *
Denis Vlasenko7b830e72009-03-31 13:05:32 +00001864 * "trap - SIGxxx":
Denys Vlasenko10c01312011-05-11 11:49:21 +02001865 * clear bit in blocked_set unless it is also in special_sig_mask
Denis Vlasenko7b830e72009-03-31 13:05:32 +00001866 * "trap 'cmd' SIGxxx":
1867 * set bit in blocked_set (even if 'cmd' is '')
Denis Vlasenkod5762932009-03-31 11:22:57 +00001868 * after [v]fork, if we plan to be a shell:
Denis Vlasenko6b9e0532009-04-18 01:23:21 +00001869 * unblock signals with special interactive handling
1870 * (child shell is not interactive),
Denys Vlasenkoe89a2412010-01-12 15:19:31 +01001871 * unset all traps except '' (note: regardless of child shell's type - {}, (), etc)
Denis Vlasenkod5762932009-03-31 11:22:57 +00001872 * after [v]fork, if we plan to exec:
Denys Vlasenko69b1cef2009-09-21 10:21:44 +02001873 * POSIX says fork clears pending signal mask in child - no need to clear it.
Denis Vlasenko7b830e72009-03-31 13:05:32 +00001874 * Restore blocked signal set to one inherited by shell just prior to exec.
Denis Vlasenkod5762932009-03-31 11:22:57 +00001875 *
Denis Vlasenko7566bae2009-03-31 17:24:49 +00001876 * Note: as a result, we do not use signal handlers much. The only uses
Denys Vlasenko8d7be232009-05-25 16:38:32 +02001877 * are to count SIGCHLDs
Denis Vlasenko7566bae2009-03-31 17:24:49 +00001878 * and to restore tty pgrp on signal-induced exit.
Denys Vlasenko4ea0ca82009-09-25 12:58:37 +02001879 *
Denys Vlasenko67f71862009-09-25 14:21:06 +02001880 * Note 2 (compat):
Denys Vlasenko4ea0ca82009-09-25 12:58:37 +02001881 * Standard says "When a subshell is entered, traps that are not being ignored
1882 * are set to the default actions". bash interprets it so that traps which
Denys Vlasenkoe89a2412010-01-12 15:19:31 +01001883 * are set to '' (ignore) are NOT reset to defaults. We do the same.
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02001884 *
1885 * Problem: the above approach makes it unwieldy to catch signals while
Denys Vlasenkoe95738f2013-07-08 03:13:08 +02001886 * we are in read builtin, or while we read commands from stdin:
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02001887 * masked signals are not visible!
1888 *
1889 * New implementation
1890 * ==================
1891 * We record each signal we are interested in by installing signal handler
1892 * for them - a bit like emulating kernel pending signal mask in userspace.
1893 * We are interested in: signals which need to have special handling
1894 * as described above, and all signals which have traps set.
Denys Vlasenko8bd810b2013-11-28 01:50:01 +01001895 * Signals are recorded in pending_set.
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02001896 * After each pipe execution, we extract any pending signals
1897 * and act on them.
1898 *
1899 * unsigned special_sig_mask: a mask of shell-special signals.
1900 * unsigned fatal_sig_mask: a mask of signals on which we restore tty pgrp.
1901 * char *traps[sig] if trap for sig is set (even if it's '').
1902 * sigset_t pending_set: set of sigs we received.
1903 *
1904 * "trap - SIGxxx":
1905 * if sig is in special_sig_mask, set handler back to:
1906 * record_pending_signo, or to IGN if it's a tty stop signal
1907 * if sig is in fatal_sig_mask, set handler back to sigexit.
1908 * else: set handler back to SIG_DFL
1909 * "trap 'cmd' SIGxxx":
1910 * set handler to record_pending_signo.
1911 * "trap '' SIGxxx":
1912 * set handler to SIG_IGN.
1913 * after [v]fork, if we plan to be a shell:
1914 * set signals with special interactive handling to SIG_DFL
1915 * (because child shell is not interactive),
1916 * unset all traps except '' (note: regardless of child shell's type - {}, (), etc)
1917 * after [v]fork, if we plan to exec:
1918 * POSIX says fork clears pending signal mask in child - no need to clear it.
1919 *
1920 * To make wait builtin interruptible, we handle SIGCHLD as special signal,
1921 * otherwise (if we leave it SIG_DFL) sigsuspend in wait builtin will not wake up on it.
1922 *
1923 * Note (compat):
1924 * Standard says "When a subshell is entered, traps that are not being ignored
1925 * are set to the default actions". bash interprets it so that traps which
1926 * are set to '' (ignore) are NOT reset to defaults. We do the same.
Denis Vlasenkod5762932009-03-31 11:22:57 +00001927 */
Denis Vlasenkoe4bd4f22009-04-17 13:52:51 +00001928enum {
1929 SPECIAL_INTERACTIVE_SIGS = 0
Denis Vlasenkoe4bd4f22009-04-17 13:52:51 +00001930 | (1 << SIGTERM)
Denis Vlasenkoe4bd4f22009-04-17 13:52:51 +00001931 | (1 << SIGINT)
Denis Vlasenkoc8653f62009-04-27 23:29:14 +00001932 | (1 << SIGHUP)
1933 ,
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02001934 SPECIAL_JOBSTOP_SIGS = 0
Mike Frysinger38478a62009-05-20 04:48:06 -04001935#if ENABLE_HUSH_JOB
Denis Vlasenkoc8653f62009-04-27 23:29:14 +00001936 | (1 << SIGTTIN)
1937 | (1 << SIGTTOU)
1938 | (1 << SIGTSTP)
1939#endif
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02001940 ,
Denis Vlasenkoe4bd4f22009-04-17 13:52:51 +00001941};
Denis Vlasenkod5762932009-03-31 11:22:57 +00001942
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02001943static void record_pending_signo(int sig)
Denys Vlasenko54e9e122011-05-09 00:52:15 +02001944{
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02001945 sigaddset(&G.pending_set, sig);
Denys Vlasenko8d7be232009-05-25 16:38:32 +02001946#if ENABLE_HUSH_FAST
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02001947 if (sig == SIGCHLD) {
1948 G.count_SIGCHLD++;
Denys Vlasenko8d7be232009-05-25 16:38:32 +02001949//bb_error_msg("[%d] SIGCHLD_handler: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02001950 }
Denys Vlasenko8d7be232009-05-25 16:38:32 +02001951#endif
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02001952}
Denis Vlasenko7566bae2009-03-31 17:24:49 +00001953
Denys Vlasenko0806e402011-05-12 23:06:20 +02001954static sighandler_t install_sighandler(int sig, sighandler_t handler)
1955{
1956 struct sigaction old_sa;
1957
1958 /* We could use signal() to install handlers... almost:
1959 * except that we need to mask ALL signals while handlers run.
1960 * I saw signal nesting in strace, race window isn't small.
1961 * SA_RESTART is also needed, but in Linux, signal()
1962 * sets SA_RESTART too.
1963 */
1964 /* memset(&G.sa, 0, sizeof(G.sa)); - already done */
1965 /* sigfillset(&G.sa.sa_mask); - already done */
1966 /* G.sa.sa_flags = SA_RESTART; - already done */
1967 G.sa.sa_handler = handler;
1968 sigaction(sig, &G.sa, &old_sa);
1969 return old_sa.sa_handler;
1970}
1971
Denys Vlasenkoe9abe752016-08-19 20:15:26 +02001972static void hush_exit(int exitcode) NORETURN;
Denys Vlasenkoe9abe752016-08-19 20:15:26 +02001973
Denys Vlasenkob6afcc72016-12-12 16:30:20 +01001974static void restore_ttypgrp_and__exit(void) NORETURN;
Denys Vlasenkoe9abe752016-08-19 20:15:26 +02001975static void restore_ttypgrp_and__exit(void)
1976{
1977 /* xfunc has failed! die die die */
1978 /* no EXIT traps, this is an escape hatch! */
1979 G.exiting = 1;
1980 hush_exit(xfunc_error_retval);
1981}
1982
Denys Vlasenkob6afcc72016-12-12 16:30:20 +01001983#if ENABLE_HUSH_JOB
1984
Denys Vlasenkoe9abe752016-08-19 20:15:26 +02001985/* Needed only on some libc:
1986 * It was observed that on exit(), fgetc'ed buffered data
1987 * gets "unwound" via lseek(fd, -NUM, SEEK_CUR).
1988 * With the net effect that even after fork(), not vfork(),
1989 * exit() in NOEXECed applet in "sh SCRIPT":
1990 * noexec_applet_here
1991 * echo END_OF_SCRIPT
1992 * lseeks fd in input FILE object from EOF to "e" in "echo END_OF_SCRIPT".
1993 * This makes "echo END_OF_SCRIPT" executed twice.
Denys Vlasenko39701202017-08-02 19:44:05 +02001994 * Similar problems can be seen with msg_and_die_if_script() -> xfunc_die()
Denys Vlasenkoe9abe752016-08-19 20:15:26 +02001995 * and in `cmd` handling.
1996 * If set as die_func(), this makes xfunc_die() exit via _exit(), not exit():
1997 */
Denys Vlasenkob6afcc72016-12-12 16:30:20 +01001998static void fflush_and__exit(void) NORETURN;
Denys Vlasenkoe9abe752016-08-19 20:15:26 +02001999static void fflush_and__exit(void)
2000{
2001 fflush_all();
2002 _exit(xfunc_error_retval);
2003}
2004
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00002005/* After [v]fork, in child: do not restore tty pgrp on xfunc death */
Denys Vlasenkoe9abe752016-08-19 20:15:26 +02002006# define disable_restore_tty_pgrp_on_exit() (die_func = fflush_and__exit)
Denis Vlasenko25af86f2009-04-07 13:29:27 +00002007/* After [v]fork, in parent: restore tty pgrp on xfunc death */
Denys Vlasenkoe9abe752016-08-19 20:15:26 +02002008# define enable_restore_tty_pgrp_on_exit() (die_func = restore_ttypgrp_and__exit)
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00002009
Denis Vlasenko54e7ffb2007-04-21 00:03:36 +00002010/* Restores tty foreground process group, and exits.
2011 * May be called as signal handler for fatal signal
Denis Vlasenko6b9e0532009-04-18 01:23:21 +00002012 * (will resend signal to itself, producing correct exit state)
Denis Vlasenko54e7ffb2007-04-21 00:03:36 +00002013 * or called directly with -EXITCODE.
Denys Vlasenkoe9abe752016-08-19 20:15:26 +02002014 * We also call it if xfunc is exiting.
2015 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002016static void sigexit(int sig) NORETURN;
Denis Vlasenko54e7ffb2007-04-21 00:03:36 +00002017static void sigexit(int sig)
2018{
Denis Vlasenkoabedaac2009-03-31 12:03:40 +00002019 /* Careful: we can end up here after [v]fork. Do not restore
Denis Vlasenko7b830e72009-03-31 13:05:32 +00002020 * tty pgrp then, only top-level shell process does that */
Denys Vlasenkoebc1ee22011-05-12 10:59:18 +02002021 if (G_saved_tty_pgrp && getpid() == G.root_pid) {
2022 /* Disable all signals: job control, SIGPIPE, etc.
2023 * Mostly paranoid measure, to prevent infinite SIGTTOU.
2024 */
2025 sigprocmask_allsigs(SIG_BLOCK);
Mike Frysinger38478a62009-05-20 04:48:06 -04002026 tcsetpgrp(G_interactive_fd, G_saved_tty_pgrp);
Denys Vlasenkoebc1ee22011-05-12 10:59:18 +02002027 }
Denis Vlasenko54e7ffb2007-04-21 00:03:36 +00002028
2029 /* Not a signal, just exit */
2030 if (sig <= 0)
2031 _exit(- sig);
2032
Denis Vlasenko400d8bb2008-02-24 13:36:01 +00002033 kill_myself_with_sig(sig); /* does not return */
Denis Vlasenko54e7ffb2007-04-21 00:03:36 +00002034}
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00002035#else
2036
Denys Vlasenko8391c482010-05-22 17:50:43 +02002037# define disable_restore_tty_pgrp_on_exit() ((void)0)
2038# define enable_restore_tty_pgrp_on_exit() ((void)0)
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00002039
Denis Vlasenkoe0755e52009-04-03 21:16:45 +00002040#endif
Denis Vlasenkob81b3df2007-04-28 16:48:04 +00002041
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02002042static sighandler_t pick_sighandler(unsigned sig)
2043{
2044 sighandler_t handler = SIG_DFL;
2045 if (sig < sizeof(unsigned)*8) {
2046 unsigned sigmask = (1 << sig);
2047
2048#if ENABLE_HUSH_JOB
Denys Vlasenko75e77de2011-05-12 13:12:47 +02002049 /* is sig fatal? */
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02002050 if (G_fatal_sig_mask & sigmask)
2051 handler = sigexit;
Denys Vlasenko75e77de2011-05-12 13:12:47 +02002052 else
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02002053#endif
2054 /* sig has special handling? */
Denys Vlasenko75e77de2011-05-12 13:12:47 +02002055 if (G.special_sig_mask & sigmask) {
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02002056 handler = record_pending_signo;
Denys Vlasenko0c40a732011-05-12 09:50:12 +02002057 /* TTIN/TTOU/TSTP can't be set to record_pending_signo
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02002058 * in order to ignore them: they will be raised
Denys Vlasenkof58f7052011-05-12 02:10:33 +02002059 * in an endless loop when we try to do some
2060 * terminal ioctls! We do have to _ignore_ these.
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02002061 */
2062 if (SPECIAL_JOBSTOP_SIGS & sigmask)
2063 handler = SIG_IGN;
Denys Vlasenko0c40a732011-05-12 09:50:12 +02002064 }
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02002065 }
2066 return handler;
2067}
2068
Mike Frysinger9f8128f2009-03-29 23:49:37 +00002069/* Restores tty foreground process group, and exits. */
Mike Frysinger9f8128f2009-03-29 23:49:37 +00002070static void hush_exit(int exitcode)
2071{
Denys Vlasenkobede2152011-09-04 16:12:33 +02002072#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
Denys Vlasenko00eb23b2020-12-21 21:36:58 +01002073 save_history(G.line_input_state); /* may be NULL */
Denys Vlasenkobede2152011-09-04 16:12:33 +02002074#endif
2075
Denys Vlasenko8ee2ada2011-02-07 02:03:51 +01002076 fflush_all();
Denys Vlasenko7a85c602017-01-08 17:40:18 +01002077 if (G.exiting <= 0 && G_traps && G_traps[0] && G_traps[0][0]) {
Denys Vlasenko27c56f12010-09-07 09:56:34 +02002078 char *argv[3];
2079 /* argv[0] is unused */
Denys Vlasenko46f839c2018-01-19 16:58:44 +01002080 argv[1] = xstrdup(G_traps[0]); /* copy, since EXIT trap handler may modify G_traps[0] */
Denys Vlasenko27c56f12010-09-07 09:56:34 +02002081 argv[2] = NULL;
Denys Vlasenkoa110c902010-09-12 15:38:04 +02002082 G.exiting = 1; /* prevent EXIT trap recursion */
Denys Vlasenko7a85c602017-01-08 17:40:18 +01002083 /* Note: G_traps[0] is not cleared!
Denys Vlasenkode8c3f62010-09-12 16:13:44 +02002084 * "trap" will still show it, if executed
2085 * in the handler */
2086 builtin_eval(argv);
Denis Vlasenkod5762932009-03-31 11:22:57 +00002087 }
Mike Frysinger9f8128f2009-03-29 23:49:37 +00002088
Denys Vlasenko75eb9d22010-12-21 21:18:12 +01002089#if ENABLE_FEATURE_CLEAN_UP
2090 {
2091 struct variable *cur_var;
2092 if (G.cwd != bb_msg_unknown)
2093 free((char*)G.cwd);
2094 cur_var = G.top_var;
2095 while (cur_var) {
2096 struct variable *tmp = cur_var;
2097 if (!cur_var->max_len)
2098 free(cur_var->varstr);
2099 cur_var = cur_var->next;
2100 free(tmp);
2101 }
2102 }
2103#endif
2104
Denys Vlasenko8131eea2009-11-02 14:19:51 +01002105 fflush_all();
Denys Vlasenko215b0ca2016-08-19 18:23:56 +02002106#if ENABLE_HUSH_JOB
Denis Vlasenkoabedaac2009-03-31 12:03:40 +00002107 sigexit(- (exitcode & 0xff));
2108#else
Denys Vlasenko215b0ca2016-08-19 18:23:56 +02002109 _exit(exitcode);
Denis Vlasenkoabedaac2009-03-31 12:03:40 +00002110#endif
Mike Frysinger9f8128f2009-03-29 23:49:37 +00002111}
2112
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02002113//TODO: return a mask of ALL handled sigs?
2114static int check_and_run_traps(void)
Denis Vlasenko6b9e0532009-04-18 01:23:21 +00002115{
Denis Vlasenko6b9e0532009-04-18 01:23:21 +00002116 int last_sig = 0;
2117
Denis Vlasenko6b9e0532009-04-18 01:23:21 +00002118 while (1) {
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02002119 int sig;
Denys Vlasenko80542ba2011-05-08 21:23:43 +02002120
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02002121 if (sigisemptyset(&G.pending_set))
Denis Vlasenko6b9e0532009-04-18 01:23:21 +00002122 break;
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02002123 sig = 0;
2124 do {
2125 sig++;
2126 if (sigismember(&G.pending_set, sig)) {
2127 sigdelset(&G.pending_set, sig);
2128 goto got_sig;
2129 }
2130 } while (sig < NSIG);
2131 break;
Denys Vlasenkob8709032011-05-08 21:20:01 +02002132 got_sig:
Denys Vlasenkobb095f42020-02-20 16:37:59 +01002133#if ENABLE_HUSH_TRAP
Denys Vlasenko7a85c602017-01-08 17:40:18 +01002134 if (G_traps && G_traps[sig]) {
Denys Vlasenko04b46bc2016-10-01 22:28:03 +02002135 debug_printf_exec("%s: sig:%d handler:'%s'\n", __func__, sig, G.traps[sig]);
Denys Vlasenko7a85c602017-01-08 17:40:18 +01002136 if (G_traps[sig][0]) {
Denis Vlasenko6b9e0532009-04-18 01:23:21 +00002137 /* We have user-defined handler */
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02002138 smalluint save_rcode;
Denys Vlasenko3ced8042020-02-21 02:55:53 +01002139 int save_pre;
Denys Vlasenko27c56f12010-09-07 09:56:34 +02002140 char *argv[3];
2141 /* argv[0] is unused */
Denys Vlasenko749575d2018-01-30 04:29:03 +01002142 argv[1] = xstrdup(G_traps[sig]);
2143 /* why strdup? trap can modify itself: trap 'trap "echo oops" INT' INT */
Denys Vlasenko27c56f12010-09-07 09:56:34 +02002144 argv[2] = NULL;
Denys Vlasenko3ced8042020-02-21 02:55:53 +01002145 save_pre = G.pre_trap_exitcode;
Denys Vlasenkocc9ecd92020-02-21 02:18:06 +01002146 G.pre_trap_exitcode = save_rcode = G.last_exitcode;
Denis Vlasenko6b9e0532009-04-18 01:23:21 +00002147 builtin_eval(argv);
Denys Vlasenko749575d2018-01-30 04:29:03 +01002148 free(argv[1]);
Denys Vlasenko3ced8042020-02-21 02:55:53 +01002149 G.pre_trap_exitcode = save_pre;
Denis Vlasenko6b9e0532009-04-18 01:23:21 +00002150 G.last_exitcode = save_rcode;
Denys Vlasenkobb095f42020-02-20 16:37:59 +01002151# if ENABLE_HUSH_FUNCTIONS
2152 if (G.return_exitcode >= 0) {
2153 debug_printf_exec("trap exitcode:%d\n", G.return_exitcode);
2154 G.last_exitcode = G.return_exitcode;
2155 }
2156# endif
Denys Vlasenkob8709032011-05-08 21:20:01 +02002157 last_sig = sig;
Denis Vlasenko6b9e0532009-04-18 01:23:21 +00002158 } /* else: "" trap, ignoring signal */
2159 continue;
2160 }
Denys Vlasenkobb095f42020-02-20 16:37:59 +01002161#endif
Denis Vlasenko6b9e0532009-04-18 01:23:21 +00002162 /* not a trap: special action */
2163 switch (sig) {
Denis Vlasenko6b9e0532009-04-18 01:23:21 +00002164 case SIGINT:
Denys Vlasenko04b46bc2016-10-01 22:28:03 +02002165 debug_printf_exec("%s: sig:%d default SIGINT handler\n", __func__, sig);
Denis Vlasenko6b9e0532009-04-18 01:23:21 +00002166 G.flag_SIGINT = 1;
Denys Vlasenkob8709032011-05-08 21:20:01 +02002167 last_sig = sig;
Denis Vlasenko6b9e0532009-04-18 01:23:21 +00002168 break;
2169#if ENABLE_HUSH_JOB
2170 case SIGHUP: {
Denys Vlasenko49e6bf22017-08-04 14:28:16 +02002171//TODO: why are we doing this? ash and dash don't do this,
2172//they have no handler for SIGHUP at all,
2173//they rely on kernel to send SIGHUP+SIGCONT to orphaned process groups
Denis Vlasenko6b9e0532009-04-18 01:23:21 +00002174 struct pipe *job;
Denys Vlasenko04b46bc2016-10-01 22:28:03 +02002175 debug_printf_exec("%s: sig:%d default SIGHUP handler\n", __func__, sig);
Denis Vlasenko6b9e0532009-04-18 01:23:21 +00002176 /* bash is observed to signal whole process groups,
2177 * not individual processes */
2178 for (job = G.job_list; job; job = job->next) {
2179 if (job->pgrp <= 0)
2180 continue;
2181 debug_printf_exec("HUPing pgrp %d\n", job->pgrp);
2182 if (kill(- job->pgrp, SIGHUP) == 0)
2183 kill(- job->pgrp, SIGCONT);
2184 }
2185 sigexit(SIGHUP);
2186 }
2187#endif
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02002188#if ENABLE_HUSH_FAST
2189 case SIGCHLD:
Denys Vlasenko04b46bc2016-10-01 22:28:03 +02002190 debug_printf_exec("%s: sig:%d default SIGCHLD handler\n", __func__, sig);
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02002191 G.count_SIGCHLD++;
2192//bb_error_msg("[%d] check_and_run_traps: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
2193 /* Note:
Denys Vlasenko10ad6222017-04-17 16:13:32 +02002194 * We don't do 'last_sig = sig' here -> NOT returning this sig.
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02002195 * This simplifies wait builtin a bit.
2196 */
2197 break;
2198#endif
Denis Vlasenko6b9e0532009-04-18 01:23:21 +00002199 default: /* ignored: */
Denys Vlasenko04b46bc2016-10-01 22:28:03 +02002200 debug_printf_exec("%s: sig:%d default handling is to ignore\n", __func__, sig);
Denis Vlasenko6b9e0532009-04-18 01:23:21 +00002201 /* SIGTERM, SIGQUIT, SIGTTIN, SIGTTOU, SIGTSTP */
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02002202 /* Note:
Denys Vlasenko10ad6222017-04-17 16:13:32 +02002203 * We don't do 'last_sig = sig' here -> NOT returning this sig.
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02002204 * Example: wait is not interrupted by TERM
Denys Vlasenkob8709032011-05-08 21:20:01 +02002205 * in interactive shell, because TERM is ignored.
2206 */
Denis Vlasenko6b9e0532009-04-18 01:23:21 +00002207 break;
2208 }
2209 }
2210 return last_sig;
2211}
2212
Denis Vlasenkob81b3df2007-04-28 16:48:04 +00002213
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +02002214static const char *get_cwd(int force)
Eric Andersen9ffb7dd2001-05-19 03:00:46 +00002215{
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +02002216 if (force || G.cwd == NULL) {
2217 /* xrealloc_getcwd_or_warn(arg) calls free(arg),
2218 * we must not try to free(bb_msg_unknown) */
2219 if (G.cwd == bb_msg_unknown)
2220 G.cwd = NULL;
2221 G.cwd = xrealloc_getcwd_or_warn((char *)G.cwd);
2222 if (!G.cwd)
2223 G.cwd = bb_msg_unknown;
2224 }
Denis Vlasenko87a86552008-07-29 19:43:10 +00002225 return G.cwd;
Eric Andersen9ffb7dd2001-05-19 03:00:46 +00002226}
2227
Denis Vlasenko83506862007-11-23 13:11:42 +00002228
Denys Vlasenkocb6ff252009-05-04 00:14:30 +02002229/*
2230 * Shell and environment variable support
2231 */
Denys Vlasenko27c56f12010-09-07 09:56:34 +02002232static struct variable **get_ptr_to_local_var(const char *name, unsigned len)
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002233{
Denys Vlasenkocb6ff252009-05-04 00:14:30 +02002234 struct variable **pp;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002235 struct variable *cur;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002236
Denys Vlasenkocb6ff252009-05-04 00:14:30 +02002237 pp = &G.top_var;
2238 while ((cur = *pp) != NULL) {
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002239 if (strncmp(cur->varstr, name, len) == 0 && cur->varstr[len] == '=')
Denys Vlasenkocb6ff252009-05-04 00:14:30 +02002240 return pp;
2241 pp = &cur->next;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002242 }
2243 return NULL;
2244}
2245
Denys Vlasenko03dad222010-01-12 23:29:57 +01002246static const char* FAST_FUNC get_local_var_value(const char *name)
Denys Vlasenkocb6ff252009-05-04 00:14:30 +02002247{
Denys Vlasenko29082232010-07-16 13:52:32 +02002248 struct variable **vpp;
Denys Vlasenko27c56f12010-09-07 09:56:34 +02002249 unsigned len = strlen(name);
Denys Vlasenko29082232010-07-16 13:52:32 +02002250
2251 if (G.expanded_assignments) {
2252 char **cpp = G.expanded_assignments;
Denys Vlasenko29082232010-07-16 13:52:32 +02002253 while (*cpp) {
2254 char *cp = *cpp;
2255 if (strncmp(cp, name, len) == 0 && cp[len] == '=')
2256 return cp + len + 1;
2257 cpp++;
2258 }
2259 }
2260
Denys Vlasenko27c56f12010-09-07 09:56:34 +02002261 vpp = get_ptr_to_local_var(name, len);
Denys Vlasenko29082232010-07-16 13:52:32 +02002262 if (vpp)
Denys Vlasenko27c56f12010-09-07 09:56:34 +02002263 return (*vpp)->varstr + len + 1;
Denys Vlasenko29082232010-07-16 13:52:32 +02002264
Denys Vlasenkodea47882009-10-09 15:40:49 +02002265 if (strcmp(name, "PPID") == 0)
2266 return utoa(G.root_ppid);
2267 // bash compat: UID? EUID?
Denys Vlasenko20b3d142009-10-09 20:59:39 +02002268#if ENABLE_HUSH_RANDOM_SUPPORT
Denys Vlasenko27c56f12010-09-07 09:56:34 +02002269 if (strcmp(name, "RANDOM") == 0)
Denys Vlasenko20b3d142009-10-09 20:59:39 +02002270 return utoa(next_random(&G.random_gen));
2271#endif
Denys Vlasenko08fb82c2019-05-19 15:26:05 +02002272#if ENABLE_HUSH_LINENO_VAR
2273 if (strcmp(name, "LINENO") == 0)
2274 return utoa(G.execute_lineno);
2275#endif
Ron Yorstona81700b2019-04-15 10:48:29 +01002276#if BASH_EPOCH_VARS
2277 {
2278 const char *fmt = NULL;
2279 if (strcmp(name, "EPOCHSECONDS") == 0)
Denys Vlasenko3c13da32020-12-30 23:48:01 +01002280 fmt = "%llu";
Ron Yorstona81700b2019-04-15 10:48:29 +01002281 else if (strcmp(name, "EPOCHREALTIME") == 0)
Denys Vlasenko3c13da32020-12-30 23:48:01 +01002282 fmt = "%llu.%06u";
Ron Yorstona81700b2019-04-15 10:48:29 +01002283 if (fmt) {
2284 struct timeval tv;
Denys Vlasenko3c13da32020-12-30 23:48:01 +01002285 xgettimeofday(&tv);
2286 sprintf(G.epoch_buf, fmt, (unsigned long long)tv.tv_sec,
Ron Yorstona81700b2019-04-15 10:48:29 +01002287 (unsigned)tv.tv_usec);
2288 return G.epoch_buf;
2289 }
2290 }
2291#endif
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002292 return NULL;
2293}
2294
Denys Vlasenko08fb82c2019-05-19 15:26:05 +02002295#if ENABLE_HUSH_GETOPTS
Denys Vlasenkocf079ff2018-04-06 14:50:12 +02002296static void handle_changed_special_names(const char *name, unsigned name_len)
2297{
Denys Vlasenko4ebcdf72019-05-16 15:39:19 +02002298 if (name_len == 6) {
Denys Vlasenko00bd7672018-04-06 14:57:53 +02002299 if (strncmp(name, "OPTIND", 6) == 0) {
Denys Vlasenkocf079ff2018-04-06 14:50:12 +02002300 G.getopt_count = 0;
Denys Vlasenko00bd7672018-04-06 14:57:53 +02002301 return;
2302 }
Denys Vlasenkocf079ff2018-04-06 14:50:12 +02002303 }
2304}
Denys Vlasenkod8bd7012019-05-14 18:53:24 +02002305#else
2306/* Do not even bother evaluating arguments */
2307# define handle_changed_special_names(...) ((void)0)
2308#endif
Denys Vlasenkocf079ff2018-04-06 14:50:12 +02002309
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002310/* str holds "NAME=VAL" and is expected to be malloced.
Mike Frysinger6379bb42009-03-28 18:55:03 +00002311 * We take ownership of it.
Mike Frysinger6379bb42009-03-28 18:55:03 +00002312 */
Denys Vlasenko3bab36b2017-07-18 01:05:24 +02002313#define SETFLAG_EXPORT (1 << 0)
2314#define SETFLAG_UNEXPORT (1 << 1)
2315#define SETFLAG_MAKE_RO (1 << 2)
Denys Vlasenko332e4112018-04-04 22:32:59 +02002316#define SETFLAG_VARLVL_SHIFT 3
Denys Vlasenko3bab36b2017-07-18 01:05:24 +02002317static int set_local_var(char *str, unsigned flags)
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002318{
Denys Vlasenko61407802018-04-04 21:14:28 +02002319 struct variable **cur_pp;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002320 struct variable *cur;
Denys Vlasenkoa7693902016-10-03 15:01:06 +02002321 char *free_me = NULL;
Denis Vlasenko950bd722009-04-21 11:23:56 +00002322 char *eq_sign;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002323 int name_len;
Denys Vlasenkod8bd7012019-05-14 18:53:24 +02002324 int retval;
Denys Vlasenko332e4112018-04-04 22:32:59 +02002325 unsigned local_lvl = (flags >> SETFLAG_VARLVL_SHIFT);
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002326
Denis Vlasenko950bd722009-04-21 11:23:56 +00002327 eq_sign = strchr(str, '=');
Denys Vlasenko929a41d2018-04-05 14:09:14 +02002328 if (HUSH_DEBUG && !eq_sign)
James Byrne69374872019-07-02 11:35:03 +02002329 bb_simple_error_msg_and_die("BUG in setvar");
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002330
Denis Vlasenko950bd722009-04-21 11:23:56 +00002331 name_len = eq_sign - str + 1; /* including '=' */
Denys Vlasenko61407802018-04-04 21:14:28 +02002332 cur_pp = &G.top_var;
2333 while ((cur = *cur_pp) != NULL) {
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002334 if (strncmp(cur->varstr, str, name_len) != 0) {
Denys Vlasenko61407802018-04-04 21:14:28 +02002335 cur_pp = &cur->next;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002336 continue;
2337 }
Denys Vlasenkoa7693902016-10-03 15:01:06 +02002338
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002339 /* We found an existing var with this name */
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002340 if (cur->flg_read_only) {
Denys Vlasenko6b48e1f2017-07-17 21:31:17 +02002341 bb_error_msg("%s: readonly variable", str);
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002342 free(str);
Denys Vlasenko5b2cc0a2017-07-18 02:44:06 +02002343//NOTE: in bash, assignment in "export READONLY_VAR=Z" fails, and sets $?=1,
2344//but export per se succeeds (does put the var in env). We don't mimic that.
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002345 return -1;
2346 }
Denys Vlasenko3bab36b2017-07-18 01:05:24 +02002347 if (flags & SETFLAG_UNEXPORT) { // && cur->flg_export ?
Denis Vlasenko950bd722009-04-21 11:23:56 +00002348 debug_printf_env("%s: unsetenv '%s'\n", __func__, str);
2349 *eq_sign = '\0';
2350 unsetenv(str);
2351 *eq_sign = '=';
2352 }
Denys Vlasenko332e4112018-04-04 22:32:59 +02002353 if (cur->var_nest_level < local_lvl) {
Denys Vlasenko295fef82009-06-03 12:47:26 +02002354 /* bash 3.2.33(1) and exported vars:
2355 * # export z=z
2356 * # f() { local z=a; env | grep ^z; }
2357 * # f
2358 * z=a
2359 * # env | grep ^z
2360 * z=z
2361 */
2362 if (cur->flg_export)
Denys Vlasenko3bab36b2017-07-18 01:05:24 +02002363 flags |= SETFLAG_EXPORT;
Denys Vlasenko929a41d2018-04-05 14:09:14 +02002364 /* New variable is local ("local VAR=VAL" or
2365 * "VAR=VAL cmd")
2366 * and existing one is global, or local
2367 * on a lower level that new one.
2368 * Remove it from global variable list:
2369 */
2370 *cur_pp = cur->next;
2371 if (G.shadowed_vars_pp) {
2372 /* Save in "shadowed" list */
2373 debug_printf_env("shadowing %s'%s'/%u by '%s'/%u\n",
2374 cur->flg_export ? "exported " : "",
2375 cur->varstr, cur->var_nest_level, str, local_lvl
2376 );
2377 cur->next = *G.shadowed_vars_pp;
2378 *G.shadowed_vars_pp = cur;
2379 } else {
2380 /* Came from pseudo_exec_argv(), no need to save: delete it */
2381 debug_printf_env("shadow-deleting %s'%s'/%u by '%s'/%u\n",
2382 cur->flg_export ? "exported " : "",
2383 cur->varstr, cur->var_nest_level, str, local_lvl
2384 );
2385 if (cur->max_len == 0) /* allocated "VAR=VAL"? */
2386 free_me = cur->varstr; /* then free it later */
2387 free(cur);
2388 }
Denys Vlasenko295fef82009-06-03 12:47:26 +02002389 break;
2390 }
Denys Vlasenko332e4112018-04-04 22:32:59 +02002391
Denis Vlasenko950bd722009-04-21 11:23:56 +00002392 if (strcmp(cur->varstr + name_len, eq_sign + 1) == 0) {
Denys Vlasenkod358b0b2018-04-05 00:51:55 +02002393 debug_printf_env("assignement '%s' does not change anything\n", str);
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002394 free_and_exp:
2395 free(str);
2396 goto exp;
2397 }
Denys Vlasenko929a41d2018-04-05 14:09:14 +02002398
2399 /* Replace the value in the found "struct variable" */
Denys Vlasenko295fef82009-06-03 12:47:26 +02002400 if (cur->max_len != 0) {
Denys Vlasenko929a41d2018-04-05 14:09:14 +02002401 if (cur->max_len >= strnlen(str, cur->max_len + 1)) {
Denys Vlasenko295fef82009-06-03 12:47:26 +02002402 /* This one is from startup env, reuse space */
Denys Vlasenkod358b0b2018-04-05 00:51:55 +02002403 debug_printf_env("reusing startup env for '%s'\n", str);
Denys Vlasenko295fef82009-06-03 12:47:26 +02002404 strcpy(cur->varstr, str);
2405 goto free_and_exp;
2406 }
Denys Vlasenkoa7693902016-10-03 15:01:06 +02002407 /* Can't reuse */
2408 cur->max_len = 0;
2409 goto set_str_and_exp;
Denys Vlasenko295fef82009-06-03 12:47:26 +02002410 }
Denys Vlasenkoa7693902016-10-03 15:01:06 +02002411 /* max_len == 0 signifies "malloced" var, which we can
2412 * (and have to) free. But we can't free(cur->varstr) here:
2413 * if cur->flg_export is 1, it is in the environment.
2414 * We should either unsetenv+free, or wait until putenv,
2415 * then putenv(new)+free(old).
2416 */
2417 free_me = cur->varstr;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002418 goto set_str_and_exp;
2419 }
2420
Denys Vlasenkod358b0b2018-04-05 00:51:55 +02002421 /* Not found or shadowed - create new variable struct */
Denys Vlasenko9db344a2018-04-09 19:05:11 +02002422 debug_printf_env("%s: alloc new var '%s'/%u\n", __func__, str, local_lvl);
Denys Vlasenko295fef82009-06-03 12:47:26 +02002423 cur = xzalloc(sizeof(*cur));
Denys Vlasenko332e4112018-04-04 22:32:59 +02002424 cur->var_nest_level = local_lvl;
Denys Vlasenko61407802018-04-04 21:14:28 +02002425 cur->next = *cur_pp;
2426 *cur_pp = cur;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002427
2428 set_str_and_exp:
2429 cur->varstr = str;
2430 exp:
Denys Vlasenko1e660422017-07-17 21:10:50 +02002431#if !BB_MMU || ENABLE_HUSH_READONLY
Denys Vlasenko3bab36b2017-07-18 01:05:24 +02002432 if (flags & SETFLAG_MAKE_RO) {
2433 cur->flg_read_only = 1;
Denys Vlasenko1e660422017-07-17 21:10:50 +02002434 }
2435#endif
Denys Vlasenko3bab36b2017-07-18 01:05:24 +02002436 if (flags & SETFLAG_EXPORT)
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002437 cur->flg_export = 1;
Denys Vlasenkod8bd7012019-05-14 18:53:24 +02002438 retval = 0;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002439 if (cur->flg_export) {
Denys Vlasenko3bab36b2017-07-18 01:05:24 +02002440 if (flags & SETFLAG_UNEXPORT) {
Denis Vlasenkoad4bd052009-04-20 22:04:21 +00002441 cur->flg_export = 0;
2442 /* unsetenv was already done */
2443 } else {
Denys Vlasenkod358b0b2018-04-05 00:51:55 +02002444 debug_printf_env("%s: putenv '%s'/%u\n", __func__, cur->varstr, cur->var_nest_level);
Denys Vlasenkod8bd7012019-05-14 18:53:24 +02002445 retval = putenv(cur->varstr);
2446 /* fall through to "free(free_me)" -
2447 * only now we can free old exported malloced string
2448 */
Denis Vlasenkoad4bd052009-04-20 22:04:21 +00002449 }
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002450 }
Denys Vlasenkoa7693902016-10-03 15:01:06 +02002451 free(free_me);
Denys Vlasenko929a41d2018-04-05 14:09:14 +02002452
Denys Vlasenkocf079ff2018-04-06 14:50:12 +02002453 handle_changed_special_names(cur->varstr, name_len - 1);
Denys Vlasenko929a41d2018-04-05 14:09:14 +02002454
Denys Vlasenkod8bd7012019-05-14 18:53:24 +02002455 return retval;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002456}
2457
Denys Vlasenkofd6f2952018-08-05 15:13:08 +02002458static void FAST_FUNC set_local_var_from_halves(const char *name, const char *val)
2459{
2460 char *var = xasprintf("%s=%s", name, val);
2461 set_local_var(var, /*flag:*/ 0);
2462}
2463
Denys Vlasenko6db47842009-09-05 20:15:17 +02002464/* Used at startup and after each cd */
Denys Vlasenko3bab36b2017-07-18 01:05:24 +02002465static void set_pwd_var(unsigned flag)
Denys Vlasenko6db47842009-09-05 20:15:17 +02002466{
Denys Vlasenko3bab36b2017-07-18 01:05:24 +02002467 set_local_var(xasprintf("PWD=%s", get_cwd(/*force:*/ 1)), flag);
Denys Vlasenko6db47842009-09-05 20:15:17 +02002468}
2469
Denys Vlasenko35a017c2018-06-26 18:27:54 +02002470#if ENABLE_HUSH_UNSET || ENABLE_HUSH_GETOPTS
Denys Vlasenkoacdc49c2009-05-04 01:58:10 +02002471static int unset_local_var_len(const char *name, int name_len)
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002472{
2473 struct variable *cur;
Denys Vlasenko61407802018-04-04 21:14:28 +02002474 struct variable **cur_pp;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002475
Denys Vlasenko61407802018-04-04 21:14:28 +02002476 cur_pp = &G.top_var;
2477 while ((cur = *cur_pp) != NULL) {
Denys Vlasenkocf079ff2018-04-06 14:50:12 +02002478 if (strncmp(cur->varstr, name, name_len) == 0
2479 && cur->varstr[name_len] == '='
2480 ) {
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002481 if (cur->flg_read_only) {
2482 bb_error_msg("%s: readonly variable", name);
Mike Frysingerd690f682009-03-30 06:50:54 +00002483 return EXIT_FAILURE;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002484 }
Denys Vlasenkocf079ff2018-04-06 14:50:12 +02002485
Denys Vlasenko61407802018-04-04 21:14:28 +02002486 *cur_pp = cur->next;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002487 debug_printf_env("%s: unsetenv '%s'\n", __func__, cur->varstr);
2488 bb_unsetenv(cur->varstr);
2489 if (!cur->max_len)
2490 free(cur->varstr);
2491 free(cur);
Denys Vlasenkocf079ff2018-04-06 14:50:12 +02002492
Denys Vlasenkof5018da2018-04-06 17:58:21 +02002493 break;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002494 }
Denys Vlasenko61407802018-04-04 21:14:28 +02002495 cur_pp = &cur->next;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002496 }
Denys Vlasenkof5018da2018-04-06 17:58:21 +02002497
Denys Vlasenko4ebcdf72019-05-16 15:39:19 +02002498 /* Handle "unset LINENO" et al even if did not find the variable to unset */
Denys Vlasenkof5018da2018-04-06 17:58:21 +02002499 handle_changed_special_names(name, name_len);
2500
Mike Frysingerd690f682009-03-30 06:50:54 +00002501 return EXIT_SUCCESS;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002502}
2503
Denys Vlasenkoacdc49c2009-05-04 01:58:10 +02002504static int unset_local_var(const char *name)
2505{
2506 return unset_local_var_len(name, strlen(name));
2507}
Denys Vlasenko10d5ece2017-01-08 18:28:43 +01002508#endif
Denys Vlasenkoacdc49c2009-05-04 01:58:10 +02002509
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00002510
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002511/*
Denys Vlasenkocb6ff252009-05-04 00:14:30 +02002512 * Helpers for "var1=val1 var2=val2 cmd" feature
2513 */
2514static void add_vars(struct variable *var)
2515{
2516 struct variable *next;
2517
2518 while (var) {
2519 next = var->next;
2520 var->next = G.top_var;
2521 G.top_var = var;
Denys Vlasenkoacdc49c2009-05-04 01:58:10 +02002522 if (var->flg_export) {
Denys Vlasenkod358b0b2018-04-05 00:51:55 +02002523 debug_printf_env("%s: restoring exported '%s'/%u\n", __func__, var->varstr, var->var_nest_level);
Denys Vlasenkocb6ff252009-05-04 00:14:30 +02002524 putenv(var->varstr);
Denys Vlasenkoacdc49c2009-05-04 01:58:10 +02002525 } else {
Denys Vlasenkod358b0b2018-04-05 00:51:55 +02002526 debug_printf_env("%s: restoring variable '%s'/%u\n", __func__, var->varstr, var->var_nest_level);
Denys Vlasenkoacdc49c2009-05-04 01:58:10 +02002527 }
Denys Vlasenkocb6ff252009-05-04 00:14:30 +02002528 var = next;
2529 }
2530}
2531
Denys Vlasenkod358b0b2018-04-05 00:51:55 +02002532/* We put strings[i] into variable table and possibly putenv them.
2533 * If variable is read only, we can free the strings[i]
2534 * which attempts to overwrite it.
2535 * The strings[] vector itself is freed.
2536 */
Denys Vlasenko929a41d2018-04-05 14:09:14 +02002537static void set_vars_and_save_old(char **strings)
Denys Vlasenkocb6ff252009-05-04 00:14:30 +02002538{
2539 char **s;
Denys Vlasenkocb6ff252009-05-04 00:14:30 +02002540
2541 if (!strings)
Denys Vlasenko929a41d2018-04-05 14:09:14 +02002542 return;
Denys Vlasenkod358b0b2018-04-05 00:51:55 +02002543
Denys Vlasenkocb6ff252009-05-04 00:14:30 +02002544 s = strings;
2545 while (*s) {
2546 struct variable *var_p;
2547 struct variable **var_pp;
2548 char *eq;
2549
2550 eq = strchr(*s, '=');
Denys Vlasenkoe36a5892018-07-18 16:12:23 +02002551 if (HUSH_DEBUG && !eq)
James Byrne69374872019-07-02 11:35:03 +02002552 bb_simple_error_msg_and_die("BUG in varexp4");
Denys Vlasenkoe36a5892018-07-18 16:12:23 +02002553 var_pp = get_ptr_to_local_var(*s, eq - *s);
2554 if (var_pp) {
2555 var_p = *var_pp;
2556 if (var_p->flg_read_only) {
2557 char **p;
2558 bb_error_msg("%s: readonly variable", *s);
2559 /*
2560 * "VAR=V BLTIN" unsets VARs after BLTIN completes.
2561 * If VAR is readonly, leaving it in the list
2562 * after asssignment error (msg above)
2563 * causes doubled error message later, on unset.
2564 */
2565 debug_printf_env("removing/freeing '%s' element\n", *s);
2566 free(*s);
2567 p = s;
2568 do { *p = p[1]; p++; } while (*p);
2569 goto next;
2570 }
2571 /* below, set_local_var() with nest level will
2572 * "shadow" (remove) this variable from
2573 * global linked list.
2574 */
Denys Vlasenkocb6ff252009-05-04 00:14:30 +02002575 }
Denys Vlasenkoe36a5892018-07-18 16:12:23 +02002576 debug_printf_env("%s: env override '%s'/%u\n", __func__, *s, G.var_nest_level);
2577 set_local_var(*s, (G.var_nest_level << SETFLAG_VARLVL_SHIFT) | SETFLAG_EXPORT);
Denys Vlasenkocb6ff252009-05-04 00:14:30 +02002578 s++;
Denys Vlasenko61407802018-04-04 21:14:28 +02002579 next: ;
Denys Vlasenkocb6ff252009-05-04 00:14:30 +02002580 }
Denys Vlasenkod358b0b2018-04-05 00:51:55 +02002581 free(strings);
Denys Vlasenkocb6ff252009-05-04 00:14:30 +02002582}
2583
2584
2585/*
Denys Vlasenkoc538d5b2014-08-13 09:57:44 +02002586 * Unicode helper
2587 */
2588static void reinit_unicode_for_hush(void)
2589{
2590 /* Unicode support should be activated even if LANG is set
2591 * _during_ shell execution, not only if it was set when
2592 * shell was started. Therefore, re-check LANG every time:
2593 */
Denys Vlasenko841f8332014-08-13 10:09:49 +02002594 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2595 || ENABLE_UNICODE_USING_LOCALE
Denys Vlasenko4c201c02018-07-17 15:04:17 +02002596 ) {
Denys Vlasenko841f8332014-08-13 10:09:49 +02002597 const char *s = get_local_var_value("LC_ALL");
2598 if (!s) s = get_local_var_value("LC_CTYPE");
2599 if (!s) s = get_local_var_value("LANG");
2600 reinit_unicode(s);
2601 }
Denys Vlasenkoc538d5b2014-08-13 09:57:44 +02002602}
2603
Denys Vlasenkoc538d5b2014-08-13 09:57:44 +02002604/*
Denys Vlasenkod17a91d2016-09-29 18:02:37 +02002605 * in_str support (strings, and "strings" read from files).
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002606 */
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002607
2608#if ENABLE_HUSH_INTERACTIVE
Denys Vlasenko4074d492016-09-30 01:49:53 +02002609/* To test correct lineedit/interactive behavior, type from command line:
2610 * echo $P\
2611 * \
2612 * AT\
2613 * H\
2614 * \
Denys Vlasenko10ad6222017-04-17 16:13:32 +02002615 * It exercises a lot of corner cases.
Denys Vlasenko4074d492016-09-30 01:49:53 +02002616 */
Denys Vlasenko8d6eab32018-04-07 17:01:31 +02002617static const char *setup_prompt_string(void)
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002618{
2619 const char *prompt_str;
Denys Vlasenkof5018da2018-04-06 17:58:21 +02002620
Denys Vlasenko8d6eab32018-04-07 17:01:31 +02002621 debug_printf_prompt("%s promptmode:%d\n", __func__, G.promptmode);
Denys Vlasenkof5018da2018-04-06 17:58:21 +02002622
Denys Vlasenko4ebcdf72019-05-16 15:39:19 +02002623# if ENABLE_FEATURE_EDITING_FANCY_PROMPT
2624 prompt_str = get_local_var_value(G.promptmode == 0 ? "PS1" : "PS2");
2625 if (!prompt_str)
2626 prompt_str = "";
2627# else
2628 prompt_str = "> "; /* if PS2, else... */
Denys Vlasenko8d6eab32018-04-07 17:01:31 +02002629 if (G.promptmode == 0) { /* PS1 */
Denys Vlasenko4ebcdf72019-05-16 15:39:19 +02002630 /* No fancy prompts supported, (re)generate "CURDIR $ " by hand */
2631 free(G.PS1);
2632 /* bash uses $PWD value, even if it is set by user.
2633 * It uses current dir only if PWD is unset.
2634 * We always use current dir. */
Denys Vlasenko649acb92020-12-23 15:29:13 +01002635 prompt_str = G.PS1 = xasprintf("%s %c ", get_cwd(0), (geteuid() != 0) ? '$' : '#');
Denys Vlasenkof5018da2018-04-06 17:58:21 +02002636 }
Denys Vlasenko4ebcdf72019-05-16 15:39:19 +02002637# endif
Denys Vlasenko4074d492016-09-30 01:49:53 +02002638 debug_printf("prompt_str '%s'\n", prompt_str);
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002639 return prompt_str;
2640}
Denys Vlasenkod17a91d2016-09-29 18:02:37 +02002641static int get_user_input(struct in_str *i)
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002642{
Denys Vlasenko46a71dc2020-12-25 18:49:29 +01002643# if ENABLE_FEATURE_EDITING
2644 /* In EDITING case, this function reads next input line,
2645 * saves it in i->p, then returns 1st char of it.
2646 */
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002647 int r;
2648 const char *prompt_str;
2649
Denys Vlasenko8d6eab32018-04-07 17:01:31 +02002650 prompt_str = setup_prompt_string();
Denys Vlasenko8660aeb2016-11-24 17:44:02 +01002651 for (;;) {
Denys Vlasenkoc538d5b2014-08-13 09:57:44 +02002652 reinit_unicode_for_hush();
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01002653 G.flag_SIGINT = 0;
Denis Vlasenko422cd7c2009-03-31 12:41:52 +00002654 /* buglet: SIGINT will not make new prompt to appear _at once_,
Denys Vlasenko4b89d512016-11-25 03:41:03 +01002655 * only after <Enter>. (^C works immediately) */
Denys Vlasenko0448c552016-09-29 20:25:44 +02002656 r = read_line_input(G.line_input_state, prompt_str,
Denys Vlasenko84ea60e2017-08-02 17:27:28 +02002657 G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1
Denys Vlasenko0448c552016-09-29 20:25:44 +02002658 );
Denys Vlasenko4b89d512016-11-25 03:41:03 +01002659 /* read_line_input intercepts ^C, "convert" it to SIGINT */
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01002660 if (r == 0) {
Denys Vlasenko8660aeb2016-11-24 17:44:02 +01002661 raise(SIGINT);
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01002662 }
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02002663 check_and_run_traps();
Denys Vlasenko8660aeb2016-11-24 17:44:02 +01002664 if (r != 0 && !G.flag_SIGINT)
2665 break;
Denys Vlasenko18bcaf32020-12-23 23:01:18 +01002666 /* ^C or SIGINT: repeat */
Denys Vlasenkodd4b4462017-08-02 16:52:12 +02002667 /* bash prints ^C even on real SIGINT (non-kbd generated) */
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01002668 write(STDOUT_FILENO, "^C\n", 3);
Denys Vlasenko93e2a222020-12-23 12:23:21 +01002669 G.last_exitcode = 128 | SIGINT;
Denys Vlasenko8660aeb2016-11-24 17:44:02 +01002670 }
Denys Vlasenkod17a91d2016-09-29 18:02:37 +02002671 if (r < 0) {
2672 /* EOF/error detected */
Denys Vlasenkof0c0c562021-04-13 16:42:17 +02002673 /* ^D on interactive input goes to next line before exiting: */
2674 write(STDOUT_FILENO, "\n", 1);
Denys Vlasenko4074d492016-09-30 01:49:53 +02002675 i->p = NULL;
2676 i->peek_buf[0] = r = EOF;
Denys Vlasenkod17a91d2016-09-29 18:02:37 +02002677 return r;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002678 }
Denys Vlasenko4074d492016-09-30 01:49:53 +02002679 i->p = G.user_input_buf;
Denys Vlasenkod17a91d2016-09-29 18:02:37 +02002680 return (unsigned char)*i->p++;
Denys Vlasenko8391c482010-05-22 17:50:43 +02002681# else
Denys Vlasenko46a71dc2020-12-25 18:49:29 +01002682 /* In !EDITING case, this function gets called for every char.
2683 * Buffering happens deeper in the call chain, in hfgetc(i->file).
2684 */
2685 int r;
2686
Denys Vlasenko8660aeb2016-11-24 17:44:02 +01002687 for (;;) {
Denis Vlasenko422cd7c2009-03-31 12:41:52 +00002688 G.flag_SIGINT = 0;
Denys Vlasenkob8709032011-05-08 21:20:01 +02002689 if (i->last_char == '\0' || i->last_char == '\n') {
Denys Vlasenko46a71dc2020-12-25 18:49:29 +01002690 const char *prompt_str = setup_prompt_string();
Denys Vlasenkob8709032011-05-08 21:20:01 +02002691 /* Why check_and_run_traps here? Try this interactively:
2692 * $ trap 'echo INT' INT; (sleep 2; kill -INT $$) &
2693 * $ <[enter], repeatedly...>
2694 * Without check_and_run_traps, handler never runs.
2695 */
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02002696 check_and_run_traps();
Ron Yorstoncad3fc72021-02-03 20:47:14 +01002697 fputs_stdout(prompt_str);
Denys Vlasenko521220e2020-12-23 23:44:55 +01002698 fflush_all();
Denys Vlasenkob8709032011-05-08 21:20:01 +02002699 }
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02002700 r = hfgetc(i->file);
Denys Vlasenko8660aeb2016-11-24 17:44:02 +01002701 /* In !ENABLE_FEATURE_EDITING we don't use read_line_input,
2702 * no ^C masking happens during fgetc, no special code for ^C:
2703 * it generates SIGINT as usual.
2704 */
2705 check_and_run_traps();
Denys Vlasenko521220e2020-12-23 23:44:55 +01002706 if (r != '\0' && !G.flag_SIGINT)
Denys Vlasenko8660aeb2016-11-24 17:44:02 +01002707 break;
Denys Vlasenko521220e2020-12-23 23:44:55 +01002708 if (G.flag_SIGINT) {
2709 /* ^C or SIGINT: repeat */
2710 /* bash prints ^C even on real SIGINT (non-kbd generated) */
2711 /* kernel prints "^C" itself, just print newline: */
2712 write(STDOUT_FILENO, "\n", 1);
2713 G.last_exitcode = 128 | SIGINT;
2714 }
Denys Vlasenko8660aeb2016-11-24 17:44:02 +01002715 }
Denys Vlasenkod17a91d2016-09-29 18:02:37 +02002716 return r;
Denys Vlasenko8391c482010-05-22 17:50:43 +02002717# endif
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002718}
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002719/* This is the magic location that prints prompts
2720 * and gets data back from the user */
Denys Vlasenko4074d492016-09-30 01:49:53 +02002721static int fgetc_interactive(struct in_str *i)
2722{
2723 int ch;
2724 /* If it's interactive stdin, get new line. */
Denys Vlasenko21806562019-11-01 14:16:07 +01002725 if (G_interactive_fd && i->file == G.HFILE_stdin) {
Denys Vlasenko4074d492016-09-30 01:49:53 +02002726 /* Returns first char (or EOF), the rest is in i->p[] */
2727 ch = get_user_input(i);
Denys Vlasenko8d6eab32018-04-07 17:01:31 +02002728 G.promptmode = 1; /* PS2 */
2729 debug_printf_prompt("%s promptmode=%d\n", __func__, G.promptmode);
Denys Vlasenko4074d492016-09-30 01:49:53 +02002730 } else {
2731 /* Not stdin: script file, sourced file, etc */
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02002732 do ch = hfgetc(i->file); while (ch == '\0');
Denys Vlasenko4074d492016-09-30 01:49:53 +02002733 }
2734 return ch;
2735}
Denys Vlasenko649acb92020-12-23 15:29:13 +01002736#else /* !INTERACTIVE */
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02002737static ALWAYS_INLINE int fgetc_interactive(struct in_str *i)
Denys Vlasenko4074d492016-09-30 01:49:53 +02002738{
2739 int ch;
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02002740 do ch = hfgetc(i->file); while (ch == '\0');
Denys Vlasenko4074d492016-09-30 01:49:53 +02002741 return ch;
2742}
Denys Vlasenko649acb92020-12-23 15:29:13 +01002743#endif /* !INTERACTIVE */
Denys Vlasenko4074d492016-09-30 01:49:53 +02002744
Denys Vlasenko87e039d2016-11-08 22:35:05 +01002745static int i_getch(struct in_str *i)
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002746{
2747 int ch;
2748
Denys Vlasenko87e039d2016-11-08 22:35:05 +01002749 if (!i->file) {
2750 /* string-based in_str */
2751 ch = (unsigned char)*i->p;
2752 if (ch != '\0') {
2753 i->p++;
2754 i->last_char = ch;
2755 return ch;
2756 }
2757 return EOF;
2758 }
2759
2760 /* FILE-based in_str */
2761
Denys Vlasenko4074d492016-09-30 01:49:53 +02002762#if ENABLE_FEATURE_EDITING
2763 /* This can be stdin, check line editing char[] buffer */
2764 if (i->p && *i->p != '\0') {
2765 ch = (unsigned char)*i->p++;
2766 goto out;
2767 }
2768#endif
Denys Vlasenkod17a91d2016-09-29 18:02:37 +02002769 /* peek_buf[] is an int array, not char. Can contain EOF. */
2770 ch = i->peek_buf[0];
Denys Vlasenko4074d492016-09-30 01:49:53 +02002771 if (ch != 0) {
Denys Vlasenkod17a91d2016-09-29 18:02:37 +02002772 int ch2 = i->peek_buf[1];
2773 i->peek_buf[0] = ch2;
2774 if (ch2 == 0) /* very likely, avoid redundant write */
2775 goto out;
2776 i->peek_buf[1] = 0;
2777 goto out;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002778 }
Denys Vlasenkod17a91d2016-09-29 18:02:37 +02002779
Denys Vlasenko4074d492016-09-30 01:49:53 +02002780 ch = fgetc_interactive(i);
Denys Vlasenkod17a91d2016-09-29 18:02:37 +02002781 out:
Denis Vlasenko913a2012009-04-05 22:17:04 +00002782 debug_printf("file_get: got '%c' %d\n", ch, ch);
Denys Vlasenkocecbc982011-03-30 18:54:52 +02002783 i->last_char = ch;
Denys Vlasenko5807e182018-02-08 19:19:04 +01002784#if ENABLE_HUSH_LINENO_VAR
2785 if (ch == '\n') {
Denys Vlasenko08fb82c2019-05-19 15:26:05 +02002786 G.parse_lineno++;
2787 debug_printf_parse("G.parse_lineno++ = %u\n", G.parse_lineno);
Denys Vlasenko5807e182018-02-08 19:19:04 +01002788 }
Denys Vlasenko6aad1dd2018-01-19 15:37:04 +01002789#endif
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002790 return ch;
2791}
2792
Denys Vlasenko87e039d2016-11-08 22:35:05 +01002793static int i_peek(struct in_str *i)
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002794{
2795 int ch;
Denys Vlasenkod17a91d2016-09-29 18:02:37 +02002796
Denys Vlasenko87e039d2016-11-08 22:35:05 +01002797 if (!i->file) {
2798 /* string-based in_str */
2799 /* Doesn't report EOF on NUL. None of the callers care. */
2800 return (unsigned char)*i->p;
2801 }
2802
2803 /* FILE-based in_str */
2804
Denys Vlasenko4074d492016-09-30 01:49:53 +02002805#if ENABLE_FEATURE_EDITING && ENABLE_HUSH_INTERACTIVE
Denys Vlasenkod17a91d2016-09-29 18:02:37 +02002806 /* This can be stdin, check line editing char[] buffer */
2807 if (i->p && *i->p != '\0')
2808 return (unsigned char)*i->p;
2809#endif
Denys Vlasenkod17a91d2016-09-29 18:02:37 +02002810 /* peek_buf[] is an int array, not char. Can contain EOF. */
2811 ch = i->peek_buf[0];
Denys Vlasenko4074d492016-09-30 01:49:53 +02002812 if (ch != 0)
2813 return ch;
Denys Vlasenkod17a91d2016-09-29 18:02:37 +02002814
Denys Vlasenko4074d492016-09-30 01:49:53 +02002815 /* Need to get a new char */
2816 ch = fgetc_interactive(i);
2817 debug_printf("file_peek: got '%c' %d\n", ch, ch);
2818
2819 /* Save it by either rolling back line editing buffer, or in i->peek_buf[0] */
2820#if ENABLE_FEATURE_EDITING && ENABLE_HUSH_INTERACTIVE
2821 if (i->p) {
2822 i->p -= 1;
2823 return ch;
2824 }
Denys Vlasenkod17a91d2016-09-29 18:02:37 +02002825#endif
Denys Vlasenko4074d492016-09-30 01:49:53 +02002826 i->peek_buf[0] = ch;
2827 /*i->peek_buf[1] = 0; - already is */
Denys Vlasenkod17a91d2016-09-29 18:02:37 +02002828 return ch;
2829}
2830
Denys Vlasenko4074d492016-09-30 01:49:53 +02002831/* Only ever called if i_peek() was called, and did not return EOF.
2832 * IOW: we know the previous peek saw an ordinary char, not EOF, not NUL,
2833 * not end-of-line. Therefore we never need to read a new editing line here.
2834 */
2835static int i_peek2(struct in_str *i)
Denys Vlasenkod17a91d2016-09-29 18:02:37 +02002836{
Denys Vlasenko4074d492016-09-30 01:49:53 +02002837 int ch;
2838
2839 /* There are two cases when i->p[] buffer exists.
2840 * (1) it's a string in_str.
Denys Vlasenko08755f92016-09-30 02:02:25 +02002841 * (2) It's a file, and we have a saved line editing buffer.
Denys Vlasenko4074d492016-09-30 01:49:53 +02002842 * In both cases, we know that i->p[0] exists and not NUL, and
2843 * the peek2 result is in i->p[1].
2844 */
2845 if (i->p)
2846 return (unsigned char)i->p[1];
2847
2848 /* Now we know it is a file-based in_str. */
2849
2850 /* peek_buf[] is an int array, not char. Can contain EOF. */
2851 /* Is there 2nd char? */
2852 ch = i->peek_buf[1];
2853 if (ch == 0) {
2854 /* We did not read it yet, get it now */
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02002855 do ch = hfgetc(i->file); while (ch == '\0');
Denys Vlasenko4074d492016-09-30 01:49:53 +02002856 i->peek_buf[1] = ch;
2857 }
2858
2859 debug_printf("file_peek2: got '%c' %d\n", ch, ch);
2860 return ch;
Denys Vlasenkod17a91d2016-09-29 18:02:37 +02002861}
2862
Denys Vlasenkoa94eeb02018-03-31 20:16:31 +02002863static int i_getch_and_eat_bkslash_nl(struct in_str *input)
2864{
2865 for (;;) {
2866 int ch, ch2;
2867
2868 ch = i_getch(input);
2869 if (ch != '\\')
2870 return ch;
2871 ch2 = i_peek(input);
2872 if (ch2 != '\n')
2873 return ch;
2874 /* backslash+newline, skip it */
2875 i_getch(input);
2876 }
2877}
2878
2879/* Note: this function _eats_ \<newline> pairs, safe to use plain
2880 * i_getch() after it instead of i_getch_and_eat_bkslash_nl().
2881 */
2882static int i_peek_and_eat_bkslash_nl(struct in_str *input)
2883{
2884 for (;;) {
2885 int ch, ch2;
2886
2887 ch = i_peek(input);
2888 if (ch != '\\')
2889 return ch;
2890 ch2 = i_peek2(input);
2891 if (ch2 != '\n')
2892 return ch;
2893 /* backslash+newline, skip it */
2894 i_getch(input);
2895 i_getch(input);
2896 }
2897}
2898
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02002899static void setup_file_in_str(struct in_str *i, HFILE *fp)
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002900{
Denys Vlasenkoa1463192011-01-18 17:55:04 +01002901 memset(i, 0, sizeof(*i));
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02002902 i->file = fp;
Denys Vlasenkoa1463192011-01-18 17:55:04 +01002903 /* i->p = NULL; */
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002904}
2905
2906static void setup_string_in_str(struct in_str *i, const char *s)
2907{
Denys Vlasenkoa1463192011-01-18 17:55:04 +01002908 memset(i, 0, sizeof(*i));
Denys Vlasenko87e039d2016-11-08 22:35:05 +01002909 /*i->file = NULL */;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002910 i->p = s;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00002911}
2912
2913
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00002914/*
2915 * o_string support
2916 */
2917#define B_CHUNK (32 * sizeof(char*))
Eric Andersen25f27032001-04-26 23:22:31 +00002918
Denis Vlasenko0b677d82009-04-10 13:49:10 +00002919static void o_reset_to_empty_unquoted(o_string *o)
Eric Andersen25f27032001-04-26 23:22:31 +00002920{
2921 o->length = 0;
Denys Vlasenko38292b62010-09-05 14:49:40 +02002922 o->has_quoted_part = 0;
Denis Vlasenkod65ea392007-10-01 10:02:25 +00002923 if (o->data)
2924 o->data[0] = '\0';
Eric Andersen25f27032001-04-26 23:22:31 +00002925}
2926
Denys Vlasenko18567402018-07-20 17:51:31 +02002927static void o_free_and_set_NULL(o_string *o)
Eric Andersen25f27032001-04-26 23:22:31 +00002928{
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00002929 free(o->data);
Denis Vlasenkod65ea392007-10-01 10:02:25 +00002930 memset(o, 0, sizeof(*o));
Eric Andersen25f27032001-04-26 23:22:31 +00002931}
2932
Denys Vlasenko18567402018-07-20 17:51:31 +02002933static ALWAYS_INLINE void o_free(o_string *o)
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00002934{
2935 free(o->data);
2936}
2937
Denis Vlasenko46ccdcb2008-06-10 18:05:12 +00002938static void o_grow_by(o_string *o, int len)
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00002939{
2940 if (o->length + len > o->maxlen) {
Denys Vlasenko46e64982016-09-29 19:50:55 +02002941 o->maxlen += (2 * len) | (B_CHUNK-1);
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00002942 o->data = xrealloc(o->data, 1 + o->maxlen);
2943 }
2944}
2945
Denis Vlasenko46ccdcb2008-06-10 18:05:12 +00002946static void o_addchr(o_string *o, int ch)
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00002947{
Denis Vlasenko46ccdcb2008-06-10 18:05:12 +00002948 debug_printf("o_addchr: '%c' o->length=%d o=%p\n", ch, o->length, o);
Denys Vlasenko46e64982016-09-29 19:50:55 +02002949 if (o->length < o->maxlen) {
2950 /* likely. avoid o_grow_by() call */
2951 add:
2952 o->data[o->length] = ch;
2953 o->length++;
2954 o->data[o->length] = '\0';
2955 return;
2956 }
Denis Vlasenko46ccdcb2008-06-10 18:05:12 +00002957 o_grow_by(o, 1);
Denys Vlasenko46e64982016-09-29 19:50:55 +02002958 goto add;
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00002959}
2960
Denys Vlasenko657086a2016-09-29 18:07:42 +02002961#if 0
2962/* Valid only if we know o_string is not empty */
2963static void o_delchr(o_string *o)
2964{
2965 o->length--;
2966 o->data[o->length] = '\0';
2967}
2968#endif
2969
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00002970static void o_addblock(o_string *o, const char *str, int len)
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00002971{
Denis Vlasenko46ccdcb2008-06-10 18:05:12 +00002972 o_grow_by(o, len);
Denys Vlasenko0675b032017-07-24 02:17:05 +02002973 ((char*)mempcpy(&o->data[o->length], str, len))[0] = '\0';
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00002974 o->length += len;
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00002975}
2976
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00002977static void o_addstr(o_string *o, const char *str)
Mike Frysinger98c52642009-04-02 10:02:37 +00002978{
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00002979 o_addblock(o, str, strlen(str));
2980}
Denys Vlasenko2e48d532010-05-22 17:30:39 +02002981
Denys Vlasenkoaa449c92018-07-28 12:13:58 +02002982static void o_addstr_with_NUL(o_string *o, const char *str)
2983{
2984 o_addblock(o, str, strlen(str) + 1);
2985}
2986
Denys Vlasenko1e811b12010-05-22 03:12:29 +02002987#if !BB_MMU
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00002988static void nommu_addchr(o_string *o, int ch)
2989{
2990 if (o)
2991 o_addchr(o, ch);
2992}
2993#else
Denys Vlasenko28a105d2009-06-01 11:26:30 +02002994# define nommu_addchr(o, str) ((void)0)
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00002995#endif
2996
Denys Vlasenkoaa449c92018-07-28 12:13:58 +02002997#if ENABLE_HUSH_MODE_X
2998static void x_mode_addchr(int ch)
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00002999{
Denys Vlasenkoaa449c92018-07-28 12:13:58 +02003000 o_addchr(&G.x_mode_buf, ch);
Mike Frysinger98c52642009-04-02 10:02:37 +00003001}
Denys Vlasenkoaa449c92018-07-28 12:13:58 +02003002static void x_mode_addstr(const char *str)
3003{
3004 o_addstr(&G.x_mode_buf, str);
3005}
3006static void x_mode_addblock(const char *str, int len)
3007{
3008 o_addblock(&G.x_mode_buf, str, len);
3009}
3010static void x_mode_prefix(void)
3011{
3012 int n = G.x_mode_depth;
3013 do x_mode_addchr('+'); while (--n >= 0);
3014}
3015static void x_mode_flush(void)
3016{
3017 int len = G.x_mode_buf.length;
3018 if (len <= 0)
3019 return;
3020 if (G.x_mode_fd > 0) {
3021 G.x_mode_buf.data[len] = '\n';
3022 full_write(G.x_mode_fd, G.x_mode_buf.data, len + 1);
3023 }
3024 G.x_mode_buf.length = 0;
3025}
3026#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00003027
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003028/*
Denys Vlasenko238081f2010-10-03 14:26:26 +02003029 * HUSH_BRACE_EXPANSION code needs corresponding quoting on variable expansion side.
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003030 * Currently, "v='{q,w}'; echo $v" erroneously expands braces in $v.
3031 * Apparently, on unquoted $v bash still does globbing
3032 * ("v='*.txt'; echo $v" prints all .txt files),
3033 * but NOT brace expansion! Thus, there should be TWO independent
3034 * quoting mechanisms on $v expansion side: one protects
3035 * $v from brace expansion, and other additionally protects "$v" against globbing.
3036 * We have only second one.
3037 */
3038
Denys Vlasenko9e800222010-10-03 14:28:04 +02003039#if ENABLE_HUSH_BRACE_EXPANSION
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003040# define MAYBE_BRACES "{}"
3041#else
3042# define MAYBE_BRACES ""
3043#endif
3044
Eric Andersen25f27032001-04-26 23:22:31 +00003045/* My analysis of quoting semantics tells me that state information
3046 * is associated with a destination, not a source.
3047 */
Denis Vlasenko7e3d33b2008-06-12 13:31:04 +00003048static void o_addqchr(o_string *o, int ch)
Eric Andersen25f27032001-04-26 23:22:31 +00003049{
Denis Vlasenko7e3d33b2008-06-12 13:31:04 +00003050 int sz = 1;
Denys Vlasenkoe4a06122020-02-21 17:21:34 +01003051 /* '-' is included because of this case:
3052 * >filename0 >filename1 >filename9; v='-'; echo filename[0"$v"9]
3053 */
3054 char *found = strchr("*?[-\\" MAYBE_BRACES, ch);
Denis Vlasenko371de4a2008-10-14 12:43:13 +00003055 if (found)
Denis Vlasenko7e3d33b2008-06-12 13:31:04 +00003056 sz++;
Denis Vlasenko371de4a2008-10-14 12:43:13 +00003057 o_grow_by(o, sz);
3058 if (found) {
Denis Vlasenko7e3d33b2008-06-12 13:31:04 +00003059 o->data[o->length] = '\\';
3060 o->length++;
Eric Andersen25f27032001-04-26 23:22:31 +00003061 }
Denis Vlasenko7e3d33b2008-06-12 13:31:04 +00003062 o->data[o->length] = ch;
3063 o->length++;
3064 o->data[o->length] = '\0';
Eric Andersen25f27032001-04-26 23:22:31 +00003065}
3066
Denis Vlasenko7e3d33b2008-06-12 13:31:04 +00003067static void o_addQchr(o_string *o, int ch)
Denis Vlasenko87f40ba2008-06-10 22:39:37 +00003068{
Denis Vlasenko7e3d33b2008-06-12 13:31:04 +00003069 int sz = 1;
Denys Vlasenko5b686cb2010-09-08 13:44:34 +02003070 if ((o->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)
Denys Vlasenkoe4a06122020-02-21 17:21:34 +01003071 && strchr("*?[-\\" MAYBE_BRACES, ch)
Denys Vlasenko5b686cb2010-09-08 13:44:34 +02003072 ) {
Denis Vlasenko7e3d33b2008-06-12 13:31:04 +00003073 sz++;
3074 o->data[o->length] = '\\';
3075 o->length++;
3076 }
3077 o_grow_by(o, sz);
3078 o->data[o->length] = ch;
3079 o->length++;
3080 o->data[o->length] = '\0';
3081}
3082
Denys Vlasenkoc49d2d92010-09-06 10:26:37 +02003083static void o_addqblock(o_string *o, const char *str, int len)
Denis Vlasenko7e3d33b2008-06-12 13:31:04 +00003084{
Denis Vlasenko87f40ba2008-06-10 22:39:37 +00003085 while (len) {
Denis Vlasenko7e3d33b2008-06-12 13:31:04 +00003086 char ch;
3087 int sz;
Denys Vlasenkoe4a06122020-02-21 17:21:34 +01003088 int ordinary_cnt = strcspn(str, "*?[-\\" MAYBE_BRACES);
Denis Vlasenko7e3d33b2008-06-12 13:31:04 +00003089 if (ordinary_cnt > len) /* paranoia */
3090 ordinary_cnt = len;
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00003091 o_addblock(o, str, ordinary_cnt);
Denis Vlasenko7e3d33b2008-06-12 13:31:04 +00003092 if (ordinary_cnt == len)
Denys Vlasenko4fb53fb2011-08-01 14:06:20 +02003093 return; /* NUL is already added by o_addblock */
Denis Vlasenko7e3d33b2008-06-12 13:31:04 +00003094 str += ordinary_cnt;
Denis Vlasenko30c9cc52008-06-17 07:24:29 +00003095 len -= ordinary_cnt + 1; /* we are processing + 1 char below */
Denis Vlasenko7e3d33b2008-06-12 13:31:04 +00003096
Denis Vlasenko87f40ba2008-06-10 22:39:37 +00003097 ch = *str++;
Denis Vlasenko7e3d33b2008-06-12 13:31:04 +00003098 sz = 1;
Denys Vlasenkoe4a06122020-02-21 17:21:34 +01003099 if (ch) { /* it is necessarily one of "*?[-\\" MAYBE_BRACES */
Denis Vlasenko7e3d33b2008-06-12 13:31:04 +00003100 sz++;
3101 o->data[o->length] = '\\';
3102 o->length++;
Denis Vlasenko87f40ba2008-06-10 22:39:37 +00003103 }
Denis Vlasenko7e3d33b2008-06-12 13:31:04 +00003104 o_grow_by(o, sz);
3105 o->data[o->length] = ch;
3106 o->length++;
Denis Vlasenko87f40ba2008-06-10 22:39:37 +00003107 }
Denys Vlasenko4fb53fb2011-08-01 14:06:20 +02003108 o->data[o->length] = '\0';
Denis Vlasenko87f40ba2008-06-10 22:39:37 +00003109}
3110
Denys Vlasenkoc49d2d92010-09-06 10:26:37 +02003111static void o_addQblock(o_string *o, const char *str, int len)
3112{
Denys Vlasenko5b686cb2010-09-08 13:44:34 +02003113 if (!(o->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)) {
Denys Vlasenkoc49d2d92010-09-06 10:26:37 +02003114 o_addblock(o, str, len);
3115 return;
3116 }
3117 o_addqblock(o, str, len);
3118}
3119
Denys Vlasenko38292b62010-09-05 14:49:40 +02003120static void o_addQstr(o_string *o, const char *str)
3121{
3122 o_addQblock(o, str, strlen(str));
3123}
3124
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00003125/* A special kind of o_string for $VAR and `cmd` expansion.
3126 * It contains char* list[] at the beginning, which is grown in 16 element
Denis Vlasenkoc7985b72008-06-17 05:43:38 +00003127 * increments. Actual string data starts at the next multiple of 16 * (char*).
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00003128 * list[i] contains an INDEX (int!) into this string data.
3129 * It means that if list[] needs to grow, data needs to be moved higher up
3130 * but list[i]'s need not be modified.
3131 * NB: remembering how many list[i]'s you have there is crucial.
Denis Vlasenko46ccdcb2008-06-10 18:05:12 +00003132 * o_finalize_list() operation post-processes this structure - calculates
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00003133 * and stores actual char* ptrs in list[]. Oh, it NULL terminates it as well.
3134 */
Denis Vlasenkob61e13d2008-06-17 05:11:43 +00003135#if DEBUG_EXPAND || DEBUG_GLOB
3136static void debug_print_list(const char *prefix, o_string *o, int n)
3137{
3138 char **list = (char**)o->data;
3139 int string_start = ((n + 0xf) & ~0xf) * sizeof(list[0]);
3140 int i = 0;
Denis Vlasenko0701dca2009-04-11 10:38:47 +00003141
3142 indent();
Denys Vlasenko75eb9d22010-12-21 21:18:12 +01003143 fdprintf(2, "%s: list:%p n:%d string_start:%d length:%d maxlen:%d glob:%d quoted:%d escape:%d\n",
Denys Vlasenko5b686cb2010-09-08 13:44:34 +02003144 prefix, list, n, string_start, o->length, o->maxlen,
3145 !!(o->o_expflags & EXP_FLAG_GLOB),
3146 o->has_quoted_part,
3147 !!(o->o_expflags & EXP_FLAG_ESC_GLOB_CHARS));
Denis Vlasenkob61e13d2008-06-17 05:11:43 +00003148 while (i < n) {
Denis Vlasenko0701dca2009-04-11 10:38:47 +00003149 indent();
Denys Vlasenko75eb9d22010-12-21 21:18:12 +01003150 fdprintf(2, " list[%d]=%d '%s' %p\n", i, (int)(uintptr_t)list[i],
3151 o->data + (int)(uintptr_t)list[i] + string_start,
3152 o->data + (int)(uintptr_t)list[i] + string_start);
Denis Vlasenkob61e13d2008-06-17 05:11:43 +00003153 i++;
3154 }
3155 if (n) {
Denys Vlasenko75eb9d22010-12-21 21:18:12 +01003156 const char *p = o->data + (int)(uintptr_t)list[n - 1] + string_start;
Denis Vlasenko0701dca2009-04-11 10:38:47 +00003157 indent();
Denys Vlasenko75eb9d22010-12-21 21:18:12 +01003158 fdprintf(2, " total_sz:%ld\n", (long)((p + strlen(p) + 1) - o->data));
Denis Vlasenkob61e13d2008-06-17 05:11:43 +00003159 }
3160}
3161#else
Denys Vlasenko28a105d2009-06-01 11:26:30 +02003162# define debug_print_list(prefix, o, n) ((void)0)
Denis Vlasenkob61e13d2008-06-17 05:11:43 +00003163#endif
3164
3165/* n = o_save_ptr_helper(str, n) "starts new string" by storing an index value
3166 * in list[n] so that it points past last stored byte so far.
3167 * It returns n+1. */
3168static int o_save_ptr_helper(o_string *o, int n)
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00003169{
3170 char **list = (char**)o->data;
Denis Vlasenko895bea22008-06-10 18:06:24 +00003171 int string_start;
3172 int string_len;
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00003173
3174 if (!o->has_empty_slot) {
Denis Vlasenko895bea22008-06-10 18:06:24 +00003175 string_start = ((n + 0xf) & ~0xf) * sizeof(list[0]);
3176 string_len = o->length - string_start;
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00003177 if (!(n & 0xf)) { /* 0, 0x10, 0x20...? */
Denis Vlasenko30c9cc52008-06-17 07:24:29 +00003178 debug_printf_list("list[%d]=%d string_start=%d (growing)\n", n, string_len, string_start);
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00003179 /* list[n] points to string_start, make space for 16 more pointers */
3180 o->maxlen += 0x10 * sizeof(list[0]);
3181 o->data = xrealloc(o->data, o->maxlen + 1);
Denis Vlasenko7049ff82008-06-25 09:53:17 +00003182 list = (char**)o->data;
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00003183 memmove(list + n + 0x10, list + n, string_len);
Denys Vlasenko186cf492018-07-27 12:14:39 +02003184 /*
3185 * expand_on_ifs() has a "previous argv[] ends in IFS?"
3186 * check. (grep for -prev-ifs-check-).
3187 * Ensure that argv[-1][last] is not garbage
3188 * but zero bytes, to save index check there.
3189 */
3190 list[n + 0x10 - 1] = 0;
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00003191 o->length += 0x10 * sizeof(list[0]);
Denis Vlasenkoa24c8ca2009-04-04 15:24:40 +00003192 } else {
3193 debug_printf_list("list[%d]=%d string_start=%d\n",
3194 n, string_len, string_start);
3195 }
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00003196 } else {
3197 /* We have empty slot at list[n], reuse without growth */
Denis Vlasenko895bea22008-06-10 18:06:24 +00003198 string_start = ((n+1 + 0xf) & ~0xf) * sizeof(list[0]); /* NB: n+1! */
3199 string_len = o->length - string_start;
Denis Vlasenkoa24c8ca2009-04-04 15:24:40 +00003200 debug_printf_list("list[%d]=%d string_start=%d (empty slot)\n",
3201 n, string_len, string_start);
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00003202 o->has_empty_slot = 0;
3203 }
Denys Vlasenko4fb53fb2011-08-01 14:06:20 +02003204 o->has_quoted_part = 0;
Denys Vlasenkoda463fb2010-09-07 09:53:50 +02003205 list[n] = (char*)(uintptr_t)string_len;
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00003206 return n + 1;
3207}
3208
Denis Vlasenkob61e13d2008-06-17 05:11:43 +00003209/* "What was our last o_save_ptr'ed position (byte offset relative o->data)?" */
Denis Vlasenko46ccdcb2008-06-10 18:05:12 +00003210static int o_get_last_ptr(o_string *o, int n)
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00003211{
3212 char **list = (char**)o->data;
3213 int string_start = ((n + 0xf) & ~0xf) * sizeof(list[0]);
3214
Denys Vlasenkoda463fb2010-09-07 09:53:50 +02003215 return ((int)(uintptr_t)list[n-1]) + string_start;
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00003216}
3217
Denys Vlasenko4bf08542018-08-11 18:44:11 +02003218/*
3219 * Globbing routines.
3220 *
3221 * Most words in commands need to be globbed, even ones which are
3222 * (single or double) quoted. This stems from the possiblity of
3223 * constructs like "abc"* and 'abc'* - these should be globbed.
3224 * Having a different code path for fully-quoted strings ("abc",
3225 * 'abc') would only help performance-wise, but we still need
3226 * code for partially-quoted strings.
3227 *
3228 * Unfortunately, if we want to match bash and ash behavior in all cases,
Denys Vlasenkoc97df292018-08-14 11:04:58 +02003229 * the logic can't be "shell-syntax argument is first transformed
Denys Vlasenko4bf08542018-08-11 18:44:11 +02003230 * to a string, then globbed, and if globbing does not match anything,
3231 * it is used verbatim". Here are two examples where it fails:
3232 *
3233 * echo 'b\*'?
3234 *
3235 * The globbing can't be avoided (because of '?' at the end).
3236 * The glob pattern is: b\\\*? - IOW, both \ and * are literals
3237 * and are glob-escaped. If this does not match, bash/ash print b\*?
Denys Vlasenkoc97df292018-08-14 11:04:58 +02003238 * - IOW: they "unbackslash" the glob pattern.
Denys Vlasenko4bf08542018-08-11 18:44:11 +02003239 * Now, look at this:
3240 *
3241 * v='\\\*'; echo b$v?
3242 *
Denys Vlasenkoc97df292018-08-14 11:04:58 +02003243 * The glob pattern is the same here: b\\\*? - the unquoted $v expansion
Denys Vlasenko4bf08542018-08-11 18:44:11 +02003244 * should be used as glob pattern with no changes. However, if glob
Denys Vlasenkoc97df292018-08-14 11:04:58 +02003245 * does not match, bash/ash print b\\\*? - NOT THE SAME as first example!
Denys Vlasenko4bf08542018-08-11 18:44:11 +02003246 *
3247 * ash implements this by having an encoded representation of the word
3248 * to glob, which IS NOT THE SAME as the glob pattern - it has more data.
3249 * Glob pattern is derived from it. If glob fails, the decision what result
3250 * should be is made using that encoded representation. Not glob pattern.
3251 */
3252
Denys Vlasenko9e800222010-10-03 14:28:04 +02003253#if ENABLE_HUSH_BRACE_EXPANSION
Denys Vlasenko5b2db972009-11-16 05:49:36 +01003254/* There in a GNU extension, GLOB_BRACE, but it is not usable:
3255 * first, it processes even {a} (no commas), second,
3256 * I didn't manage to make it return strings when they don't match
Denys Vlasenko160746b2009-11-16 05:51:18 +01003257 * existing files. Need to re-implement it.
Denys Vlasenko5b2db972009-11-16 05:49:36 +01003258 */
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003259
3260/* Helper */
3261static int glob_needed(const char *s)
3262{
3263 while (*s) {
3264 if (*s == '\\') {
3265 if (!s[1])
3266 return 0;
3267 s += 2;
3268 continue;
3269 }
3270 if (*s == '*' || *s == '[' || *s == '?' || *s == '{')
3271 return 1;
3272 s++;
3273 }
3274 return 0;
3275}
Denys Vlasenko5b2db972009-11-16 05:49:36 +01003276/* Return pointer to next closing brace or to comma */
3277static const char *next_brace_sub(const char *cp)
3278{
3279 unsigned depth = 0;
3280 cp++;
3281 while (*cp != '\0') {
3282 if (*cp == '\\') {
3283 if (*++cp == '\0')
3284 break;
3285 cp++;
3286 continue;
Denys Vlasenko3581c622010-01-25 13:39:24 +01003287 }
Denys Vlasenkoda463fb2010-09-07 09:53:50 +02003288 if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0))
Denys Vlasenko5b2db972009-11-16 05:49:36 +01003289 break;
Denys Vlasenkoda463fb2010-09-07 09:53:50 +02003290 if (*cp++ == '{')
Denys Vlasenko5b2db972009-11-16 05:49:36 +01003291 depth++;
3292 }
3293
3294 return *cp != '\0' ? cp : NULL;
3295}
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003296/* Recursive brace globber. Note: may garble pattern[]. */
3297static int glob_brace(char *pattern, o_string *o, int n)
Denys Vlasenko5b2db972009-11-16 05:49:36 +01003298{
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003299 char *new_pattern_buf;
Denys Vlasenko5b2db972009-11-16 05:49:36 +01003300 const char *begin;
Denys Vlasenko5b2db972009-11-16 05:49:36 +01003301 const char *next;
3302 const char *rest;
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003303 const char *p;
Denys Vlasenko5b2db972009-11-16 05:49:36 +01003304 size_t rest_len;
Denys Vlasenko5b2db972009-11-16 05:49:36 +01003305
3306 debug_printf_glob("glob_brace('%s')\n", pattern);
3307
3308 begin = pattern;
3309 while (1) {
3310 if (*begin == '\0')
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003311 goto simple_glob;
Denys Vlasenkoda463fb2010-09-07 09:53:50 +02003312 if (*begin == '{') {
Denys Vlasenko5b2db972009-11-16 05:49:36 +01003313 /* Find the first sub-pattern and at the same time
3314 * find the rest after the closing brace */
3315 next = next_brace_sub(begin);
3316 if (next == NULL) {
3317 /* An illegal expression */
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003318 goto simple_glob;
Denys Vlasenko5b2db972009-11-16 05:49:36 +01003319 }
Denys Vlasenkoda463fb2010-09-07 09:53:50 +02003320 if (*next == '}') {
Denys Vlasenko5b2db972009-11-16 05:49:36 +01003321 /* "{abc}" with no commas - illegal
3322 * brace expr, disregard and skip it */
3323 begin = next + 1;
3324 continue;
3325 }
3326 break;
3327 }
3328 if (*begin == '\\' && begin[1] != '\0')
3329 begin++;
3330 begin++;
3331 }
3332 debug_printf_glob("begin:%s\n", begin);
3333 debug_printf_glob("next:%s\n", next);
3334
3335 /* Now find the end of the whole brace expression */
3336 rest = next;
Denys Vlasenkoda463fb2010-09-07 09:53:50 +02003337 while (*rest != '}') {
Denys Vlasenko5b2db972009-11-16 05:49:36 +01003338 rest = next_brace_sub(rest);
3339 if (rest == NULL) {
3340 /* An illegal expression */
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003341 goto simple_glob;
Denys Vlasenko5b2db972009-11-16 05:49:36 +01003342 }
3343 debug_printf_glob("rest:%s\n", rest);
3344 }
3345 rest_len = strlen(++rest) + 1;
3346
3347 /* We are sure the brace expression is well-formed */
3348
3349 /* Allocate working buffer large enough for our work */
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003350 new_pattern_buf = xmalloc(strlen(pattern));
Denys Vlasenko5b2db972009-11-16 05:49:36 +01003351
3352 /* We have a brace expression. BEGIN points to the opening {,
3353 * NEXT points past the terminator of the first element, and REST
3354 * points past the final }. We will accumulate result names from
3355 * recursive runs for each brace alternative in the buffer using
3356 * GLOB_APPEND. */
3357
3358 p = begin + 1;
3359 while (1) {
Denys Vlasenko5b2db972009-11-16 05:49:36 +01003360 /* Construct the new glob expression */
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003361 memcpy(
3362 mempcpy(
3363 mempcpy(new_pattern_buf,
3364 /* We know the prefix for all sub-patterns */
3365 pattern, begin - pattern),
3366 p, next - p),
3367 rest, rest_len);
Denys Vlasenko5b2db972009-11-16 05:49:36 +01003368
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003369 /* Note: glob_brace() may garble new_pattern_buf[].
3370 * That's why we re-copy prefix every time (1st memcpy above).
3371 */
3372 n = glob_brace(new_pattern_buf, o, n);
Denys Vlasenkoda463fb2010-09-07 09:53:50 +02003373 if (*next == '}') {
Denys Vlasenko5b2db972009-11-16 05:49:36 +01003374 /* We saw the last entry */
3375 break;
3376 }
3377 p = next + 1;
3378 next = next_brace_sub(next);
3379 }
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003380 free(new_pattern_buf);
3381 return n;
Denys Vlasenko5b2db972009-11-16 05:49:36 +01003382
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003383 simple_glob:
3384 {
3385 int gr;
3386 glob_t globdata;
Denys Vlasenko5b2db972009-11-16 05:49:36 +01003387
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003388 memset(&globdata, 0, sizeof(globdata));
3389 gr = glob(pattern, 0, NULL, &globdata);
3390 debug_printf_glob("glob('%s'):%d\n", pattern, gr);
3391 if (gr != 0) {
3392 if (gr == GLOB_NOMATCH) {
3393 globfree(&globdata);
3394 /* NB: garbles parameter */
3395 unbackslash(pattern);
3396 o_addstr_with_NUL(o, pattern);
3397 debug_printf_glob("glob pattern '%s' is literal\n", pattern);
3398 return o_save_ptr_helper(o, n);
3399 }
3400 if (gr == GLOB_NOSPACE)
Denys Vlasenko899ae532018-04-01 19:59:37 +02003401 bb_die_memory_exhausted();
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003402 /* GLOB_ABORTED? Only happens with GLOB_ERR flag,
3403 * but we didn't specify it. Paranoia again. */
3404 bb_error_msg_and_die("glob error %d on '%s'", gr, pattern);
3405 }
3406 if (globdata.gl_pathv && globdata.gl_pathv[0]) {
3407 char **argv = globdata.gl_pathv;
3408 while (1) {
3409 o_addstr_with_NUL(o, *argv);
3410 n = o_save_ptr_helper(o, n);
3411 argv++;
3412 if (!*argv)
3413 break;
3414 }
3415 }
3416 globfree(&globdata);
3417 }
3418 return n;
Denys Vlasenko5b2db972009-11-16 05:49:36 +01003419}
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003420/* Performs globbing on last list[],
3421 * saving each result as a new list[].
3422 */
Denys Vlasenkoc49d2d92010-09-06 10:26:37 +02003423static int perform_glob(o_string *o, int n)
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003424{
3425 char *pattern, *copy;
Denys Vlasenko5b2db972009-11-16 05:49:36 +01003426
Denys Vlasenkoc49d2d92010-09-06 10:26:37 +02003427 debug_printf_glob("start perform_glob: n:%d o->data:%p\n", n, o->data);
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003428 if (!o->data)
3429 return o_save_ptr_helper(o, n);
3430 pattern = o->data + o_get_last_ptr(o, n);
3431 debug_printf_glob("glob pattern '%s'\n", pattern);
3432 if (!glob_needed(pattern)) {
3433 /* unbackslash last string in o in place, fix length */
3434 o->length = unbackslash(pattern) - o->data;
3435 debug_printf_glob("glob pattern '%s' is literal\n", pattern);
3436 return o_save_ptr_helper(o, n);
3437 }
3438
3439 copy = xstrdup(pattern);
3440 /* "forget" pattern in o */
3441 o->length = pattern - o->data;
3442 n = glob_brace(copy, o, n);
3443 free(copy);
3444 if (DEBUG_GLOB)
Denys Vlasenkoc49d2d92010-09-06 10:26:37 +02003445 debug_print_list("perform_glob returning", o, n);
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003446 return n;
3447}
3448
Denys Vlasenko238081f2010-10-03 14:26:26 +02003449#else /* !HUSH_BRACE_EXPANSION */
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003450
3451/* Helper */
3452static int glob_needed(const char *s)
3453{
3454 while (*s) {
3455 if (*s == '\\') {
3456 if (!s[1])
3457 return 0;
3458 s += 2;
3459 continue;
3460 }
3461 if (*s == '*' || *s == '[' || *s == '?')
3462 return 1;
3463 s++;
3464 }
3465 return 0;
3466}
3467/* Performs globbing on last list[],
3468 * saving each result as a new list[].
3469 */
Denys Vlasenkoc49d2d92010-09-06 10:26:37 +02003470static int perform_glob(o_string *o, int n)
Denis Vlasenkob61e13d2008-06-17 05:11:43 +00003471{
3472 glob_t globdata;
3473 int gr;
3474 char *pattern;
3475
Denys Vlasenkoc49d2d92010-09-06 10:26:37 +02003476 debug_printf_glob("start perform_glob: n:%d o->data:%p\n", n, o->data);
Denis Vlasenkob61e13d2008-06-17 05:11:43 +00003477 if (!o->data)
3478 return o_save_ptr_helper(o, n);
3479 pattern = o->data + o_get_last_ptr(o, n);
Denis Vlasenko30c9cc52008-06-17 07:24:29 +00003480 debug_printf_glob("glob pattern '%s'\n", pattern);
Denis Vlasenkob61e13d2008-06-17 05:11:43 +00003481 if (!glob_needed(pattern)) {
3482 literal:
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003483 /* unbackslash last string in o in place, fix length */
Denis Vlasenkob61e13d2008-06-17 05:11:43 +00003484 o->length = unbackslash(pattern) - o->data;
Denis Vlasenko30c9cc52008-06-17 07:24:29 +00003485 debug_printf_glob("glob pattern '%s' is literal\n", pattern);
Denis Vlasenkob61e13d2008-06-17 05:11:43 +00003486 return o_save_ptr_helper(o, n);
3487 }
3488
3489 memset(&globdata, 0, sizeof(globdata));
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003490 /* Can't use GLOB_NOCHECK: it does not unescape the string.
3491 * If we glob "*.\*" and don't find anything, we need
3492 * to fall back to using literal "*.*", but GLOB_NOCHECK
3493 * will return "*.\*"!
3494 */
Denis Vlasenkob61e13d2008-06-17 05:11:43 +00003495 gr = glob(pattern, 0, NULL, &globdata);
3496 debug_printf_glob("glob('%s'):%d\n", pattern, gr);
Denys Vlasenko5b2db972009-11-16 05:49:36 +01003497 if (gr != 0) {
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003498 if (gr == GLOB_NOMATCH) {
3499 globfree(&globdata);
3500 goto literal;
3501 }
3502 if (gr == GLOB_NOSPACE)
Denys Vlasenko899ae532018-04-01 19:59:37 +02003503 bb_die_memory_exhausted();
Denys Vlasenko5b2db972009-11-16 05:49:36 +01003504 /* GLOB_ABORTED? Only happens with GLOB_ERR flag,
3505 * but we didn't specify it. Paranoia again. */
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003506 bb_error_msg_and_die("glob error %d on '%s'", gr, pattern);
Denis Vlasenkob61e13d2008-06-17 05:11:43 +00003507 }
3508 if (globdata.gl_pathv && globdata.gl_pathv[0]) {
3509 char **argv = globdata.gl_pathv;
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003510 /* "forget" pattern in o */
3511 o->length = pattern - o->data;
Denis Vlasenkob61e13d2008-06-17 05:11:43 +00003512 while (1) {
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00003513 o_addstr_with_NUL(o, *argv);
Denis Vlasenkob61e13d2008-06-17 05:11:43 +00003514 n = o_save_ptr_helper(o, n);
3515 argv++;
3516 if (!*argv)
3517 break;
3518 }
3519 }
3520 globfree(&globdata);
3521 if (DEBUG_GLOB)
Denys Vlasenkoc49d2d92010-09-06 10:26:37 +02003522 debug_print_list("perform_glob returning", o, n);
Denis Vlasenkob61e13d2008-06-17 05:11:43 +00003523 return n;
3524}
3525
Denys Vlasenko238081f2010-10-03 14:26:26 +02003526#endif /* !HUSH_BRACE_EXPANSION */
Denys Vlasenkof3e28182009-11-17 03:35:31 +01003527
Denys Vlasenko5b686cb2010-09-08 13:44:34 +02003528/* If o->o_expflags & EXP_FLAG_GLOB, glob the string so far remembered.
Denis Vlasenkoc7985b72008-06-17 05:43:38 +00003529 * Otherwise, just finish current list[] and start new */
Denis Vlasenkob61e13d2008-06-17 05:11:43 +00003530static int o_save_ptr(o_string *o, int n)
3531{
Denys Vlasenko5b686cb2010-09-08 13:44:34 +02003532 if (o->o_expflags & EXP_FLAG_GLOB) {
Denis Vlasenkoa8b6dff2009-03-20 12:05:14 +00003533 /* If o->has_empty_slot, list[n] was already globbed
3534 * (if it was requested back then when it was filled)
3535 * so don't do that again! */
3536 if (!o->has_empty_slot)
Denys Vlasenkoc49d2d92010-09-06 10:26:37 +02003537 return perform_glob(o, n); /* o_save_ptr_helper is inside */
Denis Vlasenkoa8b6dff2009-03-20 12:05:14 +00003538 }
Denis Vlasenkob61e13d2008-06-17 05:11:43 +00003539 return o_save_ptr_helper(o, n);
3540}
3541
3542/* "Please convert list[n] to real char* ptrs, and NULL terminate it." */
Denis Vlasenko46ccdcb2008-06-10 18:05:12 +00003543static char **o_finalize_list(o_string *o, int n)
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00003544{
Denis Vlasenkob61e13d2008-06-17 05:11:43 +00003545 char **list;
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00003546 int string_start;
3547
Denis Vlasenkob61e13d2008-06-17 05:11:43 +00003548 if (DEBUG_EXPAND)
3549 debug_print_list("finalized", o, n);
Denis Vlasenko30c9cc52008-06-17 07:24:29 +00003550 debug_printf_expand("finalized n:%d\n", n);
Denis Vlasenkob61e13d2008-06-17 05:11:43 +00003551 list = (char**)o->data;
3552 string_start = ((n + 0xf) & ~0xf) * sizeof(list[0]);
3553 list[--n] = NULL;
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00003554 while (n) {
3555 n--;
Denys Vlasenko27c56f12010-09-07 09:56:34 +02003556 list[n] = o->data + (int)(uintptr_t)list[n] + string_start;
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00003557 }
3558 return list;
3559}
3560
Denys Vlasenko27c56f12010-09-07 09:56:34 +02003561static void free_pipe_list(struct pipe *pi);
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003562
Denys Vlasenko27c56f12010-09-07 09:56:34 +02003563/* Returns pi->next - next pipe in the list */
3564static struct pipe *free_pipe(struct pipe *pi)
Denis Vlasenkof886fd22008-10-13 12:36:05 +00003565{
Denys Vlasenko27c56f12010-09-07 09:56:34 +02003566 struct pipe *next;
3567 int i;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003568
Denys Vlasenko27c56f12010-09-07 09:56:34 +02003569 debug_printf_clean("free_pipe (pid %d)\n", getpid());
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003570 for (i = 0; i < pi->num_cmds; i++) {
Denys Vlasenko27c56f12010-09-07 09:56:34 +02003571 struct command *command;
3572 struct redir_struct *r, *rnext;
3573
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003574 command = &pi->cmds[i];
Denis Vlasenko0701dca2009-04-11 10:38:47 +00003575 debug_printf_clean(" command %d:\n", i);
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003576 if (command->argv) {
Denys Vlasenko27c56f12010-09-07 09:56:34 +02003577 if (DEBUG_CLEAN) {
3578 int a;
3579 char **p;
3580 for (a = 0, p = command->argv; *p; a++, p++) {
3581 debug_printf_clean(" argv[%d] = %s\n", a, *p);
3582 }
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003583 }
3584 free_strings(command->argv);
Denys Vlasenko27c56f12010-09-07 09:56:34 +02003585 //command->argv = NULL;
Denis Vlasenkob6e65562009-04-03 16:49:04 +00003586 }
3587 /* not "else if": on syntax error, we may have both! */
3588 if (command->group) {
Denys Vlasenko9d617c42009-06-09 18:40:52 +02003589 debug_printf_clean(" begin group (cmd_type:%d)\n",
3590 command->cmd_type);
Denis Vlasenko0701dca2009-04-11 10:38:47 +00003591 free_pipe_list(command->group);
3592 debug_printf_clean(" end group\n");
Denys Vlasenko27c56f12010-09-07 09:56:34 +02003593 //command->group = NULL;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003594 }
Denis Vlasenkoed055212009-04-11 10:37:10 +00003595 /* else is crucial here.
3596 * If group != NULL, child_func is meaningless */
3597#if ENABLE_HUSH_FUNCTIONS
3598 else if (command->child_func) {
3599 debug_printf_exec("cmd %p releases child func at %p\n", command, command->child_func);
3600 command->child_func->parent_cmd = NULL;
3601 }
3602#endif
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00003603#if !BB_MMU
3604 free(command->group_as_string);
Denys Vlasenko27c56f12010-09-07 09:56:34 +02003605 //command->group_as_string = NULL;
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00003606#endif
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003607 for (r = command->redirects; r; r = rnext) {
Denis Vlasenko0701dca2009-04-11 10:38:47 +00003608 debug_printf_clean(" redirect %d%s",
3609 r->rd_fd, redir_table[r->rd_type].descrip);
Denis Vlasenko02d6f1a2009-04-07 19:56:55 +00003610 /* guard against the case >$FOO, where foo is unset or blank */
3611 if (r->rd_filename) {
3612 debug_printf_clean(" fname:'%s'\n", r->rd_filename);
3613 free(r->rd_filename);
Denys Vlasenko27c56f12010-09-07 09:56:34 +02003614 //r->rd_filename = NULL;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003615 }
Denis Vlasenko02d6f1a2009-04-07 19:56:55 +00003616 debug_printf_clean(" rd_dup:%d\n", r->rd_dup);
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003617 rnext = r->next;
3618 free(r);
3619 }
Denys Vlasenko27c56f12010-09-07 09:56:34 +02003620 //command->redirects = NULL;
Denis Vlasenkof886fd22008-10-13 12:36:05 +00003621 }
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003622 free(pi->cmds); /* children are an array, they get freed all at once */
Denys Vlasenko27c56f12010-09-07 09:56:34 +02003623 //pi->cmds = NULL;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003624#if ENABLE_HUSH_JOB
3625 free(pi->cmdtext);
Denys Vlasenko27c56f12010-09-07 09:56:34 +02003626 //pi->cmdtext = NULL;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003627#endif
Denys Vlasenko27c56f12010-09-07 09:56:34 +02003628
3629 next = pi->next;
3630 free(pi);
3631 return next;
Denis Vlasenkof886fd22008-10-13 12:36:05 +00003632}
Denis Vlasenkoc7985b72008-06-17 05:43:38 +00003633
Denys Vlasenko27c56f12010-09-07 09:56:34 +02003634static void free_pipe_list(struct pipe *pi)
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003635{
Denys Vlasenko27c56f12010-09-07 09:56:34 +02003636 while (pi) {
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003637#if HAS_KEYWORDS
Denys Vlasenko27c56f12010-09-07 09:56:34 +02003638 debug_printf_clean("pipe reserved word %d\n", pi->res_word);
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003639#endif
Denis Vlasenko0701dca2009-04-11 10:38:47 +00003640 debug_printf_clean("pipe followup code %d\n", pi->followup);
Denys Vlasenko27c56f12010-09-07 09:56:34 +02003641 pi = free_pipe(pi);
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003642 }
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003643}
3644
3645
Denys Vlasenkob36abf22010-09-05 14:50:59 +02003646/*** Parsing routines ***/
Denis Vlasenkoc7985b72008-06-17 05:43:38 +00003647
Denys Vlasenko7b4c0fd2010-11-22 17:58:14 +01003648#ifndef debug_print_tree
3649static void debug_print_tree(struct pipe *pi, int lvl)
3650{
3651 static const char *const PIPE[] = {
3652 [PIPE_SEQ] = "SEQ",
3653 [PIPE_AND] = "AND",
3654 [PIPE_OR ] = "OR" ,
3655 [PIPE_BG ] = "BG" ,
3656 };
3657 static const char *RES[] = {
3658 [RES_NONE ] = "NONE" ,
3659# if ENABLE_HUSH_IF
3660 [RES_IF ] = "IF" ,
3661 [RES_THEN ] = "THEN" ,
3662 [RES_ELIF ] = "ELIF" ,
3663 [RES_ELSE ] = "ELSE" ,
3664 [RES_FI ] = "FI" ,
3665# endif
3666# if ENABLE_HUSH_LOOPS
3667 [RES_FOR ] = "FOR" ,
3668 [RES_WHILE] = "WHILE",
3669 [RES_UNTIL] = "UNTIL",
3670 [RES_DO ] = "DO" ,
3671 [RES_DONE ] = "DONE" ,
3672# endif
3673# if ENABLE_HUSH_LOOPS || ENABLE_HUSH_CASE
3674 [RES_IN ] = "IN" ,
3675# endif
3676# if ENABLE_HUSH_CASE
3677 [RES_CASE ] = "CASE" ,
3678 [RES_CASE_IN ] = "CASE_IN" ,
3679 [RES_MATCH] = "MATCH",
3680 [RES_CASE_BODY] = "CASE_BODY",
3681 [RES_ESAC ] = "ESAC" ,
3682# endif
3683 [RES_XXXX ] = "XXXX" ,
3684 [RES_SNTX ] = "SNTX" ,
3685 };
3686 static const char *const CMDTYPE[] = {
3687 "{}",
3688 "()",
3689 "[noglob]",
3690# if ENABLE_HUSH_FUNCTIONS
3691 "func()",
3692# endif
3693 };
3694
3695 int pin, prn;
3696
3697 pin = 0;
3698 while (pi) {
Denys Vlasenko83a49672021-06-15 18:12:13 +02003699 fdprintf(2, "%*spipe %d #cmds:%d %sres_word=%s followup=%d %s\n",
Denys Vlasenko5807e182018-02-08 19:19:04 +01003700 lvl*2, "",
3701 pin,
Denys Vlasenko83a49672021-06-15 18:12:13 +02003702 pi->num_cmds,
Denys Vlasenko5807e182018-02-08 19:19:04 +01003703 (IF_HAS_KEYWORDS(pi->pi_inverted ? "! " :) ""),
3704 RES[pi->res_word],
3705 pi->followup, PIPE[pi->followup]
3706 );
Denys Vlasenko7b4c0fd2010-11-22 17:58:14 +01003707 prn = 0;
3708 while (prn < pi->num_cmds) {
3709 struct command *command = &pi->cmds[prn];
3710 char **argv = command->argv;
3711
Denys Vlasenko75eb9d22010-12-21 21:18:12 +01003712 fdprintf(2, "%*s cmd %d assignment_cnt:%d",
Denys Vlasenko7b4c0fd2010-11-22 17:58:14 +01003713 lvl*2, "", prn,
3714 command->assignment_cnt);
Denys Vlasenko259747c2019-11-28 10:28:14 +01003715# if ENABLE_HUSH_LINENO_VAR
Denys Vlasenko5807e182018-02-08 19:19:04 +01003716 fdprintf(2, " LINENO:%u", command->lineno);
Denys Vlasenko259747c2019-11-28 10:28:14 +01003717# endif
Denys Vlasenko7b4c0fd2010-11-22 17:58:14 +01003718 if (command->group) {
Denys Vlasenko75eb9d22010-12-21 21:18:12 +01003719 fdprintf(2, " group %s: (argv=%p)%s%s\n",
Denys Vlasenko7b4c0fd2010-11-22 17:58:14 +01003720 CMDTYPE[command->cmd_type],
3721 argv
3722# if !BB_MMU
3723 , " group_as_string:", command->group_as_string
3724# else
3725 , "", ""
3726# endif
3727 );
3728 debug_print_tree(command->group, lvl+1);
3729 prn++;
3730 continue;
3731 }
3732 if (argv) while (*argv) {
Denys Vlasenko75eb9d22010-12-21 21:18:12 +01003733 fdprintf(2, " '%s'", *argv);
Denys Vlasenko7b4c0fd2010-11-22 17:58:14 +01003734 argv++;
3735 }
Denys Vlasenko474cb202018-07-24 13:03:03 +02003736 if (command->redirects)
3737 fdprintf(2, " {redir}");
Denys Vlasenko75eb9d22010-12-21 21:18:12 +01003738 fdprintf(2, "\n");
Denys Vlasenko7b4c0fd2010-11-22 17:58:14 +01003739 prn++;
3740 }
3741 pi = pi->next;
3742 pin++;
3743 }
3744}
3745#endif /* debug_print_tree */
3746
Denis Vlasenkoac678ec2007-04-16 22:32:04 +00003747static struct pipe *new_pipe(void)
3748{
Eric Andersen25f27032001-04-26 23:22:31 +00003749 struct pipe *pi;
Denis Vlasenko3ac0e002007-04-28 16:45:22 +00003750 pi = xzalloc(sizeof(struct pipe));
Denis Vlasenko5ec61322008-06-24 00:50:07 +00003751 /*pi->res_word = RES_NONE; - RES_NONE is 0 anyway */
Eric Andersen25f27032001-04-26 23:22:31 +00003752 return pi;
3753}
3754
Denis Vlasenkof8c1f022009-04-17 11:55:42 +00003755/* Command (member of a pipe) is complete, or we start a new pipe
3756 * if ctx->command is NULL.
3757 * No errors possible here.
3758 */
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003759static int done_command(struct parse_context *ctx)
3760{
3761 /* The command is really already in the pipe structure, so
3762 * advance the pipe counter and make a new, null command. */
3763 struct pipe *pi = ctx->pipe;
3764 struct command *command = ctx->command;
3765
Denys Vlasenkod6a37d82016-09-20 16:22:24 +02003766#if 0 /* Instead we emit error message at run time */
3767 if (ctx->pending_redirect) {
3768 /* For example, "cmd >" (no filename to redirect to) */
Denys Vlasenko39701202017-08-02 19:44:05 +02003769 syntax_error("invalid redirect");
Denys Vlasenkod6a37d82016-09-20 16:22:24 +02003770 ctx->pending_redirect = NULL;
3771 }
3772#endif
3773
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003774 if (command) {
Denis Vlasenkof8c1f022009-04-17 11:55:42 +00003775 if (IS_NULL_CMD(command)) {
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003776 debug_printf_parse("done_command: skipping null cmd, num_cmds=%d\n", pi->num_cmds);
Denis Vlasenkof8c1f022009-04-17 11:55:42 +00003777 goto clear_and_ret;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003778 }
3779 pi->num_cmds++;
3780 debug_printf_parse("done_command: ++num_cmds=%d\n", pi->num_cmds);
Denis Vlasenkocd418a22009-04-06 18:08:35 +00003781 //debug_print_tree(ctx->list_head, 20);
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003782 } else {
3783 debug_printf_parse("done_command: initializing, num_cmds=%d\n", pi->num_cmds);
3784 }
3785
3786 /* Only real trickiness here is that the uncommitted
3787 * command structure is not counted in pi->num_cmds. */
3788 pi->cmds = xrealloc(pi->cmds, sizeof(*pi->cmds) * (pi->num_cmds+1));
Denis Vlasenkof8c1f022009-04-17 11:55:42 +00003789 ctx->command = command = &pi->cmds[pi->num_cmds];
3790 clear_and_ret:
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003791 memset(command, 0, sizeof(*command));
Denys Vlasenko5807e182018-02-08 19:19:04 +01003792#if ENABLE_HUSH_LINENO_VAR
Denys Vlasenko08fb82c2019-05-19 15:26:05 +02003793 command->lineno = G.parse_lineno;
3794 debug_printf_parse("command->lineno = G.parse_lineno (%u)\n", G.parse_lineno);
Denys Vlasenko6aad1dd2018-01-19 15:37:04 +01003795#endif
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003796 return pi->num_cmds; /* used only for 0/nonzero check */
3797}
3798
3799static void done_pipe(struct parse_context *ctx, pipe_style type)
3800{
3801 int not_null;
3802
3803 debug_printf_parse("done_pipe entered, followup %d\n", type);
3804 /* Close previous command */
3805 not_null = done_command(ctx);
Denis Vlasenkocd418a22009-04-06 18:08:35 +00003806#if HAS_KEYWORDS
3807 ctx->pipe->pi_inverted = ctx->ctx_inverted;
3808 ctx->ctx_inverted = 0;
3809 ctx->pipe->res_word = ctx->ctx_res_w;
3810#endif
Denys Vlasenkob24e55d2017-07-16 20:29:35 +02003811 if (type == PIPE_BG && ctx->list_head != ctx->pipe) {
3812 /* Necessary since && and || have precedence over &:
Denys Vlasenkoee553b92017-07-15 22:51:55 +02003813 * "cmd1 && cmd2 &" must spawn both cmds, not only cmd2,
3814 * in a backgrounded subshell.
3815 */
3816 struct pipe *pi;
3817 struct command *command;
3818
Denys Vlasenkob24e55d2017-07-16 20:29:35 +02003819 /* Is this actually this construct, all pipes end with && or ||? */
Denys Vlasenkoee553b92017-07-15 22:51:55 +02003820 pi = ctx->list_head;
3821 while (pi != ctx->pipe) {
3822 if (pi->followup != PIPE_AND && pi->followup != PIPE_OR)
3823 goto no_conv;
3824 pi = pi->next;
3825 }
3826
3827 debug_printf_parse("BG with more than one pipe, converting to { p1 &&...pN; } &\n");
3828 pi->followup = PIPE_SEQ; /* close pN _not_ with "&"! */
3829 pi = xzalloc(sizeof(*pi));
3830 pi->followup = PIPE_BG;
3831 pi->num_cmds = 1;
3832 pi->cmds = xzalloc(sizeof(pi->cmds[0]));
3833 command = &pi->cmds[0];
3834 if (CMD_NORMAL != 0) /* "if xzalloc didn't do that already" */
3835 command->cmd_type = CMD_NORMAL;
3836 command->group = ctx->list_head;
3837#if !BB_MMU
Denys Vlasenkob24e55d2017-07-16 20:29:35 +02003838 command->group_as_string = xstrndup(
3839 ctx->as_string.data,
3840 ctx->as_string.length - 1 /* do not copy last char, "&" */
3841 );
Denys Vlasenkoee553b92017-07-15 22:51:55 +02003842#endif
3843 /* Replace all pipes in ctx with one newly created */
3844 ctx->list_head = ctx->pipe = pi;
Denys Vlasenko83a49672021-06-15 18:12:13 +02003845 /* for cases like "cmd && &", do not be tricked by last command
3846 * being null - the entire {...} & is NOT null! */
3847 not_null = 1;
Denys Vlasenkob24e55d2017-07-16 20:29:35 +02003848 } else {
3849 no_conv:
3850 ctx->pipe->followup = type;
Denys Vlasenkoee553b92017-07-15 22:51:55 +02003851 }
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003852
3853 /* Without this check, even just <enter> on command line generates
3854 * tree of three NOPs (!). Which is harmless but annoying.
Denis Vlasenkof8c1f022009-04-17 11:55:42 +00003855 * IOW: it is safe to do it unconditionally. */
Denis Vlasenkocd418a22009-04-06 18:08:35 +00003856 if (not_null
Denis Vlasenko7f959372009-04-14 08:06:59 +00003857#if ENABLE_HUSH_IF
Denis Vlasenkocd418a22009-04-06 18:08:35 +00003858 || ctx->ctx_res_w == RES_FI
Denis Vlasenko7f959372009-04-14 08:06:59 +00003859#endif
3860#if ENABLE_HUSH_LOOPS
Denis Vlasenkocd418a22009-04-06 18:08:35 +00003861 || ctx->ctx_res_w == RES_DONE
3862 || ctx->ctx_res_w == RES_FOR
3863 || ctx->ctx_res_w == RES_IN
Denis Vlasenko7f959372009-04-14 08:06:59 +00003864#endif
3865#if ENABLE_HUSH_CASE
Denis Vlasenkocd418a22009-04-06 18:08:35 +00003866 || ctx->ctx_res_w == RES_ESAC
3867#endif
3868 ) {
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003869 struct pipe *new_p;
3870 debug_printf_parse("done_pipe: adding new pipe: "
3871 "not_null:%d ctx->ctx_res_w:%d\n",
3872 not_null, ctx->ctx_res_w);
3873 new_p = new_pipe();
3874 ctx->pipe->next = new_p;
3875 ctx->pipe = new_p;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003876 /* RES_THEN, RES_DO etc are "sticky" -
Denis Vlasenkof8c1f022009-04-17 11:55:42 +00003877 * they remain set for pipes inside if/while.
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003878 * This is used to control execution.
3879 * RES_FOR and RES_IN are NOT sticky (needed to support
3880 * cases where variable or value happens to match a keyword):
3881 */
3882#if ENABLE_HUSH_LOOPS
3883 if (ctx->ctx_res_w == RES_FOR
3884 || ctx->ctx_res_w == RES_IN)
3885 ctx->ctx_res_w = RES_NONE;
3886#endif
3887#if ENABLE_HUSH_CASE
3888 if (ctx->ctx_res_w == RES_MATCH)
Denys Vlasenkoe9bda902009-05-23 16:50:07 +02003889 ctx->ctx_res_w = RES_CASE_BODY;
3890 if (ctx->ctx_res_w == RES_CASE)
3891 ctx->ctx_res_w = RES_CASE_IN;
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003892#endif
Denis Vlasenkob6e65562009-04-03 16:49:04 +00003893 ctx->command = NULL; /* trick done_command below */
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003894 /* Create the memory for command, roughly:
3895 * ctx->pipe->cmds = new struct command;
3896 * ctx->command = &ctx->pipe->cmds[0];
3897 */
3898 done_command(ctx);
Denis Vlasenkocd418a22009-04-06 18:08:35 +00003899 //debug_print_tree(ctx->list_head, 10);
Denis Vlasenko424f79b2009-03-22 14:23:34 +00003900 }
3901 debug_printf_parse("done_pipe return\n");
3902}
3903
Denis Vlasenko9af22c72008-10-09 12:54:58 +00003904static void initialize_context(struct parse_context *ctx)
Eric Andersen25f27032001-04-26 23:22:31 +00003905{
Denis Vlasenkoa8442002008-06-14 11:00:17 +00003906 memset(ctx, 0, sizeof(*ctx));
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02003907 if (MAYBE_ASSIGNMENT != 0)
3908 ctx->is_assignment = MAYBE_ASSIGNMENT;
Denis Vlasenko1a735862007-05-23 00:32:25 +00003909 ctx->pipe = ctx->list_head = new_pipe();
Denis Vlasenko9af22c72008-10-09 12:54:58 +00003910 /* Create the memory for command, roughly:
3911 * ctx->pipe->cmds = new struct command;
3912 * ctx->command = &ctx->pipe->cmds[0];
Denis Vlasenkoa8442002008-06-14 11:00:17 +00003913 */
3914 done_command(ctx);
Eric Andersen25f27032001-04-26 23:22:31 +00003915}
3916
Denis Vlasenkoa8442002008-06-14 11:00:17 +00003917/* If a reserved word is found and processed, parse context is modified
3918 * and 1 is returned.
Eric Andersen25f27032001-04-26 23:22:31 +00003919 */
Denis Vlasenko5ec61322008-06-24 00:50:07 +00003920#if HAS_KEYWORDS
Denis Vlasenkoc3735272008-10-09 12:58:26 +00003921struct reserved_combo {
3922 char literal[6];
3923 unsigned char res;
3924 unsigned char assignment_flag;
Denys Vlasenko965b7952020-11-30 13:03:03 +01003925 uint32_t flag;
Denis Vlasenkoc3735272008-10-09 12:58:26 +00003926};
3927enum {
3928 FLAG_END = (1 << RES_NONE ),
Denys Vlasenkoc0836532009-10-19 13:13:06 +02003929# if ENABLE_HUSH_IF
Denis Vlasenkoc3735272008-10-09 12:58:26 +00003930 FLAG_IF = (1 << RES_IF ),
3931 FLAG_THEN = (1 << RES_THEN ),
3932 FLAG_ELIF = (1 << RES_ELIF ),
3933 FLAG_ELSE = (1 << RES_ELSE ),
3934 FLAG_FI = (1 << RES_FI ),
Denys Vlasenkoc0836532009-10-19 13:13:06 +02003935# endif
3936# if ENABLE_HUSH_LOOPS
Denis Vlasenkoc3735272008-10-09 12:58:26 +00003937 FLAG_FOR = (1 << RES_FOR ),
3938 FLAG_WHILE = (1 << RES_WHILE),
3939 FLAG_UNTIL = (1 << RES_UNTIL),
3940 FLAG_DO = (1 << RES_DO ),
3941 FLAG_DONE = (1 << RES_DONE ),
3942 FLAG_IN = (1 << RES_IN ),
Denys Vlasenkoc0836532009-10-19 13:13:06 +02003943# endif
3944# if ENABLE_HUSH_CASE
Denis Vlasenkoc3735272008-10-09 12:58:26 +00003945 FLAG_MATCH = (1 << RES_MATCH),
3946 FLAG_ESAC = (1 << RES_ESAC ),
Denys Vlasenkoc0836532009-10-19 13:13:06 +02003947# endif
Denis Vlasenkoc3735272008-10-09 12:58:26 +00003948 FLAG_START = (1 << RES_XXXX ),
3949};
3950
3951static const struct reserved_combo* match_reserved_word(o_string *word)
3952{
Eric Andersen25f27032001-04-26 23:22:31 +00003953 /* Mostly a list of accepted follow-up reserved words.
3954 * FLAG_END means we are done with the sequence, and are ready
3955 * to turn the compound list into a command.
3956 * FLAG_START means the word must start a new compound list.
3957 */
Denys Vlasenko965b7952020-11-30 13:03:03 +01003958 static const struct reserved_combo reserved_list[] ALIGN4 = {
Denys Vlasenkoc0836532009-10-19 13:13:06 +02003959# if ENABLE_HUSH_IF
Denys Vlasenko29f9b722011-05-14 11:27:36 +02003960 { "!", RES_NONE, NOT_ASSIGNMENT , 0 },
3961 { "if", RES_IF, MAYBE_ASSIGNMENT, FLAG_THEN | FLAG_START },
3962 { "then", RES_THEN, MAYBE_ASSIGNMENT, FLAG_ELIF | FLAG_ELSE | FLAG_FI },
3963 { "elif", RES_ELIF, MAYBE_ASSIGNMENT, FLAG_THEN },
3964 { "else", RES_ELSE, MAYBE_ASSIGNMENT, FLAG_FI },
3965 { "fi", RES_FI, NOT_ASSIGNMENT , FLAG_END },
Denys Vlasenkoc0836532009-10-19 13:13:06 +02003966# endif
3967# if ENABLE_HUSH_LOOPS
Denys Vlasenko29f9b722011-05-14 11:27:36 +02003968 { "for", RES_FOR, NOT_ASSIGNMENT , FLAG_IN | FLAG_DO | FLAG_START },
3969 { "while", RES_WHILE, MAYBE_ASSIGNMENT, FLAG_DO | FLAG_START },
3970 { "until", RES_UNTIL, MAYBE_ASSIGNMENT, FLAG_DO | FLAG_START },
3971 { "in", RES_IN, NOT_ASSIGNMENT , FLAG_DO },
3972 { "do", RES_DO, MAYBE_ASSIGNMENT, FLAG_DONE },
3973 { "done", RES_DONE, NOT_ASSIGNMENT , FLAG_END },
Denys Vlasenkoc0836532009-10-19 13:13:06 +02003974# endif
3975# if ENABLE_HUSH_CASE
Denys Vlasenko29f9b722011-05-14 11:27:36 +02003976 { "case", RES_CASE, NOT_ASSIGNMENT , FLAG_MATCH | FLAG_START },
3977 { "esac", RES_ESAC, NOT_ASSIGNMENT , FLAG_END },
Denys Vlasenkoc0836532009-10-19 13:13:06 +02003978# endif
Eric Andersen25f27032001-04-26 23:22:31 +00003979 };
Denis Vlasenkoc3735272008-10-09 12:58:26 +00003980 const struct reserved_combo *r;
3981
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02003982 for (r = reserved_list; r < reserved_list + ARRAY_SIZE(reserved_list); r++) {
Denis Vlasenkoc3735272008-10-09 12:58:26 +00003983 if (strcmp(word->data, r->literal) == 0)
3984 return r;
3985 }
3986 return NULL;
3987}
Denys Vlasenko5807e182018-02-08 19:19:04 +01003988/* Return NULL: not a keyword, else: keyword
Denis Vlasenkobb929512009-04-16 10:59:40 +00003989 */
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02003990static const struct reserved_combo* reserved_word(struct parse_context *ctx)
Denis Vlasenkoc3735272008-10-09 12:58:26 +00003991{
Denys Vlasenkoc0836532009-10-19 13:13:06 +02003992# if ENABLE_HUSH_CASE
Denis Vlasenko17f02e72008-07-14 04:32:29 +00003993 static const struct reserved_combo reserved_match = {
Denis Vlasenko2b576b82008-08-04 00:46:07 +00003994 "", RES_MATCH, NOT_ASSIGNMENT , FLAG_MATCH | FLAG_ESAC
Denis Vlasenko17f02e72008-07-14 04:32:29 +00003995 };
Denys Vlasenkoc0836532009-10-19 13:13:06 +02003996# endif
Denis Vlasenkoc72c1ed2007-01-30 22:31:26 +00003997 const struct reserved_combo *r;
Denis Vlasenkoc72c1ed2007-01-30 22:31:26 +00003998
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02003999 if (ctx->word.has_quoted_part)
Denis Vlasenkobb929512009-04-16 10:59:40 +00004000 return 0;
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02004001 r = match_reserved_word(&ctx->word);
Denis Vlasenkoc3735272008-10-09 12:58:26 +00004002 if (!r)
Denys Vlasenko5807e182018-02-08 19:19:04 +01004003 return r; /* NULL */
Denis Vlasenkoc3735272008-10-09 12:58:26 +00004004
4005 debug_printf("found reserved word %s, res %d\n", r->literal, r->res);
Denys Vlasenkoc0836532009-10-19 13:13:06 +02004006# if ENABLE_HUSH_CASE
Denys Vlasenkoe9bda902009-05-23 16:50:07 +02004007 if (r->res == RES_IN && ctx->ctx_res_w == RES_CASE_IN) {
4008 /* "case word IN ..." - IN part starts first MATCH part */
Denis Vlasenkoc3735272008-10-09 12:58:26 +00004009 r = &reserved_match;
Denys Vlasenkoe9bda902009-05-23 16:50:07 +02004010 } else
Denys Vlasenkoc0836532009-10-19 13:13:06 +02004011# endif
Denis Vlasenkoc3735272008-10-09 12:58:26 +00004012 if (r->flag == 0) { /* '!' */
4013 if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */
Denis Vlasenko05d3b7c2009-04-09 19:16:15 +00004014 syntax_error("! ! command");
Denis Vlasenkobb929512009-04-16 10:59:40 +00004015 ctx->ctx_res_w = RES_SNTX;
Eric Andersen25f27032001-04-26 23:22:31 +00004016 }
Denis Vlasenkoc3735272008-10-09 12:58:26 +00004017 ctx->ctx_inverted = 1;
Denys Vlasenko5807e182018-02-08 19:19:04 +01004018 return r;
Eric Andersen25f27032001-04-26 23:22:31 +00004019 }
Denis Vlasenkoc3735272008-10-09 12:58:26 +00004020 if (r->flag & FLAG_START) {
Denis Vlasenkob6e65562009-04-03 16:49:04 +00004021 struct parse_context *old;
Denis Vlasenkobb929512009-04-16 10:59:40 +00004022
Denys Vlasenko9e55a152017-07-10 10:01:12 +02004023 old = xmemdup(ctx, sizeof(*ctx));
Denis Vlasenkob6e65562009-04-03 16:49:04 +00004024 debug_printf_parse("push stack %p\n", old);
Denis Vlasenkoc3735272008-10-09 12:58:26 +00004025 initialize_context(ctx);
Denis Vlasenkob6e65562009-04-03 16:49:04 +00004026 ctx->stack = old;
Denis Vlasenkoc3735272008-10-09 12:58:26 +00004027 } else if (/*ctx->ctx_res_w == RES_NONE ||*/ !(ctx->old_flag & (1 << r->res))) {
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02004028 syntax_error_at(ctx->word.data);
Denis Vlasenkoc3735272008-10-09 12:58:26 +00004029 ctx->ctx_res_w = RES_SNTX;
Denys Vlasenko5807e182018-02-08 19:19:04 +01004030 return r;
Denis Vlasenkobb929512009-04-16 10:59:40 +00004031 } else {
4032 /* "{...} fi" is ok. "{...} if" is not
4033 * Example:
4034 * if { echo foo; } then { echo bar; } fi */
4035 if (ctx->command->group)
4036 done_pipe(ctx, PIPE_SEQ);
Denis Vlasenkoc3735272008-10-09 12:58:26 +00004037 }
Denis Vlasenkobb929512009-04-16 10:59:40 +00004038
Denis Vlasenkoc3735272008-10-09 12:58:26 +00004039 ctx->ctx_res_w = r->res;
4040 ctx->old_flag = r->flag;
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02004041 ctx->is_assignment = r->assignment_flag;
4042 debug_printf_parse("ctx->is_assignment='%s'\n", assignment_flag[ctx->is_assignment]);
Denis Vlasenkobb929512009-04-16 10:59:40 +00004043
Denis Vlasenkoc3735272008-10-09 12:58:26 +00004044 if (ctx->old_flag & FLAG_END) {
4045 struct parse_context *old;
Denis Vlasenkobb929512009-04-16 10:59:40 +00004046
Denis Vlasenkoc3735272008-10-09 12:58:26 +00004047 done_pipe(ctx, PIPE_SEQ);
Denis Vlasenkob6e65562009-04-03 16:49:04 +00004048 debug_printf_parse("pop stack %p\n", ctx->stack);
Denis Vlasenkoc3735272008-10-09 12:58:26 +00004049 old = ctx->stack;
4050 old->command->group = ctx->list_head;
Denys Vlasenko9d617c42009-06-09 18:40:52 +02004051 old->command->cmd_type = CMD_NORMAL;
Denys Vlasenkoc0836532009-10-19 13:13:06 +02004052# if !BB_MMU
Denys Vlasenkob5be13c2015-09-04 06:22:10 +02004053 /* At this point, the compound command's string is in
4054 * ctx->as_string... except for the leading keyword!
4055 * Consider this example: "echo a | if true; then echo a; fi"
4056 * ctx->as_string will contain "true; then echo a; fi",
4057 * with "if " remaining in old->as_string!
4058 */
4059 {
4060 char *str;
4061 int len = old->as_string.length;
4062 /* Concatenate halves */
4063 o_addstr(&old->as_string, ctx->as_string.data);
Denys Vlasenko18567402018-07-20 17:51:31 +02004064 o_free(&ctx->as_string);
Denys Vlasenkob5be13c2015-09-04 06:22:10 +02004065 /* Find where leading keyword starts in first half */
4066 str = old->as_string.data + len;
4067 if (str > old->as_string.data)
4068 str--; /* skip whitespace after keyword */
4069 while (str > old->as_string.data && isalpha(str[-1]))
4070 str--;
4071 /* Ugh, we're done with this horrid hack */
4072 old->command->group_as_string = xstrdup(str);
4073 debug_printf_parse("pop, remembering as:'%s'\n",
4074 old->command->group_as_string);
4075 }
Denys Vlasenkoc0836532009-10-19 13:13:06 +02004076# endif
Denis Vlasenkoc3735272008-10-09 12:58:26 +00004077 *ctx = *old; /* physical copy */
4078 free(old);
4079 }
Denys Vlasenko5807e182018-02-08 19:19:04 +01004080 return r;
Eric Andersen25f27032001-04-26 23:22:31 +00004081}
Denys Vlasenkoc0836532009-10-19 13:13:06 +02004082#endif /* HAS_KEYWORDS */
Eric Andersen25f27032001-04-26 23:22:31 +00004083
Denis Vlasenkoa8442002008-06-14 11:00:17 +00004084/* Word is complete, look at it and update parsing context.
Denis Vlasenkob6e65562009-04-03 16:49:04 +00004085 * Normal return is 0. Syntax errors return 1.
4086 * Note: on return, word is reset, but not o_free'd!
4087 */
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02004088static int done_word(struct parse_context *ctx)
Eric Andersen25f27032001-04-26 23:22:31 +00004089{
Denis Vlasenko9af22c72008-10-09 12:54:58 +00004090 struct command *command = ctx->command;
Eric Andersen25f27032001-04-26 23:22:31 +00004091
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02004092 debug_printf_parse("done_word entered: '%s' %p\n", ctx->word.data, command);
4093 if (ctx->word.length == 0 && !ctx->word.has_quoted_part) {
Denis Vlasenkoab876cd2008-06-18 16:29:32 +00004094 debug_printf_parse("done_word return 0: true null, ignored\n");
4095 return 0;
Eric Andersen25f27032001-04-26 23:22:31 +00004096 }
Denis Vlasenko2b576b82008-08-04 00:46:07 +00004097
Eric Andersen25f27032001-04-26 23:22:31 +00004098 if (ctx->pending_redirect) {
Denis Vlasenkoab876cd2008-06-18 16:29:32 +00004099 /* We do not glob in e.g. >*.tmp case. bash seems to glob here
4100 * only if run as "bash", not "sh" */
Denys Vlasenkoe84212f2018-04-01 20:11:23 +02004101 /* http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004102 * "2.7 Redirection
Denys Vlasenkoe84212f2018-04-01 20:11:23 +02004103 * If the redirection operator is "<<" or "<<-", the word
4104 * that follows the redirection operator shall be
4105 * subjected to quote removal; it is unspecified whether
4106 * any of the other expansions occur. For the other
4107 * redirection operators, the word that follows the
4108 * redirection operator shall be subjected to tilde
4109 * expansion, parameter expansion, command substitution,
4110 * arithmetic expansion, and quote removal.
4111 * Pathname expansion shall not be performed
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004112 * on the word by a non-interactive shell; an interactive
4113 * shell may perform it, but shall do so only when
4114 * the expansion would result in one word."
4115 */
Denys Vlasenkobb6f5732018-04-01 18:55:00 +02004116//bash does not do parameter/command substitution or arithmetic expansion
4117//for _heredoc_ redirection word: these constructs look for exact eof marker
4118// as written:
4119// <<EOF$t
4120// <<EOF$((1))
Denys Vlasenkoe84212f2018-04-01 20:11:23 +02004121// <<EOF`true` [this case also makes heredoc "quoted", a-la <<"EOF". Probably bash-4.3.43 bug]
4122
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02004123 ctx->pending_redirect->rd_filename = xstrdup(ctx->word.data);
Denis Vlasenkoc96865f2009-04-10 00:20:58 +00004124 /* Cater for >\file case:
4125 * >\a creates file a; >\\a, >"\a", >"\\a" create file \a
4126 * Same with heredocs:
4127 * for <<\H delim is H; <<\\H, <<"\H", <<"\\H" - \H
4128 */
Denys Vlasenkoe640cb42009-05-28 16:49:11 +02004129 if (ctx->pending_redirect->rd_type == REDIRECT_HEREDOC) {
4130 unbackslash(ctx->pending_redirect->rd_filename);
4131 /* Is it <<"HEREDOC"? */
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02004132 if (ctx->word.has_quoted_part) {
Denys Vlasenkoe640cb42009-05-28 16:49:11 +02004133 ctx->pending_redirect->rd_dup |= HEREDOC_QUOTED;
4134 }
Denis Vlasenko02d6f1a2009-04-07 19:56:55 +00004135 }
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02004136 debug_printf_parse("word stored in rd_filename: '%s'\n", ctx->word.data);
Denis Vlasenko1fd1ea42009-04-10 12:03:20 +00004137 ctx->pending_redirect = NULL;
Eric Andersen25f27032001-04-26 23:22:31 +00004138 } else {
Denis Vlasenko5ec61322008-06-24 00:50:07 +00004139#if HAS_KEYWORDS
Denis Vlasenkoc96865f2009-04-10 00:20:58 +00004140# if ENABLE_HUSH_CASE
Denis Vlasenko757361f2008-07-14 08:26:47 +00004141 if (ctx->ctx_dsemicolon
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02004142 && strcmp(ctx->word.data, "esac") != 0 /* not "... pattern) cmd;; esac" */
Denis Vlasenko757361f2008-07-14 08:26:47 +00004143 ) {
Denis Vlasenko395ae452008-07-14 06:29:38 +00004144 /* already done when ctx_dsemicolon was set to 1: */
Denis Vlasenko17f02e72008-07-14 04:32:29 +00004145 /* ctx->ctx_res_w = RES_MATCH; */
4146 ctx->ctx_dsemicolon = 0;
4147 } else
Denis Vlasenkoc96865f2009-04-10 00:20:58 +00004148# endif
Denys Vlasenkod2241f52020-10-31 03:34:07 +01004149# if defined(CMD_TEST2_SINGLEWORD_NOGLOB)
4150 if (command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB
4151 && strcmp(ctx->word.data, "]]") == 0
4152 ) {
4153 /* allow "[[ ]] >file" etc */
4154 command->cmd_type = CMD_SINGLEWORD_NOGLOB;
4155 } else
4156# endif
Denis Vlasenko9af22c72008-10-09 12:54:58 +00004157 if (!command->argv /* if it's the first word... */
Denis Vlasenkoc96865f2009-04-10 00:20:58 +00004158# if ENABLE_HUSH_LOOPS
Denis Vlasenko733e3fb2008-07-06 10:01:13 +00004159 && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */
4160 && ctx->ctx_res_w != RES_IN
Denis Vlasenkoc96865f2009-04-10 00:20:58 +00004161# endif
Denys Vlasenkoe9bda902009-05-23 16:50:07 +02004162# if ENABLE_HUSH_CASE
4163 && ctx->ctx_res_w != RES_CASE
4164# endif
Denis Vlasenko733e3fb2008-07-06 10:01:13 +00004165 ) {
Denys Vlasenko5807e182018-02-08 19:19:04 +01004166 const struct reserved_combo *reserved;
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02004167 reserved = reserved_word(ctx);
Denys Vlasenko5807e182018-02-08 19:19:04 +01004168 debug_printf_parse("checking for reserved-ness: %d\n", !!reserved);
Denys Vlasenko29f9b722011-05-14 11:27:36 +02004169 if (reserved) {
Denys Vlasenko5807e182018-02-08 19:19:04 +01004170# if ENABLE_HUSH_LINENO_VAR
4171/* Case:
4172 * "while ...; do
4173 * cmd ..."
4174 * If we don't close the pipe _now_, immediately after "do", lineno logic
4175 * sees "cmd" as starting at "do" - i.e., at the previous line.
4176 */
4177 if (0
4178 IF_HUSH_IF(|| reserved->res == RES_THEN)
4179 IF_HUSH_IF(|| reserved->res == RES_ELIF)
4180 IF_HUSH_IF(|| reserved->res == RES_ELSE)
4181 IF_HUSH_LOOPS(|| reserved->res == RES_DO)
4182 ) {
4183 done_pipe(ctx, PIPE_SEQ);
4184 }
4185# endif
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02004186 o_reset_to_empty_unquoted(&ctx->word);
Denis Vlasenkoa24c8ca2009-04-04 15:24:40 +00004187 debug_printf_parse("done_word return %d\n",
4188 (ctx->ctx_res_w == RES_SNTX));
Denis Vlasenko5ec61322008-06-24 00:50:07 +00004189 return (ctx->ctx_res_w == RES_SNTX);
Denis Vlasenkoe725bfe2007-05-03 22:45:39 +00004190 }
Denys Vlasenkod2241f52020-10-31 03:34:07 +01004191# if defined(CMD_TEST2_SINGLEWORD_NOGLOB)
4192 if (strcmp(ctx->word.data, "[[") == 0) {
4193 command->cmd_type = CMD_TEST2_SINGLEWORD_NOGLOB;
4194 } else
4195# endif
Denys Vlasenko11752d42018-04-03 08:20:58 +02004196# if defined(CMD_SINGLEWORD_NOGLOB)
4197 if (0
Denys Vlasenko11752d42018-04-03 08:20:58 +02004198 /* In bash, local/export/readonly are special, args
4199 * are assignments and therefore expansion of them
4200 * should be "one-word" expansion:
4201 * $ export i=`echo 'a b'` # one arg: "i=a b"
4202 * compare with:
4203 * $ ls i=`echo 'a b'` # two args: "i=a" and "b"
4204 * ls: cannot access i=a: No such file or directory
4205 * ls: cannot access b: No such file or directory
4206 * Note: bash 3.2.33(1) does this only if export word
4207 * itself is not quoted:
4208 * $ export i=`echo 'aaa bbb'`; echo "$i"
4209 * aaa bbb
4210 * $ "export" i=`echo 'aaa bbb'`; echo "$i"
4211 * aaa
4212 */
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02004213 IF_HUSH_LOCAL( || strcmp(ctx->word.data, "local") == 0)
4214 IF_HUSH_EXPORT( || strcmp(ctx->word.data, "export") == 0)
4215 IF_HUSH_READONLY(|| strcmp(ctx->word.data, "readonly") == 0)
Denys Vlasenko11752d42018-04-03 08:20:58 +02004216 ) {
Denys Vlasenko9d617c42009-06-09 18:40:52 +02004217 command->cmd_type = CMD_SINGLEWORD_NOGLOB;
4218 }
Denys Vlasenkod2241f52020-10-31 03:34:07 +01004219# else
4220 { /* empty block to pair "if ... else" */ }
Denys Vlasenko9ca656b2009-06-10 13:39:35 +02004221# endif
Eric Andersen25f27032001-04-26 23:22:31 +00004222 }
Denys Vlasenko11752d42018-04-03 08:20:58 +02004223#endif /* HAS_KEYWORDS */
4224
Denis Vlasenkobb929512009-04-16 10:59:40 +00004225 if (command->group) {
4226 /* "{ echo foo; } echo bar" - bad */
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02004227 syntax_error_at(ctx->word.data);
Denis Vlasenkobb929512009-04-16 10:59:40 +00004228 debug_printf_parse("done_word return 1: syntax error, "
4229 "groups and arglists don't mix\n");
4230 return 1;
4231 }
Denys Vlasenko29f9b722011-05-14 11:27:36 +02004232
4233 /* If this word wasn't an assignment, next ones definitely
4234 * can't be assignments. Even if they look like ones. */
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02004235 if (ctx->is_assignment != DEFINITELY_ASSIGNMENT
4236 && ctx->is_assignment != WORD_IS_KEYWORD
Denys Vlasenko29f9b722011-05-14 11:27:36 +02004237 ) {
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02004238 ctx->is_assignment = NOT_ASSIGNMENT;
Denys Vlasenko29f9b722011-05-14 11:27:36 +02004239 } else {
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02004240 if (ctx->is_assignment == DEFINITELY_ASSIGNMENT) {
Denys Vlasenko29f9b722011-05-14 11:27:36 +02004241 command->assignment_cnt++;
4242 debug_printf_parse("++assignment_cnt=%d\n", command->assignment_cnt);
4243 }
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02004244 debug_printf_parse("ctx->is_assignment was:'%s'\n", assignment_flag[ctx->is_assignment]);
4245 ctx->is_assignment = MAYBE_ASSIGNMENT;
Denys Vlasenko29f9b722011-05-14 11:27:36 +02004246 }
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02004247 debug_printf_parse("ctx->is_assignment='%s'\n", assignment_flag[ctx->is_assignment]);
4248 command->argv = add_string_to_strings(command->argv, xstrdup(ctx->word.data));
Denis Vlasenko9af22c72008-10-09 12:54:58 +00004249 debug_print_strings("word appended to argv", command->argv);
Denis Vlasenkoe725bfe2007-05-03 22:45:39 +00004250 }
Eric Andersen25f27032001-04-26 23:22:31 +00004251
Denis Vlasenko06810332007-05-21 23:30:54 +00004252#if ENABLE_HUSH_LOOPS
Denis Vlasenko733e3fb2008-07-06 10:01:13 +00004253 if (ctx->ctx_res_w == RES_FOR) {
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02004254 if (ctx->word.has_quoted_part
Denys Vlasenkod8bd7012019-05-14 18:53:24 +02004255 || endofname(command->argv[0])[0] != '\0'
Denis Vlasenko1fd1ea42009-04-10 12:03:20 +00004256 ) {
Denis Vlasenkob7d8c0d2009-04-10 19:05:43 +00004257 /* bash says just "not a valid identifier" */
Denys Vlasenko457825f2021-06-06 12:07:11 +02004258 syntax_error("bad variable name in for");
Denis Vlasenko05d3b7c2009-04-09 19:16:15 +00004259 return 1;
4260 }
Denis Vlasenko1fd1ea42009-04-10 12:03:20 +00004261 /* Force FOR to have just one word (variable name) */
4262 /* NB: basically, this makes hush see "for v in ..."
4263 * syntax as if it is "for v; in ...". FOR and IN become
4264 * two pipe structs in parse tree. */
Denis Vlasenkofbf6dea2007-04-13 19:56:56 +00004265 done_pipe(ctx, PIPE_SEQ);
Denis Vlasenko733e3fb2008-07-06 10:01:13 +00004266 }
Denis Vlasenko06810332007-05-21 23:30:54 +00004267#endif
Denis Vlasenko17f02e72008-07-14 04:32:29 +00004268#if ENABLE_HUSH_CASE
4269 /* Force CASE to have just one word */
4270 if (ctx->ctx_res_w == RES_CASE) {
4271 done_pipe(ctx, PIPE_SEQ);
4272 }
4273#endif
Denis Vlasenko1fd1ea42009-04-10 12:03:20 +00004274
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02004275 o_reset_to_empty_unquoted(&ctx->word);
Denis Vlasenko1fd1ea42009-04-10 12:03:20 +00004276
Denis Vlasenkoe725bfe2007-05-03 22:45:39 +00004277 debug_printf_parse("done_word return 0\n");
Eric Andersen25f27032001-04-26 23:22:31 +00004278 return 0;
4279}
4280
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004281
4282/* Peek ahead in the input to find out if we have a "&n" construct,
4283 * as in "2>&1", that represents duplicating a file descriptor.
Denis Vlasenkoc96865f2009-04-10 00:20:58 +00004284 * Return:
4285 * REDIRFD_CLOSE if >&- "close fd" construct is seen,
4286 * REDIRFD_SYNTAX_ERR if syntax error,
4287 * REDIRFD_TO_FILE if no & was seen,
4288 * or the number found.
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004289 */
4290#if BB_MMU
Denis Vlasenkoc96865f2009-04-10 00:20:58 +00004291#define parse_redir_right_fd(as_string, input) \
4292 parse_redir_right_fd(input)
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004293#endif
Denis Vlasenkoc96865f2009-04-10 00:20:58 +00004294static int parse_redir_right_fd(o_string *as_string, struct in_str *input)
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004295{
4296 int ch, d, ok;
4297
4298 ch = i_peek(input);
4299 if (ch != '&')
Denis Vlasenkoc96865f2009-04-10 00:20:58 +00004300 return REDIRFD_TO_FILE;
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004301
4302 ch = i_getch(input); /* get the & */
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00004303 nommu_addchr(as_string, ch);
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004304 ch = i_peek(input);
4305 if (ch == '-') {
4306 ch = i_getch(input);
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00004307 nommu_addchr(as_string, ch);
Denis Vlasenko02d6f1a2009-04-07 19:56:55 +00004308 return REDIRFD_CLOSE;
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004309 }
4310 d = 0;
4311 ok = 0;
4312 while (ch != EOF && isdigit(ch)) {
4313 d = d*10 + (ch-'0');
4314 ok = 1;
4315 ch = i_getch(input);
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00004316 nommu_addchr(as_string, ch);
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004317 ch = i_peek(input);
4318 }
4319 if (ok) return d;
4320
4321//TODO: this is the place to catch ">&file" bashism (redirect both fd 1 and 2)
4322
James Byrne69374872019-07-02 11:35:03 +02004323 bb_simple_error_msg("ambiguous redirect");
Denis Vlasenkoc96865f2009-04-10 00:20:58 +00004324 return REDIRFD_SYNTAX_ERR;
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004325}
4326
Denis Vlasenkoc96865f2009-04-10 00:20:58 +00004327/* Return code is 0 normal, 1 if a syntax error is detected
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004328 */
4329static int parse_redirect(struct parse_context *ctx,
4330 int fd,
4331 redir_type style,
4332 struct in_str *input)
4333{
4334 struct command *command = ctx->command;
4335 struct redir_struct *redir;
4336 struct redir_struct **redirp;
4337 int dup_num;
4338
Denis Vlasenkoc96865f2009-04-10 00:20:58 +00004339 dup_num = REDIRFD_TO_FILE;
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004340 if (style != REDIRECT_HEREDOC) {
Denis Vlasenkoc96865f2009-04-10 00:20:58 +00004341 /* Check for a '>&1' type redirect */
4342 dup_num = parse_redir_right_fd(&ctx->as_string, input);
4343 if (dup_num == REDIRFD_SYNTAX_ERR)
4344 return 1;
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00004345 } else {
Denys Vlasenkoa94eeb02018-03-31 20:16:31 +02004346 int ch = i_peek_and_eat_bkslash_nl(input);
Denis Vlasenko02d6f1a2009-04-07 19:56:55 +00004347 dup_num = (ch == '-'); /* HEREDOC_SKIPTABS bit is 1 */
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00004348 if (dup_num) { /* <<-... */
4349 ch = i_getch(input);
4350 nommu_addchr(&ctx->as_string, ch);
4351 ch = i_peek(input);
4352 }
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004353 }
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004354
Denis Vlasenkoc96865f2009-04-10 00:20:58 +00004355 if (style == REDIRECT_OVERWRITE && dup_num == REDIRFD_TO_FILE) {
Denys Vlasenkoa94eeb02018-03-31 20:16:31 +02004356 int ch = i_peek_and_eat_bkslash_nl(input);
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004357 if (ch == '|') {
4358 /* >|FILE redirect ("clobbering" >).
4359 * Since we do not support "set -o noclobber" yet,
4360 * >| and > are the same for now. Just eat |.
4361 */
4362 ch = i_getch(input);
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00004363 nommu_addchr(&ctx->as_string, ch);
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004364 }
4365 }
4366
4367 /* Create a new redir_struct and append it to the linked list */
4368 redirp = &command->redirects;
4369 while ((redir = *redirp) != NULL) {
4370 redirp = &(redir->next);
4371 }
4372 *redirp = redir = xzalloc(sizeof(*redir));
4373 /* redir->next = NULL; */
4374 /* redir->rd_filename = NULL; */
4375 redir->rd_type = style;
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00004376 redir->rd_fd = (fd == -1) ? redir_table[style].default_fd : fd;
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004377
Denis Vlasenko02d6f1a2009-04-07 19:56:55 +00004378 debug_printf_parse("redirect type %d %s\n", redir->rd_fd,
4379 redir_table[style].descrip);
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004380
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00004381 redir->rd_dup = dup_num;
Denis Vlasenkoc96865f2009-04-10 00:20:58 +00004382 if (style != REDIRECT_HEREDOC && dup_num != REDIRFD_TO_FILE) {
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004383 /* Erik had a check here that the file descriptor in question
4384 * is legit; I postpone that to "run time"
4385 * A "-" representation of "close me" shows up as a -3 here */
Denis Vlasenko02d6f1a2009-04-07 19:56:55 +00004386 debug_printf_parse("duplicating redirect '%d>&%d'\n",
4387 redir->rd_fd, redir->rd_dup);
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004388 } else {
Denys Vlasenkod6a37d82016-09-20 16:22:24 +02004389#if 0 /* Instead we emit error message at run time */
4390 if (ctx->pending_redirect) {
4391 /* For example, "cmd > <file" */
Denys Vlasenko39701202017-08-02 19:44:05 +02004392 syntax_error("invalid redirect");
Denys Vlasenkod6a37d82016-09-20 16:22:24 +02004393 }
4394#endif
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004395 /* Set ctx->pending_redirect, so we know what to do at the
4396 * end of the next parsed word. */
4397 ctx->pending_redirect = redir;
4398 }
4399 return 0;
4400}
4401
Eric Andersen25f27032001-04-26 23:22:31 +00004402/* If a redirect is immediately preceded by a number, that number is
4403 * supposed to tell which file descriptor to redirect. This routine
4404 * looks for such preceding numbers. In an ideal world this routine
4405 * needs to handle all the following classes of redirects...
4406 * echo 2>foo # redirects fd 2 to file "foo", nothing passed to echo
4407 * echo 49>foo # redirects fd 49 to file "foo", nothing passed to echo
4408 * echo -2>foo # redirects fd 1 to file "foo", "-2" passed to echo
4409 * echo 49x>foo # redirects fd 1 to file "foo", "49x" passed to echo
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004410 *
4411 * http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html
4412 * "2.7 Redirection
4413 * ... If n is quoted, the number shall not be recognized as part of
4414 * the redirection expression. For example:
4415 * echo \2>a
4416 * writes the character 2 into file a"
Denys Vlasenko38292b62010-09-05 14:49:40 +02004417 * We are getting it right by setting ->has_quoted_part on any \<char>
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004418 *
4419 * A -1 return means no valid number was found,
4420 * the caller should use the appropriate default for this redirection.
Eric Andersen25f27032001-04-26 23:22:31 +00004421 */
4422static int redirect_opt_num(o_string *o)
4423{
4424 int num;
4425
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004426 if (o->data == NULL)
Denis Vlasenkobb81c582007-01-30 22:32:09 +00004427 return -1;
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004428 num = bb_strtou(o->data, NULL, 10);
4429 if (errno || num < 0)
4430 return -1;
Denis Vlasenko0b677d82009-04-10 13:49:10 +00004431 o_reset_to_empty_unquoted(o);
Eric Andersen25f27032001-04-26 23:22:31 +00004432 return num;
4433}
4434
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00004435#if BB_MMU
4436#define fetch_till_str(as_string, input, word, skip_tabs) \
4437 fetch_till_str(input, word, skip_tabs)
4438#endif
4439static char *fetch_till_str(o_string *as_string,
4440 struct in_str *input,
4441 const char *word,
Denys Vlasenko77b32cc2010-09-06 11:27:32 +02004442 int heredoc_flags)
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004443{
4444 o_string heredoc = NULL_O_STRING;
Denys Vlasenko5b6210c2010-09-09 13:32:21 +02004445 unsigned past_EOL;
Denys Vlasenko77b32cc2010-09-06 11:27:32 +02004446 int prev = 0; /* not \ */
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004447 int ch;
4448
Denys Vlasenkod73cdbf2018-07-23 15:43:57 +02004449 /* Starting with "" is necessary for this case:
4450 * cat <<EOF
4451 *
4452 * xxx
4453 * EOF
4454 */
4455 heredoc.data = xzalloc(1); /* start as "", not as NULL */
4456
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00004457 goto jump_in;
Denys Vlasenkob8709032011-05-08 21:20:01 +02004458
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004459 while (1) {
4460 ch = i_getch(input);
Denys Vlasenko5b6210c2010-09-09 13:32:21 +02004461 if (ch != EOF)
4462 nommu_addchr(as_string, ch);
Denys Vlasenko0f018b32017-07-29 20:43:26 +02004463 if (ch == '\n' || ch == EOF) {
4464 check_heredoc_end:
4465 if ((heredoc_flags & HEREDOC_QUOTED) || prev != '\\') {
Denys Vlasenkodfc73942018-07-24 14:03:18 +02004466 /* End-of-line, and not a line continuation */
Denys Vlasenko0f018b32017-07-29 20:43:26 +02004467 if (strcmp(heredoc.data + past_EOL, word) == 0) {
4468 heredoc.data[past_EOL] = '\0';
Denys Vlasenko3675c372018-07-23 16:31:21 +02004469 debug_printf_heredoc("parsed '%s' heredoc '%s'\n", word, heredoc.data);
Denys Vlasenko0f018b32017-07-29 20:43:26 +02004470 return heredoc.data;
4471 }
4472 if (ch == '\n') {
4473 /* This is a new line.
4474 * Remember position and backslash-escaping status.
4475 */
4476 o_addchr(&heredoc, ch);
4477 prev = ch;
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00004478 jump_in:
Denys Vlasenko0f018b32017-07-29 20:43:26 +02004479 past_EOL = heredoc.length;
4480 /* Get 1st char of next line, possibly skipping leading tabs */
4481 do {
4482 ch = i_getch(input);
4483 if (ch != EOF)
4484 nommu_addchr(as_string, ch);
4485 } while ((heredoc_flags & HEREDOC_SKIPTABS) && ch == '\t');
4486 /* If this immediately ended the line,
4487 * go back to end-of-line checks.
4488 */
4489 if (ch == '\n')
4490 goto check_heredoc_end;
4491 }
Denys Vlasenkodfc73942018-07-24 14:03:18 +02004492 } else {
4493 /* Backslash-line continuation in an unquoted
4494 * heredoc. This does not need special handling
4495 * for heredoc body (unquoted heredocs are
4496 * expanded on "execution" and that would take
4497 * care of this case too), but not the case
4498 * of line continuation *in terminator*:
4499 * cat <<EOF
4500 * Ok1
4501 * EO\
4502 * F
4503 */
4504 heredoc.data[--heredoc.length] = '\0';
4505 prev = 0; /* not '\' */
4506 continue;
Denys Vlasenko5b6210c2010-09-09 13:32:21 +02004507 }
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00004508 }
4509 if (ch == EOF) {
Denys Vlasenko18567402018-07-20 17:51:31 +02004510 o_free(&heredoc);
Denys Vlasenkodfc73942018-07-24 14:03:18 +02004511 return NULL; /* error */
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004512 }
4513 o_addchr(&heredoc, ch);
Denys Vlasenko5b6210c2010-09-09 13:32:21 +02004514 nommu_addchr(as_string, ch);
Denys Vlasenkoc3adfac2010-09-06 11:46:03 +02004515 if (prev == '\\' && ch == '\\')
4516 /* Correctly handle foo\\<eol> (not a line cont.) */
Denys Vlasenkodfc73942018-07-24 14:03:18 +02004517 prev = 0; /* not '\' */
Denys Vlasenkoc3adfac2010-09-06 11:46:03 +02004518 else
4519 prev = ch;
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004520 }
4521}
4522
Denis Vlasenko3dfb0352009-04-08 09:29:14 +00004523/* Look at entire parse tree for not-yet-loaded REDIRECT_HEREDOCs
4524 * and load them all. There should be exactly heredoc_cnt of them.
4525 */
Denys Vlasenko474cb202018-07-24 13:03:03 +02004526#if BB_MMU
4527#define fetch_heredocs(as_string, pi, heredoc_cnt, input) \
4528 fetch_heredocs(pi, heredoc_cnt, input)
4529#endif
4530static int fetch_heredocs(o_string *as_string, struct pipe *pi, int heredoc_cnt, struct in_str *input)
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004531{
Denis Vlasenko05d3b7c2009-04-09 19:16:15 +00004532 while (pi && heredoc_cnt) {
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004533 int i;
4534 struct command *cmd = pi->cmds;
4535
Denys Vlasenko3675c372018-07-23 16:31:21 +02004536 debug_printf_heredoc("fetch_heredocs: num_cmds:%d cmd argv0:'%s'\n",
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004537 pi->num_cmds,
Denys Vlasenko3675c372018-07-23 16:31:21 +02004538 cmd->argv ? cmd->argv[0] : "NONE"
4539 );
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004540 for (i = 0; i < pi->num_cmds; i++) {
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00004541 struct redir_struct *redir = cmd->redirects;
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004542
Denys Vlasenko3675c372018-07-23 16:31:21 +02004543 debug_printf_heredoc("fetch_heredocs: %d cmd argv0:'%s'\n",
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004544 i, cmd->argv ? cmd->argv[0] : "NONE");
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00004545 while (redir) {
4546 if (redir->rd_type == REDIRECT_HEREDOC) {
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004547 char *p;
4548
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00004549 redir->rd_type = REDIRECT_HEREDOC2;
Denys Vlasenko764b2f02009-06-07 16:05:04 +02004550 /* redir->rd_dup is (ab)used to indicate <<- */
Denys Vlasenko474cb202018-07-24 13:03:03 +02004551 p = fetch_till_str(as_string, input,
Denys Vlasenko77b32cc2010-09-06 11:27:32 +02004552 redir->rd_filename, redir->rd_dup);
Denis Vlasenko3dfb0352009-04-08 09:29:14 +00004553 if (!p) {
Denis Vlasenko05d3b7c2009-04-09 19:16:15 +00004554 syntax_error("unexpected EOF in here document");
Denys Vlasenko474cb202018-07-24 13:03:03 +02004555 return -1;
Denis Vlasenko3dfb0352009-04-08 09:29:14 +00004556 }
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00004557 free(redir->rd_filename);
4558 redir->rd_filename = p;
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004559 heredoc_cnt--;
4560 }
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00004561 redir = redir->next;
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004562 }
Denys Vlasenko474cb202018-07-24 13:03:03 +02004563 if (cmd->group) {
4564 //bb_error_msg("%s:%u heredoc_cnt:%d", __func__, __LINE__, heredoc_cnt);
4565 heredoc_cnt = fetch_heredocs(as_string, cmd->group, heredoc_cnt, input);
4566 //bb_error_msg("%s:%u heredoc_cnt:%d", __func__, __LINE__, heredoc_cnt);
4567 if (heredoc_cnt < 0)
4568 return heredoc_cnt; /* error */
4569 }
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004570 cmd++;
4571 }
4572 pi = pi->next;
4573 }
Denys Vlasenko474cb202018-07-24 13:03:03 +02004574 return heredoc_cnt;
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00004575}
4576
4577
Denys Vlasenkob36abf22010-09-05 14:50:59 +02004578static int run_list(struct pipe *pi);
4579#if BB_MMU
Denys Vlasenko474cb202018-07-24 13:03:03 +02004580#define parse_stream(pstring, heredoc_cnt_ptr, input, end_trigger) \
4581 parse_stream(heredoc_cnt_ptr, input, end_trigger)
Denys Vlasenkob36abf22010-09-05 14:50:59 +02004582#endif
4583static struct pipe *parse_stream(char **pstring,
Denys Vlasenko474cb202018-07-24 13:03:03 +02004584 int *heredoc_cnt_ptr,
Denys Vlasenkob36abf22010-09-05 14:50:59 +02004585 struct in_str *input,
4586 int end_trigger);
Denis Vlasenkoba7cf262007-05-25 14:34:30 +00004587
Denys Vlasenko474cb202018-07-24 13:03:03 +02004588/* Returns number of heredocs not yet consumed,
4589 * or -1 on error.
4590 */
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02004591static int parse_group(struct parse_context *ctx,
Denys Vlasenko474cb202018-07-24 13:03:03 +02004592 struct in_str *input, int ch)
Eric Andersen25f27032001-04-26 23:22:31 +00004593{
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02004594 /* ctx->word contains characters seen prior to ( or {.
Denis Vlasenko027e3fd2009-04-02 22:50:40 +00004595 * Typically it's empty, but for function defs,
Denis Vlasenko371de4a2008-10-14 12:43:13 +00004596 * it contains function name (without '()'). */
Denys Vlasenkofbf44852018-04-03 14:56:52 +02004597#if BB_MMU
4598# define as_string NULL
4599#else
4600 char *as_string = NULL;
4601#endif
Denis Vlasenkob6e65562009-04-03 16:49:04 +00004602 struct pipe *pipe_list;
Denys Vlasenko474cb202018-07-24 13:03:03 +02004603 int heredoc_cnt = 0;
Denis Vlasenko240c2552009-04-03 03:45:05 +00004604 int endch;
Denis Vlasenko9af22c72008-10-09 12:54:58 +00004605 struct command *command = ctx->command;
Denis Vlasenkoe725bfe2007-05-03 22:45:39 +00004606
4607 debug_printf_parse("parse_group entered\n");
Denis Vlasenko371de4a2008-10-14 12:43:13 +00004608#if ENABLE_HUSH_FUNCTIONS
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02004609 if (ch == '(' && !ctx->word.has_quoted_part) {
4610 if (ctx->word.length)
4611 if (done_word(ctx))
Denys Vlasenko474cb202018-07-24 13:03:03 +02004612 return -1;
Denis Vlasenkoc0ea3292009-04-10 21:22:02 +00004613 if (!command->argv)
4614 goto skip; /* (... */
4615 if (command->argv[1]) { /* word word ... (... */
4616 syntax_error_unexpected_ch('(');
Denys Vlasenko474cb202018-07-24 13:03:03 +02004617 return -1;
Denis Vlasenkob7d8c0d2009-04-10 19:05:43 +00004618 }
Denis Vlasenkoc0ea3292009-04-10 21:22:02 +00004619 /* it is "word(..." or "word (..." */
4620 do
4621 ch = i_getch(input);
4622 while (ch == ' ' || ch == '\t');
4623 if (ch != ')') {
4624 syntax_error_unexpected_ch(ch);
Denys Vlasenko474cb202018-07-24 13:03:03 +02004625 return -1;
Denis Vlasenkoc0ea3292009-04-10 21:22:02 +00004626 }
4627 nommu_addchr(&ctx->as_string, ch);
4628 do
4629 ch = i_getch(input);
4630 while (ch == ' ' || ch == '\t' || ch == '\n');
Denys Vlasenkofbf44852018-04-03 14:56:52 +02004631 if (ch != '{' && ch != '(') {
Denis Vlasenkoc0ea3292009-04-10 21:22:02 +00004632 syntax_error_unexpected_ch(ch);
Denys Vlasenko474cb202018-07-24 13:03:03 +02004633 return -1;
Denis Vlasenkoc0ea3292009-04-10 21:22:02 +00004634 }
4635 nommu_addchr(&ctx->as_string, ch);
Denys Vlasenko9d617c42009-06-09 18:40:52 +02004636 command->cmd_type = CMD_FUNCDEF;
Denis Vlasenkoc0ea3292009-04-10 21:22:02 +00004637 goto skip;
Denis Vlasenko371de4a2008-10-14 12:43:13 +00004638 }
4639#endif
Denys Vlasenkod8389ad2009-11-16 03:18:46 +01004640
4641#if 0 /* Prevented by caller */
Denis Vlasenkob7d8c0d2009-04-10 19:05:43 +00004642 if (command->argv /* word [word]{... */
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02004643 || ctx->word.length /* word{... */
4644 || ctx->word.has_quoted_part /* ""{... */
Denis Vlasenko9af22c72008-10-09 12:54:58 +00004645 ) {
Denis Vlasenko05d3b7c2009-04-09 19:16:15 +00004646 syntax_error(NULL);
Denys Vlasenko474cb202018-07-24 13:03:03 +02004647 debug_printf_parse("parse_group return -1: "
Denis Vlasenkoa24c8ca2009-04-04 15:24:40 +00004648 "syntax error, groups and arglists don't mix\n");
Denys Vlasenko474cb202018-07-24 13:03:03 +02004649 return -1;
Eric Andersen25f27032001-04-26 23:22:31 +00004650 }
Denys Vlasenkod8389ad2009-11-16 03:18:46 +01004651#endif
Denis Vlasenkob7d8c0d2009-04-10 19:05:43 +00004652
Denys Vlasenkofbf44852018-04-03 14:56:52 +02004653 IF_HUSH_FUNCTIONS(skip:)
4654
Denis Vlasenko240c2552009-04-03 03:45:05 +00004655 endch = '}';
Denis Vlasenko90e485c2007-05-23 15:22:50 +00004656 if (ch == '(') {
Denis Vlasenko240c2552009-04-03 03:45:05 +00004657 endch = ')';
Denys Vlasenkofbf44852018-04-03 14:56:52 +02004658 IF_HUSH_FUNCTIONS(if (command->cmd_type != CMD_FUNCDEF))
4659 command->cmd_type = CMD_SUBSHELL;
Denis Vlasenkof8c1f022009-04-17 11:55:42 +00004660 } else {
4661 /* bash does not allow "{echo...", requires whitespace */
Denys Vlasenko672a55e2016-11-04 18:46:14 +01004662 ch = i_peek(input);
4663 if (ch != ' ' && ch != '\t' && ch != '\n'
4664 && ch != '(' /* but "{(..." is allowed (without whitespace) */
4665 ) {
Denis Vlasenkof8c1f022009-04-17 11:55:42 +00004666 syntax_error_unexpected_ch(ch);
Denys Vlasenko474cb202018-07-24 13:03:03 +02004667 return -1;
Denis Vlasenkof8c1f022009-04-17 11:55:42 +00004668 }
Denys Vlasenko672a55e2016-11-04 18:46:14 +01004669 if (ch != '(') {
4670 ch = i_getch(input);
4671 nommu_addchr(&ctx->as_string, ch);
4672 }
Eric Andersen25f27032001-04-26 23:22:31 +00004673 }
Denis Vlasenkob7d8c0d2009-04-10 19:05:43 +00004674
Denys Vlasenko474cb202018-07-24 13:03:03 +02004675 debug_printf_heredoc("calling parse_stream, heredoc_cnt:%d\n", heredoc_cnt);
4676 pipe_list = parse_stream(&as_string, &heredoc_cnt, input, endch);
4677 debug_printf_heredoc("parse_stream returned: heredoc_cnt:%d\n", heredoc_cnt);
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00004678#if !BB_MMU
Denys Vlasenkofbf44852018-04-03 14:56:52 +02004679 if (as_string)
4680 o_addstr(&ctx->as_string, as_string);
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00004681#endif
Denys Vlasenkofbf44852018-04-03 14:56:52 +02004682
4683 /* empty ()/{} or parse error? */
4684 if (!pipe_list || pipe_list == ERR_PTR) {
4685 /* parse_stream already emitted error msg */
4686 if (!BB_MMU)
4687 free(as_string);
Denys Vlasenko474cb202018-07-24 13:03:03 +02004688 debug_printf_parse("parse_group return -1: "
Denys Vlasenkofbf44852018-04-03 14:56:52 +02004689 "parse_stream returned %p\n", pipe_list);
Denys Vlasenko474cb202018-07-24 13:03:03 +02004690 return -1;
Denis Vlasenkof8d01d32008-06-14 17:13:20 +00004691 }
Denys Vlasenkofbf44852018-04-03 14:56:52 +02004692#if !BB_MMU
4693 as_string[strlen(as_string) - 1] = '\0'; /* plink ')' or '}' */
4694 command->group_as_string = as_string;
4695 debug_printf_parse("end of group, remembering as:'%s'\n",
4696 command->group_as_string);
4697#endif
4698
4699#if ENABLE_HUSH_FUNCTIONS
4700 /* Convert "f() (cmds)" to "f() {(cmds)}" */
4701 if (command->cmd_type == CMD_FUNCDEF && endch == ')') {
4702 struct command *cmd2;
4703
4704 cmd2 = xzalloc(sizeof(*cmd2));
4705 cmd2->cmd_type = CMD_SUBSHELL;
4706 cmd2->group = pipe_list;
4707# if !BB_MMU
4708//UNTESTED!
4709 cmd2->group_as_string = command->group_as_string;
4710 command->group_as_string = xasprintf("(%s)", command->group_as_string);
4711# endif
4712
4713 pipe_list = new_pipe();
4714 pipe_list->cmds = cmd2;
4715 pipe_list->num_cmds = 1;
4716 }
4717#endif
4718
4719 command->group = pipe_list;
4720
Denys Vlasenko474cb202018-07-24 13:03:03 +02004721 debug_printf_parse("parse_group return %d\n", heredoc_cnt);
4722 return heredoc_cnt;
Denis Vlasenko9af22c72008-10-09 12:54:58 +00004723 /* command remains "open", available for possible redirects */
Denys Vlasenkofbf44852018-04-03 14:56:52 +02004724#undef as_string
Eric Andersen25f27032001-04-26 23:22:31 +00004725}
4726
Denys Vlasenko0b883582016-12-23 16:49:07 +01004727#if ENABLE_HUSH_TICK || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_DOLLAR_OPS
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00004728/* Subroutines for copying $(...) and `...` things */
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00004729/* '...' */
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01004730static int add_till_single_quote(o_string *dest, struct in_str *input)
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00004731{
4732 while (1) {
Denis Vlasenko46ccdcb2008-06-10 18:05:12 +00004733 int ch = i_getch(input);
Denis Vlasenko5c090a92009-04-08 21:51:33 +00004734 if (ch == EOF) {
Denis Vlasenkod68ae082009-04-09 20:41:34 +00004735 syntax_error_unterm_ch('\'');
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01004736 return 0;
Denis Vlasenko5c090a92009-04-08 21:51:33 +00004737 }
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00004738 if (ch == '\'')
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01004739 return 1;
Denis Vlasenko82dfec32008-06-16 12:47:11 +00004740 o_addchr(dest, ch);
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00004741 }
4742}
Denys Vlasenko4c3c8a12018-07-20 19:11:09 +02004743static int add_till_single_quote_dquoted(o_string *dest, struct in_str *input)
4744{
4745 while (1) {
4746 int ch = i_getch(input);
4747 if (ch == EOF) {
4748 syntax_error_unterm_ch('\'');
4749 return 0;
4750 }
4751 if (ch == '\'')
4752 return 1;
4753 o_addqchr(dest, ch);
4754 }
4755}
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00004756/* "...\"...`..`...." - do we need to handle "...$(..)..." too? */
Denys Vlasenko4c3c8a12018-07-20 19:11:09 +02004757static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote);
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01004758static int add_till_double_quote(o_string *dest, struct in_str *input)
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00004759{
4760 while (1) {
Denis Vlasenko46ccdcb2008-06-10 18:05:12 +00004761 int ch = i_getch(input);
Denis Vlasenko5c090a92009-04-08 21:51:33 +00004762 if (ch == EOF) {
Denis Vlasenkod68ae082009-04-09 20:41:34 +00004763 syntax_error_unterm_ch('"');
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01004764 return 0;
Denis Vlasenko5c090a92009-04-08 21:51:33 +00004765 }
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00004766 if (ch == '"')
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01004767 return 1;
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00004768 if (ch == '\\') { /* \x. Copy both chars. */
Denis Vlasenko82dfec32008-06-16 12:47:11 +00004769 o_addchr(dest, ch);
Denis Vlasenko46ccdcb2008-06-10 18:05:12 +00004770 ch = i_getch(input);
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00004771 }
Denis Vlasenko82dfec32008-06-16 12:47:11 +00004772 o_addchr(dest, ch);
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00004773 if (ch == '`') {
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01004774 if (!add_till_backquote(dest, input, /*in_dquote:*/ 1))
4775 return 0;
Denis Vlasenko82dfec32008-06-16 12:47:11 +00004776 o_addchr(dest, ch);
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00004777 continue;
4778 }
Denis Vlasenko5703c222008-06-15 11:49:42 +00004779 //if (ch == '$') ...
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00004780 }
4781}
4782/* Process `cmd` - copy contents until "`" is seen. Complicated by
4783 * \` quoting.
4784 * "Within the backquoted style of command substitution, backslash
4785 * shall retain its literal meaning, except when followed by: '$', '`', or '\'.
4786 * The search for the matching backquote shall be satisfied by the first
4787 * backquote found without a preceding backslash; during this search,
4788 * if a non-escaped backquote is encountered within a shell comment,
4789 * a here-document, an embedded command substitution of the $(command)
4790 * form, or a quoted string, undefined results occur. A single-quoted
4791 * or double-quoted string that begins, but does not end, within the
4792 * "`...`" sequence produces undefined results."
4793 * Example Output
4794 * echo `echo '\'TEST\`echo ZZ\`BEST` \TESTZZBEST
4795 */
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01004796static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote)
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00004797{
4798 while (1) {
Denis Vlasenko46ccdcb2008-06-10 18:05:12 +00004799 int ch = i_getch(input);
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00004800 if (ch == '`')
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01004801 return 1;
Denis Vlasenko5c090a92009-04-08 21:51:33 +00004802 if (ch == '\\') {
Denys Vlasenkoacd5bc82010-09-12 15:05:39 +02004803 /* \x. Copy both unless it is \`, \$, \\ and maybe \" */
4804 ch = i_getch(input);
4805 if (ch != '`'
4806 && ch != '$'
4807 && ch != '\\'
4808 && (!in_dquote || ch != '"')
4809 ) {
4810 o_addchr(dest, '\\');
Denis Vlasenko5c090a92009-04-08 21:51:33 +00004811 }
Denys Vlasenkoacd5bc82010-09-12 15:05:39 +02004812 }
4813 if (ch == EOF) {
4814 syntax_error_unterm_ch('`');
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01004815 return 0;
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00004816 }
Denis Vlasenko82dfec32008-06-16 12:47:11 +00004817 o_addchr(dest, ch);
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00004818 }
4819}
4820/* Process $(cmd) - copy contents until ")" is seen. Complicated by
4821 * quoting and nested ()s.
4822 * "With the $(command) style of command substitution, all characters
4823 * following the open parenthesis to the matching closing parenthesis
4824 * constitute the command. Any valid shell script can be used for command,
4825 * except a script consisting solely of redirections which produces
4826 * unspecified results."
4827 * Example Output
4828 * echo $(echo '(TEST)' BEST) (TEST) BEST
4829 * echo $(echo 'TEST)' BEST) TEST) BEST
4830 * echo $(echo \(\(TEST\) BEST) ((TEST) BEST
Denys Vlasenko74369502010-05-21 19:52:01 +02004831 *
Denys Vlasenko1e811b12010-05-22 03:12:29 +02004832 * Also adapted to eat ${var%...} and $((...)) constructs, since ... part
Denys Vlasenkoa6ad3972010-05-22 00:26:06 +02004833 * can contain arbitrary constructs, just like $(cmd).
Denys Vlasenko36f774a2010-09-05 14:45:38 +02004834 * In bash compat mode, it needs to also be able to stop on ':' or '/'
4835 * for ${var:N[:M]} and ${var/P[/R]} parsing.
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00004836 */
Denys Vlasenko74369502010-05-21 19:52:01 +02004837#define DOUBLE_CLOSE_CHAR_FLAG 0x80
Denys Vlasenko1e811b12010-05-22 03:12:29 +02004838static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsigned end_ch)
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00004839{
Denys Vlasenko1e811b12010-05-22 03:12:29 +02004840 int ch;
Denys Vlasenko74369502010-05-21 19:52:01 +02004841 char dbl = end_ch & DOUBLE_CLOSE_CHAR_FLAG;
Kang-Che Sung027d3ab2017-01-11 14:18:15 +01004842# if BASH_SUBSTR || BASH_PATTERN_SUBST
Denys Vlasenko1e811b12010-05-22 03:12:29 +02004843 char end_char2 = end_ch >> 8;
Denys Vlasenko9297dbc2010-07-05 21:37:12 +02004844# endif
Denys Vlasenko1e811b12010-05-22 03:12:29 +02004845 end_ch &= (DOUBLE_CLOSE_CHAR_FLAG - 1);
4846
Denys Vlasenko259747c2019-11-28 10:28:14 +01004847# if ENABLE_HUSH_INTERACTIVE
Denys Vlasenko8d6eab32018-04-07 17:01:31 +02004848 G.promptmode = 1; /* PS2 */
Denys Vlasenko259747c2019-11-28 10:28:14 +01004849# endif
Denys Vlasenko8d6eab32018-04-07 17:01:31 +02004850 debug_printf_prompt("%s promptmode=%d\n", __func__, G.promptmode);
4851
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00004852 while (1) {
Denys Vlasenko1e811b12010-05-22 03:12:29 +02004853 ch = i_getch(input);
Denis Vlasenko5c090a92009-04-08 21:51:33 +00004854 if (ch == EOF) {
Denys Vlasenkoa6ad3972010-05-22 00:26:06 +02004855 syntax_error_unterm_ch(end_ch);
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01004856 return 0;
Denis Vlasenko5c090a92009-04-08 21:51:33 +00004857 }
Kang-Che Sung027d3ab2017-01-11 14:18:15 +01004858 if (ch == end_ch
4859# if BASH_SUBSTR || BASH_PATTERN_SUBST
Denys Vlasenko55f81332018-03-02 18:12:12 +01004860 || ch == end_char2
Kang-Che Sung027d3ab2017-01-11 14:18:15 +01004861# endif
4862 ) {
Denys Vlasenkoa6ad3972010-05-22 00:26:06 +02004863 if (!dbl)
4864 break;
4865 /* we look for closing )) of $((EXPR)) */
Denys Vlasenko657086a2016-09-29 18:07:42 +02004866 if (i_peek_and_eat_bkslash_nl(input) == end_ch) {
Denys Vlasenkoa6ad3972010-05-22 00:26:06 +02004867 i_getch(input); /* eat second ')' */
4868 break;
Mike Frysinger98c52642009-04-02 10:02:37 +00004869 }
Denis Vlasenkoa24c8ca2009-04-04 15:24:40 +00004870 }
Denis Vlasenko82dfec32008-06-16 12:47:11 +00004871 o_addchr(dest, ch);
Denys Vlasenkod4802c62018-03-02 20:48:36 +01004872 //bb_error_msg("%s:o_addchr('%c')", __func__, ch);
Denys Vlasenkoa6ad3972010-05-22 00:26:06 +02004873 if (ch == '(' || ch == '{') {
4874 ch = (ch == '(' ? ')' : '}');
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01004875 if (!add_till_closing_bracket(dest, input, ch))
4876 return 0;
Denys Vlasenkoa6ad3972010-05-22 00:26:06 +02004877 o_addchr(dest, ch);
4878 continue;
4879 }
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00004880 if (ch == '\'') {
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01004881 if (!add_till_single_quote(dest, input))
4882 return 0;
Denis Vlasenko82dfec32008-06-16 12:47:11 +00004883 o_addchr(dest, ch);
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00004884 continue;
4885 }
4886 if (ch == '"') {
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01004887 if (!add_till_double_quote(dest, input))
4888 return 0;
Denis Vlasenko82dfec32008-06-16 12:47:11 +00004889 o_addchr(dest, ch);
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00004890 continue;
4891 }
Denys Vlasenkoa6ad3972010-05-22 00:26:06 +02004892 if (ch == '`') {
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01004893 if (!add_till_backquote(dest, input, /*in_dquote:*/ 0))
4894 return 0;
Denys Vlasenkoa6ad3972010-05-22 00:26:06 +02004895 o_addchr(dest, ch);
4896 continue;
4897 }
Denis Vlasenko5c090a92009-04-08 21:51:33 +00004898 if (ch == '\\') {
4899 /* \x. Copy verbatim. Important for \(, \) */
Denis Vlasenko76db5ad2008-06-12 12:58:20 +00004900 ch = i_getch(input);
Denis Vlasenko5c090a92009-04-08 21:51:33 +00004901 if (ch == EOF) {
Denys Vlasenkod4802c62018-03-02 20:48:36 +01004902 syntax_error_unterm_ch(end_ch);
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01004903 return 0;
Denis Vlasenko5c090a92009-04-08 21:51:33 +00004904 }
Denys Vlasenko259747c2019-11-28 10:28:14 +01004905# if 0
Denys Vlasenko657086a2016-09-29 18:07:42 +02004906 if (ch == '\n') {
4907 /* "backslash+newline", ignore both */
4908 o_delchr(dest); /* undo insertion of '\' */
4909 continue;
4910 }
Denys Vlasenko259747c2019-11-28 10:28:14 +01004911# endif
Denis Vlasenko82dfec32008-06-16 12:47:11 +00004912 o_addchr(dest, ch);
Denys Vlasenkod4802c62018-03-02 20:48:36 +01004913 //bb_error_msg("%s:o_addchr('%c') after '\\'", __func__, ch);
Denis Vlasenko76db5ad2008-06-12 12:58:20 +00004914 continue;
4915 }
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00004916 }
Denys Vlasenko8d6eab32018-04-07 17:01:31 +02004917 debug_printf_parse("%s return '%s' ch:'%c'\n", __func__, dest->data, ch);
Denys Vlasenko1e811b12010-05-22 03:12:29 +02004918 return ch;
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00004919}
Denys Vlasenko0b883582016-12-23 16:49:07 +01004920#endif /* ENABLE_HUSH_TICK || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_DOLLAR_OPS */
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00004921
Denis Vlasenkoc7985b72008-06-17 05:43:38 +00004922/* Return code: 0 for OK, 1 for syntax error */
Denis Vlasenko609f2ab2009-04-04 23:15:14 +00004923#if BB_MMU
Denys Vlasenko101a4e32010-09-09 14:04:57 +02004924#define parse_dollar(as_string, dest, input, quote_mask) \
4925 parse_dollar(dest, input, quote_mask)
Denys Vlasenkoddc62f62010-05-22 00:53:32 +02004926#define as_string NULL
Denis Vlasenko609f2ab2009-04-04 23:15:14 +00004927#endif
Denys Vlasenko2e48d532010-05-22 17:30:39 +02004928static int parse_dollar(o_string *as_string,
Denis Vlasenko609f2ab2009-04-04 23:15:14 +00004929 o_string *dest,
Denys Vlasenko101a4e32010-09-09 14:04:57 +02004930 struct in_str *input, unsigned char quote_mask)
Eric Andersen25f27032001-04-26 23:22:31 +00004931{
Denys Vlasenko657086a2016-09-29 18:07:42 +02004932 int ch = i_peek_and_eat_bkslash_nl(input); /* first character after the $ */
Denis Vlasenkoe0a33672007-05-10 23:06:55 +00004933
Denys Vlasenko2e48d532010-05-22 17:30:39 +02004934 debug_printf_parse("parse_dollar entered: ch='%c'\n", ch);
Denis Vlasenko1f4cf512007-05-16 10:39:24 +00004935 if (isalpha(ch)) {
Denys Vlasenko0ca31982018-01-25 13:20:50 +01004936 make_var:
Denis Vlasenko609f2ab2009-04-04 23:15:14 +00004937 ch = i_getch(input);
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00004938 nommu_addchr(as_string, ch);
Denys Vlasenko0ca31982018-01-25 13:20:50 +01004939 /*make_var1:*/
Denis Vlasenko46ccdcb2008-06-10 18:05:12 +00004940 o_addchr(dest, SPECIAL_VAR_SYMBOL);
Denis Vlasenkoe0a33672007-05-10 23:06:55 +00004941 while (1) {
Denis Vlasenkoe0a33672007-05-10 23:06:55 +00004942 debug_printf_parse(": '%c'\n", ch);
Denis Vlasenko46ccdcb2008-06-10 18:05:12 +00004943 o_addchr(dest, ch | quote_mask);
Denis Vlasenko1f4cf512007-05-16 10:39:24 +00004944 quote_mask = 0;
Denys Vlasenko657086a2016-09-29 18:07:42 +02004945 ch = i_peek_and_eat_bkslash_nl(input);
Denys Vlasenkod17a91d2016-09-29 18:02:37 +02004946 if (!isalnum(ch) && ch != '_') {
Denys Vlasenkod17a91d2016-09-29 18:02:37 +02004947 /* End of variable name reached */
Denis Vlasenko602d13c2007-05-13 18:34:53 +00004948 break;
Denys Vlasenkod17a91d2016-09-29 18:02:37 +02004949 }
Denis Vlasenko609f2ab2009-04-04 23:15:14 +00004950 ch = i_getch(input);
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00004951 nommu_addchr(as_string, ch);
Eric Andersen25f27032001-04-26 23:22:31 +00004952 }
Denis Vlasenko46ccdcb2008-06-10 18:05:12 +00004953 o_addchr(dest, SPECIAL_VAR_SYMBOL);
Eric Andersen25f27032001-04-26 23:22:31 +00004954 } else if (isdigit(ch)) {
Denis Vlasenko602d13c2007-05-13 18:34:53 +00004955 make_one_char_var:
Denis Vlasenko609f2ab2009-04-04 23:15:14 +00004956 ch = i_getch(input);
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00004957 nommu_addchr(as_string, ch);
Denis Vlasenko46ccdcb2008-06-10 18:05:12 +00004958 o_addchr(dest, SPECIAL_VAR_SYMBOL);
Denis Vlasenko602d13c2007-05-13 18:34:53 +00004959 debug_printf_parse(": '%c'\n", ch);
Denis Vlasenko46ccdcb2008-06-10 18:05:12 +00004960 o_addchr(dest, ch | quote_mask);
4961 o_addchr(dest, SPECIAL_VAR_SYMBOL);
Eric Andersen25f27032001-04-26 23:22:31 +00004962 } else switch (ch) {
Denis Vlasenkoa24c8ca2009-04-04 15:24:40 +00004963 case '$': /* pid */
4964 case '!': /* last bg pid */
4965 case '?': /* last exit code */
4966 case '#': /* number of args */
4967 case '*': /* args */
4968 case '@': /* args */
Denys Vlasenkoef8985c2019-05-19 16:29:09 +02004969 case '-': /* $- option flags set by set builtin or shell options (-i etc) */
Denis Vlasenkoa24c8ca2009-04-04 15:24:40 +00004970 goto make_one_char_var;
4971 case '{': {
Denys Vlasenko2093ad22017-07-26 00:07:27 +02004972 char len_single_ch;
4973
Mike Frysingeref3e7fd2009-06-01 14:13:39 -04004974 o_addchr(dest, SPECIAL_VAR_SYMBOL);
4975
Denys Vlasenko74369502010-05-21 19:52:01 +02004976 ch = i_getch(input); /* eat '{' */
4977 nommu_addchr(as_string, ch);
4978
Denys Vlasenko46e64982016-09-29 19:50:55 +02004979 ch = i_getch_and_eat_bkslash_nl(input); /* first char after '{' */
Denys Vlasenko74369502010-05-21 19:52:01 +02004980 /* It should be ${?}, or ${#var},
4981 * or even ${?+subst} - operator acting on a special variable,
4982 * or the beginning of variable name.
4983 */
Denys Vlasenko101a4e32010-09-09 14:04:57 +02004984 if (ch == EOF
4985 || (!strchr(_SPECIAL_VARS_STR, ch) && !isalnum(ch)) /* not one of those */
4986 ) {
Denys Vlasenko74369502010-05-21 19:52:01 +02004987 bad_dollar_syntax:
4988 syntax_error_unterm_str("${name}");
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01004989 debug_printf_parse("parse_dollar return 0: unterminated ${name}\n");
4990 return 0;
Denys Vlasenko74369502010-05-21 19:52:01 +02004991 }
Denys Vlasenko101a4e32010-09-09 14:04:57 +02004992 nommu_addchr(as_string, ch);
Denys Vlasenko2093ad22017-07-26 00:07:27 +02004993 len_single_ch = ch;
Denys Vlasenko74369502010-05-21 19:52:01 +02004994 ch |= quote_mask;
4995
Denys Vlasenkoddc62f62010-05-22 00:53:32 +02004996 /* It's possible to just call add_till_closing_bracket() at this point.
Denys Vlasenko74369502010-05-21 19:52:01 +02004997 * However, this regresses some of our testsuite cases
4998 * which check invalid constructs like ${%}.
4999 * Oh well... let's check that the var name part is fine... */
5000
Denis Vlasenkoa24c8ca2009-04-04 15:24:40 +00005001 while (1) {
Denys Vlasenkoddc62f62010-05-22 00:53:32 +02005002 unsigned pos;
5003
Denys Vlasenko74369502010-05-21 19:52:01 +02005004 o_addchr(dest, ch);
5005 debug_printf_parse(": '%c'\n", ch);
5006
Denis Vlasenkoa24c8ca2009-04-04 15:24:40 +00005007 ch = i_getch(input);
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00005008 nommu_addchr(as_string, ch);
Denys Vlasenko74369502010-05-21 19:52:01 +02005009 if (ch == '}')
Mike Frysinger98c52642009-04-02 10:02:37 +00005010 break;
Mike Frysinger98c52642009-04-02 10:02:37 +00005011
Denys Vlasenko74369502010-05-21 19:52:01 +02005012 if (!isalnum(ch) && ch != '_') {
Denys Vlasenko1e811b12010-05-22 03:12:29 +02005013 unsigned end_ch;
5014 unsigned char last_ch;
Denis Vlasenkoa24c8ca2009-04-04 15:24:40 +00005015 /* handle parameter expansions
5016 * http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_02
5017 */
Denys Vlasenko2093ad22017-07-26 00:07:27 +02005018 if (!strchr(VAR_SUBST_OPS, ch)) { /* ${var<bad_char>... */
5019 if (len_single_ch != '#'
5020 /*|| !strchr(SPECIAL_VARS_STR, ch) - disallow errors like ${#+} ? */
5021 || i_peek(input) != '}'
5022 ) {
5023 goto bad_dollar_syntax;
5024 }
5025 /* else: it's "length of C" ${#C} op,
5026 * where C is a single char
5027 * special var name, e.g. ${#!}.
5028 */
5029 }
Denys Vlasenko1e811b12010-05-22 03:12:29 +02005030 /* Eat everything until closing '}' (or ':') */
5031 end_ch = '}';
Kang-Che Sung027d3ab2017-01-11 14:18:15 +01005032 if (BASH_SUBSTR
Denys Vlasenko1e811b12010-05-22 03:12:29 +02005033 && ch == ':'
Denys Vlasenko36f774a2010-09-05 14:45:38 +02005034 && !strchr(MINUS_PLUS_EQUAL_QUESTION, i_peek(input))
Denys Vlasenko1e811b12010-05-22 03:12:29 +02005035 ) {
5036 /* It's ${var:N[:M]} thing */
5037 end_ch = '}' * 0x100 + ':';
5038 }
Kang-Che Sung027d3ab2017-01-11 14:18:15 +01005039 if (BASH_PATTERN_SUBST
Denys Vlasenko36f774a2010-09-05 14:45:38 +02005040 && ch == '/'
5041 ) {
5042 /* It's ${var/[/]pattern[/repl]} thing */
5043 if (i_peek(input) == '/') { /* ${var//pattern[/repl]}? */
5044 i_getch(input);
5045 nommu_addchr(as_string, '/');
5046 ch = '\\';
5047 }
5048 end_ch = '}' * 0x100 + '/';
5049 }
5050 o_addchr(dest, ch);
Denys Vlasenkoc2aa2182018-08-04 22:25:28 +02005051 /* The pattern can't be empty.
5052 * IOW: if the first char after "${v//" is a slash,
5053 * it does not terminate the pattern - it's the first char of the pattern:
5054 * v=/dev/ram; echo ${v////-} prints -dev-ram (pattern is "/")
5055 * v=/dev/ram; echo ${v///r/-} prints /dev-am (pattern is "/r")
5056 */
5057 if (i_peek(input) == '/') {
5058 o_addchr(dest, i_getch(input));
5059 }
Denys Vlasenko1e811b12010-05-22 03:12:29 +02005060 again:
Denys Vlasenkoddc62f62010-05-22 00:53:32 +02005061 if (!BB_MMU)
5062 pos = dest->length;
Denys Vlasenko9297dbc2010-07-05 21:37:12 +02005063#if ENABLE_HUSH_DOLLAR_OPS
Denys Vlasenko1e811b12010-05-22 03:12:29 +02005064 last_ch = add_till_closing_bracket(dest, input, end_ch);
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01005065 if (last_ch == 0) /* error? */
5066 return 0;
Denys Vlasenko9297dbc2010-07-05 21:37:12 +02005067#else
Denys Vlasenko259747c2019-11-28 10:28:14 +01005068# error Simple code to only allow ${var} is not implemented
Denys Vlasenko9297dbc2010-07-05 21:37:12 +02005069#endif
Denys Vlasenkoddc62f62010-05-22 00:53:32 +02005070 if (as_string) {
5071 o_addstr(as_string, dest->data + pos);
Denys Vlasenko1e811b12010-05-22 03:12:29 +02005072 o_addchr(as_string, last_ch);
Denys Vlasenkoddc62f62010-05-22 00:53:32 +02005073 }
Denys Vlasenko1e811b12010-05-22 03:12:29 +02005074
Kang-Che Sung027d3ab2017-01-11 14:18:15 +01005075 if ((BASH_SUBSTR || BASH_PATTERN_SUBST)
5076 && (end_ch & 0xff00)
5077 ) {
Denys Vlasenko1e811b12010-05-22 03:12:29 +02005078 /* close the first block: */
5079 o_addchr(dest, SPECIAL_VAR_SYMBOL);
Denys Vlasenko36f774a2010-09-05 14:45:38 +02005080 /* while parsing N from ${var:N[:M]}
5081 * or pattern from ${var/[/]pattern[/repl]} */
Denys Vlasenko1e811b12010-05-22 03:12:29 +02005082 if ((end_ch & 0xff) == last_ch) {
Denys Vlasenko36f774a2010-09-05 14:45:38 +02005083 /* got ':' or '/'- parse the rest */
Denys Vlasenko1e811b12010-05-22 03:12:29 +02005084 end_ch = '}';
5085 goto again;
5086 }
Denys Vlasenko36f774a2010-09-05 14:45:38 +02005087 /* got '}' */
Kang-Che Sung027d3ab2017-01-11 14:18:15 +01005088 if (BASH_SUBSTR && end_ch == '}' * 0x100 + ':') {
Denys Vlasenko36f774a2010-09-05 14:45:38 +02005089 /* it's ${var:N} - emulate :999999999 */
5090 o_addstr(dest, "999999999");
5091 } /* else: it's ${var/[/]pattern} */
Denys Vlasenko1e811b12010-05-22 03:12:29 +02005092 }
Denys Vlasenko74369502010-05-21 19:52:01 +02005093 break;
Denis Vlasenkoa24c8ca2009-04-04 15:24:40 +00005094 }
Denys Vlasenko2093ad22017-07-26 00:07:27 +02005095 len_single_ch = 0; /* it can't be ${#C} op */
Denys Vlasenko74369502010-05-21 19:52:01 +02005096 }
Denis Vlasenkoa24c8ca2009-04-04 15:24:40 +00005097 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5098 break;
5099 }
Denys Vlasenko0b883582016-12-23 16:49:07 +01005100#if ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_TICK
Denis Vlasenkoa24c8ca2009-04-04 15:24:40 +00005101 case '(': {
Denys Vlasenkoddc62f62010-05-22 00:53:32 +02005102 unsigned pos;
5103
Denis Vlasenko609f2ab2009-04-04 23:15:14 +00005104 ch = i_getch(input);
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00005105 nommu_addchr(as_string, ch);
Denys Vlasenko0b883582016-12-23 16:49:07 +01005106# if ENABLE_FEATURE_SH_MATH
Denys Vlasenko657086a2016-09-29 18:07:42 +02005107 if (i_peek_and_eat_bkslash_nl(input) == '(') {
Denis Vlasenko609f2ab2009-04-04 23:15:14 +00005108 ch = i_getch(input);
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00005109 nommu_addchr(as_string, ch);
Denis Vlasenkoa24c8ca2009-04-04 15:24:40 +00005110 o_addchr(dest, SPECIAL_VAR_SYMBOL);
Denys Vlasenkoe4a06122020-02-21 17:21:34 +01005111 o_addchr(dest, quote_mask | '+');
Denys Vlasenkoddc62f62010-05-22 00:53:32 +02005112 if (!BB_MMU)
5113 pos = dest->length;
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01005114 if (!add_till_closing_bracket(dest, input, ')' | DOUBLE_CLOSE_CHAR_FLAG))
5115 return 0; /* error */
Denis Vlasenkoc4a7af52009-04-05 20:33:27 +00005116 if (as_string) {
5117 o_addstr(as_string, dest->data + pos);
5118 o_addchr(as_string, ')');
5119 o_addchr(as_string, ')');
Denis Vlasenko0bb4a232009-04-05 01:42:59 +00005120 }
Denis Vlasenkoa24c8ca2009-04-04 15:24:40 +00005121 o_addchr(dest, SPECIAL_VAR_SYMBOL);
Eric Andersen25f27032001-04-26 23:22:31 +00005122 break;
Denis Vlasenko76db5ad2008-06-12 12:58:20 +00005123 }
Denis Vlasenkod85a5df2009-04-05 08:43:57 +00005124# endif
5125# if ENABLE_HUSH_TICK
Denis Vlasenkoa24c8ca2009-04-04 15:24:40 +00005126 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5127 o_addchr(dest, quote_mask | '`');
Denys Vlasenkoddc62f62010-05-22 00:53:32 +02005128 if (!BB_MMU)
5129 pos = dest->length;
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01005130 if (!add_till_closing_bracket(dest, input, ')'))
5131 return 0; /* error */
Denis Vlasenkoc4a7af52009-04-05 20:33:27 +00005132 if (as_string) {
5133 o_addstr(as_string, dest->data + pos);
Denys Vlasenkob70cef72010-01-12 13:45:45 +01005134 o_addchr(as_string, ')');
Denis Vlasenko0bb4a232009-04-05 01:42:59 +00005135 }
Denis Vlasenkoa24c8ca2009-04-04 15:24:40 +00005136 o_addchr(dest, SPECIAL_VAR_SYMBOL);
Denis Vlasenkod85a5df2009-04-05 08:43:57 +00005137# endif
Denis Vlasenkoa24c8ca2009-04-04 15:24:40 +00005138 break;
5139 }
Denis Vlasenkod85a5df2009-04-05 08:43:57 +00005140#endif
Denis Vlasenkoa24c8ca2009-04-04 15:24:40 +00005141 case '_':
Denys Vlasenko0ca31982018-01-25 13:20:50 +01005142 goto make_var;
5143#if 0
Denys Vlasenkoef8985c2019-05-19 16:29:09 +02005144 /* TODO: $_: */
Denys Vlasenko69b1cef2009-09-21 10:21:44 +02005145 /* $_ Shell or shell script name; or last argument of last command
5146 * (if last command wasn't a pipe; if it was, bash sets $_ to "");
5147 * but in command's env, set to full pathname used to invoke it */
Denys Vlasenko0ca31982018-01-25 13:20:50 +01005148 ch = i_getch(input);
5149 nommu_addchr(as_string, ch);
5150 ch = i_peek_and_eat_bkslash_nl(input);
5151 if (isalnum(ch)) { /* it's $_name or $_123 */
5152 ch = '_';
5153 goto make_var1;
5154 }
5155 /* else: it's $_ */
5156#endif
Denis Vlasenkoa24c8ca2009-04-04 15:24:40 +00005157 default:
5158 o_addQchr(dest, '$');
Eric Andersen25f27032001-04-26 23:22:31 +00005159 }
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01005160 debug_printf_parse("parse_dollar return 1 (ok)\n");
5161 return 1;
Denys Vlasenkoddc62f62010-05-22 00:53:32 +02005162#undef as_string
Eric Andersen25f27032001-04-26 23:22:31 +00005163}
5164
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00005165#if BB_MMU
Denys Vlasenkob762c782018-07-17 14:21:38 +02005166#define encode_string(as_string, dest, input, dquote_end) \
Denys Vlasenkod98e5c62010-09-10 10:44:23 +02005167 encode_string(dest, input, dquote_end)
Denys Vlasenkoddc62f62010-05-22 00:53:32 +02005168#define as_string NULL
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00005169#endif
Denys Vlasenkod98e5c62010-09-10 10:44:23 +02005170static int encode_string(o_string *as_string,
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00005171 o_string *dest,
5172 struct in_str *input,
Denys Vlasenkob762c782018-07-17 14:21:38 +02005173 int dquote_end)
Denis Vlasenko2f1d3942009-04-02 16:31:29 +00005174{
Denis Vlasenko6da69cd2009-04-04 12:12:58 +00005175 int ch;
Denis Vlasenko2f1d3942009-04-02 16:31:29 +00005176 int next;
5177
5178 again:
5179 ch = i_getch(input);
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00005180 if (ch != EOF)
5181 nommu_addchr(as_string, ch);
Denis Vlasenko2f1d3942009-04-02 16:31:29 +00005182 if (ch == dquote_end) { /* may be only '"' or EOF */
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01005183 debug_printf_parse("encode_string return 1 (ok)\n");
5184 return 1;
Denis Vlasenko2f1d3942009-04-02 16:31:29 +00005185 }
Denis Vlasenko3dfb0352009-04-08 09:29:14 +00005186 /* note: can't move it above ch == dquote_end check! */
Denis Vlasenko2f1d3942009-04-02 16:31:29 +00005187 if (ch == EOF) {
Denis Vlasenkod68ae082009-04-09 20:41:34 +00005188 syntax_error_unterm_ch('"');
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01005189 return 0; /* error */
Denis Vlasenko2f1d3942009-04-02 16:31:29 +00005190 }
5191 next = '\0';
Denis Vlasenko2f1d3942009-04-02 16:31:29 +00005192 if (ch != '\n') {
5193 next = i_peek(input);
5194 }
Denys Vlasenkof37eb392009-10-18 11:46:35 +02005195 debug_printf_parse("\" ch=%c (%d) escape=%d\n",
Denys Vlasenko5b686cb2010-09-08 13:44:34 +02005196 ch, ch, !!(dest->o_expflags & EXP_FLAG_ESC_GLOB_CHARS));
Denys Vlasenkob762c782018-07-17 14:21:38 +02005197 if (ch == '\\') {
Denis Vlasenko2f1d3942009-04-02 16:31:29 +00005198 if (next == EOF) {
Denys Vlasenko4709df02018-04-10 14:49:01 +02005199 /* Testcase: in interactive shell a file with
5200 * echo "unterminated string\<eof>
5201 * is sourced.
5202 */
5203 syntax_error_unterm_ch('"');
5204 return 0; /* error */
Denis Vlasenko2f1d3942009-04-02 16:31:29 +00005205 }
5206 /* bash:
5207 * "The backslash retains its special meaning [in "..."]
5208 * only when followed by one of the following characters:
5209 * $, `, ", \, or <newline>. A double quote may be quoted
Denys Vlasenkoe640cb42009-05-28 16:49:11 +02005210 * within double quotes by preceding it with a backslash."
Denys Vlasenkod98e5c62010-09-10 10:44:23 +02005211 * NB: in (unquoted) heredoc, above does not apply to ",
5212 * therefore we check for it by "next == dquote_end" cond.
Denis Vlasenko2f1d3942009-04-02 16:31:29 +00005213 */
Denys Vlasenkod98e5c62010-09-10 10:44:23 +02005214 if (next == dquote_end || strchr("$`\\\n", next)) {
Denys Vlasenko850b15b2010-09-09 12:58:19 +02005215 ch = i_getch(input); /* eat next */
5216 if (ch == '\n')
5217 goto again; /* skip \<newline> */
Denys Vlasenko4f870492010-09-10 11:06:01 +02005218 } /* else: ch remains == '\\', and we double it below: */
5219 o_addqchr(dest, ch); /* \c if c is a glob char, else just c */
Denys Vlasenko850b15b2010-09-09 12:58:19 +02005220 nommu_addchr(as_string, ch);
Denis Vlasenko2f1d3942009-04-02 16:31:29 +00005221 goto again;
5222 }
5223 if (ch == '$') {
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01005224 if (!parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80)) {
5225 debug_printf_parse("encode_string return 0: "
5226 "parse_dollar returned 0 (error)\n");
5227 return 0;
Denis Vlasenko2f1d3942009-04-02 16:31:29 +00005228 }
5229 goto again;
5230 }
5231#if ENABLE_HUSH_TICK
5232 if (ch == '`') {
Denys Vlasenkoddc62f62010-05-22 00:53:32 +02005233 //unsigned pos = dest->length;
Denis Vlasenko2f1d3942009-04-02 16:31:29 +00005234 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5235 o_addchr(dest, 0x80 | '`');
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01005236 if (!add_till_backquote(dest, input, /*in_dquote:*/ dquote_end == '"'))
5237 return 0; /* error */
Denis Vlasenko2f1d3942009-04-02 16:31:29 +00005238 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5239 //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos);
Denis Vlasenkof328e002009-04-02 16:55:38 +00005240 goto again;
Denis Vlasenko2f1d3942009-04-02 16:31:29 +00005241 }
5242#endif
Denis Vlasenkof328e002009-04-02 16:55:38 +00005243 o_addQchr(dest, ch);
Denys Vlasenko1b7a9b62021-06-15 16:05:57 +02005244 if (ch == SPECIAL_VAR_SYMBOL) {
5245 /* Convert "^C" to corresponding special variable reference */
5246 o_addchr(dest, SPECIAL_VAR_QUOTED_SVS);
5247 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5248 }
Denis Vlasenko2f1d3942009-04-02 16:31:29 +00005249 goto again;
Denys Vlasenkoddc62f62010-05-22 00:53:32 +02005250#undef as_string
Denis Vlasenko2f1d3942009-04-02 16:31:29 +00005251}
5252
Denis Vlasenkob6e65562009-04-03 16:49:04 +00005253/*
5254 * Scan input until EOF or end_trigger char.
5255 * Return a list of pipes to execute, or NULL on EOF
5256 * or if end_trigger character is met.
Denys Vlasenkocecbc982011-03-30 18:54:52 +02005257 * On syntax error, exit if shell is not interactive,
Denis Vlasenkob6e65562009-04-03 16:49:04 +00005258 * reset parsing machinery and start parsing anew,
5259 * or return ERR_PTR.
Denis Vlasenko027e3fd2009-04-02 22:50:40 +00005260 */
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00005261static struct pipe *parse_stream(char **pstring,
Denys Vlasenko474cb202018-07-24 13:03:03 +02005262 int *heredoc_cnt_ptr,
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00005263 struct in_str *input,
5264 int end_trigger)
Eric Andersen25f27032001-04-26 23:22:31 +00005265{
Denis Vlasenkob6e65562009-04-03 16:49:04 +00005266 struct parse_context ctx;
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00005267 int heredoc_cnt;
Eric Andersen25f27032001-04-26 23:22:31 +00005268
Denys Vlasenko77a7b552010-09-09 12:40:03 +02005269 /* Single-quote triggers a bypass of the main loop until its mate is
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005270 * found. When recursing, quote state is passed in via ctx.word.o_expflags.
Denis Vlasenkoa24c8ca2009-04-04 15:24:40 +00005271 */
Denis Vlasenkob6e65562009-04-03 16:49:04 +00005272 debug_printf_parse("parse_stream entered, end_trigger='%c'\n",
Denys Vlasenko90a99042009-09-06 02:36:23 +02005273 end_trigger ? end_trigger : 'X');
Denis Vlasenko0701dca2009-04-11 10:38:47 +00005274 debug_enter();
Denis Vlasenkoe725bfe2007-05-03 22:45:39 +00005275
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005276 initialize_context(&ctx);
5277
5278 /* If very first arg is "" or '', ctx.word.data may end up NULL.
5279 * Preventing this:
5280 */
Denys Vlasenko8b08d5a2018-07-18 15:48:53 +02005281 ctx.word.data = xzalloc(1); /* start as "", not as NULL */
Denys Vlasenkof37eb392009-10-18 11:46:35 +02005282
Denys Vlasenko1fd3d942010-09-08 13:31:53 +02005283 /* We used to separate words on $IFS here. This was wrong.
5284 * $IFS is used only for word splitting when $var is expanded,
Denys Vlasenko77a7b552010-09-09 12:40:03 +02005285 * here we should use blank chars as separators, not $IFS
Denys Vlasenko1fd3d942010-09-08 13:31:53 +02005286 */
Denys Vlasenko77a7b552010-09-09 12:40:03 +02005287
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00005288 heredoc_cnt = 0;
Denis Vlasenko1a735862007-05-23 00:32:25 +00005289 while (1) {
Denys Vlasenko1fd3d942010-09-08 13:31:53 +02005290 const char *is_blank;
Denis Vlasenko6da69cd2009-04-04 12:12:58 +00005291 const char *is_special;
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00005292 int ch;
5293 int next;
5294 int redir_fd;
5295 redir_type redir_style;
Denis Vlasenko6da69cd2009-04-04 12:12:58 +00005296
Denis Vlasenko46ccdcb2008-06-10 18:05:12 +00005297 ch = i_getch(input);
Denis Vlasenko6da69cd2009-04-04 12:12:58 +00005298 debug_printf_parse(": ch=%c (%d) escape=%d\n",
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005299 ch, ch, !!(ctx.word.o_expflags & EXP_FLAG_ESC_GLOB_CHARS));
Denis Vlasenko6da69cd2009-04-04 12:12:58 +00005300 if (ch == EOF) {
5301 struct pipe *pi;
Denys Vlasenko18bcaf32020-12-23 23:01:18 +01005302
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00005303 if (heredoc_cnt) {
Denis Vlasenkod68ae082009-04-09 20:41:34 +00005304 syntax_error_unterm_str("here document");
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01005305 goto parse_error_exitcode1;
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00005306 }
Denys Vlasenkob1cfc452009-05-02 17:18:34 +02005307 if (end_trigger == ')') {
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01005308 syntax_error_unterm_ch('(');
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01005309 goto parse_error_exitcode1;
Denys Vlasenkob1cfc452009-05-02 17:18:34 +02005310 }
Denys Vlasenko42246472016-11-07 16:22:35 +01005311 if (end_trigger == '}') {
5312 syntax_error_unterm_ch('{');
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01005313 goto parse_error_exitcode1;
Denys Vlasenko42246472016-11-07 16:22:35 +01005314 }
Denys Vlasenkob1cfc452009-05-02 17:18:34 +02005315
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005316 if (done_word(&ctx)) {
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01005317 goto parse_error_exitcode1;
Denis Vlasenko55789c62008-06-18 16:30:42 +00005318 }
Denys Vlasenko18567402018-07-20 17:51:31 +02005319 o_free_and_set_NULL(&ctx.word);
Denis Vlasenko6da69cd2009-04-04 12:12:58 +00005320 done_pipe(&ctx, PIPE_SEQ);
Denis Vlasenko6da69cd2009-04-04 12:12:58 +00005321 pi = ctx.list_head;
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00005322 /* If we got nothing... */
Denis Vlasenko0b677d82009-04-10 13:49:10 +00005323 /* (this makes bare "&" cmd a no-op.
5324 * bash says: "syntax error near unexpected token '&'") */
Denis Vlasenko6da69cd2009-04-04 12:12:58 +00005325 if (pi->num_cmds == 0
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01005326 IF_HAS_KEYWORDS(&& pi->res_word == RES_NONE)
Denis Vlasenko6da69cd2009-04-04 12:12:58 +00005327 ) {
Denis Vlasenko0701dca2009-04-11 10:38:47 +00005328 free_pipe_list(pi);
Denis Vlasenko6da69cd2009-04-04 12:12:58 +00005329 pi = NULL;
5330 }
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00005331#if !BB_MMU
Denys Vlasenkob5be13c2015-09-04 06:22:10 +02005332 debug_printf_parse("as_string1 '%s'\n", ctx.as_string.data);
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00005333 if (pstring)
5334 *pstring = ctx.as_string.data;
5335 else
Denys Vlasenko18567402018-07-20 17:51:31 +02005336 o_free(&ctx.as_string);
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00005337#endif
Denys Vlasenko474cb202018-07-24 13:03:03 +02005338 // heredoc_cnt must be 0 here anyway
5339 //if (heredoc_cnt_ptr)
5340 // *heredoc_cnt_ptr = heredoc_cnt;
Denis Vlasenko0701dca2009-04-11 10:38:47 +00005341 debug_leave();
Denys Vlasenko474cb202018-07-24 13:03:03 +02005342 debug_printf_heredoc("parse_stream return heredoc_cnt:%d\n", heredoc_cnt);
Denis Vlasenko0701dca2009-04-11 10:38:47 +00005343 debug_printf_parse("parse_stream return %p\n", pi);
Denis Vlasenko6da69cd2009-04-04 12:12:58 +00005344 return pi;
Denis Vlasenko1a735862007-05-23 00:32:25 +00005345 }
Denys Vlasenkod8389ad2009-11-16 03:18:46 +01005346
Denys Vlasenko0403bed2018-04-11 01:33:54 +02005347 /* Handle "'" and "\" first, as they won't play nice with
5348 * i_peek_and_eat_bkslash_nl() anyway:
5349 * echo z\\
5350 * and
5351 * echo '\
5352 * '
5353 * would break.
5354 */
Denys Vlasenkof693b602018-04-11 20:00:43 +02005355 if (ch == '\\') {
5356 ch = i_getch(input);
5357 if (ch == '\n')
5358 continue; /* drop \<newline>, get next char */
5359 nommu_addchr(&ctx.as_string, '\\');
Denys Vlasenko1b7a9b62021-06-15 16:05:57 +02005360 if (ch == SPECIAL_VAR_SYMBOL) {
5361 nommu_addchr(&ctx.as_string, ch);
5362 /* Convert \^C to corresponding special variable reference */
5363 goto case_SPECIAL_VAR_SYMBOL;
5364 }
Denys Vlasenkof693b602018-04-11 20:00:43 +02005365 o_addchr(&ctx.word, '\\');
5366 if (ch == EOF) {
5367 /* Testcase: eval 'echo Ok\' */
5368 /* bash-4.3.43 was removing backslash,
5369 * but 4.4.19 retains it, most other shells too
5370 */
5371 continue; /* get next char */
5372 }
5373 /* Example: echo Hello \2>file
5374 * we need to know that word 2 is quoted
5375 */
5376 ctx.word.has_quoted_part = 1;
5377 nommu_addchr(&ctx.as_string, ch);
5378 o_addchr(&ctx.word, ch);
5379 continue; /* get next char */
5380 }
5381 nommu_addchr(&ctx.as_string, ch);
Denys Vlasenko92a930b2018-04-10 14:20:48 +02005382 if (ch == '\'') {
5383 ctx.word.has_quoted_part = 1;
5384 next = i_getch(input);
5385 if (next == '\'' && !ctx.pending_redirect)
5386 goto insert_empty_quoted_str_marker;
5387
5388 ch = next;
5389 while (1) {
5390 if (ch == EOF) {
5391 syntax_error_unterm_ch('\'');
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01005392 goto parse_error_exitcode1;
Denys Vlasenko92a930b2018-04-10 14:20:48 +02005393 }
5394 nommu_addchr(&ctx.as_string, ch);
5395 if (ch == '\'')
5396 break;
5397 if (ch == SPECIAL_VAR_SYMBOL) {
5398 /* Convert raw ^C to corresponding special variable reference */
5399 o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL);
5400 o_addchr(&ctx.word, SPECIAL_VAR_QUOTED_SVS);
5401 }
5402 o_addqchr(&ctx.word, ch);
5403 ch = i_getch(input);
5404 }
5405 continue; /* get next char */
Denys Vlasenko1e5111b2018-04-01 03:04:55 +02005406 }
Denys Vlasenko92a930b2018-04-10 14:20:48 +02005407
Denys Vlasenko0403bed2018-04-11 01:33:54 +02005408 next = '\0';
5409 if (ch != '\n')
5410 next = i_peek_and_eat_bkslash_nl(input);
5411
Denys Vlasenkod2241f52020-10-31 03:34:07 +01005412 is_special = "{}<>&|();#" /* special outside of "str" */
Denys Vlasenko0403bed2018-04-11 01:33:54 +02005413 "$\"" IF_HUSH_TICK("`") /* always special */
Denys Vlasenko932b9972018-01-11 12:39:48 +01005414 SPECIAL_VAR_SYMBOL_STR;
Denys Vlasenkod2241f52020-10-31 03:34:07 +01005415#if defined(CMD_TEST2_SINGLEWORD_NOGLOB)
5416 if (ctx.command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB) {
5417 /* In [[ ]], {}<>&|() are not special */
5418 is_special += 8;
5419 } else
5420#endif
Denys Vlasenkod8389ad2009-11-16 03:18:46 +01005421 /* Are { and } special here? */
Denys Vlasenko3227d3f2010-05-17 09:49:47 +02005422 if (ctx.command->argv /* word [word]{... - non-special */
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005423 || ctx.word.length /* word{... - non-special */
5424 || ctx.word.has_quoted_part /* ""{... - non-special */
Denys Vlasenko1fd3d942010-09-08 13:31:53 +02005425 || (next != ';' /* }; - special */
5426 && next != ')' /* }) - special */
Denys Vlasenko672a55e2016-11-04 18:46:14 +01005427 && next != '(' /* {( - special */
Denys Vlasenko1fd3d942010-09-08 13:31:53 +02005428 && next != '&' /* }& and }&& ... - special */
5429 && next != '|' /* }|| ... - special */
5430 && !strchr(defifs, next) /* {word - non-special */
Denys Vlasenko3227d3f2010-05-17 09:49:47 +02005431 )
Denys Vlasenkod8389ad2009-11-16 03:18:46 +01005432 ) {
5433 /* They are not special, skip "{}" */
5434 is_special += 2;
5435 }
5436 is_special = strchr(is_special, ch);
Denys Vlasenko1fd3d942010-09-08 13:31:53 +02005437 is_blank = strchr(defifs, ch);
Denis Vlasenko6da69cd2009-04-04 12:12:58 +00005438
Denys Vlasenko1fd3d942010-09-08 13:31:53 +02005439 if (!is_special && !is_blank) { /* ordinary char */
Denis Vlasenkobf25fbc2009-04-19 13:57:51 +00005440 ordinary_char:
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005441 o_addQchr(&ctx.word, ch);
5442 if ((ctx.is_assignment == MAYBE_ASSIGNMENT
5443 || ctx.is_assignment == WORD_IS_KEYWORD)
Denis Vlasenko55789c62008-06-18 16:30:42 +00005444 && ch == '='
Denys Vlasenkod8bd7012019-05-14 18:53:24 +02005445 && endofname(ctx.word.data)[0] == '='
Denis Vlasenko55789c62008-06-18 16:30:42 +00005446 ) {
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005447 ctx.is_assignment = DEFINITELY_ASSIGNMENT;
5448 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]);
Denis Vlasenko55789c62008-06-18 16:30:42 +00005449 }
Denis Vlasenkobb81c582007-01-30 22:32:09 +00005450 continue;
5451 }
Denis Vlasenko240c2552009-04-03 03:45:05 +00005452
Denys Vlasenko1fd3d942010-09-08 13:31:53 +02005453 if (is_blank) {
Denys Vlasenko5807e182018-02-08 19:19:04 +01005454#if ENABLE_HUSH_LINENO_VAR
5455/* Case:
5456 * "while ...; do<whitespace><newline>
5457 * cmd ..."
5458 * would think that "cmd" starts in <whitespace> -
5459 * i.e., at the previous line.
5460 * We need to skip all whitespace before newlines.
5461 */
Denys Vlasenkof7869012018-02-08 19:39:42 +01005462 while (ch != '\n') {
5463 next = i_peek(input);
5464 if (next != ' ' && next != '\t' && next != '\n')
5465 break; /* next char is not ws */
5466 ch = i_getch(input);
Denys Vlasenko5807e182018-02-08 19:19:04 +01005467 }
Denys Vlasenkof7869012018-02-08 19:39:42 +01005468 /* ch == last eaten whitespace char */
Denys Vlasenko5807e182018-02-08 19:19:04 +01005469#endif
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005470 if (done_word(&ctx)) {
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01005471 goto parse_error_exitcode1;
Eric Andersenaac75e52001-04-30 18:18:45 +00005472 }
Denis Vlasenko37181682009-04-03 03:19:15 +00005473 if (ch == '\n') {
Denys Vlasenko7b4c0fd2010-11-22 17:58:14 +01005474 /* Is this a case when newline is simply ignored?
5475 * Some examples:
5476 * "cmd | <newline> cmd ..."
5477 * "case ... in <newline> word) ..."
5478 */
5479 if (IS_NULL_CMD(ctx.command)
Denys Vlasenko3675c372018-07-23 16:31:21 +02005480 && ctx.word.length == 0
5481 && !ctx.word.has_quoted_part
5482 && heredoc_cnt == 0
Denis Vlasenkof1736072008-07-31 10:09:26 +00005483 ) {
Denys Vlasenko642e71a2011-01-07 15:16:05 +01005484 /* This newline can be ignored. But...
Denys Vlasenko98c46d12011-01-18 17:30:07 +01005485 * Without check #1, interactive shell
5486 * ignores even bare <newline>,
5487 * and shows the continuation prompt:
Denys Vlasenko642e71a2011-01-07 15:16:05 +01005488 * ps1_prompt$ <enter>
Denys Vlasenko98c46d12011-01-18 17:30:07 +01005489 * ps2> _ <=== wrong, should be ps1
5490 * Without check #2, "cmd & <newline>"
5491 * is similarly mistreated.
5492 * (BTW, this makes "cmd & cmd"
5493 * and "cmd && cmd" non-orthogonal.
5494 * Really, ask yourself, why
5495 * "cmd && <newline>" doesn't start
5496 * cmd but waits for more input?
Denys Vlasenkob24e55d2017-07-16 20:29:35 +02005497 * The only reason is that it might be
5498 * a "cmd1 && <nl> cmd2 &" construct,
5499 * cmd1 may need to run in BG).
Denys Vlasenko642e71a2011-01-07 15:16:05 +01005500 */
5501 struct pipe *pi = ctx.list_head;
Denys Vlasenko98c46d12011-01-18 17:30:07 +01005502 if (pi->num_cmds != 0 /* check #1 */
5503 && pi->followup != PIPE_BG /* check #2 */
5504 ) {
Denys Vlasenko642e71a2011-01-07 15:16:05 +01005505 continue;
Denys Vlasenko98c46d12011-01-18 17:30:07 +01005506 }
Denis Vlasenkof1736072008-07-31 10:09:26 +00005507 }
Denis Vlasenko240c2552009-04-03 03:45:05 +00005508 /* Treat newline as a command separator. */
Denis Vlasenkob6e65562009-04-03 16:49:04 +00005509 done_pipe(&ctx, PIPE_SEQ);
Denys Vlasenko3675c372018-07-23 16:31:21 +02005510 debug_printf_heredoc("heredoc_cnt:%d\n", heredoc_cnt);
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00005511 if (heredoc_cnt) {
Denys Vlasenko474cb202018-07-24 13:03:03 +02005512 heredoc_cnt = fetch_heredocs(&ctx.as_string, ctx.list_head, heredoc_cnt, input);
5513 if (heredoc_cnt != 0)
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01005514 goto parse_error_exitcode1;
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00005515 }
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005516 ctx.is_assignment = MAYBE_ASSIGNMENT;
5517 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]);
Denis Vlasenko240c2552009-04-03 03:45:05 +00005518 ch = ';';
Denys Vlasenko1fd3d942010-09-08 13:31:53 +02005519 /* note: if (is_blank) continue;
Denis Vlasenko240c2552009-04-03 03:45:05 +00005520 * will still trigger for us */
Denis Vlasenkoe725bfe2007-05-03 22:45:39 +00005521 }
Denis Vlasenkobb81c582007-01-30 22:32:09 +00005522 }
Denis Vlasenko9f8d9382009-04-19 14:03:11 +00005523
5524 /* "cmd}" or "cmd }..." without semicolon or &:
5525 * } is an ordinary char in this case, even inside { cmd; }
5526 * Pathological example: { ""}; } should exec "}" cmd
5527 */
Denis Vlasenkodcd78c42009-04-19 23:07:51 +00005528 if (ch == '}') {
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005529 if (ctx.word.length != 0 /* word} */
5530 || ctx.word.has_quoted_part /* ""} */
Denis Vlasenkodcd78c42009-04-19 23:07:51 +00005531 ) {
5532 goto ordinary_char;
5533 }
Denys Vlasenko672a55e2016-11-04 18:46:14 +01005534 if (!IS_NULL_CMD(ctx.command)) { /* cmd } */
5535 /* Generally, there should be semicolon: "cmd; }"
5536 * However, bash allows to omit it if "cmd" is
5537 * a group. Examples:
5538 * { { echo 1; } }
5539 * {(echo 1)}
5540 * { echo 0 >&2 | { echo 1; } }
5541 * { while false; do :; done }
5542 * { case a in b) ;; esac }
5543 */
5544 if (ctx.command->group)
5545 goto term_group;
5546 goto ordinary_char;
5547 }
Denis Vlasenkodcd78c42009-04-19 23:07:51 +00005548 if (!IS_NULL_PIPE(ctx.pipe)) /* cmd | } */
Denys Vlasenko672a55e2016-11-04 18:46:14 +01005549 /* Can't be an end of {cmd}, skip the check */
Denis Vlasenkodcd78c42009-04-19 23:07:51 +00005550 goto skip_end_trigger;
5551 /* else: } does terminate a group */
Denis Vlasenko9f8d9382009-04-19 14:03:11 +00005552 }
Denys Vlasenko672a55e2016-11-04 18:46:14 +01005553 term_group:
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00005554 if (end_trigger && end_trigger == ch
Denys Vlasenkoe9bda902009-05-23 16:50:07 +02005555 && (ch != ';' || heredoc_cnt == 0)
5556#if ENABLE_HUSH_CASE
5557 && (ch != ')'
5558 || ctx.ctx_res_w != RES_MATCH
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005559 || (!ctx.word.has_quoted_part && strcmp(ctx.word.data, "esac") == 0)
Denys Vlasenkoe9bda902009-05-23 16:50:07 +02005560 )
5561#endif
Denis Vlasenko6c9be7f2009-04-07 02:29:51 +00005562 ) {
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005563 if (done_word(&ctx)) {
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01005564 goto parse_error_exitcode1;
Denis Vlasenkob6e65562009-04-03 16:49:04 +00005565 }
5566 done_pipe(&ctx, PIPE_SEQ);
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005567 ctx.is_assignment = MAYBE_ASSIGNMENT;
5568 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]);
Denis Vlasenko240c2552009-04-03 03:45:05 +00005569 /* Do we sit outside of any if's, loops or case's? */
Denis Vlasenko37181682009-04-03 03:19:15 +00005570 if (!HAS_KEYWORDS
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01005571 IF_HAS_KEYWORDS(|| (ctx.ctx_res_w == RES_NONE && ctx.old_flag == 0))
Denis Vlasenko37181682009-04-03 03:19:15 +00005572 ) {
Denys Vlasenko18567402018-07-20 17:51:31 +02005573 o_free_and_set_NULL(&ctx.word);
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00005574#if !BB_MMU
Denys Vlasenkob5be13c2015-09-04 06:22:10 +02005575 debug_printf_parse("as_string2 '%s'\n", ctx.as_string.data);
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00005576 if (pstring)
5577 *pstring = ctx.as_string.data;
5578 else
Denys Vlasenko18567402018-07-20 17:51:31 +02005579 o_free(&ctx.as_string);
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00005580#endif
Denys Vlasenko39701202017-08-02 19:44:05 +02005581 if (ch != ';' && IS_NULL_PIPE(ctx.list_head)) {
5582 /* Example: bare "{ }", "()" */
5583 G.last_exitcode = 2; /* bash compat */
5584 syntax_error_unexpected_ch(ch);
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01005585 goto parse_error;
Denys Vlasenko39701202017-08-02 19:44:05 +02005586 }
Denys Vlasenko474cb202018-07-24 13:03:03 +02005587 if (heredoc_cnt_ptr)
5588 *heredoc_cnt_ptr = heredoc_cnt;
5589 debug_printf_heredoc("parse_stream return heredoc_cnt:%d\n", heredoc_cnt);
Denis Vlasenko0701dca2009-04-11 10:38:47 +00005590 debug_printf_parse("parse_stream return %p: "
5591 "end_trigger char found\n",
5592 ctx.list_head);
Denys Vlasenko39701202017-08-02 19:44:05 +02005593 debug_leave();
Denis Vlasenkob6e65562009-04-03 16:49:04 +00005594 return ctx.list_head;
Denis Vlasenkof8d01d32008-06-14 17:13:20 +00005595 }
Denis Vlasenkobb81c582007-01-30 22:32:09 +00005596 }
Denys Vlasenko92a930b2018-04-10 14:20:48 +02005597
Denys Vlasenko1fd3d942010-09-08 13:31:53 +02005598 if (is_blank)
Denis Vlasenkobb81c582007-01-30 22:32:09 +00005599 continue;
Denis Vlasenko55789c62008-06-18 16:30:42 +00005600
Denis Vlasenkoc96865f2009-04-10 00:20:58 +00005601 /* Catch <, > before deciding whether this word is
5602 * an assignment. a=1 2>z b=2: b=2 is still assignment */
5603 switch (ch) {
5604 case '>':
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005605 redir_fd = redirect_opt_num(&ctx.word);
5606 if (done_word(&ctx)) {
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01005607 goto parse_error_exitcode1;
Denis Vlasenkoc96865f2009-04-10 00:20:58 +00005608 }
5609 redir_style = REDIRECT_OVERWRITE;
5610 if (next == '>') {
5611 redir_style = REDIRECT_APPEND;
5612 ch = i_getch(input);
5613 nommu_addchr(&ctx.as_string, ch);
5614 }
5615#if 0
5616 else if (next == '(') {
5617 syntax_error(">(process) not supported");
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01005618 goto parse_error_exitcode1;
Denis Vlasenkoc96865f2009-04-10 00:20:58 +00005619 }
5620#endif
5621 if (parse_redirect(&ctx, redir_fd, redir_style, input))
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01005622 goto parse_error_exitcode1;
Denys Vlasenko92a930b2018-04-10 14:20:48 +02005623 continue; /* get next char */
Denis Vlasenkoc96865f2009-04-10 00:20:58 +00005624 case '<':
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005625 redir_fd = redirect_opt_num(&ctx.word);
5626 if (done_word(&ctx)) {
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01005627 goto parse_error_exitcode1;
Denis Vlasenkoc96865f2009-04-10 00:20:58 +00005628 }
5629 redir_style = REDIRECT_INPUT;
5630 if (next == '<') {
5631 redir_style = REDIRECT_HEREDOC;
5632 heredoc_cnt++;
Denys Vlasenko3675c372018-07-23 16:31:21 +02005633 debug_printf_heredoc("++heredoc_cnt=%d\n", heredoc_cnt);
Denis Vlasenkoc96865f2009-04-10 00:20:58 +00005634 ch = i_getch(input);
5635 nommu_addchr(&ctx.as_string, ch);
5636 } else if (next == '>') {
5637 redir_style = REDIRECT_IO;
5638 ch = i_getch(input);
5639 nommu_addchr(&ctx.as_string, ch);
5640 }
5641#if 0
5642 else if (next == '(') {
5643 syntax_error("<(process) not supported");
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01005644 goto parse_error_exitcode1;
Denis Vlasenkoc96865f2009-04-10 00:20:58 +00005645 }
5646#endif
5647 if (parse_redirect(&ctx, redir_fd, redir_style, input))
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01005648 goto parse_error_exitcode1;
Denys Vlasenko92a930b2018-04-10 14:20:48 +02005649 continue; /* get next char */
Denys Vlasenko7b4c0fd2010-11-22 17:58:14 +01005650 case '#':
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005651 if (ctx.word.length == 0 && !ctx.word.has_quoted_part) {
Denys Vlasenko7b4c0fd2010-11-22 17:58:14 +01005652 /* skip "#comment" */
Denys Vlasenko25f3b732017-10-22 15:55:48 +02005653 /* note: we do not add it to &ctx.as_string */
5654/* TODO: in bash:
5655 * comment inside $() goes to the next \n, even inside quoted string (!):
5656 * cmd "$(cmd2 #comment)" - syntax error
5657 * cmd "`cmd2 #comment`" - ok
5658 * We accept both (comment ends where command subst ends, in both cases).
5659 */
Denys Vlasenko7b4c0fd2010-11-22 17:58:14 +01005660 while (1) {
5661 ch = i_peek(input);
Denys Vlasenko25f3b732017-10-22 15:55:48 +02005662 if (ch == '\n') {
5663 nommu_addchr(&ctx.as_string, '\n');
Denys Vlasenko7b4c0fd2010-11-22 17:58:14 +01005664 break;
Denys Vlasenko25f3b732017-10-22 15:55:48 +02005665 }
5666 ch = i_getch(input);
5667 if (ch == EOF)
5668 break;
Denys Vlasenko7b4c0fd2010-11-22 17:58:14 +01005669 }
Denys Vlasenko92a930b2018-04-10 14:20:48 +02005670 continue; /* get next char */
Denys Vlasenko7b4c0fd2010-11-22 17:58:14 +01005671 }
5672 break;
Denis Vlasenkoc96865f2009-04-10 00:20:58 +00005673 }
Denys Vlasenko92a930b2018-04-10 14:20:48 +02005674 skip_end_trigger:
Denis Vlasenkoc96865f2009-04-10 00:20:58 +00005675
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005676 if (ctx.is_assignment == MAYBE_ASSIGNMENT
Denis Vlasenkoc96865f2009-04-10 00:20:58 +00005677 /* check that we are not in word in "a=1 2>word b=1": */
5678 && !ctx.pending_redirect
5679 ) {
5680 /* ch is a special char and thus this word
5681 * cannot be an assignment */
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005682 ctx.is_assignment = NOT_ASSIGNMENT;
5683 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]);
Denis Vlasenkoc96865f2009-04-10 00:20:58 +00005684 }
5685
Denys Vlasenkocbfe6ad2009-08-12 19:47:44 +02005686 /* Note: nommu_addchr(&ctx.as_string, ch) is already done */
5687
Denis Vlasenkobb81c582007-01-30 22:32:09 +00005688 switch (ch) {
Denys Vlasenko1b7a9b62021-06-15 16:05:57 +02005689 case_SPECIAL_VAR_SYMBOL:
Denys Vlasenko932b9972018-01-11 12:39:48 +01005690 case SPECIAL_VAR_SYMBOL:
5691 /* Convert raw ^C to corresponding special variable reference */
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005692 o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL);
5693 o_addchr(&ctx.word, SPECIAL_VAR_QUOTED_SVS);
Denys Vlasenko932b9972018-01-11 12:39:48 +01005694 /* fall through */
5695 case '#':
5696 /* non-comment #: "echo a#b" etc */
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005697 o_addchr(&ctx.word, ch);
Denys Vlasenkoe8b1bc02018-04-10 13:13:10 +02005698 continue; /* get next char */
Eric Andersen25f27032001-04-26 23:22:31 +00005699 case '$':
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005700 if (!parse_dollar(&ctx.as_string, &ctx.word, input, /*quote_mask:*/ 0)) {
Denis Vlasenkoa24c8ca2009-04-04 15:24:40 +00005701 debug_printf_parse("parse_stream parse error: "
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01005702 "parse_dollar returned 0 (error)\n");
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01005703 goto parse_error_exitcode1;
Denis Vlasenkoe725bfe2007-05-03 22:45:39 +00005704 }
Denys Vlasenkoe8b1bc02018-04-10 13:13:10 +02005705 continue; /* get next char */
Denys Vlasenkoe8b1bc02018-04-10 13:13:10 +02005706 case '"':
5707 ctx.word.has_quoted_part = 1;
5708 if (next == '"' && !ctx.pending_redirect) {
Denys Vlasenko92a930b2018-04-10 14:20:48 +02005709 i_getch(input); /* eat second " */
Denys Vlasenko6e42b892011-08-01 18:16:43 +02005710 insert_empty_quoted_str_marker:
5711 nommu_addchr(&ctx.as_string, next);
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005712 o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL);
5713 o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL);
Denys Vlasenkoe8b1bc02018-04-10 13:13:10 +02005714 continue; /* get next char */
Eric Andersen25f27032001-04-26 23:22:31 +00005715 }
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005716 if (ctx.is_assignment == NOT_ASSIGNMENT)
5717 ctx.word.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS;
Denys Vlasenkob762c782018-07-17 14:21:38 +02005718 if (!encode_string(&ctx.as_string, &ctx.word, input, '"'))
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01005719 goto parse_error_exitcode1;
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005720 ctx.word.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS;
Denys Vlasenkoe8b1bc02018-04-10 13:13:10 +02005721 continue; /* get next char */
Denis Vlasenko14b5dd92007-05-20 21:51:38 +00005722#if ENABLE_HUSH_TICK
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00005723 case '`': {
Denys Vlasenko60a94142011-05-13 20:57:01 +02005724 USE_FOR_NOMMU(unsigned pos;)
Denys Vlasenko2e48d532010-05-22 17:30:39 +02005725
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005726 o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL);
5727 o_addchr(&ctx.word, '`');
5728 USE_FOR_NOMMU(pos = ctx.word.length;)
5729 if (!add_till_backquote(&ctx.word, input, /*in_dquote:*/ 0))
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01005730 goto parse_error_exitcode1;
Denys Vlasenko2e48d532010-05-22 17:30:39 +02005731# if !BB_MMU
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005732 o_addstr(&ctx.as_string, ctx.word.data + pos);
Denis Vlasenko5c090a92009-04-08 21:51:33 +00005733 o_addchr(&ctx.as_string, '`');
Denys Vlasenko2e48d532010-05-22 17:30:39 +02005734# endif
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005735 o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL);
5736 //debug_printf_subst("SUBST RES3 '%s'\n", ctx.word.data + pos);
Denys Vlasenkoe8b1bc02018-04-10 13:13:10 +02005737 continue; /* get next char */
Denis Vlasenko7b4f3f12008-06-10 18:04:32 +00005738 }
Denis Vlasenko14b5dd92007-05-20 21:51:38 +00005739#endif
Eric Andersen25f27032001-04-26 23:22:31 +00005740 case ';':
Denis Vlasenko17f02e72008-07-14 04:32:29 +00005741#if ENABLE_HUSH_CASE
5742 case_semi:
5743#endif
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005744 if (done_word(&ctx)) {
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01005745 goto parse_error_exitcode1;
Denis Vlasenkob6e65562009-04-03 16:49:04 +00005746 }
5747 done_pipe(&ctx, PIPE_SEQ);
Denis Vlasenko17f02e72008-07-14 04:32:29 +00005748#if ENABLE_HUSH_CASE
5749 /* Eat multiple semicolons, detect
5750 * whether it means something special */
5751 while (1) {
Denys Vlasenko1e5111b2018-04-01 03:04:55 +02005752 ch = i_peek_and_eat_bkslash_nl(input);
Denis Vlasenko17f02e72008-07-14 04:32:29 +00005753 if (ch != ';')
5754 break;
Denis Vlasenko609f2ab2009-04-04 23:15:14 +00005755 ch = i_getch(input);
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00005756 nommu_addchr(&ctx.as_string, ch);
Denys Vlasenkoe9bda902009-05-23 16:50:07 +02005757 if (ctx.ctx_res_w == RES_CASE_BODY) {
Denis Vlasenkob6e65562009-04-03 16:49:04 +00005758 ctx.ctx_dsemicolon = 1;
5759 ctx.ctx_res_w = RES_MATCH;
Denis Vlasenko17f02e72008-07-14 04:32:29 +00005760 break;
5761 }
5762 }
5763#endif
Denis Vlasenko2b576b82008-08-04 00:46:07 +00005764 new_cmd:
5765 /* We just finished a cmd. New one may start
5766 * with an assignment */
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005767 ctx.is_assignment = MAYBE_ASSIGNMENT;
5768 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]);
Denys Vlasenkoe8b1bc02018-04-10 13:13:10 +02005769 continue; /* get next char */
Eric Andersen25f27032001-04-26 23:22:31 +00005770 case '&':
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005771 if (done_word(&ctx)) {
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01005772 goto parse_error_exitcode1;
Denis Vlasenkob6e65562009-04-03 16:49:04 +00005773 }
Denis Vlasenkobb81c582007-01-30 22:32:09 +00005774 if (next == '&') {
Denis Vlasenko609f2ab2009-04-04 23:15:14 +00005775 ch = i_getch(input);
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00005776 nommu_addchr(&ctx.as_string, ch);
Denis Vlasenkob6e65562009-04-03 16:49:04 +00005777 done_pipe(&ctx, PIPE_AND);
Eric Andersen25f27032001-04-26 23:22:31 +00005778 } else {
Denis Vlasenkob6e65562009-04-03 16:49:04 +00005779 done_pipe(&ctx, PIPE_BG);
Eric Andersen25f27032001-04-26 23:22:31 +00005780 }
Denis Vlasenko2b576b82008-08-04 00:46:07 +00005781 goto new_cmd;
Eric Andersen25f27032001-04-26 23:22:31 +00005782 case '|':
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005783 if (done_word(&ctx)) {
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01005784 goto parse_error_exitcode1;
Denis Vlasenkob6e65562009-04-03 16:49:04 +00005785 }
Denis Vlasenkofbeeb322008-07-31 00:17:01 +00005786#if ENABLE_HUSH_CASE
Denis Vlasenkob6e65562009-04-03 16:49:04 +00005787 if (ctx.ctx_res_w == RES_MATCH)
Denis Vlasenkof1736072008-07-31 10:09:26 +00005788 break; /* we are in case's "word | word)" */
Denis Vlasenkofbeeb322008-07-31 00:17:01 +00005789#endif
Denis Vlasenko2b576b82008-08-04 00:46:07 +00005790 if (next == '|') { /* || */
Denis Vlasenko609f2ab2009-04-04 23:15:14 +00005791 ch = i_getch(input);
Denis Vlasenkoaf07b7c2009-04-07 13:26:18 +00005792 nommu_addchr(&ctx.as_string, ch);
Denis Vlasenkob6e65562009-04-03 16:49:04 +00005793 done_pipe(&ctx, PIPE_OR);
Eric Andersen25f27032001-04-26 23:22:31 +00005794 } else {
5795 /* we could pick up a file descriptor choice here
5796 * with redirect_opt_num(), but bash doesn't do it.
5797 * "echo foo 2| cat" yields "foo 2". */
Denis Vlasenkob6e65562009-04-03 16:49:04 +00005798 done_command(&ctx);
Eric Andersen25f27032001-04-26 23:22:31 +00005799 }
Denis Vlasenko2b576b82008-08-04 00:46:07 +00005800 goto new_cmd;
Eric Andersen25f27032001-04-26 23:22:31 +00005801 case '(':
Denis Vlasenko17f02e72008-07-14 04:32:29 +00005802#if ENABLE_HUSH_CASE
Denis Vlasenkof1736072008-07-31 10:09:26 +00005803 /* "case... in [(]word)..." - skip '(' */
Denis Vlasenkob6e65562009-04-03 16:49:04 +00005804 if (ctx.ctx_res_w == RES_MATCH
5805 && ctx.command->argv == NULL /* not (word|(... */
Denys Vlasenko09b7a7e2018-04-10 03:22:10 +02005806 && ctx.word.length == 0 /* not word(... */
5807 && ctx.word.has_quoted_part == 0 /* not ""(... */
Denis Vlasenko17f02e72008-07-14 04:32:29 +00005808 ) {
Denys Vlasenkoe8b1bc02018-04-10 13:13:10 +02005809 continue; /* get next char */
Denis Vlasenko17f02e72008-07-14 04:32:29 +00005810 }
5811#endif
Denys Vlasenko474cb202018-07-24 13:03:03 +02005812 /* fall through */
5813 case '{': {
5814 int n = parse_group(&ctx, input, ch);
5815 if (n < 0) {
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01005816 goto parse_error_exitcode1;
Denis Vlasenkoe725bfe2007-05-03 22:45:39 +00005817 }
Denys Vlasenko474cb202018-07-24 13:03:03 +02005818 debug_printf_heredoc("parse_group done, needs heredocs:%d\n", n);
5819 heredoc_cnt += n;
Denis Vlasenko2b576b82008-08-04 00:46:07 +00005820 goto new_cmd;
Denys Vlasenko474cb202018-07-24 13:03:03 +02005821 }
Eric Andersen25f27032001-04-26 23:22:31 +00005822 case ')':
Denis Vlasenko17f02e72008-07-14 04:32:29 +00005823#if ENABLE_HUSH_CASE
Denis Vlasenkob6e65562009-04-03 16:49:04 +00005824 if (ctx.ctx_res_w == RES_MATCH)
Denis Vlasenko17f02e72008-07-14 04:32:29 +00005825 goto case_semi;
5826#endif
Denys Vlasenko474cb202018-07-24 13:03:03 +02005827
Eric Andersen25f27032001-04-26 23:22:31 +00005828 case '}':
Denis Vlasenkoc3735272008-10-09 12:58:26 +00005829 /* proper use of this character is caught by end_trigger:
5830 * if we see {, we call parse_group(..., end_trigger='}')
5831 * and it will match } earlier (not here). */
Denys Vlasenkob05bcaf2017-01-03 11:47:50 +01005832 G.last_exitcode = 2;
Denys Vlasenko39701202017-08-02 19:44:05 +02005833 syntax_error_unexpected_ch(ch);
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01005834 goto parse_error;
Eric Andersen25f27032001-04-26 23:22:31 +00005835 default:
Denis Vlasenko5ec61322008-06-24 00:50:07 +00005836 if (HUSH_DEBUG)
Denys Vlasenko332e4112018-04-04 22:32:59 +02005837 bb_error_msg_and_die("BUG: unexpected %c", ch);
Eric Andersen25f27032001-04-26 23:22:31 +00005838 }
Denis Vlasenkof8d01d32008-06-14 17:13:20 +00005839 } /* while (1) */
Denis Vlasenko027e3fd2009-04-02 22:50:40 +00005840
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01005841 parse_error_exitcode1:
Denys Vlasenkob05bcaf2017-01-03 11:47:50 +01005842 G.last_exitcode = 1;
Denys Vlasenkodc9c10a2020-11-16 13:00:44 +01005843 parse_error:
Denis Vlasenkob6e65562009-04-03 16:49:04 +00005844 {
Denis Vlasenko60b392f2009-04-03 19:14:32 +00005845 struct parse_context *pctx;
5846 IF_HAS_KEYWORDS(struct parse_context *p2;)
Denis Vlasenkob6e65562009-04-03 16:49:04 +00005847
5848 /* Clean up allocated tree.
Denys Vlasenko764b2f02009-06-07 16:05:04 +02005849 * Sample for finding leaks on syntax error recovery path.
5850 * Run it from interactive shell, watch pmap `pidof hush`.
Denis Vlasenkob6e65562009-04-03 16:49:04 +00005851 * while if false; then false; fi; do break; fi
Denis Vlasenkocc4c6932009-04-05 07:38:48 +00005852 * Samples to catch leaks at execution:
Denys Vlasenko5d5a6112016-11-07 19:36:50 +01005853 * while if (true | { true;}); then echo ok; fi; do break; done
5854 * while if (true | { true;}); then echo ok; fi; do (if echo ok; break; then :; fi) | cat; break; done
Denis Vlasenkob6e65562009-04-03 16:49:04 +00005855 */
5856 pctx = &ctx;
5857 do {
5858 /* Update pipe/command counts,
5859 * otherwise freeing may miss some */
5860 done_pipe(pctx, PIPE_SEQ);
5861 debug_printf_clean("freeing list %p from ctx %p\n",
5862 pctx->list_head, pctx);
5863 debug_print_tree(pctx->list_head, 0);
Denis Vlasenko0701dca2009-04-11 10:38:47 +00005864 free_pipe_list(pctx->list_head);
Denis Vlasenkob6e65562009-04-03 16:49:04 +00005865 debug_printf_clean("freed list %p\n", pctx->list_head);
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00005866#if !BB_MMU
Denys Vlasenko18567402018-07-20 17:51:31 +02005867 o_free(&pctx->as_string);
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00005868#endif
Denis Vlasenko60b392f2009-04-03 19:14:32 +00005869 IF_HAS_KEYWORDS(p2 = pctx->stack;)
Denis Vlasenkob6e65562009-04-03 16:49:04 +00005870 if (pctx != &ctx) {
5871 free(pctx);
5872 }
Denis Vlasenko60b392f2009-04-03 19:14:32 +00005873 IF_HAS_KEYWORDS(pctx = p2;)
5874 } while (HAS_KEYWORDS && pctx);
Denys Vlasenkocecbc982011-03-30 18:54:52 +02005875
Denys Vlasenko474cb202018-07-24 13:03:03 +02005876 o_free(&ctx.word);
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00005877#if !BB_MMU
Denys Vlasenkocecbc982011-03-30 18:54:52 +02005878 if (pstring)
5879 *pstring = NULL;
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00005880#endif
Denys Vlasenkocecbc982011-03-30 18:54:52 +02005881 debug_leave();
5882 return ERR_PTR;
Denis Vlasenko027e3fd2009-04-02 22:50:40 +00005883 }
Eric Andersen25f27032001-04-26 23:22:31 +00005884}
5885
Denys Vlasenkob36abf22010-09-05 14:50:59 +02005886
5887/*** Execution routines ***/
5888
5889/* Expansion can recurse, need forward decls: */
Denys Vlasenko637982f2017-07-06 01:52:23 +02005890#if !BASH_PATTERN_SUBST && !ENABLE_HUSH_CASE
Denys Vlasenko34179952018-04-11 13:47:59 +02005891#define expand_string_to_string(str, EXP_flags, do_unbackslash) \
Denys Vlasenkod98e5c62010-09-10 10:44:23 +02005892 expand_string_to_string(str)
5893#endif
Denys Vlasenko34179952018-04-11 13:47:59 +02005894static char *expand_string_to_string(const char *str, int EXP_flags, int do_unbackslash);
Denys Vlasenko26777aa2010-11-22 23:49:10 +01005895#if ENABLE_HUSH_TICK
Denys Vlasenkob36abf22010-09-05 14:50:59 +02005896static int process_command_subs(o_string *dest, const char *s);
Denys Vlasenko26777aa2010-11-22 23:49:10 +01005897#endif
Denys Vlasenko4c3c8a12018-07-20 19:11:09 +02005898static int expand_vars_to_list(o_string *output, int n, char *arg);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02005899
5900/* expand_strvec_to_strvec() takes a list of strings, expands
5901 * all variable references within and returns a pointer to
5902 * a list of expanded strings, possibly with larger number
5903 * of strings. (Think VAR="a b"; echo $VAR).
5904 * This new list is allocated as a single malloc block.
5905 * NULL-terminated list of char* pointers is at the beginning of it,
Denys Vlasenko1fd3d942010-09-08 13:31:53 +02005906 * followed by strings themselves.
Denys Vlasenkob36abf22010-09-05 14:50:59 +02005907 * Caller can deallocate entire list by single free(list). */
5908
Denys Vlasenko238081f2010-10-03 14:26:26 +02005909/* A horde of its helpers come first: */
5910
5911static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len)
5912{
5913 while (--len >= 0) {
Denys Vlasenko9e800222010-10-03 14:28:04 +02005914 char c = *str++;
Denys Vlasenko957f79f2010-10-03 17:15:50 +02005915
Denys Vlasenko9e800222010-10-03 14:28:04 +02005916#if ENABLE_HUSH_BRACE_EXPANSION
5917 if (c == '{' || c == '}') {
5918 /* { -> \{, } -> \} */
5919 o_addchr(o, '\\');
Denys Vlasenko957f79f2010-10-03 17:15:50 +02005920 /* And now we want to add { or } and continue:
5921 * o_addchr(o, c);
5922 * continue;
Denys Vlasenko10ad6222017-04-17 16:13:32 +02005923 * luckily, just falling through achieves this.
Denys Vlasenko957f79f2010-10-03 17:15:50 +02005924 */
Denys Vlasenko9e800222010-10-03 14:28:04 +02005925 }
5926#endif
5927 o_addchr(o, c);
5928 if (c == '\\') {
Denys Vlasenko238081f2010-10-03 14:26:26 +02005929 /* \z -> \\\z; \<eol> -> \\<eol> */
5930 o_addchr(o, '\\');
5931 if (len) {
5932 len--;
5933 o_addchr(o, '\\');
5934 o_addchr(o, *str++);
5935 }
5936 }
5937 }
5938}
5939
Denys Vlasenkob36abf22010-09-05 14:50:59 +02005940/* Store given string, finalizing the word and starting new one whenever
5941 * we encounter IFS char(s). This is used for expanding variable values.
Denys Vlasenko6e42b892011-08-01 18:16:43 +02005942 * End-of-string does NOT finalize word: think about 'echo -$VAR-'.
Denys Vlasenko168579a2018-07-19 13:45:54 +02005943 * Return in output->ended_in_ifs:
Denys Vlasenko6e42b892011-08-01 18:16:43 +02005944 * 1 - ended with IFS char, else 0 (this includes case of empty str).
5945 */
Denys Vlasenko168579a2018-07-19 13:45:54 +02005946static int expand_on_ifs(o_string *output, int n, const char *str)
Denys Vlasenkob36abf22010-09-05 14:50:59 +02005947{
Denys Vlasenko6e42b892011-08-01 18:16:43 +02005948 int last_is_ifs = 0;
5949
Denys Vlasenkob36abf22010-09-05 14:50:59 +02005950 while (1) {
Denys Vlasenko4fb53fb2011-08-01 14:06:20 +02005951 int word_len;
5952
5953 if (!*str) /* EOL - do not finalize word */
5954 break;
5955 word_len = strcspn(str, G.ifs);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02005956 if (word_len) {
Denys Vlasenko4fb53fb2011-08-01 14:06:20 +02005957 /* We have WORD_LEN leading non-IFS chars */
Denys Vlasenko238081f2010-10-03 14:26:26 +02005958 if (!(output->o_expflags & EXP_FLAG_GLOB)) {
Denys Vlasenkoc49d2d92010-09-06 10:26:37 +02005959 o_addblock(output, str, word_len);
Denys Vlasenko238081f2010-10-03 14:26:26 +02005960 } else {
Denys Vlasenkoc49d2d92010-09-06 10:26:37 +02005961 /* Protect backslashes against globbing up :)
Denys Vlasenkoa769e022010-09-10 10:12:34 +02005962 * Example: "v='\*'; echo b$v" prints "b\*"
5963 * (and does not try to glob on "*")
Denys Vlasenkoc49d2d92010-09-06 10:26:37 +02005964 */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02005965 o_addblock_duplicate_backslash(output, str, word_len);
Denys Vlasenkoc49d2d92010-09-06 10:26:37 +02005966 /*/ Why can't we do it easier? */
5967 /*o_addblock(output, str, word_len); - WRONG: "v='\*'; echo Z$v" prints "Z*" instead of "Z\*" */
5968 /*o_addqblock(output, str, word_len); - WRONG: "v='*'; echo Z$v" prints "Z*" instead of Z* files */
5969 }
Denys Vlasenko6e42b892011-08-01 18:16:43 +02005970 last_is_ifs = 0;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02005971 str += word_len;
Denys Vlasenko4fb53fb2011-08-01 14:06:20 +02005972 if (!*str) /* EOL - do not finalize word */
5973 break;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02005974 }
Denys Vlasenko6e42b892011-08-01 18:16:43 +02005975
5976 /* We know str here points to at least one IFS char */
5977 last_is_ifs = 1;
Denys Vlasenko96786362018-04-11 16:02:58 +02005978 str += strspn(str, G.ifs_whitespace); /* skip IFS whitespace chars */
Denys Vlasenko6e42b892011-08-01 18:16:43 +02005979 if (!*str) /* EOL - do not finalize word */
5980 break;
5981
Denys Vlasenko96786362018-04-11 16:02:58 +02005982 if (G.ifs_whitespace != G.ifs /* usually false ($IFS is usually all whitespace), */
5983 && strchr(G.ifs, *str) /* the second check would fail */
5984 ) {
5985 /* This is a non-whitespace $IFS char */
5986 /* Skip it and IFS whitespace chars, start new word */
5987 str++;
5988 str += strspn(str, G.ifs_whitespace);
5989 goto new_word;
5990 }
5991
Denys Vlasenko6e42b892011-08-01 18:16:43 +02005992 /* Start new word... but not always! */
5993 /* Case "v=' a'; echo ''$v": we do need to finalize empty word: */
Denys Vlasenko4fb53fb2011-08-01 14:06:20 +02005994 if (output->has_quoted_part
Denys Vlasenko186cf492018-07-27 12:14:39 +02005995 /*
5996 * Case "v=' a'; echo $v":
Denys Vlasenko4fb53fb2011-08-01 14:06:20 +02005997 * here nothing precedes the space in $v expansion,
5998 * therefore we should not finish the word
Denys Vlasenko6e42b892011-08-01 18:16:43 +02005999 * (IOW: if there *is* word to finalize, only then do it):
Denys Vlasenko186cf492018-07-27 12:14:39 +02006000 * It's okay if this accesses the byte before first argv[]:
6001 * past call to o_save_ptr() cleared it to zero byte
6002 * (grep for -prev-ifs-check-).
Denys Vlasenko4fb53fb2011-08-01 14:06:20 +02006003 */
Denys Vlasenko186cf492018-07-27 12:14:39 +02006004 || output->data[output->length - 1]
Denys Vlasenko4fb53fb2011-08-01 14:06:20 +02006005 ) {
Denys Vlasenko96786362018-04-11 16:02:58 +02006006 new_word:
Denys Vlasenko4fb53fb2011-08-01 14:06:20 +02006007 o_addchr(output, '\0');
6008 debug_print_list("expand_on_ifs", output, n);
6009 n = o_save_ptr(output, n);
6010 }
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006011 }
Denys Vlasenko6e42b892011-08-01 18:16:43 +02006012
Denys Vlasenko168579a2018-07-19 13:45:54 +02006013 output->ended_in_ifs = last_is_ifs;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006014 debug_print_list("expand_on_ifs[1]", output, n);
6015 return n;
6016}
6017
6018/* Helper to expand $((...)) and heredoc body. These act as if
6019 * they are in double quotes, with the exception that they are not :).
6020 * Just the rules are similar: "expand only $var and `cmd`"
6021 *
6022 * Returns malloced string.
6023 * As an optimization, we return NULL if expansion is not needed.
6024 */
Denys Vlasenkob762c782018-07-17 14:21:38 +02006025static char *encode_then_expand_string(const char *str)
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006026{
6027 char *exp_str;
6028 struct in_str input;
6029 o_string dest = NULL_O_STRING;
Denys Vlasenko0d2e0de2018-07-17 14:33:19 +02006030 const char *cp;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006031
Denys Vlasenko0d2e0de2018-07-17 14:33:19 +02006032 cp = str;
6033 for (;;) {
6034 if (!*cp) return NULL; /* string has no special chars */
6035 if (*cp == '$') break;
6036 if (*cp == '\\') break;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006037#if ENABLE_HUSH_TICK
Denys Vlasenko0d2e0de2018-07-17 14:33:19 +02006038 if (*cp == '`') break;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006039#endif
Denys Vlasenko0d2e0de2018-07-17 14:33:19 +02006040 cp++;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006041 }
6042
6043 /* We need to expand. Example:
6044 * echo $(($a + `echo 1`)) $((1 + $((2)) ))
6045 */
6046 setup_string_in_str(&input, str);
Denys Vlasenkob762c782018-07-17 14:21:38 +02006047 encode_string(NULL, &dest, &input, EOF);
Denys Vlasenko3eab24e2011-03-24 05:25:59 +01006048//TODO: error check (encode_string returns 0 on error)?
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006049 //bb_error_msg("'%s' -> '%s'", str, dest.data);
Denys Vlasenko34179952018-04-11 13:47:59 +02006050 exp_str = expand_string_to_string(dest.data,
Denys Vlasenkob762c782018-07-17 14:21:38 +02006051 EXP_FLAG_ESC_GLOB_CHARS,
6052 /*unbackslash:*/ 1
6053 );
6054 //bb_error_msg("'%s' -> '%s'", dest.data, exp_str);
Denys Vlasenko18567402018-07-20 17:51:31 +02006055 o_free(&dest);
Denys Vlasenkob762c782018-07-17 14:21:38 +02006056 return exp_str;
6057}
6058
Denys Vlasenko54fdabd2018-07-31 10:36:29 +02006059static const char *first_special_char_in_vararg(const char *cp)
6060{
6061 for (;;) {
6062 if (!*cp) return NULL; /* string has no special chars */
6063 if (*cp == '$') return cp;
6064 if (*cp == '\\') return cp;
6065 if (*cp == '\'') return cp;
6066 if (*cp == '"') return cp;
6067#if ENABLE_HUSH_TICK
6068 if (*cp == '`') return cp;
6069#endif
6070 /* dquoted "${x:+ARG}" should not glob, therefore
6071 * '*' et al require some non-literal processing: */
6072 if (*cp == '*') return cp;
6073 if (*cp == '?') return cp;
6074 if (*cp == '[') return cp;
6075 cp++;
6076 }
6077}
6078
Denys Vlasenko4c3c8a12018-07-20 19:11:09 +02006079/* Expanding ARG in ${var#ARG}, ${var%ARG}, or ${var/ARG/ARG}.
6080 * These can contain single- and double-quoted strings,
6081 * and treated as if the ARG string is initially unquoted. IOW:
6082 * ${var#ARG} and "${var#ARG}" treat ARG the same (ARG can even be
6083 * a dquoted string: "${var#"zz"}"), the difference only comes later
6084 * (word splitting and globbing of the ${var...} result).
6085 */
Denys Vlasenkob762c782018-07-17 14:21:38 +02006086#if !BASH_PATTERN_SUBST
6087#define encode_then_expand_vararg(str, handle_squotes, do_unbackslash) \
6088 encode_then_expand_vararg(str, handle_squotes)
6089#endif
6090static char *encode_then_expand_vararg(const char *str, int handle_squotes, int do_unbackslash)
6091{
Denys Vlasenko3d27d432018-12-27 18:03:20 +01006092#if !BASH_PATTERN_SUBST && ENABLE_HUSH_CASE
Denys Vlasenkob762c782018-07-17 14:21:38 +02006093 const int do_unbackslash = 0;
6094#endif
6095 char *exp_str;
6096 struct in_str input;
6097 o_string dest = NULL_O_STRING;
6098
Denys Vlasenko54fdabd2018-07-31 10:36:29 +02006099 if (!first_special_char_in_vararg(str)) {
6100 /* string has no special chars */
6101 return NULL;
Denys Vlasenkob762c782018-07-17 14:21:38 +02006102 }
6103
Denys Vlasenkob762c782018-07-17 14:21:38 +02006104 setup_string_in_str(&input, str);
Denys Vlasenko8b08d5a2018-07-18 15:48:53 +02006105 dest.data = xzalloc(1); /* start as "", not as NULL */
Denys Vlasenkob762c782018-07-17 14:21:38 +02006106 exp_str = NULL;
6107
6108 for (;;) {
6109 int ch;
Denys Vlasenkob762c782018-07-17 14:21:38 +02006110
6111 ch = i_getch(&input);
Denys Vlasenkob762c782018-07-17 14:21:38 +02006112 debug_printf_parse("%s: ch=%c (%d) escape=%d\n",
6113 __func__, ch, ch, !!dest.o_expflags);
Denys Vlasenko4c3c8a12018-07-20 19:11:09 +02006114
6115 if (!dest.o_expflags) {
6116 if (ch == EOF)
6117 break;
6118 if (handle_squotes && ch == '\'') {
6119 if (!add_till_single_quote_dquoted(&dest, &input))
Denys Vlasenkob762c782018-07-17 14:21:38 +02006120 goto ret; /* error */
Denys Vlasenko4c3c8a12018-07-20 19:11:09 +02006121 continue;
Denys Vlasenkob762c782018-07-17 14:21:38 +02006122 }
Denys Vlasenko4c3c8a12018-07-20 19:11:09 +02006123 }
6124 if (ch == EOF) {
6125 syntax_error_unterm_ch('"');
6126 goto ret; /* error */
Denys Vlasenkob762c782018-07-17 14:21:38 +02006127 }
6128 if (ch == '"') {
6129 dest.o_expflags ^= EXP_FLAG_ESC_GLOB_CHARS;
6130 continue;
6131 }
6132 if (ch == '\\') {
6133 ch = i_getch(&input);
6134 if (ch == EOF) {
6135//example? error message? syntax_error_unterm_ch('"');
6136 debug_printf_parse("%s: error: \\<eof>\n", __func__);
6137 goto ret;
6138 }
6139 o_addqchr(&dest, ch);
6140 continue;
6141 }
Denys Vlasenkob762c782018-07-17 14:21:38 +02006142 if (ch == '$') {
6143 if (!parse_dollar(NULL, &dest, &input, /*quote_mask:*/ 0x80)) {
6144 debug_printf_parse("%s: error: parse_dollar returned 0 (error)\n", __func__);
6145 goto ret;
6146 }
6147 continue;
6148 }
6149#if ENABLE_HUSH_TICK
6150 if (ch == '`') {
6151 //unsigned pos = dest->length;
6152 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
6153 o_addchr(&dest, 0x80 | '`');
6154 if (!add_till_backquote(&dest, &input,
6155 /*in_dquote:*/ dest.o_expflags /* nonzero if EXP_FLAG_ESC_GLOB_CHARS set */
6156 )
6157 ) {
6158 goto ret; /* error */
6159 }
6160 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
6161 //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos);
6162 continue;
6163 }
6164#endif
6165 o_addQchr(&dest, ch);
6166 } /* for (;;) */
6167
6168 debug_printf_parse("encode: '%s' -> '%s'\n", str, dest.data);
6169 exp_str = expand_string_to_string(dest.data,
Denys Vlasenko34179952018-04-11 13:47:59 +02006170 do_unbackslash ? EXP_FLAG_ESC_GLOB_CHARS : 0,
6171 do_unbackslash
6172 );
Denys Vlasenkob762c782018-07-17 14:21:38 +02006173 ret:
6174 debug_printf_parse("expand: '%s' -> '%s'\n", dest.data, exp_str);
Denys Vlasenko18567402018-07-20 17:51:31 +02006175 o_free(&dest);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006176 return exp_str;
6177}
6178
Denys Vlasenko4c3c8a12018-07-20 19:11:09 +02006179/* Expanding ARG in ${var+ARG}, ${var-ARG}
6180 */
Denys Vlasenko294eb462018-07-20 16:18:59 +02006181static int encode_then_append_var_plusminus(o_string *output, int n,
Denys Vlasenko54fdabd2018-07-31 10:36:29 +02006182 char *str, int dquoted)
Denys Vlasenko294eb462018-07-20 16:18:59 +02006183{
6184 struct in_str input;
6185 o_string dest = NULL_O_STRING;
6186
Denys Vlasenko54fdabd2018-07-31 10:36:29 +02006187 if (!first_special_char_in_vararg(str)
6188 && '\0' == str[strcspn(str, G.ifs)]
6189 ) {
6190 /* string has no special chars
6191 * && string has no $IFS chars
6192 */
Denys Vlasenko9e0adb92019-05-15 13:39:19 +02006193 if (dquoted) {
6194 /* Prints 1 (quoted expansion is a "" word, not nothing):
6195 * set -- "${notexist-}"; echo $#
6196 */
6197 output->has_quoted_part = 1;
6198 }
Denys Vlasenko54fdabd2018-07-31 10:36:29 +02006199 return expand_vars_to_list(output, n, str);
Denys Vlasenko294eb462018-07-20 16:18:59 +02006200 }
Denys Vlasenko294eb462018-07-20 16:18:59 +02006201
Denys Vlasenko294eb462018-07-20 16:18:59 +02006202 setup_string_in_str(&input, str);
6203
6204 for (;;) {
6205 int ch;
6206
6207 ch = i_getch(&input);
6208 debug_printf_parse("%s: ch=%c (%d) escape=%x\n",
6209 __func__, ch, ch, dest.o_expflags);
6210
6211 if (!dest.o_expflags) {
6212 if (ch == EOF)
6213 break;
6214 if (!dquoted && strchr(G.ifs, ch)) {
6215 /* PREFIX${x:d${e}f ...} and we met space: expand "d${e}f" and start new word.
6216 * do not assume we are at the start of the word (PREFIX above).
6217 */
6218 if (dest.data) {
6219 n = expand_vars_to_list(output, n, dest.data);
Denys Vlasenko18567402018-07-20 17:51:31 +02006220 o_free_and_set_NULL(&dest);
Denys Vlasenko294eb462018-07-20 16:18:59 +02006221 o_addchr(output, '\0');
6222 n = o_save_ptr(output, n); /* create next word */
6223 } else
6224 if (output->length != o_get_last_ptr(output, n)
6225 || output->has_quoted_part
6226 ) {
6227 /* For these cases:
6228 * f() { for i; do echo "|$i|"; done; }; x=x
6229 * f a${x:+ }b # 1st condition
6230 * |a|
6231 * |b|
6232 * f ""${x:+ }b # 2nd condition
6233 * ||
6234 * |b|
6235 */
6236 o_addchr(output, '\0');
6237 n = o_save_ptr(output, n); /* create next word */
6238 }
6239 continue;
6240 }
6241 if (!dquoted && ch == '\'') {
Denys Vlasenko4c3c8a12018-07-20 19:11:09 +02006242 if (!add_till_single_quote_dquoted(&dest, &input))
6243 goto ret; /* error */
Denys Vlasenko83e434d2018-07-20 17:36:06 +02006244 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
6245 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
Denys Vlasenko294eb462018-07-20 16:18:59 +02006246 continue;
6247 }
6248 }
6249 if (ch == EOF) {
6250 syntax_error_unterm_ch('"');
6251 goto ret; /* error */
6252 }
6253 if (ch == '"') {
6254 dest.o_expflags ^= EXP_FLAG_ESC_GLOB_CHARS;
Denys Vlasenko83e434d2018-07-20 17:36:06 +02006255 if (dest.o_expflags) {
6256 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
6257 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
6258 }
Denys Vlasenko294eb462018-07-20 16:18:59 +02006259 continue;
6260 }
6261 if (ch == '\\') {
6262 ch = i_getch(&input);
6263 if (ch == EOF) {
6264//example? error message? syntax_error_unterm_ch('"');
6265 debug_printf_parse("%s: error: \\<eof>\n", __func__);
6266 goto ret;
6267 }
6268 o_addqchr(&dest, ch);
6269 continue;
6270 }
6271 if (ch == '$') {
6272 if (!parse_dollar(NULL, &dest, &input, /*quote_mask:*/ (dest.o_expflags || dquoted) ? 0x80 : 0)) {
6273 debug_printf_parse("%s: error: parse_dollar returned 0 (error)\n", __func__);
6274 goto ret;
6275 }
6276 continue;
6277 }
6278#if ENABLE_HUSH_TICK
6279 if (ch == '`') {
6280 //unsigned pos = dest->length;
6281 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
6282 o_addchr(&dest, (dest.o_expflags || dquoted) ? 0x80 | '`' : '`');
6283 if (!add_till_backquote(&dest, &input,
6284 /*in_dquote:*/ dest.o_expflags /* nonzero if EXP_FLAG_ESC_GLOB_CHARS set */
6285 )
6286 ) {
6287 goto ret; /* error */
6288 }
6289 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
6290 //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos);
6291 continue;
6292 }
6293#endif
Denys Vlasenkof36caa42018-07-20 19:29:41 +02006294 if (dquoted) {
6295 /* Always glob-protect if in dquotes:
6296 * x=x; echo "${x:+/bin/c*}" - prints: /bin/c*
6297 * x=x; echo "${x:+"/bin/c*"}" - prints: /bin/c*
6298 */
6299 o_addqchr(&dest, ch);
6300 } else {
6301 /* Glob-protect only if char is quoted:
6302 * x=x; echo ${x:+/bin/c*} - prints many filenames
6303 * x=x; echo ${x:+"/bin/c*"} - prints: /bin/c*
6304 */
6305 o_addQchr(&dest, ch);
6306 }
Denys Vlasenko294eb462018-07-20 16:18:59 +02006307 } /* for (;;) */
6308
6309 if (dest.data) {
6310 n = expand_vars_to_list(output, n, dest.data);
6311 }
6312 ret:
Denys Vlasenko18567402018-07-20 17:51:31 +02006313 o_free(&dest);
Denys Vlasenko294eb462018-07-20 16:18:59 +02006314 return n;
6315}
6316
Denys Vlasenko0b883582016-12-23 16:49:07 +01006317#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko063847d2010-09-15 13:33:02 +02006318static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p)
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006319{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02006320 arith_state_t math_state;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006321 arith_t res;
6322 char *exp_str;
6323
Denys Vlasenko06d44d72010-09-13 12:49:03 +02006324 math_state.lookupvar = get_local_var_value;
6325 math_state.setvar = set_local_var_from_halves;
6326 //math_state.endofname = endofname;
Denys Vlasenkob762c782018-07-17 14:21:38 +02006327 exp_str = encode_then_expand_string(arg);
Denys Vlasenko06d44d72010-09-13 12:49:03 +02006328 res = arith(&math_state, exp_str ? exp_str : arg);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006329 free(exp_str);
Denys Vlasenko063847d2010-09-15 13:33:02 +02006330 if (errmsg_p)
6331 *errmsg_p = math_state.errmsg;
6332 if (math_state.errmsg)
Denys Vlasenko39701202017-08-02 19:44:05 +02006333 msg_and_die_if_script(math_state.errmsg);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006334 return res;
6335}
6336#endif
6337
Kang-Che Sung027d3ab2017-01-11 14:18:15 +01006338#if BASH_PATTERN_SUBST
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006339/* ${var/[/]pattern[/repl]} helpers */
6340static char *strstr_pattern(char *val, const char *pattern, int *size)
6341{
6342 while (1) {
6343 char *end = scan_and_match(val, pattern, SCAN_MOVE_FROM_RIGHT + SCAN_MATCH_LEFT_HALF);
6344 debug_printf_varexp("val:'%s' pattern:'%s' end:'%s'\n", val, pattern, end);
6345 if (end) {
6346 *size = end - val;
6347 return val;
6348 }
6349 if (*val == '\0')
6350 return NULL;
6351 /* Optimization: if "*pat" did not match the start of "string",
6352 * we know that "tring", "ring" etc will not match too:
6353 */
6354 if (pattern[0] == '*')
6355 return NULL;
6356 val++;
6357 }
6358}
6359static char *replace_pattern(char *val, const char *pattern, const char *repl, char exp_op)
6360{
6361 char *result = NULL;
6362 unsigned res_len = 0;
6363 unsigned repl_len = strlen(repl);
6364
Denys Vlasenkocba79a82018-01-25 14:07:40 +01006365 /* Null pattern never matches, including if "var" is empty */
6366 if (!pattern[0])
6367 return result; /* NULL, no replaces happened */
6368
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006369 while (1) {
6370 int size;
6371 char *s = strstr_pattern(val, pattern, &size);
6372 if (!s)
6373 break;
6374
6375 result = xrealloc(result, res_len + (s - val) + repl_len + 1);
Denys Vlasenko0675b032017-07-24 02:17:05 +02006376 strcpy(mempcpy(result + res_len, val, s - val), repl);
6377 res_len += (s - val) + repl_len;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006378 debug_printf_varexp("val:'%s' s:'%s' result:'%s'\n", val, s, result);
6379
6380 val = s + size;
6381 if (exp_op == '/')
6382 break;
6383 }
Denys Vlasenko0675b032017-07-24 02:17:05 +02006384 if (*val && result) {
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006385 result = xrealloc(result, res_len + strlen(val) + 1);
6386 strcpy(result + res_len, val);
6387 debug_printf_varexp("val:'%s' result:'%s'\n", val, result);
6388 }
6389 debug_printf_varexp("result:'%s'\n", result);
6390 return result;
6391}
Kang-Che Sung027d3ab2017-01-11 14:18:15 +01006392#endif /* BASH_PATTERN_SUBST */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006393
Denys Vlasenko168579a2018-07-19 13:45:54 +02006394static int append_str_maybe_ifs_split(o_string *output, int n,
Denys Vlasenko18e8b612018-07-20 14:24:56 +02006395 int first_ch, const char *val)
Denys Vlasenko116b50a2018-07-19 11:16:53 +02006396{
6397 if (!(first_ch & 0x80)) { /* unquoted $VAR */
6398 debug_printf_expand("unquoted '%s', output->o_escape:%d\n", val,
6399 !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS));
6400 if (val && val[0])
Denys Vlasenko168579a2018-07-19 13:45:54 +02006401 n = expand_on_ifs(output, n, val);
Denys Vlasenko116b50a2018-07-19 11:16:53 +02006402 } else { /* quoted "$VAR" */
6403 output->has_quoted_part = 1;
6404 debug_printf_expand("quoted '%s', output->o_escape:%d\n", val,
6405 !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS));
6406 if (val && val[0])
6407 o_addQstr(output, val);
6408 }
6409 return n;
6410}
6411
Denys Vlasenko4c3c8a12018-07-20 19:11:09 +02006412/* Handle <SPECIAL_VAR_SYMBOL>varname...<SPECIAL_VAR_SYMBOL> construct.
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006413 */
Denys Vlasenko4c3c8a12018-07-20 19:11:09 +02006414static NOINLINE int expand_one_var(o_string *output, int n,
6415 int first_ch, char *arg, char **pp)
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006416{
Denys Vlasenko0ca31982018-01-25 13:20:50 +01006417 const char *val;
6418 char *to_be_freed;
6419 char *p;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006420 char *var;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006421 char exp_op;
6422 char exp_save = exp_save; /* for compiler */
6423 char *exp_saveptr; /* points to expansion operator */
6424 char *exp_word = exp_word; /* for compiler */
Denys Vlasenkobfc02a72010-09-09 14:38:46 +02006425 char arg0;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006426
Denys Vlasenko0ca31982018-01-25 13:20:50 +01006427 val = NULL;
6428 to_be_freed = NULL;
6429 p = *pp;
Denys Vlasenko1fd3d942010-09-08 13:31:53 +02006430 *p = '\0'; /* replace trailing SPECIAL_VAR_SYMBOL */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006431 var = arg;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006432 exp_saveptr = arg[1] ? strchr(VAR_ENCODED_SUBST_OPS, arg[1]) : NULL;
Denys Vlasenkobfc02a72010-09-09 14:38:46 +02006433 arg0 = arg[0];
Denys Vlasenkob762c782018-07-17 14:21:38 +02006434 arg[0] = (arg0 & 0x7f);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006435 exp_op = 0;
6436
Denys Vlasenkob762c782018-07-17 14:21:38 +02006437 if (arg[0] == '#' && arg[1] /* ${#...} but not ${#} */
Denys Vlasenko2093ad22017-07-26 00:07:27 +02006438 && (!exp_saveptr /* and ( not(${#<op_char>...}) */
6439 || (arg[2] == '\0' && strchr(SPECIAL_VARS_STR, arg[1])) /* or ${#C} "len of $C" ) */
6440 ) /* NB: skipping ^^^specvar check mishandles ${#::2} */
Denys Vlasenko1fd3d942010-09-08 13:31:53 +02006441 ) {
6442 /* It must be length operator: ${#var} */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006443 var++;
6444 exp_op = 'L';
6445 } else {
Denys Vlasenko1fd3d942010-09-08 13:31:53 +02006446 /* Maybe handle parameter expansion */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006447 if (exp_saveptr /* if 2nd char is one of expansion operators */
Denys Vlasenkob762c782018-07-17 14:21:38 +02006448 && strchr(NUMERIC_SPECVARS_STR, arg[0]) /* 1st char is special variable */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006449 ) {
6450 /* ${?:0}, ${#[:]%0} etc */
6451 exp_saveptr = var + 1;
6452 } else {
6453 /* ${?}, ${var}, ${var:0}, ${var[:]%0} etc */
6454 exp_saveptr = var+1 + strcspn(var+1, VAR_ENCODED_SUBST_OPS);
6455 }
6456 exp_op = exp_save = *exp_saveptr;
6457 if (exp_op) {
6458 exp_word = exp_saveptr + 1;
6459 if (exp_op == ':') {
6460 exp_op = *exp_word++;
Denys Vlasenko1fd3d942010-09-08 13:31:53 +02006461//TODO: try ${var:} and ${var:bogus} in non-bash config
Kang-Che Sung027d3ab2017-01-11 14:18:15 +01006462 if (BASH_SUBSTR
Denys Vlasenko1fd3d942010-09-08 13:31:53 +02006463 && (!exp_op || !strchr(MINUS_PLUS_EQUAL_QUESTION, exp_op))
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006464 ) {
6465 /* oops... it's ${var:N[:M]}, not ${var:?xxx} or some such */
6466 exp_op = ':';
6467 exp_word--;
6468 }
6469 }
6470 *exp_saveptr = '\0';
6471 } /* else: it's not an expansion op, but bare ${var} */
6472 }
6473
Denys Vlasenko1fd3d942010-09-08 13:31:53 +02006474 /* Look up the variable in question */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006475 if (isdigit(var[0])) {
Denys Vlasenko77a7b552010-09-09 12:40:03 +02006476 /* parse_dollar should have vetted var for us */
Denys Vlasenko8a6a4612018-07-19 12:14:47 +02006477 int nn = xatoi_positive(var);
6478 if (nn < G.global_argc)
6479 val = G.global_argv[nn];
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006480 /* else val remains NULL: $N with too big N */
6481 } else {
6482 switch (var[0]) {
6483 case '$': /* pid */
6484 val = utoa(G.root_pid);
6485 break;
6486 case '!': /* bg pid */
6487 val = G.last_bg_pid ? utoa(G.last_bg_pid) : "";
6488 break;
6489 case '?': /* exitcode */
6490 val = utoa(G.last_exitcode);
6491 break;
6492 case '#': /* argc */
6493 val = utoa(G.global_argc ? G.global_argc-1 : 0);
6494 break;
Denys Vlasenkoef8985c2019-05-19 16:29:09 +02006495 case '-': { /* active options */
6496 /* Check set_mode() to see what option chars we support */
6497 char *cp;
6498 val = cp = G.optstring_buf;
6499 if (G.o_opt[OPT_O_ERREXIT])
6500 *cp++ = 'e';
6501 if (G_interactive_fd)
6502 *cp++ = 'i';
6503 if (G_x_mode)
6504 *cp++ = 'x';
6505 /* If G.o_opt[OPT_O_NOEXEC] is true,
6506 * commands read but are not executed,
6507 * so $- can not execute too, 'n' is never seen in $-.
6508 */
Denys Vlasenkof3634582019-06-03 12:21:04 +02006509 if (G.opt_c)
6510 *cp++ = 'c';
Denys Vlasenkod8740b22019-05-19 19:11:21 +02006511 if (G.opt_s)
6512 *cp++ = 's';
Denys Vlasenkoef8985c2019-05-19 16:29:09 +02006513 *cp = '\0';
6514 break;
6515 }
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006516 default:
6517 val = get_local_var_value(var);
6518 }
6519 }
6520
6521 /* Handle any expansions */
6522 if (exp_op == 'L') {
Denys Vlasenkoc538d5b2014-08-13 09:57:44 +02006523 reinit_unicode_for_hush();
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006524 debug_printf_expand("expand: length(%s)=", val);
Denys Vlasenkoc538d5b2014-08-13 09:57:44 +02006525 val = utoa(val ? unicode_strlen(val) : 0);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006526 debug_printf_expand("%s\n", val);
6527 } else if (exp_op) {
6528 if (exp_op == '%' || exp_op == '#') {
6529 /* Standard-mandated substring removal ops:
6530 * ${parameter%word} - remove smallest suffix pattern
6531 * ${parameter%%word} - remove largest suffix pattern
6532 * ${parameter#word} - remove smallest prefix pattern
6533 * ${parameter##word} - remove largest prefix pattern
6534 *
6535 * Word is expanded to produce a glob pattern.
6536 * Then var's value is matched to it and matching part removed.
6537 */
Denys Vlasenko07abc7c2020-12-21 10:09:48 +01006538 /* bash compat: if x is "" and no shrinking of it is possible,
6539 * inner ${...} is not evaluated. Example:
6540 * unset b; : ${a%${b=B}}; echo $b
6541 * assignment b=B only happens if $a is not "".
6542 */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006543 if (val && val[0]) {
Denys Vlasenko4f870492010-09-10 11:06:01 +02006544 char *t;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006545 char *exp_exp_word;
6546 char *loc;
6547 unsigned scan_flags = pick_scan(exp_op, *exp_word);
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02006548 if (exp_op == *exp_word) /* ## or %% */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006549 exp_word++;
Denys Vlasenko55f81332018-03-02 18:12:12 +01006550 debug_printf_expand("expand: exp_word:'%s'\n", exp_word);
Denys Vlasenkob762c782018-07-17 14:21:38 +02006551 exp_exp_word = encode_then_expand_vararg(exp_word, /*handle_squotes:*/ 1, /*unbackslash:*/ 0);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006552 if (exp_exp_word)
6553 exp_word = exp_exp_word;
Denys Vlasenkob762c782018-07-17 14:21:38 +02006554 debug_printf_expand("expand: exp_word:'%s'\n", exp_word);
6555 /*
6556 * HACK ALERT. We depend here on the fact that
Denys Vlasenko4f870492010-09-10 11:06:01 +02006557 * G.global_argv and results of utoa and get_local_var_value
6558 * are actually in writable memory:
Denys Vlasenkob762c782018-07-17 14:21:38 +02006559 * scan_and_match momentarily stores NULs there.
6560 */
Denys Vlasenko4f870492010-09-10 11:06:01 +02006561 t = (char*)val;
6562 loc = scan_and_match(t, exp_word, scan_flags);
Denys Vlasenko55f81332018-03-02 18:12:12 +01006563 debug_printf_expand("op:%c str:'%s' pat:'%s' res:'%s'\n", exp_op, t, exp_word, loc);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006564 free(exp_exp_word);
6565 if (loc) { /* match was found */
6566 if (scan_flags & SCAN_MATCH_LEFT_HALF) /* #[#] */
Denys Vlasenko4f870492010-09-10 11:06:01 +02006567 val = loc; /* take right part */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006568 else /* %[%] */
Denys Vlasenko4f870492010-09-10 11:06:01 +02006569 val = to_be_freed = xstrndup(val, loc - val); /* left */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006570 }
6571 }
6572 }
Kang-Che Sung027d3ab2017-01-11 14:18:15 +01006573#if BASH_PATTERN_SUBST
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006574 else if (exp_op == '/' || exp_op == '\\') {
Denys Vlasenkoc49d2d92010-09-06 10:26:37 +02006575 /* It's ${var/[/]pattern[/repl]} thing.
6576 * Note that in encoded form it has TWO parts:
6577 * var/pattern<SPECIAL_VAR_SYMBOL>repl<SPECIAL_VAR_SYMBOL>
Denys Vlasenko4f870492010-09-10 11:06:01 +02006578 * and if // is used, it is encoded as \:
6579 * var\pattern<SPECIAL_VAR_SYMBOL>repl<SPECIAL_VAR_SYMBOL>
Denys Vlasenkoc49d2d92010-09-06 10:26:37 +02006580 */
Denys Vlasenko07abc7c2020-12-21 10:09:48 +01006581 /* bash compat: if var is "", both pattern and repl
6582 * are still evaluated, if it is unset, then not:
6583 * unset b; a=; : ${a/z/${b=3}}; echo $b # b=3
6584 * unset b; unset a; : ${a/z/${b=3}}; echo $b # b not set
6585 */
6586 if (val /*&& val[0]*/) {
Denys Vlasenko4f870492010-09-10 11:06:01 +02006587 /* pattern uses non-standard expansion.
Denys Vlasenko1fd3d942010-09-08 13:31:53 +02006588 * repl should be unbackslashed and globbed
Denys Vlasenkoc49d2d92010-09-06 10:26:37 +02006589 * by the usual expansion rules:
Denys Vlasenkode026252018-04-05 17:04:53 +02006590 * >az >bz
6591 * v='a bz'; echo "${v/a*z/a*z}" #prints "a*z"
6592 * v='a bz'; echo "${v/a*z/\z}" #prints "z"
6593 * v='a bz'; echo ${v/a*z/a*z} #prints "az"
6594 * v='a bz'; echo ${v/a*z/\z} #prints "z"
Denys Vlasenkoc49d2d92010-09-06 10:26:37 +02006595 * (note that a*z _pattern_ is never globbed!)
6596 */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006597 char *pattern, *repl, *t;
Denys Vlasenkob762c782018-07-17 14:21:38 +02006598 pattern = encode_then_expand_vararg(exp_word, /*handle_squotes:*/ 1, /*unbackslash:*/ 0);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006599 if (!pattern)
6600 pattern = xstrdup(exp_word);
6601 debug_printf_varexp("pattern:'%s'->'%s'\n", exp_word, pattern);
6602 *p++ = SPECIAL_VAR_SYMBOL;
6603 exp_word = p;
6604 p = strchr(p, SPECIAL_VAR_SYMBOL);
6605 *p = '\0';
Denys Vlasenkob762c782018-07-17 14:21:38 +02006606 repl = encode_then_expand_vararg(exp_word, /*handle_squotes:*/ 1, /*unbackslash:*/ 1);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006607 debug_printf_varexp("repl:'%s'->'%s'\n", exp_word, repl);
6608 /* HACK ALERT. We depend here on the fact that
6609 * G.global_argv and results of utoa and get_local_var_value
6610 * are actually in writable memory:
6611 * replace_pattern momentarily stores NULs there. */
6612 t = (char*)val;
6613 to_be_freed = replace_pattern(t,
6614 pattern,
6615 (repl ? repl : exp_word),
6616 exp_op);
6617 if (to_be_freed) /* at least one replace happened */
6618 val = to_be_freed;
6619 free(pattern);
6620 free(repl);
Denys Vlasenkocba79a82018-01-25 14:07:40 +01006621 } else {
Denys Vlasenko07abc7c2020-12-21 10:09:48 +01006622 /* Unset variable always gives nothing */
6623 // a=; echo ${a/*/w} # "w"
6624 // unset a; echo ${a/*/w} # ""
Denys Vlasenkocba79a82018-01-25 14:07:40 +01006625 /* Just skip "replace" part */
6626 *p++ = SPECIAL_VAR_SYMBOL;
6627 p = strchr(p, SPECIAL_VAR_SYMBOL);
6628 *p = '\0';
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006629 }
6630 }
Kang-Che Sung027d3ab2017-01-11 14:18:15 +01006631#endif /* BASH_PATTERN_SUBST */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006632 else if (exp_op == ':') {
Kang-Che Sung027d3ab2017-01-11 14:18:15 +01006633#if BASH_SUBSTR && ENABLE_FEATURE_SH_MATH
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006634 /* It's ${var:N[:M]} bashism.
6635 * Note that in encoded form it has TWO parts:
6636 * var:N<SPECIAL_VAR_SYMBOL>M<SPECIAL_VAR_SYMBOL>
6637 */
6638 arith_t beg, len;
Denys Vlasenko07abc7c2020-12-21 10:09:48 +01006639 unsigned vallen;
Denys Vlasenko063847d2010-09-15 13:33:02 +02006640 const char *errmsg;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006641
Denys Vlasenko063847d2010-09-15 13:33:02 +02006642 beg = expand_and_evaluate_arith(exp_word, &errmsg);
6643 if (errmsg)
Denys Vlasenko07abc7c2020-12-21 10:09:48 +01006644 goto empty_result;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006645 debug_printf_varexp("beg:'%s'=%lld\n", exp_word, (long long)beg);
6646 *p++ = SPECIAL_VAR_SYMBOL;
6647 exp_word = p;
6648 p = strchr(p, SPECIAL_VAR_SYMBOL);
6649 *p = '\0';
Denys Vlasenkoa7b52d22020-12-23 12:38:03 +01006650 vallen = val ? strlen(val) : 0;
Denys Vlasenkoe32b6502017-07-17 16:46:57 +02006651 if (beg < 0) {
6652 /* negative beg counts from the end */
Denys Vlasenko07abc7c2020-12-21 10:09:48 +01006653 beg = (arith_t)vallen + beg;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006654 }
Denys Vlasenko07abc7c2020-12-21 10:09:48 +01006655 /* If expansion will be empty, do not even evaluate len */
6656 if (!val || beg < 0 || beg > vallen) {
6657 /* Why > vallen, not >=? bash:
6658 * unset b; a=ab; : ${a:2:${b=3}}; echo $b # "", b=3 (!!!)
6659 * unset b; a=a; : ${a:2:${b=3}}; echo $b # "", b not set
6660 */
6661 goto empty_result;
6662 }
6663 len = expand_and_evaluate_arith(exp_word, &errmsg);
6664 if (errmsg)
6665 goto empty_result;
6666 debug_printf_varexp("len:'%s'=%lld\n", exp_word, (long long)len);
Denys Vlasenkoe32b6502017-07-17 16:46:57 +02006667 debug_printf_varexp("from val:'%s'\n", val);
6668 if (len < 0) {
6669 /* in bash, len=-n means strlen()-n */
Denys Vlasenko07abc7c2020-12-21 10:09:48 +01006670 len = (arith_t)vallen - beg + len;
Denys Vlasenkoe32b6502017-07-17 16:46:57 +02006671 if (len < 0) /* bash compat */
Denys Vlasenko39701202017-08-02 19:44:05 +02006672 msg_and_die_if_script("%s: substring expression < 0", var);
Denys Vlasenkoe32b6502017-07-17 16:46:57 +02006673 }
Denys Vlasenko07abc7c2020-12-21 10:09:48 +01006674 if (len <= 0 || !val /*|| beg >= vallen*/) {
6675 empty_result:
Denys Vlasenkoe32b6502017-07-17 16:46:57 +02006676 val = NULL;
6677 } else {
6678 /* Paranoia. What if user entered 9999999999999
6679 * which fits in arith_t but not int? */
Denys Vlasenko07abc7c2020-12-21 10:09:48 +01006680 if (len > INT_MAX)
Denys Vlasenkoe32b6502017-07-17 16:46:57 +02006681 len = INT_MAX;
6682 val = to_be_freed = xstrndup(val + beg, len);
6683 }
6684 debug_printf_varexp("val:'%s'\n", val);
6685#else /* not (HUSH_SUBSTR_EXPANSION && FEATURE_SH_MATH) */
Denys Vlasenko39701202017-08-02 19:44:05 +02006686 msg_and_die_if_script("malformed ${%s:...}", var);
Denys Vlasenkoe32b6502017-07-17 16:46:57 +02006687 val = NULL;
6688#endif
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006689 } else { /* one of "-=+?" */
6690 /* Standard-mandated substitution ops:
6691 * ${var?word} - indicate error if unset
6692 * If var is unset, word (or a message indicating it is unset
6693 * if word is null) is written to standard error
6694 * and the shell exits with a non-zero exit status.
6695 * Otherwise, the value of var is substituted.
6696 * ${var-word} - use default value
6697 * If var is unset, word is substituted.
6698 * ${var=word} - assign and use default value
6699 * If var is unset, word is assigned to var.
6700 * In all cases, final value of var is substituted.
6701 * ${var+word} - use alternative value
6702 * If var is unset, null is substituted.
6703 * Otherwise, word is substituted.
6704 *
6705 * Word is subjected to tilde expansion, parameter expansion,
6706 * command substitution, and arithmetic expansion.
6707 * If word is not needed, it is not expanded.
6708 *
6709 * Colon forms (${var:-word}, ${var:=word} etc) do the same,
6710 * but also treat null var as if it is unset.
Denys Vlasenko294eb462018-07-20 16:18:59 +02006711 *
6712 * Word-splitting and single quote behavior:
6713 *
Denys Vlasenkoc7ef8182020-12-27 16:04:54 +01006714 * $ f() { for i; do echo "|$i|"; done; }
Denys Vlasenko294eb462018-07-20 16:18:59 +02006715 *
Denys Vlasenkoc7ef8182020-12-27 16:04:54 +01006716 * $ x=; f ${x:?'x y' z}; echo $?
6717 * bash: x: x y z # neither f nor "echo $?" executes
6718 * (if interactive, bash does not exit, but merely aborts to prompt. $? is set to 1)
Denys Vlasenko294eb462018-07-20 16:18:59 +02006719 * $ x=; f "${x:?'x y' z}"
Denys Vlasenkoc7ef8182020-12-27 16:04:54 +01006720 * bash: x: x y z # dash prints: dash: x: 'x y' z
Denys Vlasenko294eb462018-07-20 16:18:59 +02006721 *
6722 * $ x=; f ${x:='x y' z}
6723 * |x|
6724 * |y|
6725 * |z|
6726 * $ x=; f "${x:='x y' z}"
6727 * |'x y' z|
6728 *
Denys Vlasenko4c3c8a12018-07-20 19:11:09 +02006729 * $ x=x; f ${x:+'x y' z}
Denys Vlasenko294eb462018-07-20 16:18:59 +02006730 * |x y|
6731 * |z|
6732 * $ x=x; f "${x:+'x y' z}"
6733 * |'x y' z|
6734 *
6735 * $ x=; f ${x:-'x y' z}
6736 * |x y|
6737 * |z|
6738 * $ x=; f "${x:-'x y' z}"
6739 * |'x y' z|
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006740 */
6741 int use_word = (!val || ((exp_save == ':') && !val[0]));
6742 if (exp_op == '+')
6743 use_word = !use_word;
6744 debug_printf_expand("expand: op:%c (null:%s) test:%i\n", exp_op,
6745 (exp_save == ':') ? "true" : "false", use_word);
6746 if (use_word) {
Denys Vlasenko294eb462018-07-20 16:18:59 +02006747 if (exp_op == '+' || exp_op == '-') {
6748 /* ${var+word} - use alternative value */
6749 /* ${var-word} - use default value */
6750 n = encode_then_append_var_plusminus(output, n, exp_word,
6751 /*dquoted:*/ (arg0 & 0x80)
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006752 );
Denys Vlasenko294eb462018-07-20 16:18:59 +02006753 val = NULL;
6754 } else {
6755 /* ${var?word} - indicate error if unset */
6756 /* ${var=word} - assign and use default value */
6757 to_be_freed = encode_then_expand_vararg(exp_word,
6758 /*handle_squotes:*/ !(arg0 & 0x80),
6759 /*unbackslash:*/ 0
6760 );
6761 if (to_be_freed)
6762 exp_word = to_be_freed;
6763 if (exp_op == '?') {
6764 /* mimic bash message */
6765 msg_and_die_if_script("%s: %s",
6766 var,
6767 exp_word[0]
6768 ? exp_word
6769 : "parameter null or not set"
6770 /* ash has more specific messages, a-la: */
6771 /*: (exp_save == ':' ? "parameter null or not set" : "parameter not set")*/
6772 );
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006773//TODO: how interactive bash aborts expansion mid-command?
Denys Vlasenko168579a2018-07-19 13:45:54 +02006774//It aborts the entire line, returns to prompt:
Denys Vlasenko8a6a4612018-07-19 12:14:47 +02006775// $ f() { for i; do echo "|$i|"; done; }; x=; f "${x:?'x y' z}"; echo YO
6776// bash: x: x y z
6777// $
6778// ("echo YO" is not executed, neither the f function call)
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006779 } else {
Denys Vlasenko294eb462018-07-20 16:18:59 +02006780 val = exp_word;
6781 }
6782 if (exp_op == '=') {
6783 /* ${var=[word]} or ${var:=[word]} */
6784 if (isdigit(var[0]) || var[0] == '#') {
6785 /* mimic bash message */
6786 msg_and_die_if_script("$%s: cannot assign in this way", var);
6787 val = NULL;
6788 } else {
6789 char *new_var = xasprintf("%s=%s", var, val);
6790 set_local_var(new_var, /*flag:*/ 0);
6791 }
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006792 }
6793 }
6794 }
6795 } /* one of "-=+?" */
6796
6797 *exp_saveptr = exp_save;
6798 } /* if (exp_op) */
6799
Denys Vlasenkobfc02a72010-09-09 14:38:46 +02006800 arg[0] = arg0;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006801 *pp = p;
Denys Vlasenko8a6a4612018-07-19 12:14:47 +02006802
Denys Vlasenko168579a2018-07-19 13:45:54 +02006803 n = append_str_maybe_ifs_split(output, n, first_ch, val);
Denys Vlasenko8a6a4612018-07-19 12:14:47 +02006804
6805 free(to_be_freed);
6806 return n;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006807}
6808
6809/* Expand all variable references in given string, adding words to list[]
6810 * at n, n+1,... positions. Return updated n (so that list[n] is next one
6811 * to be filled). This routine is extremely tricky: has to deal with
6812 * variables/parameters with whitespace, $* and $@, and constructs like
6813 * 'echo -$*-'. If you play here, you must run testsuite afterwards! */
Denys Vlasenko95d48f22010-09-08 13:58:55 +02006814static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006815{
Denys Vlasenko95d48f22010-09-08 13:58:55 +02006816 /* output->o_expflags & EXP_FLAG_SINGLEWORD (0x80) if we are in
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006817 * expansion of right-hand side of assignment == 1-element expand.
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006818 */
Denys Vlasenkobfc02a72010-09-09 14:38:46 +02006819 char cant_be_null = 0; /* only bit 0x80 matters */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006820 char *p;
6821
Denys Vlasenko95d48f22010-09-08 13:58:55 +02006822 debug_printf_expand("expand_vars_to_list: arg:'%s' singleword:%x\n", arg,
6823 !!(output->o_expflags & EXP_FLAG_SINGLEWORD));
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006824 debug_print_list("expand_vars_to_list[0]", output, n);
6825
6826 while ((p = strchr(arg, SPECIAL_VAR_SYMBOL)) != NULL) {
6827 char first_ch;
Denys Vlasenko0b883582016-12-23 16:49:07 +01006828#if ENABLE_FEATURE_SH_MATH
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006829 char arith_buf[sizeof(arith_t)*3 + 2];
6830#endif
Denys Vlasenko6e42b892011-08-01 18:16:43 +02006831
Denys Vlasenko168579a2018-07-19 13:45:54 +02006832 if (output->ended_in_ifs) {
Denys Vlasenko6e42b892011-08-01 18:16:43 +02006833 o_addchr(output, '\0');
6834 n = o_save_ptr(output, n);
Denys Vlasenko168579a2018-07-19 13:45:54 +02006835 output->ended_in_ifs = 0;
Denys Vlasenko6e42b892011-08-01 18:16:43 +02006836 }
6837
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006838 o_addblock(output, arg, p - arg);
6839 debug_print_list("expand_vars_to_list[1]", output, n);
6840 arg = ++p;
6841 p = strchr(p, SPECIAL_VAR_SYMBOL);
6842
Denys Vlasenkobfc02a72010-09-09 14:38:46 +02006843 /* Fetch special var name (if it is indeed one of them)
6844 * and quote bit, force the bit on if singleword expansion -
6845 * important for not getting v=$@ expand to many words. */
Denys Vlasenko95d48f22010-09-08 13:58:55 +02006846 first_ch = arg[0] | (output->o_expflags & EXP_FLAG_SINGLEWORD);
Denys Vlasenkobfc02a72010-09-09 14:38:46 +02006847
6848 /* Is this variable quoted and thus expansion can't be null?
6849 * "$@" is special. Even if quoted, it can still
6850 * expand to nothing (not even an empty string),
6851 * thus it is excluded. */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006852 if ((first_ch & 0x7f) != '@')
Denys Vlasenkobfc02a72010-09-09 14:38:46 +02006853 cant_be_null |= first_ch;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006854
6855 switch (first_ch & 0x7f) {
6856 /* Highest bit in first_ch indicates that var is double-quoted */
6857 case '*':
Denys Vlasenkoc49d2d92010-09-06 10:26:37 +02006858 case '@': {
6859 int i;
6860 if (!G.global_argv[1])
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006861 break;
Denys Vlasenkoc49d2d92010-09-06 10:26:37 +02006862 i = 1;
Denys Vlasenkobfc02a72010-09-09 14:38:46 +02006863 cant_be_null |= first_ch; /* do it for "$@" _now_, when we know it's not empty */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006864 if (!(first_ch & 0x80)) { /* unquoted $* or $@ */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006865 while (G.global_argv[i]) {
Denys Vlasenko168579a2018-07-19 13:45:54 +02006866 n = expand_on_ifs(output, n, G.global_argv[i]);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006867 debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, G.global_argc - 1);
6868 if (G.global_argv[i++][0] && G.global_argv[i]) {
6869 /* this argv[] is not empty and not last:
6870 * put terminating NUL, start new word */
6871 o_addchr(output, '\0');
6872 debug_print_list("expand_vars_to_list[2]", output, n);
6873 n = o_save_ptr(output, n);
6874 debug_print_list("expand_vars_to_list[3]", output, n);
6875 }
6876 }
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006877 } else
Denys Vlasenko95d48f22010-09-08 13:58:55 +02006878 /* If EXP_FLAG_SINGLEWORD, we handle assignment 'a=....$@.....'
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006879 * and in this case should treat it like '$*' - see 'else...' below */
Denys Vlasenko6ffaa002018-03-31 00:46:07 +02006880 if (first_ch == (char)('@'|0x80) /* quoted $@ */
Denys Vlasenkobfc02a72010-09-09 14:38:46 +02006881 && !(output->o_expflags & EXP_FLAG_SINGLEWORD) /* not v="$@" case */
Denys Vlasenko95d48f22010-09-08 13:58:55 +02006882 ) {
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006883 while (1) {
6884 o_addQstr(output, G.global_argv[i]);
6885 if (++i >= G.global_argc)
6886 break;
6887 o_addchr(output, '\0');
6888 debug_print_list("expand_vars_to_list[4]", output, n);
6889 n = o_save_ptr(output, n);
6890 }
Denys Vlasenkobfc02a72010-09-09 14:38:46 +02006891 } else { /* quoted $* (or v="$@" case): add as one word */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006892 while (1) {
6893 o_addQstr(output, G.global_argv[i]);
6894 if (!G.global_argv[++i])
6895 break;
6896 if (G.ifs[0])
6897 o_addchr(output, G.ifs[0]);
6898 }
Denys Vlasenko4fb53fb2011-08-01 14:06:20 +02006899 output->has_quoted_part = 1;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006900 }
6901 break;
Denys Vlasenkoc49d2d92010-09-06 10:26:37 +02006902 }
Denys Vlasenko18e8b612018-07-20 14:24:56 +02006903 case SPECIAL_VAR_SYMBOL: {
6904 /* <SPECIAL_VAR_SYMBOL><SPECIAL_VAR_SYMBOL> */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006905 /* "Empty variable", used to make "" etc to not disappear */
Denys Vlasenko4fb53fb2011-08-01 14:06:20 +02006906 output->has_quoted_part = 1;
Denys Vlasenkobfc02a72010-09-09 14:38:46 +02006907 cant_be_null = 0x80;
Denys Vlasenko18e8b612018-07-20 14:24:56 +02006908 arg++;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006909 break;
Denys Vlasenko18e8b612018-07-20 14:24:56 +02006910 }
Denys Vlasenko932b9972018-01-11 12:39:48 +01006911 case SPECIAL_VAR_QUOTED_SVS:
6912 /* <SPECIAL_VAR_SYMBOL><SPECIAL_VAR_QUOTED_SVS><SPECIAL_VAR_SYMBOL> */
Denys Vlasenko18e8b612018-07-20 14:24:56 +02006913 /* "^C variable", represents literal ^C char (possible in scripts) */
Denys Vlasenko83e434d2018-07-20 17:36:06 +02006914 o_addchr(output, SPECIAL_VAR_SYMBOL);
Denys Vlasenko932b9972018-01-11 12:39:48 +01006915 arg++;
Denys Vlasenko932b9972018-01-11 12:39:48 +01006916 break;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006917#if ENABLE_HUSH_TICK
Denys Vlasenko18e8b612018-07-20 14:24:56 +02006918 case '`': {
6919 /* <SPECIAL_VAR_SYMBOL>`cmd<SPECIAL_VAR_SYMBOL> */
Denys Vlasenko116b50a2018-07-19 11:16:53 +02006920 o_string subst_result = NULL_O_STRING;
6921
Denys Vlasenkobfc02a72010-09-09 14:38:46 +02006922 *p = '\0'; /* replace trailing <SPECIAL_VAR_SYMBOL> */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006923 arg++;
6924 /* Can't just stuff it into output o_string,
6925 * expanded result may need to be globbed
Denys Vlasenko10ad6222017-04-17 16:13:32 +02006926 * and $IFS-split */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006927 debug_printf_subst("SUBST '%s' first_ch %x\n", arg, first_ch);
6928 G.last_exitcode = process_command_subs(&subst_result, arg);
Denys Vlasenko5fa05052018-04-03 11:21:13 +02006929 G.expand_exitcode = G.last_exitcode;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006930 debug_printf_subst("SUBST RES:%d '%s'\n", G.last_exitcode, subst_result.data);
Denys Vlasenko168579a2018-07-19 13:45:54 +02006931 n = append_str_maybe_ifs_split(output, n, first_ch, subst_result.data);
Denys Vlasenko18567402018-07-20 17:51:31 +02006932 o_free(&subst_result);
Denys Vlasenko18e8b612018-07-20 14:24:56 +02006933 break;
Denys Vlasenko116b50a2018-07-19 11:16:53 +02006934 }
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006935#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01006936#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko18e8b612018-07-20 14:24:56 +02006937 case '+': {
6938 /* <SPECIAL_VAR_SYMBOL>+arith<SPECIAL_VAR_SYMBOL> */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006939 arith_t res;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006940
6941 arg++; /* skip '+' */
6942 *p = '\0'; /* replace trailing <SPECIAL_VAR_SYMBOL> */
6943 debug_printf_subst("ARITH '%s' first_ch %x\n", arg, first_ch);
Denys Vlasenko063847d2010-09-15 13:33:02 +02006944 res = expand_and_evaluate_arith(arg, NULL);
Denys Vlasenkobed7c812010-09-16 11:50:46 +02006945 debug_printf_subst("ARITH RES '"ARITH_FMT"'\n", res);
6946 sprintf(arith_buf, ARITH_FMT, res);
Denys Vlasenkoe4a06122020-02-21 17:21:34 +01006947 if (res < 0
6948 && first_ch == (char)('+'|0x80)
6949 /* && (output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS) */
6950 ) {
6951 /* Quoted negative ariths, like filename[0"$((-9))"],
6952 * should not be interpreted as glob ranges.
6953 * Convert leading '-' to '\-':
6954 */
6955 o_grow_by(output, 1);
6956 output->data[output->length++] = '\\';
6957 }
Denys Vlasenko18e8b612018-07-20 14:24:56 +02006958 o_addstr(output, arith_buf);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006959 break;
6960 }
6961#endif
Denys Vlasenko8a6a4612018-07-19 12:14:47 +02006962 default:
Denys Vlasenko18e8b612018-07-20 14:24:56 +02006963 /* <SPECIAL_VAR_SYMBOL>varname[ops]<SPECIAL_VAR_SYMBOL> */
Denys Vlasenko168579a2018-07-19 13:45:54 +02006964 n = expand_one_var(output, n, first_ch, arg, &p);
Denys Vlasenko18e8b612018-07-20 14:24:56 +02006965 break;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006966 } /* switch (char after <SPECIAL_VAR_SYMBOL>) */
6967
Denys Vlasenkobfc02a72010-09-09 14:38:46 +02006968 /* Restore NULL'ed SPECIAL_VAR_SYMBOL.
6969 * Do the check to avoid writing to a const string. */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006970 if (*p != SPECIAL_VAR_SYMBOL)
6971 *p = SPECIAL_VAR_SYMBOL;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006972 arg = ++p;
6973 } /* end of "while (SPECIAL_VAR_SYMBOL is found) ..." */
6974
Denys Vlasenko4c3c8a12018-07-20 19:11:09 +02006975 if (*arg) {
6976 /* handle trailing string */
Denys Vlasenko168579a2018-07-19 13:45:54 +02006977 if (output->ended_in_ifs) {
Denys Vlasenko6e42b892011-08-01 18:16:43 +02006978 o_addchr(output, '\0');
6979 n = o_save_ptr(output, n);
6980 }
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006981 debug_print_list("expand_vars_to_list[a]", output, n);
6982 /* this part is literal, and it was already pre-quoted
Denys Vlasenko294eb462018-07-20 16:18:59 +02006983 * if needed (much earlier), do not use o_addQstr here!
6984 */
6985 o_addstr(output, arg);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006986 debug_print_list("expand_vars_to_list[b]", output, n);
Denys Vlasenko18567402018-07-20 17:51:31 +02006987 } else
6988 if (output->length == o_get_last_ptr(output, n) /* expansion is empty */
Denys Vlasenko83e434d2018-07-20 17:36:06 +02006989 && !(cant_be_null & 0x80) /* and all vars were not quoted */
6990 && !output->has_quoted_part
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006991 ) {
6992 n--;
6993 /* allow to reuse list[n] later without re-growth */
6994 output->has_empty_slot = 1;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02006995 }
6996
6997 return n;
6998}
6999
Denys Vlasenko95d48f22010-09-08 13:58:55 +02007000static char **expand_variables(char **argv, unsigned expflags)
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007001{
7002 int n;
7003 char **list;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007004 o_string output = NULL_O_STRING;
7005
Denys Vlasenko95d48f22010-09-08 13:58:55 +02007006 output.o_expflags = expflags;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007007
7008 n = 0;
Denys Vlasenko57235be2018-07-20 14:45:12 +02007009 for (;;) {
7010 /* go to next list[n] */
7011 output.ended_in_ifs = 0;
7012 n = o_save_ptr(&output, n);
7013
7014 if (!*argv)
7015 break;
7016
7017 /* expand argv[i] */
7018 n = expand_vars_to_list(&output, n, *argv++);
Denys Vlasenko294eb462018-07-20 16:18:59 +02007019 /* if (!output->has_empty_slot) -- need this?? */
7020 o_addchr(&output, '\0');
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007021 }
7022 debug_print_list("expand_variables", &output, n);
7023
7024 /* output.data (malloced in one block) gets returned in "list" */
7025 list = o_finalize_list(&output, n);
7026 debug_print_strings("expand_variables[1]", list);
7027 return list;
7028}
7029
7030static char **expand_strvec_to_strvec(char **argv)
7031{
Denys Vlasenko5b686cb2010-09-08 13:44:34 +02007032 return expand_variables(argv, EXP_FLAG_GLOB | EXP_FLAG_ESC_GLOB_CHARS);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007033}
7034
Denys Vlasenkod2241f52020-10-31 03:34:07 +01007035#if defined(CMD_SINGLEWORD_NOGLOB) || defined(CMD_TEST2_SINGLEWORD_NOGLOB)
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007036static char **expand_strvec_to_strvec_singleword_noglob(char **argv)
7037{
Denys Vlasenko5b686cb2010-09-08 13:44:34 +02007038 return expand_variables(argv, EXP_FLAG_SINGLEWORD);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007039}
7040#endif
7041
Denys Vlasenko1fd3d942010-09-08 13:31:53 +02007042/* Used for expansion of right hand of assignments,
Denys Vlasenkod358b0b2018-04-05 00:51:55 +02007043 * $((...)), heredocs, variable expansion parts.
Denys Vlasenko1fd3d942010-09-08 13:31:53 +02007044 *
7045 * NB: should NOT do globbing!
7046 * "export v=/bin/c*; env | grep ^v=" outputs "v=/bin/c*"
7047 */
Denys Vlasenko34179952018-04-11 13:47:59 +02007048static char *expand_string_to_string(const char *str, int EXP_flags, int do_unbackslash)
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007049{
Denys Vlasenko637982f2017-07-06 01:52:23 +02007050#if !BASH_PATTERN_SUBST && !ENABLE_HUSH_CASE
Denys Vlasenkod98e5c62010-09-10 10:44:23 +02007051 const int do_unbackslash = 1;
Denys Vlasenko34179952018-04-11 13:47:59 +02007052 const int EXP_flags = EXP_FLAG_ESC_GLOB_CHARS;
Denys Vlasenkod98e5c62010-09-10 10:44:23 +02007053#endif
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007054 char *argv[2], **list;
7055
Denys Vlasenkoebee4102010-09-10 10:17:53 +02007056 debug_printf_expand("string_to_string<='%s'\n", str);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007057 /* This is generally an optimization, but it also
7058 * handles "", which otherwise trips over !list[0] check below.
7059 * (is this ever happens that we actually get str="" here?)
7060 */
7061 if (!strchr(str, SPECIAL_VAR_SYMBOL) && !strchr(str, '\\')) {
7062 //TODO: Can use on strings with \ too, just unbackslash() them?
Denys Vlasenkoebee4102010-09-10 10:17:53 +02007063 debug_printf_expand("string_to_string(fast)=>'%s'\n", str);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007064 return xstrdup(str);
7065 }
7066
7067 argv[0] = (char*)str;
7068 argv[1] = NULL;
Denys Vlasenko34179952018-04-11 13:47:59 +02007069 list = expand_variables(argv, EXP_flags | EXP_FLAG_SINGLEWORD);
Denys Vlasenko2e711012018-07-18 16:02:25 +02007070 if (!list[0]) {
7071 /* Example where it happens:
7072 * x=; echo ${x:-"$@"}
7073 */
7074 ((char*)list)[0] = '\0';
7075 } else {
7076 if (HUSH_DEBUG)
7077 if (list[1])
James Byrne69374872019-07-02 11:35:03 +02007078 bb_simple_error_msg_and_die("BUG in varexp2");
Denys Vlasenko2e711012018-07-18 16:02:25 +02007079 /* actually, just move string 2*sizeof(char*) bytes back */
7080 overlapping_strcpy((char*)list, list[0]);
7081 if (do_unbackslash)
7082 unbackslash((char*)list);
7083 }
Denys Vlasenkoebee4102010-09-10 10:17:53 +02007084 debug_printf_expand("string_to_string=>'%s'\n", (char*)list);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007085 return (char*)list;
7086}
7087
Denys Vlasenkoabf75562018-04-02 17:25:18 +02007088#if 0
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007089static char* expand_strvec_to_string(char **argv)
7090{
7091 char **list;
7092
Denys Vlasenko5b686cb2010-09-08 13:44:34 +02007093 list = expand_variables(argv, EXP_FLAG_SINGLEWORD);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007094 /* Convert all NULs to spaces */
7095 if (list[0]) {
7096 int n = 1;
7097 while (list[n]) {
7098 if (HUSH_DEBUG)
7099 if (list[n-1] + strlen(list[n-1]) + 1 != list[n])
7100 bb_error_msg_and_die("BUG in varexp3");
7101 /* bash uses ' ' regardless of $IFS contents */
7102 list[n][-1] = ' ';
7103 n++;
7104 }
7105 }
Denys Vlasenko78c9c732016-09-29 01:44:17 +02007106 overlapping_strcpy((char*)list, list[0] ? list[0] : "");
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007107 debug_printf_expand("strvec_to_string='%s'\n", (char*)list);
7108 return (char*)list;
7109}
Denys Vlasenko1f191122018-01-11 13:17:30 +01007110#endif
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007111
7112static char **expand_assignments(char **argv, int count)
7113{
7114 int i;
7115 char **p;
7116
7117 G.expanded_assignments = p = NULL;
7118 /* Expand assignments into one string each */
7119 for (i = 0; i < count; i++) {
Denys Vlasenko34179952018-04-11 13:47:59 +02007120 p = add_string_to_strings(p,
7121 expand_string_to_string(argv[i],
7122 EXP_FLAG_ESC_GLOB_CHARS,
7123 /*unbackslash:*/ 1
7124 )
7125 );
7126 G.expanded_assignments = p;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007127 }
7128 G.expanded_assignments = NULL;
7129 return p;
7130}
7131
7132
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02007133static void switch_off_special_sigs(unsigned mask)
7134{
7135 unsigned sig = 0;
7136 while ((mask >>= 1) != 0) {
7137 sig++;
7138 if (!(mask & 1))
7139 continue;
Denys Vlasenko7a85c602017-01-08 17:40:18 +01007140#if ENABLE_HUSH_TRAP
7141 if (G_traps) {
7142 if (G_traps[sig] && !G_traps[sig][0])
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02007143 /* trap is '', has to remain SIG_IGN */
7144 continue;
Denys Vlasenko7a85c602017-01-08 17:40:18 +01007145 free(G_traps[sig]);
7146 G_traps[sig] = NULL;
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02007147 }
Denys Vlasenko7a85c602017-01-08 17:40:18 +01007148#endif
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02007149 /* We are here only if no trap or trap was not '' */
Denys Vlasenko0806e402011-05-12 23:06:20 +02007150 install_sighandler(sig, SIG_DFL);
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02007151 }
7152}
7153
Denys Vlasenkob347df92011-08-09 22:49:15 +02007154#if BB_MMU
7155/* never called */
7156void re_execute_shell(char ***to_free, const char *s,
7157 char *g_argv0, char **g_argv,
7158 char **builtin_argv) NORETURN;
7159
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007160static void reset_traps_to_defaults(void)
7161{
7162 /* This function is always called in a child shell
7163 * after fork (not vfork, NOMMU doesn't use this function).
7164 */
Denys Vlasenko7a85c602017-01-08 17:40:18 +01007165 IF_HUSH_TRAP(unsigned sig;)
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007166 unsigned mask;
7167
7168 /* Child shells are not interactive.
7169 * SIGTTIN/SIGTTOU/SIGTSTP should not have special handling.
7170 * Testcase: (while :; do :; done) + ^Z should background.
7171 * Same goes for SIGTERM, SIGHUP, SIGINT.
7172 */
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02007173 mask = (G.special_sig_mask & SPECIAL_INTERACTIVE_SIGS) | G_fatal_sig_mask;
Denys Vlasenko7a85c602017-01-08 17:40:18 +01007174 if (!G_traps && !mask)
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02007175 return; /* already no traps and no special sigs */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007176
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02007177 /* Switch off special sigs */
7178 switch_off_special_sigs(mask);
Denys Vlasenko7a85c602017-01-08 17:40:18 +01007179# if ENABLE_HUSH_JOB
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02007180 G_fatal_sig_mask = 0;
Denys Vlasenko7a85c602017-01-08 17:40:18 +01007181# endif
Denys Vlasenko10c01312011-05-11 11:49:21 +02007182 G.special_sig_mask &= ~SPECIAL_INTERACTIVE_SIGS;
Denys Vlasenkof58f7052011-05-12 02:10:33 +02007183 /* SIGQUIT,SIGCHLD and maybe SPECIAL_JOBSTOP_SIGS
7184 * remain set in G.special_sig_mask */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007185
Denys Vlasenko7a85c602017-01-08 17:40:18 +01007186# if ENABLE_HUSH_TRAP
7187 if (!G_traps)
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02007188 return;
7189
7190 /* Reset all sigs to default except ones with empty traps */
7191 for (sig = 0; sig < NSIG; sig++) {
Denys Vlasenko7a85c602017-01-08 17:40:18 +01007192 if (!G_traps[sig])
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02007193 continue; /* no trap: nothing to do */
Denys Vlasenko7a85c602017-01-08 17:40:18 +01007194 if (!G_traps[sig][0])
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02007195 continue; /* empty trap: has to remain SIG_IGN */
7196 /* sig has non-empty trap, reset it: */
Denys Vlasenko7a85c602017-01-08 17:40:18 +01007197 free(G_traps[sig]);
7198 G_traps[sig] = NULL;
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02007199 /* There is no signal for trap 0 (EXIT) */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007200 if (sig == 0)
7201 continue;
Denys Vlasenko0806e402011-05-12 23:06:20 +02007202 install_sighandler(sig, pick_sighandler(sig));
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007203 }
Denys Vlasenko7a85c602017-01-08 17:40:18 +01007204# endif
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007205}
7206
7207#else /* !BB_MMU */
7208
7209static void re_execute_shell(char ***to_free, const char *s,
7210 char *g_argv0, char **g_argv,
7211 char **builtin_argv) NORETURN;
7212static void re_execute_shell(char ***to_free, const char *s,
7213 char *g_argv0, char **g_argv,
7214 char **builtin_argv)
7215{
7216# define NOMMU_HACK_FMT ("-$%x:%x:%x:%x:%x:%llx" IF_HUSH_LOOPS(":%x"))
7217 /* delims + 2 * (number of bytes in printed hex numbers) */
7218 char param_buf[sizeof(NOMMU_HACK_FMT) + 2 * (sizeof(int)*6 + sizeof(long long)*1)];
7219 char *heredoc_argv[4];
7220 struct variable *cur;
7221# if ENABLE_HUSH_FUNCTIONS
7222 struct function *funcp;
7223# endif
7224 char **argv, **pp;
7225 unsigned cnt;
7226 unsigned long long empty_trap_mask;
7227
7228 if (!g_argv0) { /* heredoc */
7229 argv = heredoc_argv;
7230 argv[0] = (char *) G.argv0_for_re_execing;
7231 argv[1] = (char *) "-<";
7232 argv[2] = (char *) s;
7233 argv[3] = NULL;
7234 pp = &argv[3]; /* used as pointer to empty environment */
7235 goto do_exec;
7236 }
7237
7238 cnt = 0;
7239 pp = builtin_argv;
7240 if (pp) while (*pp++)
7241 cnt++;
7242
7243 empty_trap_mask = 0;
Denys Vlasenko7a85c602017-01-08 17:40:18 +01007244 if (G_traps) {
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007245 int sig;
7246 for (sig = 1; sig < NSIG; sig++) {
Denys Vlasenko7a85c602017-01-08 17:40:18 +01007247 if (G_traps[sig] && !G_traps[sig][0])
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007248 empty_trap_mask |= 1LL << sig;
7249 }
7250 }
7251
7252 sprintf(param_buf, NOMMU_HACK_FMT
7253 , (unsigned) G.root_pid
7254 , (unsigned) G.root_ppid
7255 , (unsigned) G.last_bg_pid
7256 , (unsigned) G.last_exitcode
7257 , cnt
7258 , empty_trap_mask
7259 IF_HUSH_LOOPS(, G.depth_of_loop)
7260 );
7261# undef NOMMU_HACK_FMT
7262 /* 1:hush 2:-$<pid>:<pid>:<exitcode>:<etc...> <vars...> <funcs...>
7263 * 3:-c 4:<cmd> 5:<arg0> <argN...> 6:NULL
7264 */
7265 cnt += 6;
7266 for (cur = G.top_var; cur; cur = cur->next) {
7267 if (!cur->flg_export || cur->flg_read_only)
7268 cnt += 2;
7269 }
7270# if ENABLE_HUSH_FUNCTIONS
7271 for (funcp = G.top_func; funcp; funcp = funcp->next)
7272 cnt += 3;
7273# endif
7274 pp = g_argv;
7275 while (*pp++)
7276 cnt++;
7277 *to_free = argv = pp = xzalloc(sizeof(argv[0]) * cnt);
7278 *pp++ = (char *) G.argv0_for_re_execing;
7279 *pp++ = param_buf;
7280 for (cur = G.top_var; cur; cur = cur->next) {
7281 if (strcmp(cur->varstr, hush_version_str) == 0)
7282 continue;
7283 if (cur->flg_read_only) {
7284 *pp++ = (char *) "-R";
7285 *pp++ = cur->varstr;
7286 } else if (!cur->flg_export) {
7287 *pp++ = (char *) "-V";
7288 *pp++ = cur->varstr;
7289 }
7290 }
7291# if ENABLE_HUSH_FUNCTIONS
7292 for (funcp = G.top_func; funcp; funcp = funcp->next) {
7293 *pp++ = (char *) "-F";
7294 *pp++ = funcp->name;
7295 *pp++ = funcp->body_as_string;
7296 }
7297# endif
7298 /* We can pass activated traps here. Say, -Tnn:trap_string
7299 *
7300 * However, POSIX says that subshells reset signals with traps
7301 * to SIG_DFL.
7302 * I tested bash-3.2 and it not only does that with true subshells
7303 * of the form ( list ), but with any forked children shells.
7304 * I set trap "echo W" WINCH; and then tried:
7305 *
7306 * { echo 1; sleep 20; echo 2; } &
7307 * while true; do echo 1; sleep 20; echo 2; break; done &
7308 * true | { echo 1; sleep 20; echo 2; } | cat
7309 *
7310 * In all these cases sending SIGWINCH to the child shell
7311 * did not run the trap. If I add trap "echo V" WINCH;
7312 * _inside_ group (just before echo 1), it works.
7313 *
7314 * I conclude it means we don't need to pass active traps here.
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007315 */
7316 *pp++ = (char *) "-c";
7317 *pp++ = (char *) s;
7318 if (builtin_argv) {
7319 while (*++builtin_argv)
7320 *pp++ = *builtin_argv;
7321 *pp++ = (char *) "";
7322 }
7323 *pp++ = g_argv0;
7324 while (*g_argv)
7325 *pp++ = *g_argv++;
7326 /* *pp = NULL; - is already there */
7327 pp = environ;
7328
7329 do_exec:
7330 debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s);
Denys Vlasenko75e77de2011-05-12 13:12:47 +02007331 /* Don't propagate SIG_IGN to the child */
7332 if (SPECIAL_JOBSTOP_SIGS != 0)
7333 switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007334 execve(bb_busybox_exec_path, argv, pp);
7335 /* Fallback. Useful for init=/bin/hush usage etc */
7336 if (argv[0][0] == '/')
7337 execve(argv[0], argv, pp);
7338 xfunc_error_retval = 127;
James Byrne69374872019-07-02 11:35:03 +02007339 bb_simple_error_msg_and_die("can't re-execute the shell");
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007340}
7341#endif /* !BB_MMU */
7342
7343
7344static int run_and_free_list(struct pipe *pi);
7345
Denis Vlasenko9aa7d6f2009-04-04 22:47:50 +00007346/* Executing from string: eval, sh -c '...'
Denis Vlasenkob6e65562009-04-03 16:49:04 +00007347 * or from file: /etc/profile, . file, sh <script>, sh (intereactive)
7348 * end_trigger controls how often we stop parsing
7349 * NUL: parse all, execute, return
7350 * ';': parse till ';' or newline, execute, repeat till EOF
7351 */
7352static void parse_and_run_stream(struct in_str *inp, int end_trigger)
Eric Andersen25f27032001-04-26 23:22:31 +00007353{
Denys Vlasenko00243b02009-11-16 02:00:03 +01007354 /* Why we need empty flag?
7355 * An obscure corner case "false; ``; echo $?":
7356 * empty command in `` should still set $? to 0.
7357 * But we can't just set $? to 0 at the start,
7358 * this breaks "false; echo `echo $?`" case.
7359 */
7360 bool empty = 1;
Denis Vlasenkob6e65562009-04-03 16:49:04 +00007361 while (1) {
7362 struct pipe *pipe_list;
Denis Vlasenkof8d01d32008-06-14 17:13:20 +00007363
Denys Vlasenkoa1463192011-01-18 17:55:04 +01007364#if ENABLE_HUSH_INTERACTIVE
Denys Vlasenko8d6eab32018-04-07 17:01:31 +02007365 if (end_trigger == ';') {
7366 G.promptmode = 0; /* PS1 */
7367 debug_printf_prompt("%s promptmode=%d\n", __func__, G.promptmode);
7368 }
Denys Vlasenkoa1463192011-01-18 17:55:04 +01007369#endif
Denys Vlasenko474cb202018-07-24 13:03:03 +02007370 pipe_list = parse_stream(NULL, NULL, inp, end_trigger);
Denys Vlasenkocecbc982011-03-30 18:54:52 +02007371 if (!pipe_list || pipe_list == ERR_PTR) { /* EOF/error */
7372 /* If we are in "big" script
7373 * (not in `cmd` or something similar)...
7374 */
7375 if (pipe_list == ERR_PTR && end_trigger == ';') {
7376 /* Discard cached input (rest of line) */
7377 int ch = inp->last_char;
7378 while (ch != EOF && ch != '\n') {
7379 //bb_error_msg("Discarded:'%c'", ch);
7380 ch = i_getch(inp);
7381 }
7382 /* Force prompt */
7383 inp->p = NULL;
7384 /* This stream isn't empty */
7385 empty = 0;
7386 continue;
7387 }
7388 if (!pipe_list && empty)
Denys Vlasenko00243b02009-11-16 02:00:03 +01007389 G.last_exitcode = 0;
Denis Vlasenkob6e65562009-04-03 16:49:04 +00007390 break;
Denys Vlasenko00243b02009-11-16 02:00:03 +01007391 }
Denis Vlasenkob6e65562009-04-03 16:49:04 +00007392 debug_print_tree(pipe_list, 0);
7393 debug_printf_exec("parse_and_run_stream: run_and_free_list\n");
7394 run_and_free_list(pipe_list);
Denys Vlasenko00243b02009-11-16 02:00:03 +01007395 empty = 0;
Denys Vlasenko04b46bc2016-10-01 22:28:03 +02007396 if (G_flag_return_in_progress == 1)
Denys Vlasenko68d5cb52011-03-24 02:50:03 +01007397 break;
Denis Vlasenkob6e65562009-04-03 16:49:04 +00007398 }
Eric Andersen25f27032001-04-26 23:22:31 +00007399}
7400
Denis Vlasenkob6e65562009-04-03 16:49:04 +00007401static void parse_and_run_string(const char *s)
Eric Andersen25f27032001-04-26 23:22:31 +00007402{
7403 struct in_str input;
Denys Vlasenko08fb82c2019-05-19 15:26:05 +02007404 //IF_HUSH_LINENO_VAR(unsigned sv = G.parse_lineno;)
Denys Vlasenkoaa617ac2018-02-13 15:30:13 +01007405
Eric Andersen25f27032001-04-26 23:22:31 +00007406 setup_string_in_str(&input, s);
Denis Vlasenkob6e65562009-04-03 16:49:04 +00007407 parse_and_run_stream(&input, '\0');
Denys Vlasenko08fb82c2019-05-19 15:26:05 +02007408 //IF_HUSH_LINENO_VAR(G.parse_lineno = sv;)
Eric Andersen25f27032001-04-26 23:22:31 +00007409}
7410
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02007411static void parse_and_run_file(HFILE *fp)
Eric Andersen25f27032001-04-26 23:22:31 +00007412{
Eric Andersen25f27032001-04-26 23:22:31 +00007413 struct in_str input;
Denys Vlasenko08fb82c2019-05-19 15:26:05 +02007414 IF_HUSH_LINENO_VAR(unsigned sv = G.parse_lineno;)
Denys Vlasenko6aad1dd2018-01-19 15:37:04 +01007415
Denys Vlasenko08fb82c2019-05-19 15:26:05 +02007416 IF_HUSH_LINENO_VAR(G.parse_lineno = 1;)
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02007417 setup_file_in_str(&input, fp);
Denis Vlasenkob6e65562009-04-03 16:49:04 +00007418 parse_and_run_stream(&input, ';');
Denys Vlasenko08fb82c2019-05-19 15:26:05 +02007419 IF_HUSH_LINENO_VAR(G.parse_lineno = sv;)
Eric Andersen25f27032001-04-26 23:22:31 +00007420}
7421
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007422#if ENABLE_HUSH_TICK
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02007423static int generate_stream_from_string(const char *s, pid_t *pid_p)
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007424{
7425 pid_t pid;
7426 int channel[2];
7427# if !BB_MMU
7428 char **to_free = NULL;
7429# endif
7430
7431 xpipe(channel);
7432 pid = BB_MMU ? xfork() : xvfork();
7433 if (pid == 0) { /* child */
7434 disable_restore_tty_pgrp_on_exit();
7435 /* Process substitution is not considered to be usual
7436 * 'command execution'.
7437 * SUSv3 says ctrl-Z should be ignored, ctrl-C should not.
7438 */
7439 bb_signals(0
7440 + (1 << SIGTSTP)
7441 + (1 << SIGTTIN)
7442 + (1 << SIGTTOU)
7443 , SIG_IGN);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007444 close(channel[0]); /* NB: close _first_, then move fd! */
7445 xmove_fd(channel[1], 1);
Denys Vlasenko7a85c602017-01-08 17:40:18 +01007446# if ENABLE_HUSH_TRAP
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007447 /* Awful hack for `trap` or $(trap).
7448 *
7449 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
7450 * contains an example where "trap" is executed in a subshell:
7451 *
7452 * save_traps=$(trap)
7453 * ...
7454 * eval "$save_traps"
7455 *
7456 * Standard does not say that "trap" in subshell shall print
7457 * parent shell's traps. It only says that its output
7458 * must have suitable form, but then, in the above example
7459 * (which is not supposed to be normative), it implies that.
7460 *
7461 * bash (and probably other shell) does implement it
7462 * (traps are reset to defaults, but "trap" still shows them),
7463 * but as a result, "trap" logic is hopelessly messed up:
7464 *
7465 * # trap
7466 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
7467 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
7468 * # true | trap <--- trap is in subshell - no output (ditto)
7469 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
7470 * trap -- 'echo Ho' SIGWINCH
7471 * # echo `(trap)` <--- in subshell in subshell - output
7472 * trap -- 'echo Ho' SIGWINCH
7473 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
7474 * trap -- 'echo Ho' SIGWINCH
7475 *
7476 * The rules when to forget and when to not forget traps
7477 * get really complex and nonsensical.
7478 *
7479 * Our solution: ONLY bare $(trap) or `trap` is special.
7480 */
7481 s = skip_whitespace(s);
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01007482 if (is_prefixed_with(s, "trap")
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007483 && skip_whitespace(s + 4)[0] == '\0'
7484 ) {
7485 static const char *const argv[] = { NULL, NULL };
7486 builtin_trap((char**)argv);
Denys Vlasenkoe9abe752016-08-19 20:15:26 +02007487 fflush_all(); /* important */
7488 _exit(0);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007489 }
Denys Vlasenko7a85c602017-01-08 17:40:18 +01007490# endif
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007491# if BB_MMU
Denys Vlasenko7c5f18a2018-07-26 15:21:50 +02007492 /* Prevent it from trying to handle ctrl-z etc */
7493 IF_HUSH_JOB(G.run_list_level = 1;)
7494 CLEAR_RANDOM_T(&G.random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007495 reset_traps_to_defaults();
Denys Vlasenko7c5f18a2018-07-26 15:21:50 +02007496 IF_HUSH_MODE_X(G.x_mode_depth++;)
Denys Vlasenko9dda9272018-07-27 14:12:05 +02007497 //bb_error_msg("%s: ++x_mode_depth=%d", __func__, G.x_mode_depth);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007498 parse_and_run_string(s);
7499 _exit(G.last_exitcode);
7500# else
7501 /* We re-execute after vfork on NOMMU. This makes this script safe:
7502 * yes "0123456789012345678901234567890" | dd bs=32 count=64k >BIG
7503 * huge=`cat BIG` # was blocking here forever
7504 * echo OK
7505 */
7506 re_execute_shell(&to_free,
7507 s,
7508 G.global_argv[0],
7509 G.global_argv + 1,
7510 NULL);
7511# endif
7512 }
7513
7514 /* parent */
7515 *pid_p = pid;
7516# if ENABLE_HUSH_FAST
7517 G.count_SIGCHLD++;
7518//bb_error_msg("[%d] fork in generate_stream_from_string:"
7519// " G.count_SIGCHLD:%d G.handled_SIGCHLD:%d",
7520// getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
7521# endif
7522 enable_restore_tty_pgrp_on_exit();
7523# if !BB_MMU
7524 free(to_free);
7525# endif
7526 close(channel[1]);
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02007527 return channel[0];
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007528}
7529
7530/* Return code is exit status of the process that is run. */
7531static int process_command_subs(o_string *dest, const char *s)
7532{
7533 FILE *fp;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007534 pid_t pid;
7535 int status, ch, eol_cnt;
7536
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02007537 fp = xfdopen_for_read(generate_stream_from_string(s, &pid));
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007538
7539 /* Now send results of command back into original context */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007540 eol_cnt = 0;
Denys Vlasenkoaa617ac2018-02-13 15:30:13 +01007541 while ((ch = getc(fp)) != EOF) {
7542 if (ch == '\0')
7543 continue;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007544 if (ch == '\n') {
7545 eol_cnt++;
7546 continue;
7547 }
7548 while (eol_cnt) {
7549 o_addchr(dest, '\n');
7550 eol_cnt--;
7551 }
7552 o_addQchr(dest, ch);
7553 }
7554
7555 debug_printf("done reading from `cmd` pipe, closing it\n");
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02007556 fclose(fp);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007557 /* We need to extract exitcode. Test case
7558 * "true; echo `sleep 1; false` $?"
7559 * should print 1 */
7560 safe_waitpid(pid, &status, 0);
7561 debug_printf("child exited. returning its exitcode:%d\n", WEXITSTATUS(status));
7562 return WEXITSTATUS(status);
7563}
7564#endif /* ENABLE_HUSH_TICK */
7565
7566
7567static void setup_heredoc(struct redir_struct *redir)
7568{
7569 struct fd_pair pair;
7570 pid_t pid;
7571 int len, written;
7572 /* the _body_ of heredoc (misleading field name) */
7573 const char *heredoc = redir->rd_filename;
7574 char *expanded;
7575#if !BB_MMU
7576 char **to_free;
7577#endif
7578
7579 expanded = NULL;
7580 if (!(redir->rd_dup & HEREDOC_QUOTED)) {
Denys Vlasenkob762c782018-07-17 14:21:38 +02007581 expanded = encode_then_expand_string(heredoc);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007582 if (expanded)
7583 heredoc = expanded;
7584 }
7585 len = strlen(heredoc);
7586
7587 close(redir->rd_fd); /* often saves dup2+close in xmove_fd */
7588 xpiped_pair(pair);
7589 xmove_fd(pair.rd, redir->rd_fd);
7590
7591 /* Try writing without forking. Newer kernels have
7592 * dynamically growing pipes. Must use non-blocking write! */
7593 ndelay_on(pair.wr);
7594 while (1) {
7595 written = write(pair.wr, heredoc, len);
7596 if (written <= 0)
7597 break;
7598 len -= written;
7599 if (len == 0) {
7600 close(pair.wr);
7601 free(expanded);
7602 return;
7603 }
7604 heredoc += written;
7605 }
7606 ndelay_off(pair.wr);
7607
7608 /* Okay, pipe buffer was not big enough */
7609 /* Note: we must not create a stray child (bastard? :)
7610 * for the unsuspecting parent process. Child creates a grandchild
7611 * and exits before parent execs the process which consumes heredoc
7612 * (that exec happens after we return from this function) */
7613#if !BB_MMU
7614 to_free = NULL;
7615#endif
7616 pid = xvfork();
7617 if (pid == 0) {
7618 /* child */
7619 disable_restore_tty_pgrp_on_exit();
7620 pid = BB_MMU ? xfork() : xvfork();
7621 if (pid != 0)
7622 _exit(0);
7623 /* grandchild */
7624 close(redir->rd_fd); /* read side of the pipe */
7625#if BB_MMU
7626 full_write(pair.wr, heredoc, len); /* may loop or block */
7627 _exit(0);
7628#else
7629 /* Delegate blocking writes to another process */
7630 xmove_fd(pair.wr, STDOUT_FILENO);
7631 re_execute_shell(&to_free, heredoc, NULL, NULL, NULL);
7632#endif
7633 }
7634 /* parent */
7635#if ENABLE_HUSH_FAST
7636 G.count_SIGCHLD++;
7637//bb_error_msg("[%d] fork in setup_heredoc: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
7638#endif
7639 enable_restore_tty_pgrp_on_exit();
7640#if !BB_MMU
7641 free(to_free);
7642#endif
7643 close(pair.wr);
7644 free(expanded);
7645 wait(NULL); /* wait till child has died */
7646}
7647
Denys Vlasenko2db74612017-07-07 22:07:28 +02007648struct squirrel {
7649 int orig_fd;
7650 int moved_to;
7651 /* moved_to = n: fd was moved to n; restore back to orig_fd after redir */
7652 /* moved_to = -1: fd was opened by redirect; close orig_fd after redir */
7653};
7654
Denys Vlasenko621fc502017-07-24 12:42:17 +02007655static struct squirrel *append_squirrel(struct squirrel *sq, int i, int orig, int moved)
7656{
7657 sq = xrealloc(sq, (i + 2) * sizeof(sq[0]));
7658 sq[i].orig_fd = orig;
7659 sq[i].moved_to = moved;
7660 sq[i+1].orig_fd = -1; /* end marker */
7661 return sq;
7662}
7663
Denys Vlasenko2db74612017-07-07 22:07:28 +02007664static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd)
7665{
Denys Vlasenko621fc502017-07-24 12:42:17 +02007666 int moved_to;
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02007667 int i;
Denys Vlasenko2db74612017-07-07 22:07:28 +02007668
Denys Vlasenkod16e6122017-08-11 15:41:39 +02007669 i = 0;
7670 if (sq) for (; sq[i].orig_fd >= 0; i++) {
Denys Vlasenko2db74612017-07-07 22:07:28 +02007671 /* If we collide with an already moved fd... */
7672 if (fd == sq[i].moved_to) {
Denys Vlasenko9acd63c2018-03-28 18:35:07 +02007673 sq[i].moved_to = dup_CLOEXEC(sq[i].moved_to, avoid_fd);
Denys Vlasenko2db74612017-07-07 22:07:28 +02007674 debug_printf_redir("redirect_fd %d: already busy, moving to %d\n", fd, sq[i].moved_to);
7675 if (sq[i].moved_to < 0) /* what? */
7676 xfunc_die();
7677 return sq;
7678 }
7679 if (fd == sq[i].orig_fd) {
7680 /* Example: echo Hello >/dev/null 1>&2 */
7681 debug_printf_redir("redirect_fd %d: already moved\n", fd);
7682 return sq;
7683 }
Denys Vlasenko2db74612017-07-07 22:07:28 +02007684 }
7685
Denys Vlasenko2db74612017-07-07 22:07:28 +02007686 /* If this fd is open, we move and remember it; if it's closed, moved_to = -1 */
Denys Vlasenko9acd63c2018-03-28 18:35:07 +02007687 moved_to = dup_CLOEXEC(fd, avoid_fd);
Denys Vlasenko621fc502017-07-24 12:42:17 +02007688 debug_printf_redir("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, moved_to);
7689 if (moved_to < 0 && errno != EBADF)
Denys Vlasenko2db74612017-07-07 22:07:28 +02007690 xfunc_die();
Denys Vlasenko621fc502017-07-24 12:42:17 +02007691 return append_squirrel(sq, i, fd, moved_to);
Denys Vlasenko2db74612017-07-07 22:07:28 +02007692}
7693
Denys Vlasenko657e9002017-07-30 23:34:04 +02007694static struct squirrel *add_squirrel_closed(struct squirrel *sq, int fd)
7695{
7696 int i;
7697
Denys Vlasenkod16e6122017-08-11 15:41:39 +02007698 i = 0;
7699 if (sq) for (; sq[i].orig_fd >= 0; i++) {
Denys Vlasenko657e9002017-07-30 23:34:04 +02007700 /* If we collide with an already moved fd... */
7701 if (fd == sq[i].orig_fd) {
7702 /* Examples:
7703 * "echo 3>FILE 3>&- 3>FILE"
7704 * "echo 3>&- 3>FILE"
7705 * No need for last redirect to insert
7706 * another "need to close 3" indicator.
7707 */
7708 debug_printf_redir("redirect_fd %d: already moved or closed\n", fd);
7709 return sq;
7710 }
Denys Vlasenko657e9002017-07-30 23:34:04 +02007711 }
7712
7713 debug_printf_redir("redirect_fd %d: previous fd was closed\n", fd);
7714 return append_squirrel(sq, i, fd, -1);
7715}
7716
Denys Vlasenkoaa3576a2016-08-22 19:54:12 +02007717/* fd: redirect wants this fd to be used (e.g. 3>file).
7718 * Move all conflicting internally used fds,
7719 * and remember them so that we can restore them later.
7720 */
Denys Vlasenko657e9002017-07-30 23:34:04 +02007721static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp)
Denys Vlasenkoaa3576a2016-08-22 19:54:12 +02007722{
Denys Vlasenko2db74612017-07-07 22:07:28 +02007723 if (avoid_fd < 9) /* the important case here is that it can be -1 */
7724 avoid_fd = 9;
Denys Vlasenkoaa3576a2016-08-22 19:54:12 +02007725
7726#if ENABLE_HUSH_INTERACTIVE
Denys Vlasenko21806562019-11-01 14:16:07 +01007727 if (fd != 0 /* don't trigger for G_interactive_fd == 0 (that's "not interactive" flag) */
7728 && fd == G_interactive_fd
7729 ) {
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02007730 /* Testcase: "ls -l /proc/$$/fd 255>&-" should work */
Denys Vlasenkod8bd7012019-05-14 18:53:24 +02007731 G_interactive_fd = xdup_CLOEXEC_and_close(G_interactive_fd, avoid_fd);
7732 debug_printf_redir("redirect_fd %d: matches interactive_fd, moving it to %d\n", fd, G_interactive_fd);
Denys Vlasenko2db74612017-07-07 22:07:28 +02007733 return 1; /* "we closed fd" */
Denys Vlasenkoaa3576a2016-08-22 19:54:12 +02007734 }
7735#endif
Denys Vlasenko945e9b02018-07-24 18:01:22 +02007736 /* Are we called from setup_redirects(squirrel==NULL)
7737 * in redirect in a [v]forked child?
7738 */
7739 if (sqp == NULL) {
7740 /* No need to move script fds.
7741 * For NOMMU case, it's actively wrong: we'd change ->fd
7742 * fields in memory for the parent, but parent's fds
Denys Vlasenko21806562019-11-01 14:16:07 +01007743 * aren't moved, it would use wrong fd!
Denys Vlasenko945e9b02018-07-24 18:01:22 +02007744 * Reproducer: "cmd 3>FILE" in script.
7745 * If we would call move_HFILEs_on_redirect(), child would:
7746 * fcntl64(3, F_DUPFD_CLOEXEC, 10) = 10
7747 * close(3) = 0
7748 * and change ->fd to 10 if fd#3 is a script fd. WRONG.
7749 */
7750 //bb_error_msg("sqp == NULL: [v]forked child");
7751 return 0;
7752 }
7753
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02007754 /* If this one of script's fds? */
7755 if (move_HFILEs_on_redirect(fd, avoid_fd))
7756 return 1; /* yes. "we closed fd" (actually moved it) */
7757
Denys Vlasenko945e9b02018-07-24 18:01:22 +02007758 /* Are we called for "exec 3>FILE"? Came through
7759 * redirect_and_varexp_helper(squirrel=ERR_PTR) -> setup_redirects(ERR_PTR)
7760 * This case used to fail for this script:
7761 * exec 3>FILE
7762 * echo Ok
7763 * ...100000 more lines...
7764 * echo Ok
7765 * as follows:
7766 * read(3, "exec 3>FILE\necho Ok\necho Ok"..., 1024) = 1024
7767 * open("FILE", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = 4
7768 * dup2(4, 3) = 3
7769 * ^^^^^^^^ oops, we lost fd#3 opened to our script!
7770 * close(4) = 0
7771 * write(1, "Ok\n", 3) = 3
7772 * ... = 3
7773 * write(1, "Ok\n", 3) = 3
7774 * read(3, 0x94fbc08, 1024) = -1 EBADF (Bad file descriptor)
7775 * ^^^^^^^^ oops, wrong fd!!!
7776 * With this case separate from sqp == NULL and *after* move_HFILEs,
7777 * it now works:
Denys Vlasenkoaa3576a2016-08-22 19:54:12 +02007778 */
Denys Vlasenko945e9b02018-07-24 18:01:22 +02007779 if (sqp == ERR_PTR) {
7780 /* Don't preserve redirected fds: exec is _meant_ to change these */
7781 //bb_error_msg("sqp == ERR_PTR: exec >FILE");
Denys Vlasenkoaa3576a2016-08-22 19:54:12 +02007782 return 0;
Denys Vlasenko945e9b02018-07-24 18:01:22 +02007783 }
Denys Vlasenkoaa3576a2016-08-22 19:54:12 +02007784
Denys Vlasenko2db74612017-07-07 22:07:28 +02007785 /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */
7786 *sqp = add_squirrel(*sqp, fd, avoid_fd);
7787 return 0; /* "we did not close fd" */
Denys Vlasenkoaa3576a2016-08-22 19:54:12 +02007788}
7789
Denys Vlasenko2db74612017-07-07 22:07:28 +02007790static void restore_redirects(struct squirrel *sq)
Denys Vlasenkoaa3576a2016-08-22 19:54:12 +02007791{
Denys Vlasenko2db74612017-07-07 22:07:28 +02007792 if (sq) {
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02007793 int i;
7794 for (i = 0; sq[i].orig_fd >= 0; i++) {
Denys Vlasenko2db74612017-07-07 22:07:28 +02007795 if (sq[i].moved_to >= 0) {
7796 /* We simply die on error */
7797 debug_printf_redir("restoring redirected fd from %d to %d\n", sq[i].moved_to, sq[i].orig_fd);
7798 xmove_fd(sq[i].moved_to, sq[i].orig_fd);
7799 } else {
7800 /* cmd1 9>FILE; cmd2_should_see_fd9_closed */
7801 debug_printf_redir("restoring redirected fd %d: closing it\n", sq[i].orig_fd);
7802 close(sq[i].orig_fd);
7803 }
Denys Vlasenkoaa3576a2016-08-22 19:54:12 +02007804 }
Denys Vlasenko2db74612017-07-07 22:07:28 +02007805 free(sq);
Denys Vlasenkoaa3576a2016-08-22 19:54:12 +02007806 }
Denys Vlasenko21806562019-11-01 14:16:07 +01007807 if (G.HFILE_stdin
Denys Vlasenko1237d622020-12-25 19:01:49 +01007808 && G.HFILE_stdin->fd > STDIN_FILENO
7809 /* we compare > STDIN, not == STDIN, since hfgetc()
7810 * closes fd and sets ->fd to -1 if EOF is reached.
7811 * Testcase: echo 'pwd' | hush
7812 */
Denys Vlasenko21806562019-11-01 14:16:07 +01007813 ) {
7814 /* Testcase: interactive "read r <FILE; echo $r; read r; echo $r".
7815 * Redirect moves ->fd to e.g. 10,
7816 * and it is not restored above (we do not restore script fds
7817 * after redirects, we just use new, "moved" fds).
7818 * However for stdin, get_user_input() -> read_line_input(),
7819 * and read builtin, depend on fd == STDIN_FILENO.
7820 */
7821 debug_printf_redir("restoring %d to stdin\n", G.HFILE_stdin->fd);
7822 xmove_fd(G.HFILE_stdin->fd, STDIN_FILENO);
7823 G.HFILE_stdin->fd = STDIN_FILENO;
7824 }
Denys Vlasenkoaa3576a2016-08-22 19:54:12 +02007825
Denys Vlasenkod8bd7012019-05-14 18:53:24 +02007826 /* If moved, G_interactive_fd stays on new fd, not restoring it */
Denys Vlasenkoaa3576a2016-08-22 19:54:12 +02007827}
7828
Denys Vlasenkobf1c3442017-07-31 04:54:53 +02007829#if ENABLE_FEATURE_SH_STANDALONE && BB_MMU
Denys Vlasenko5b3d2eb2017-07-31 18:02:28 +02007830static void close_saved_fds_and_FILE_fds(void)
Denys Vlasenkobf1c3442017-07-31 04:54:53 +02007831{
7832 if (G_interactive_fd)
7833 close(G_interactive_fd);
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02007834 close_all_HFILE_list();
Denys Vlasenkobf1c3442017-07-31 04:54:53 +02007835}
7836#endif
7837
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02007838static int internally_opened_fd(int fd, struct squirrel *sq)
7839{
7840 int i;
7841
7842#if ENABLE_HUSH_INTERACTIVE
Denys Vlasenkod8bd7012019-05-14 18:53:24 +02007843 if (fd == G_interactive_fd)
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02007844 return 1;
7845#endif
7846 /* If this one of script's fds? */
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02007847 if (fd_in_HFILEs(fd))
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02007848 return 1;
7849
7850 if (sq) for (i = 0; sq[i].orig_fd >= 0; i++) {
7851 if (fd == sq[i].moved_to)
7852 return 1;
7853 }
7854 return 0;
7855}
7856
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007857/* squirrel != NULL means we squirrel away copies of stdin, stdout,
7858 * and stderr if they are redirected. */
Denys Vlasenko2db74612017-07-07 22:07:28 +02007859static int setup_redirects(struct command *prog, struct squirrel **sqp)
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007860{
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007861 struct redir_struct *redir;
7862
7863 for (redir = prog->redirects; redir; redir = redir->next) {
Denys Vlasenko657e9002017-07-30 23:34:04 +02007864 int newfd;
7865 int closed;
7866
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007867 if (redir->rd_type == REDIRECT_HEREDOC2) {
Denys Vlasenko869994c2016-08-20 15:16:00 +02007868 /* "rd_fd<<HERE" case */
Denys Vlasenko657e9002017-07-30 23:34:04 +02007869 save_fd_on_redirect(redir->rd_fd, /*avoid:*/ 0, sqp);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007870 /* for REDIRECT_HEREDOC2, rd_filename holds _contents_
7871 * of the heredoc */
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02007872 debug_printf_redir("set heredoc '%s'\n",
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007873 redir->rd_filename);
7874 setup_heredoc(redir);
7875 continue;
7876 }
7877
7878 if (redir->rd_dup == REDIRFD_TO_FILE) {
Denys Vlasenko869994c2016-08-20 15:16:00 +02007879 /* "rd_fd<*>file" case (<*> is <,>,>>,<>) */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007880 char *p;
Denys Vlasenko657e9002017-07-30 23:34:04 +02007881 int mode;
7882
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007883 if (redir->rd_filename == NULL) {
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02007884 /* Examples:
Denys Vlasenkod6a37d82016-09-20 16:22:24 +02007885 * "cmd >" (no filename)
7886 * "cmd > <file" (2nd redirect starts too early)
7887 */
Denys Vlasenko39701202017-08-02 19:44:05 +02007888 syntax_error("invalid redirect");
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007889 continue;
7890 }
7891 mode = redir_table[redir->rd_type].mode;
Denys Vlasenko34179952018-04-11 13:47:59 +02007892 p = expand_string_to_string(redir->rd_filename,
7893 EXP_FLAG_ESC_GLOB_CHARS, /*unbackslash:*/ 1);
Denys Vlasenko657e9002017-07-30 23:34:04 +02007894 newfd = open_or_warn(p, mode);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007895 free(p);
Denys Vlasenko657e9002017-07-30 23:34:04 +02007896 if (newfd < 0) {
Denys Vlasenko869994c2016-08-20 15:16:00 +02007897 /* Error message from open_or_warn can be lost
7898 * if stderr has been redirected, but bash
7899 * and ash both lose it as well
7900 * (though zsh doesn't!)
7901 */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007902 return 1;
7903 }
Denys Vlasenko657e9002017-07-30 23:34:04 +02007904 if (newfd == redir->rd_fd && sqp) {
Denys Vlasenko621fc502017-07-24 12:42:17 +02007905 /* open() gave us precisely the fd we wanted.
7906 * This means that this fd was not busy
7907 * (not opened to anywhere).
7908 * Remember to close it on restore:
7909 */
Denys Vlasenko657e9002017-07-30 23:34:04 +02007910 *sqp = add_squirrel_closed(*sqp, newfd);
7911 debug_printf_redir("redir to previously closed fd %d\n", newfd);
Denys Vlasenko621fc502017-07-24 12:42:17 +02007912 }
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007913 } else {
Denys Vlasenko657e9002017-07-30 23:34:04 +02007914 /* "rd_fd>&rd_dup" or "rd_fd>&-" case */
7915 newfd = redir->rd_dup;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007916 }
7917
Denys Vlasenko657e9002017-07-30 23:34:04 +02007918 if (newfd == redir->rd_fd)
7919 continue;
7920
7921 /* if "N>FILE": move newfd to redir->rd_fd */
7922 /* if "N>&M": dup newfd to redir->rd_fd */
7923 /* if "N>&-": close redir->rd_fd (newfd is REDIRFD_CLOSE) */
7924
7925 closed = save_fd_on_redirect(redir->rd_fd, /*avoid:*/ newfd, sqp);
7926 if (newfd == REDIRFD_CLOSE) {
7927 /* "N>&-" means "close me" */
7928 if (!closed) {
7929 /* ^^^ optimization: saving may already
7930 * have closed it. If not... */
7931 close(redir->rd_fd);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007932 }
Denys Vlasenko657e9002017-07-30 23:34:04 +02007933 /* Sometimes we do another close on restore, getting EBADF.
7934 * Consider "echo 3>FILE 3>&-"
7935 * first redirect remembers "need to close 3",
7936 * and second redirect closes 3! Restore code then closes 3 again.
7937 */
7938 } else {
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02007939 /* if newfd is a script fd or saved fd, simulate EBADF */
Denys Vlasenko945e9b02018-07-24 18:01:22 +02007940 if (internally_opened_fd(newfd, sqp && sqp != ERR_PTR ? *sqp : NULL)) {
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02007941 //errno = EBADF;
7942 //bb_perror_msg_and_die("can't duplicate file descriptor");
7943 newfd = -1; /* same effect as code above */
7944 }
Denys Vlasenko657e9002017-07-30 23:34:04 +02007945 xdup2(newfd, redir->rd_fd);
7946 if (redir->rd_dup == REDIRFD_TO_FILE)
7947 /* "rd_fd > FILE" */
7948 close(newfd);
7949 /* else: "rd_fd > rd_dup" */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007950 }
7951 }
7952 return 0;
7953}
7954
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007955static char *find_in_path(const char *arg)
7956{
7957 char *ret = NULL;
7958 const char *PATH = get_local_var_value("PATH");
7959
7960 if (!PATH)
7961 return NULL;
7962
7963 while (1) {
7964 const char *end = strchrnul(PATH, ':');
7965 int sz = end - PATH; /* must be int! */
7966
7967 free(ret);
7968 if (sz != 0) {
7969 ret = xasprintf("%.*s/%s", sz, PATH, arg);
7970 } else {
7971 /* We have xxx::yyyy in $PATH,
7972 * it means "use current dir" */
7973 ret = xstrdup(arg);
7974 }
7975 if (access(ret, F_OK) == 0)
7976 break;
7977
7978 if (*end == '\0') {
7979 free(ret);
7980 return NULL;
7981 }
7982 PATH = end + 1;
7983 }
7984
7985 return ret;
7986}
7987
Denys Vlasenkoda463fb2010-09-07 09:53:50 +02007988static const struct built_in_command *find_builtin_helper(const char *name,
Denys Vlasenkob36abf22010-09-05 14:50:59 +02007989 const struct built_in_command *x,
7990 const struct built_in_command *end)
7991{
7992 while (x != end) {
7993 if (strcmp(name, x->b_cmd) != 0) {
7994 x++;
7995 continue;
7996 }
7997 debug_printf_exec("found builtin '%s'\n", name);
7998 return x;
7999 }
8000 return NULL;
8001}
Denys Vlasenkoda463fb2010-09-07 09:53:50 +02008002static const struct built_in_command *find_builtin1(const char *name)
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008003{
8004 return find_builtin_helper(name, bltins1, &bltins1[ARRAY_SIZE(bltins1)]);
8005}
Denys Vlasenkoda463fb2010-09-07 09:53:50 +02008006static const struct built_in_command *find_builtin(const char *name)
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008007{
8008 const struct built_in_command *x = find_builtin1(name);
8009 if (x)
8010 return x;
8011 return find_builtin_helper(name, bltins2, &bltins2[ARRAY_SIZE(bltins2)]);
8012}
8013
Denys Vlasenkod5314e72020-06-24 09:31:30 +02008014#if ENABLE_HUSH_JOB && EDITING_HAS_get_exe_name
Ron Yorston9e2a5662020-01-21 16:01:58 +00008015static const char * FAST_FUNC get_builtin_name(int i)
8016{
8017 if (/*i >= 0 && */ i < ARRAY_SIZE(bltins1)) {
8018 return bltins1[i].b_cmd;
8019 }
8020 i -= ARRAY_SIZE(bltins1);
8021 if (i < ARRAY_SIZE(bltins2)) {
8022 return bltins2[i].b_cmd;
8023 }
8024 return NULL;
8025}
8026#endif
8027
Denys Vlasenko99496dc2018-06-26 15:36:58 +02008028static void remove_nested_vars(void)
8029{
8030 struct variable *cur;
8031 struct variable **cur_pp;
8032
8033 cur_pp = &G.top_var;
8034 while ((cur = *cur_pp) != NULL) {
8035 if (cur->var_nest_level <= G.var_nest_level) {
8036 cur_pp = &cur->next;
8037 continue;
8038 }
8039 /* Unexport */
8040 if (cur->flg_export) {
8041 debug_printf_env("unexporting nested '%s'/%u\n", cur->varstr, cur->var_nest_level);
8042 bb_unsetenv(cur->varstr);
8043 }
8044 /* Remove from global list */
8045 *cur_pp = cur->next;
8046 /* Free */
8047 if (!cur->max_len) {
8048 debug_printf_env("freeing nested '%s'/%u\n", cur->varstr, cur->var_nest_level);
8049 free(cur->varstr);
8050 }
8051 free(cur);
8052 }
8053}
8054
8055static void enter_var_nest_level(void)
8056{
8057 G.var_nest_level++;
8058 debug_printf_env("var_nest_level++ %u\n", G.var_nest_level);
8059
8060 /* Try: f() { echo -n .; f; }; f
8061 * struct variable::var_nest_level is uint16_t,
8062 * thus limiting recursion to < 2^16.
8063 * In any case, with 8 Mbyte stack SEGV happens
8064 * not too long after 2^16 recursions anyway.
8065 */
8066 if (G.var_nest_level > 0xff00)
8067 bb_error_msg_and_die("fatal recursion (depth %u)", G.var_nest_level);
8068}
8069
8070static void leave_var_nest_level(void)
8071{
8072 G.var_nest_level--;
8073 debug_printf_env("var_nest_level-- %u\n", G.var_nest_level);
8074 if (HUSH_DEBUG && (int)G.var_nest_level < 0)
James Byrne69374872019-07-02 11:35:03 +02008075 bb_simple_error_msg_and_die("BUG: nesting underflow");
Denys Vlasenko99496dc2018-06-26 15:36:58 +02008076
8077 remove_nested_vars();
8078}
8079
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008080#if ENABLE_HUSH_FUNCTIONS
8081static struct function **find_function_slot(const char *name)
8082{
Denys Vlasenko33f7c8f2018-03-06 17:21:57 +01008083 struct function *funcp;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008084 struct function **funcpp = &G.top_func;
Denys Vlasenko33f7c8f2018-03-06 17:21:57 +01008085
8086 while ((funcp = *funcpp) != NULL) {
8087 if (strcmp(name, funcp->name) == 0) {
8088 debug_printf_exec("found function '%s'\n", name);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008089 break;
8090 }
Denys Vlasenko33f7c8f2018-03-06 17:21:57 +01008091 funcpp = &funcp->next;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008092 }
8093 return funcpp;
8094}
8095
Denys Vlasenko33f7c8f2018-03-06 17:21:57 +01008096static ALWAYS_INLINE const struct function *find_function(const char *name)
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008097{
8098 const struct function *funcp = *find_function_slot(name);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008099 return funcp;
8100}
8101
8102/* Note: takes ownership on name ptr */
8103static struct function *new_function(char *name)
8104{
8105 struct function **funcpp = find_function_slot(name);
8106 struct function *funcp = *funcpp;
8107
8108 if (funcp != NULL) {
8109 struct command *cmd = funcp->parent_cmd;
8110 debug_printf_exec("func %p parent_cmd %p\n", funcp, cmd);
8111 if (!cmd) {
8112 debug_printf_exec("freeing & replacing function '%s'\n", funcp->name);
8113 free(funcp->name);
8114 /* Note: if !funcp->body, do not free body_as_string!
8115 * This is a special case of "-F name body" function:
8116 * body_as_string was not malloced! */
8117 if (funcp->body) {
8118 free_pipe_list(funcp->body);
8119# if !BB_MMU
8120 free(funcp->body_as_string);
8121# endif
8122 }
8123 } else {
8124 debug_printf_exec("reinserting in tree & replacing function '%s'\n", funcp->name);
8125 cmd->argv[0] = funcp->name;
8126 cmd->group = funcp->body;
8127# if !BB_MMU
8128 cmd->group_as_string = funcp->body_as_string;
8129# endif
8130 }
8131 } else {
8132 debug_printf_exec("remembering new function '%s'\n", name);
8133 funcp = *funcpp = xzalloc(sizeof(*funcp));
8134 /*funcp->next = NULL;*/
8135 }
8136
8137 funcp->name = name;
8138 return funcp;
8139}
8140
Denys Vlasenko10d5ece2017-01-08 18:28:43 +01008141# if ENABLE_HUSH_UNSET
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008142static void unset_func(const char *name)
8143{
8144 struct function **funcpp = find_function_slot(name);
8145 struct function *funcp = *funcpp;
8146
8147 if (funcp != NULL) {
8148 debug_printf_exec("freeing function '%s'\n", funcp->name);
8149 *funcpp = funcp->next;
8150 /* funcp is unlinked now, deleting it.
8151 * Note: if !funcp->body, the function was created by
8152 * "-F name body", do not free ->body_as_string
8153 * and ->name as they were not malloced. */
8154 if (funcp->body) {
8155 free_pipe_list(funcp->body);
8156 free(funcp->name);
Denys Vlasenko10d5ece2017-01-08 18:28:43 +01008157# if !BB_MMU
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008158 free(funcp->body_as_string);
Denys Vlasenko10d5ece2017-01-08 18:28:43 +01008159# endif
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008160 }
8161 free(funcp);
8162 }
8163}
Denys Vlasenko10d5ece2017-01-08 18:28:43 +01008164# endif
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008165
8166# if BB_MMU
8167#define exec_function(to_free, funcp, argv) \
8168 exec_function(funcp, argv)
8169# endif
8170static void exec_function(char ***to_free,
8171 const struct function *funcp,
8172 char **argv) NORETURN;
8173static void exec_function(char ***to_free,
8174 const struct function *funcp,
8175 char **argv)
8176{
8177# if BB_MMU
Denys Vlasenkod4e4fdb2017-07-03 21:31:16 +02008178 int n;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008179
8180 argv[0] = G.global_argv[0];
8181 G.global_argv = argv;
Denys Vlasenkod4e4fdb2017-07-03 21:31:16 +02008182 G.global_argc = n = 1 + string_array_len(argv + 1);
Denys Vlasenko5b3d2eb2017-07-31 18:02:28 +02008183
8184// Example when we are here: "cmd | func"
8185// func will run with saved-redirect fds open.
8186// $ f() { echo /proc/self/fd/*; }
8187// $ true | f
8188// /proc/self/fd/0 /proc/self/fd/1 /proc/self/fd/2 /proc/self/fd/255 /proc/self/fd/3
8189// stdio^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ G_interactive_fd^ DIR fd for glob
8190// Same in script:
8191// $ . ./SCRIPT
8192// /proc/self/fd/0 /proc/self/fd/1 /proc/self/fd/2 /proc/self/fd/255 /proc/self/fd/3 /proc/self/fd/4
8193// stdio^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ G_interactive_fd^ opened ./SCRIPT DIR fd for glob
8194// They are CLOEXEC so external programs won't see them, but
8195// for "more correctness" we might want to close those extra fds here:
8196//? close_saved_fds_and_FILE_fds();
8197
Denys Vlasenko332e4112018-04-04 22:32:59 +02008198 /* "we are in a function, ok to use return" */
Denys Vlasenko5b3d2eb2017-07-31 18:02:28 +02008199 G_flag_return_in_progress = -1;
Denys Vlasenko9db344a2018-04-09 19:05:11 +02008200 enter_var_nest_level();
Denys Vlasenko5b3d2eb2017-07-31 18:02:28 +02008201 IF_HUSH_LOCAL(G.func_nest_level++;)
8202
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008203 /* On MMU, funcp->body is always non-NULL */
8204 n = run_list(funcp->body);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008205 _exit(n);
8206# else
Denys Vlasenko5b3d2eb2017-07-31 18:02:28 +02008207//? close_saved_fds_and_FILE_fds();
8208
8209//TODO: check whether "true | func_with_return" works
8210
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008211 re_execute_shell(to_free,
8212 funcp->body_as_string,
8213 G.global_argv[0],
8214 argv + 1,
8215 NULL);
8216# endif
8217}
8218
8219static int run_function(const struct function *funcp, char **argv)
8220{
8221 int rc;
8222 save_arg_t sv;
8223 smallint sv_flg;
8224
8225 save_and_replace_G_args(&sv, argv);
8226
Denys Vlasenkod358b0b2018-04-05 00:51:55 +02008227 /* "We are in function, ok to use return" */
Denys Vlasenko04b46bc2016-10-01 22:28:03 +02008228 sv_flg = G_flag_return_in_progress;
8229 G_flag_return_in_progress = -1;
Denys Vlasenko332e4112018-04-04 22:32:59 +02008230
Denys Vlasenkod358b0b2018-04-05 00:51:55 +02008231 /* Make "local" variables properly shadow previous ones */
8232 IF_HUSH_LOCAL(enter_var_nest_level();)
Denys Vlasenko5b3d2eb2017-07-31 18:02:28 +02008233 IF_HUSH_LOCAL(G.func_nest_level++;)
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008234
8235 /* On MMU, funcp->body is always non-NULL */
8236# if !BB_MMU
8237 if (!funcp->body) {
8238 /* Function defined by -F */
8239 parse_and_run_string(funcp->body_as_string);
8240 rc = G.last_exitcode;
8241 } else
8242# endif
8243 {
8244 rc = run_list(funcp->body);
8245 }
8246
Denys Vlasenko332e4112018-04-04 22:32:59 +02008247 IF_HUSH_LOCAL(G.func_nest_level--;)
Denys Vlasenkod358b0b2018-04-05 00:51:55 +02008248 IF_HUSH_LOCAL(leave_var_nest_level();)
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008249
Denys Vlasenko04b46bc2016-10-01 22:28:03 +02008250 G_flag_return_in_progress = sv_flg;
Denys Vlasenkobb095f42020-02-20 16:37:59 +01008251# if ENABLE_HUSH_TRAP
8252 debug_printf_exec("G.return_exitcode=-1\n");
8253 G.return_exitcode = -1; /* invalidate stashed return value */
8254# endif
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008255
8256 restore_G_args(&sv, argv);
8257
8258 return rc;
8259}
8260#endif /* ENABLE_HUSH_FUNCTIONS */
8261
8262
8263#if BB_MMU
8264#define exec_builtin(to_free, x, argv) \
8265 exec_builtin(x, argv)
8266#else
8267#define exec_builtin(to_free, x, argv) \
8268 exec_builtin(to_free, argv)
8269#endif
8270static void exec_builtin(char ***to_free,
8271 const struct built_in_command *x,
8272 char **argv) NORETURN;
8273static void exec_builtin(char ***to_free,
8274 const struct built_in_command *x,
8275 char **argv)
8276{
8277#if BB_MMU
Denys Vlasenko8ee2ada2011-02-07 02:03:51 +01008278 int rcode;
Denys Vlasenko5b3d2eb2017-07-31 18:02:28 +02008279//? close_saved_fds_and_FILE_fds();
Denys Vlasenko8ee2ada2011-02-07 02:03:51 +01008280 rcode = x->b_function(argv);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008281 fflush_all();
8282 _exit(rcode);
8283#else
Denys Vlasenko8ee2ada2011-02-07 02:03:51 +01008284 fflush_all();
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008285 /* On NOMMU, we must never block!
8286 * Example: { sleep 99 | read line; } & echo Ok
8287 */
8288 re_execute_shell(to_free,
8289 argv[0],
8290 G.global_argv[0],
8291 G.global_argv + 1,
8292 argv);
8293#endif
8294}
8295
8296
8297static void execvp_or_die(char **argv) NORETURN;
8298static void execvp_or_die(char **argv)
8299{
Denys Vlasenko04465da2016-10-03 01:01:15 +02008300 int e;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008301 debug_printf_exec("execing '%s'\n", argv[0]);
Denys Vlasenko75e77de2011-05-12 13:12:47 +02008302 /* Don't propagate SIG_IGN to the child */
8303 if (SPECIAL_JOBSTOP_SIGS != 0)
8304 switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008305 execvp(argv[0], argv);
Denys Vlasenko04465da2016-10-03 01:01:15 +02008306 e = 2;
8307 if (errno == EACCES) e = 126;
8308 if (errno == ENOENT) e = 127;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008309 bb_perror_msg("can't execute '%s'", argv[0]);
Denys Vlasenko04465da2016-10-03 01:01:15 +02008310 _exit(e);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008311}
8312
8313#if ENABLE_HUSH_MODE_X
Denys Vlasenkoaa449c92018-07-28 12:13:58 +02008314static void x_mode_print_optionally_squoted(const char *str)
Denys Vlasenko4b70c922018-07-27 17:42:38 +02008315{
8316 unsigned len;
8317 const char *cp;
8318
8319 cp = str;
Denys Vlasenkoaa449c92018-07-28 12:13:58 +02008320
8321 /* the set of chars which-cause-string-to-be-squoted mimics bash */
8322 /* test a char with: bash -c 'set -x; echo "CH"' */
8323 if (str[strcspn(str, "\\\"'`$(){}[]<>;#&|~*?!^"
8324 " " "\001\002\003\004\005\006\007"
8325 "\010\011\012\013\014\015\016\017"
8326 "\020\021\022\023\024\025\026\027"
8327 "\030\031\032\033\034\035\036\037"
8328 )
8329 ] == '\0'
8330 ) {
8331 /* string has no special chars */
8332 x_mode_addstr(str);
8333 return;
Denys Vlasenko4b70c922018-07-27 17:42:38 +02008334 }
8335
8336 cp = str;
8337 for (;;) {
8338 /* print '....' up to EOL or first squote */
8339 len = (int)(strchrnul(cp, '\'') - cp);
8340 if (len != 0) {
Denys Vlasenkoaa449c92018-07-28 12:13:58 +02008341 x_mode_addchr('\'');
8342 x_mode_addblock(cp, len);
8343 x_mode_addchr('\'');
Denys Vlasenko4b70c922018-07-27 17:42:38 +02008344 cp += len;
8345 }
8346 if (*cp == '\0')
8347 break;
8348 /* string contains squote(s), print them as \' */
Denys Vlasenkoaa449c92018-07-28 12:13:58 +02008349 x_mode_addchr('\\');
8350 x_mode_addchr('\'');
Denys Vlasenko4b70c922018-07-27 17:42:38 +02008351 cp++;
8352 }
8353}
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008354static void dump_cmd_in_x_mode(char **argv)
8355{
8356 if (G_x_mode && argv) {
Denys Vlasenko9dda9272018-07-27 14:12:05 +02008357 unsigned n;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008358
Denys Vlasenko4b70c922018-07-27 17:42:38 +02008359 /* "+[+++...][ cmd...]\n\0" */
Denys Vlasenkoaa449c92018-07-28 12:13:58 +02008360 x_mode_prefix();
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008361 n = 0;
Denys Vlasenko4b70c922018-07-27 17:42:38 +02008362 while (argv[n]) {
Denys Vlasenkoaa449c92018-07-28 12:13:58 +02008363 x_mode_addchr(' ');
8364 if (argv[n][0] == '\0') {
8365 x_mode_addchr('\'');
8366 x_mode_addchr('\'');
8367 } else {
8368 x_mode_print_optionally_squoted(argv[n]);
Denys Vlasenko4b70c922018-07-27 17:42:38 +02008369 }
8370 n++;
8371 }
Denys Vlasenkoaa449c92018-07-28 12:13:58 +02008372 x_mode_flush();
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008373 }
8374}
8375#else
8376# define dump_cmd_in_x_mode(argv) ((void)0)
8377#endif
8378
Denys Vlasenko57000292018-01-12 14:41:45 +01008379#if ENABLE_HUSH_COMMAND
8380static void if_command_vV_print_and_exit(char opt_vV, char *cmd, const char *explanation)
8381{
8382 char *to_free;
Denys Vlasenkoafb73a22018-01-12 16:17:59 +01008383
Denys Vlasenko57000292018-01-12 14:41:45 +01008384 if (!opt_vV)
8385 return;
8386
8387 to_free = NULL;
8388 if (!explanation) {
8389 char *path = getenv("PATH");
8390 explanation = to_free = find_executable(cmd, &path); /* path == NULL is ok */
Denys Vlasenkoafb73a22018-01-12 16:17:59 +01008391 if (!explanation)
8392 _exit(1); /* PROG was not found */
Denys Vlasenko57000292018-01-12 14:41:45 +01008393 if (opt_vV != 'V')
8394 cmd = to_free; /* -v PROG prints "/path/to/PROG" */
8395 }
Denys Vlasenkoafb73a22018-01-12 16:17:59 +01008396 printf((opt_vV == 'V') ? "%s is %s\n" : "%s\n", cmd, explanation);
Denys Vlasenko57000292018-01-12 14:41:45 +01008397 free(to_free);
8398 fflush_all();
Denys Vlasenkoafb73a22018-01-12 16:17:59 +01008399 _exit(0);
Denys Vlasenko57000292018-01-12 14:41:45 +01008400}
8401#else
8402# define if_command_vV_print_and_exit(a,b,c) ((void)0)
8403#endif
8404
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008405#if BB_MMU
8406#define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \
8407 pseudo_exec_argv(argv, assignment_cnt, argv_expanded)
8408#define pseudo_exec(nommu_save, command, argv_expanded) \
8409 pseudo_exec(command, argv_expanded)
8410#endif
8411
8412/* Called after [v]fork() in run_pipe, or from builtin_exec.
8413 * Never returns.
8414 * Don't exit() here. If you don't exec, use _exit instead.
8415 * The at_exit handlers apparently confuse the calling process,
Denys Vlasenko215b0ca2016-08-19 18:23:56 +02008416 * in particular stdin handling. Not sure why? -- because of vfork! (vda)
Denys Vlasenko215b0ca2016-08-19 18:23:56 +02008417 */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008418static void pseudo_exec_argv(nommu_save_t *nommu_save,
8419 char **argv, int assignment_cnt,
8420 char **argv_expanded) NORETURN;
8421static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
8422 char **argv, int assignment_cnt,
8423 char **argv_expanded)
8424{
Denys Vlasenko57000292018-01-12 14:41:45 +01008425 const struct built_in_command *x;
Denys Vlasenko929a41d2018-04-05 14:09:14 +02008426 struct variable **sv_shadowed;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008427 char **new_env;
Denys Vlasenko34f6b122018-04-05 11:30:17 +02008428 IF_HUSH_COMMAND(char opt_vV = 0;)
8429 IF_HUSH_FUNCTIONS(const struct function *funcp;)
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008430
8431 new_env = expand_assignments(argv, assignment_cnt);
8432 dump_cmd_in_x_mode(new_env);
8433
8434 if (!argv[assignment_cnt]) {
8435 /* Case when we are here: ... | var=val | ...
8436 * (note that we do not exit early, i.e., do not optimize out
8437 * expand_assignments(): think about ... | var=`sleep 1` | ...
8438 */
8439 free_strings(new_env);
8440 _exit(EXIT_SUCCESS);
8441 }
8442
Denys Vlasenko929a41d2018-04-05 14:09:14 +02008443 sv_shadowed = G.shadowed_vars_pp;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008444#if BB_MMU
Denys Vlasenko929a41d2018-04-05 14:09:14 +02008445 G.shadowed_vars_pp = NULL; /* "don't save, free them instead" */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008446#else
Denys Vlasenko929a41d2018-04-05 14:09:14 +02008447 G.shadowed_vars_pp = &nommu_save->old_vars;
Denys Vlasenko9db344a2018-04-09 19:05:11 +02008448 G.var_nest_level++;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008449#endif
Denys Vlasenko929a41d2018-04-05 14:09:14 +02008450 set_vars_and_save_old(new_env);
8451 G.shadowed_vars_pp = sv_shadowed;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008452
8453 if (argv_expanded) {
8454 argv = argv_expanded;
8455 } else {
8456 argv = expand_strvec_to_strvec(argv + assignment_cnt);
8457#if !BB_MMU
8458 nommu_save->argv = argv;
8459#endif
8460 }
8461 dump_cmd_in_x_mode(argv);
8462
8463#if ENABLE_FEATURE_SH_STANDALONE || BB_MMU
8464 if (strchr(argv[0], '/') != NULL)
8465 goto skip;
8466#endif
8467
Denys Vlasenko75481d32017-07-31 05:27:09 +02008468#if ENABLE_HUSH_FUNCTIONS
8469 /* Check if the command matches any functions (this goes before bltins) */
Denys Vlasenko34f6b122018-04-05 11:30:17 +02008470 funcp = find_function(argv[0]);
8471 if (funcp)
8472 exec_function(&nommu_save->argv_from_re_execing, funcp, argv);
Denys Vlasenko75481d32017-07-31 05:27:09 +02008473#endif
8474
Denys Vlasenko57000292018-01-12 14:41:45 +01008475#if ENABLE_HUSH_COMMAND
8476 /* "command BAR": run BAR without looking it up among functions
8477 * "command -v BAR": print "BAR" or "/path/to/BAR"; or exit 1
8478 * "command -V BAR": print "BAR is {a function,a shell builtin,/path/to/BAR}"
8479 */
8480 while (strcmp(argv[0], "command") == 0 && argv[1]) {
8481 char *p;
8482
8483 argv++;
8484 p = *argv;
8485 if (p[0] != '-' || !p[1])
8486 continue; /* bash allows "command command command [-OPT] BAR" */
8487
8488 for (;;) {
8489 p++;
8490 switch (*p) {
8491 case '\0':
8492 argv++;
8493 p = *argv;
8494 if (p[0] != '-' || !p[1])
8495 goto after_opts;
8496 continue; /* next arg is also -opts, process it too */
8497 case 'v':
8498 case 'V':
8499 opt_vV = *p;
8500 continue;
8501 default:
8502 bb_error_msg_and_die("%s: %s: invalid option", "command", argv[0]);
8503 }
8504 }
8505 }
8506 after_opts:
8507# if ENABLE_HUSH_FUNCTIONS
8508 if (opt_vV && find_function(argv[0]))
8509 if_command_vV_print_and_exit(opt_vV, argv[0], "a function");
8510# endif
8511#endif
8512
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008513 /* Check if the command matches any of the builtins.
8514 * Depending on context, this might be redundant. But it's
8515 * easier to waste a few CPU cycles than it is to figure out
8516 * if this is one of those cases.
8517 */
Denys Vlasenko57000292018-01-12 14:41:45 +01008518 /* Why "BB_MMU ? :" difference in logic? -
8519 * On NOMMU, it is more expensive to re-execute shell
8520 * just in order to run echo or test builtin.
8521 * It's better to skip it here and run corresponding
8522 * non-builtin later. */
8523 x = BB_MMU ? find_builtin(argv[0]) : find_builtin1(argv[0]);
8524 if (x) {
8525 if_command_vV_print_and_exit(opt_vV, argv[0], "a shell builtin");
8526 exec_builtin(&nommu_save->argv_from_re_execing, x, argv);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008527 }
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008528
8529#if ENABLE_FEATURE_SH_STANDALONE
8530 /* Check if the command matches any busybox applets */
8531 {
8532 int a = find_applet_by_name(argv[0]);
8533 if (a >= 0) {
Denys Vlasenko57000292018-01-12 14:41:45 +01008534 if_command_vV_print_and_exit(opt_vV, argv[0], "an applet");
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008535# if BB_MMU /* see above why on NOMMU it is not allowed */
8536 if (APPLET_IS_NOEXEC(a)) {
Denys Vlasenkobf1c3442017-07-31 04:54:53 +02008537 /* Do not leak open fds from opened script files etc.
8538 * Testcase: interactive "ls -l /proc/self/fd"
8539 * should not show tty fd open.
8540 */
Denys Vlasenko5b3d2eb2017-07-31 18:02:28 +02008541 close_saved_fds_and_FILE_fds();
Denys Vlasenko75481d32017-07-31 05:27:09 +02008542//FIXME: should also close saved redir fds
Denys Vlasenko9acd63c2018-03-28 18:35:07 +02008543//This casuses test failures in
8544//redir_children_should_not_see_saved_fd_2.tests
8545//redir_children_should_not_see_saved_fd_3.tests
8546//if you replace "busybox find" with just "find" in them
Denys Vlasenko7c40ddd2017-08-02 16:37:39 +02008547 /* Without this, "rm -i FILE" can't be ^C'ed: */
8548 switch_off_special_sigs(G.special_sig_mask);
Denys Vlasenkoc9c1ccc2017-08-07 18:59:35 +02008549 debug_printf_exec("running applet '%s'\n", argv[0]);
Denys Vlasenko80e8e3c2017-08-07 19:24:57 +02008550 run_noexec_applet_and_exit(a, argv[0], argv);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008551 }
8552# endif
8553 /* Re-exec ourselves */
8554 debug_printf_exec("re-execing applet '%s'\n", argv[0]);
Denys Vlasenko75e77de2011-05-12 13:12:47 +02008555 /* Don't propagate SIG_IGN to the child */
8556 if (SPECIAL_JOBSTOP_SIGS != 0)
8557 switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008558 execv(bb_busybox_exec_path, argv);
8559 /* If they called chroot or otherwise made the binary no longer
8560 * executable, fall through */
8561 }
8562 }
8563#endif
8564
8565#if ENABLE_FEATURE_SH_STANDALONE || BB_MMU
8566 skip:
8567#endif
Denys Vlasenko57000292018-01-12 14:41:45 +01008568 if_command_vV_print_and_exit(opt_vV, argv[0], NULL);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008569 execvp_or_die(argv);
8570}
8571
8572/* Called after [v]fork() in run_pipe
8573 */
8574static void pseudo_exec(nommu_save_t *nommu_save,
8575 struct command *command,
8576 char **argv_expanded) NORETURN;
8577static void pseudo_exec(nommu_save_t *nommu_save,
8578 struct command *command,
8579 char **argv_expanded)
8580{
Denys Vlasenko49015a62018-04-03 13:02:43 +02008581#if ENABLE_HUSH_FUNCTIONS
8582 if (command->cmd_type == CMD_FUNCDEF) {
8583 /* Ignore funcdefs in pipes:
8584 * true | f() { cmd }
8585 */
8586 _exit(0);
8587 }
8588#endif
8589
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008590 if (command->argv) {
8591 pseudo_exec_argv(nommu_save, command->argv,
8592 command->assignment_cnt, argv_expanded);
8593 }
8594
8595 if (command->group) {
8596 /* Cases when we are here:
8597 * ( list )
8598 * { list } &
8599 * ... | ( list ) | ...
8600 * ... | { list } | ...
8601 */
8602#if BB_MMU
8603 int rcode;
8604 debug_printf_exec("pseudo_exec: run_list\n");
8605 reset_traps_to_defaults();
8606 rcode = run_list(command->group);
8607 /* OK to leak memory by not calling free_pipe_list,
8608 * since this process is about to exit */
8609 _exit(rcode);
8610#else
8611 re_execute_shell(&nommu_save->argv_from_re_execing,
8612 command->group_as_string,
8613 G.global_argv[0],
8614 G.global_argv + 1,
8615 NULL);
8616#endif
8617 }
8618
8619 /* Case when we are here: ... | >file */
8620 debug_printf_exec("pseudo_exec'ed null command\n");
8621 _exit(EXIT_SUCCESS);
8622}
8623
8624#if ENABLE_HUSH_JOB
8625static const char *get_cmdtext(struct pipe *pi)
8626{
8627 char **argv;
8628 char *p;
8629 int len;
8630
8631 /* This is subtle. ->cmdtext is created only on first backgrounding.
8632 * (Think "cat, <ctrl-z>, fg, <ctrl-z>, fg, <ctrl-z>...." here...)
8633 * On subsequent bg argv is trashed, but we won't use it */
8634 if (pi->cmdtext)
8635 return pi->cmdtext;
Denys Vlasenko1eada9a2016-11-08 17:28:45 +01008636
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008637 argv = pi->cmds[0].argv;
Denys Vlasenko1eada9a2016-11-08 17:28:45 +01008638 if (!argv) {
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008639 pi->cmdtext = xzalloc(1);
8640 return pi->cmdtext;
8641 }
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008642 len = 0;
8643 do {
8644 len += strlen(*argv) + 1;
8645 } while (*++argv);
8646 p = xmalloc(len);
8647 pi->cmdtext = p;
8648 argv = pi->cmds[0].argv;
8649 do {
Denys Vlasenko1eada9a2016-11-08 17:28:45 +01008650 p = stpcpy(p, *argv);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008651 *p++ = ' ';
8652 } while (*++argv);
8653 p[-1] = '\0';
8654 return pi->cmdtext;
8655}
8656
Denys Vlasenko2ed74e22017-07-14 19:58:46 +02008657static void remove_job_from_table(struct pipe *pi)
8658{
8659 struct pipe *prev_pipe;
8660
8661 if (pi == G.job_list) {
8662 G.job_list = pi->next;
8663 } else {
8664 prev_pipe = G.job_list;
8665 while (prev_pipe->next != pi)
8666 prev_pipe = prev_pipe->next;
8667 prev_pipe->next = pi->next;
8668 }
8669 G.last_jobid = 0;
8670 if (G.job_list)
8671 G.last_jobid = G.job_list->jobid;
8672}
8673
8674static void delete_finished_job(struct pipe *pi)
8675{
8676 remove_job_from_table(pi);
8677 free_pipe(pi);
8678}
8679
8680static void clean_up_last_dead_job(void)
8681{
8682 if (G.job_list && !G.job_list->alive_cmds)
8683 delete_finished_job(G.job_list);
8684}
8685
Denys Vlasenko16096292017-07-10 10:00:28 +02008686static void insert_job_into_table(struct pipe *pi)
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008687{
8688 struct pipe *job, **jobp;
8689 int i;
8690
Denys Vlasenko2ed74e22017-07-14 19:58:46 +02008691 clean_up_last_dead_job();
8692
Denys Vlasenko9e55a152017-07-10 10:01:12 +02008693 /* Find the end of the list, and find next job ID to use */
8694 i = 0;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008695 jobp = &G.job_list;
Denys Vlasenko9e55a152017-07-10 10:01:12 +02008696 while ((job = *jobp) != NULL) {
8697 if (job->jobid > i)
8698 i = job->jobid;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008699 jobp = &job->next;
Denys Vlasenko9e55a152017-07-10 10:01:12 +02008700 }
8701 pi->jobid = i + 1;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008702
Denys Vlasenko9e55a152017-07-10 10:01:12 +02008703 /* Create a new job struct at the end */
8704 job = *jobp = xmemdup(pi, sizeof(*pi));
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008705 job->next = NULL;
8706 job->cmds = xzalloc(sizeof(pi->cmds[0]) * pi->num_cmds);
8707 /* Cannot copy entire pi->cmds[] vector! This causes double frees */
8708 for (i = 0; i < pi->num_cmds; i++) {
8709 job->cmds[i].pid = pi->cmds[i].pid;
8710 /* all other fields are not used and stay zero */
8711 }
8712 job->cmdtext = xstrdup(get_cmdtext(pi));
8713
8714 if (G_interactive_fd)
Denys Vlasenkod5b5c2f2017-01-08 15:46:04 +01008715 printf("[%u] %u %s\n", job->jobid, (unsigned)job->cmds[0].pid, job->cmdtext);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008716 G.last_jobid = job->jobid;
8717}
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008718#endif /* JOB */
8719
Denys Vlasenko62b717b2016-11-07 22:12:18 +01008720static int job_exited_or_stopped(struct pipe *pi)
8721{
8722 int rcode, i;
8723
8724 if (pi->alive_cmds != pi->stopped_cmds)
8725 return -1;
8726
8727 /* All processes in fg pipe have exited or stopped */
8728 rcode = 0;
8729 i = pi->num_cmds;
8730 while (--i >= 0) {
8731 rcode = pi->cmds[i].cmd_exitcode;
8732 /* usually last process gives overall exitstatus,
8733 * but with "set -o pipefail", last *failed* process does */
8734 if (G.o_opt[OPT_O_PIPEFAIL] == 0 || rcode != 0)
8735 break;
8736 }
8737 IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;)
8738 return rcode;
8739}
8740
Denys Vlasenko7e675362016-10-28 21:57:31 +02008741static int process_wait_result(struct pipe *fg_pipe, pid_t childpid, int status)
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008742{
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008743#if ENABLE_HUSH_JOB
8744 struct pipe *pi;
8745#endif
Denys Vlasenko7e675362016-10-28 21:57:31 +02008746 int i, dead;
8747
8748 dead = WIFEXITED(status) || WIFSIGNALED(status);
8749
8750#if DEBUG_JOBS
8751 if (WIFSTOPPED(status))
8752 debug_printf_jobs("pid %d stopped by sig %d (exitcode %d)\n",
8753 childpid, WSTOPSIG(status), WEXITSTATUS(status));
8754 if (WIFSIGNALED(status))
8755 debug_printf_jobs("pid %d killed by sig %d (exitcode %d)\n",
8756 childpid, WTERMSIG(status), WEXITSTATUS(status));
8757 if (WIFEXITED(status))
8758 debug_printf_jobs("pid %d exited, exitcode %d\n",
8759 childpid, WEXITSTATUS(status));
8760#endif
8761 /* Were we asked to wait for a fg pipe? */
8762 if (fg_pipe) {
8763 i = fg_pipe->num_cmds;
Denys Vlasenko62b717b2016-11-07 22:12:18 +01008764
Denys Vlasenko7e675362016-10-28 21:57:31 +02008765 while (--i >= 0) {
Denys Vlasenko62b717b2016-11-07 22:12:18 +01008766 int rcode;
8767
Denys Vlasenko7e675362016-10-28 21:57:31 +02008768 debug_printf_jobs("check pid %d\n", fg_pipe->cmds[i].pid);
8769 if (fg_pipe->cmds[i].pid != childpid)
8770 continue;
8771 if (dead) {
8772 int ex;
8773 fg_pipe->cmds[i].pid = 0;
8774 fg_pipe->alive_cmds--;
8775 ex = WEXITSTATUS(status);
8776 /* bash prints killer signal's name for *last*
8777 * process in pipe (prints just newline for SIGINT/SIGPIPE).
8778 * Mimic this. Example: "sleep 5" + (^\ or kill -QUIT)
8779 */
8780 if (WIFSIGNALED(status)) {
8781 int sig = WTERMSIG(status);
Denys Vlasenko77a51a22020-12-29 16:53:11 +01008782#if ENABLE_HUSH_JOB
Denys Vlasenkob65d6cb2020-10-24 03:33:32 +02008783 if (G.run_list_level == 1
8784 /* ^^^^^ Do not print in nested contexts, example:
8785 * echo `sleep 1; sh -c 'kill -9 $$'` - prints "137", NOT "Killed 137"
8786 */
8787 && i == fg_pipe->num_cmds-1
8788 ) {
Denys Vlasenkoe16f7eb2020-10-24 04:26:43 +02008789 /* strsignal() is for bash compat. ~600 bloat versus bbox's get_signame() */
8790 puts(sig == SIGINT || sig == SIGPIPE ? "" : strsignal(sig));
Denys Vlasenkob65d6cb2020-10-24 03:33:32 +02008791 }
Denys Vlasenko77a51a22020-12-29 16:53:11 +01008792#endif
Denys Vlasenko7e675362016-10-28 21:57:31 +02008793 /* TODO: if (WCOREDUMP(status)) + " (core dumped)"; */
Denys Vlasenko93e2a222020-12-23 12:23:21 +01008794 /* MIPS has 128 sigs (1..128), if sig==128,
8795 * 128 + sig would result in exitcode 256 -> 0!
8796 */
8797 ex = 128 | sig;
Denys Vlasenko7e675362016-10-28 21:57:31 +02008798 }
8799 fg_pipe->cmds[i].cmd_exitcode = ex;
8800 } else {
8801 fg_pipe->stopped_cmds++;
8802 }
8803 debug_printf_jobs("fg_pipe: alive_cmds %d stopped_cmds %d\n",
8804 fg_pipe->alive_cmds, fg_pipe->stopped_cmds);
Denys Vlasenko62b717b2016-11-07 22:12:18 +01008805 rcode = job_exited_or_stopped(fg_pipe);
8806 if (rcode >= 0) {
Denys Vlasenko7e675362016-10-28 21:57:31 +02008807/* Note: *non-interactive* bash does not continue if all processes in fg pipe
8808 * are stopped. Testcase: "cat | cat" in a script (not on command line!)
8809 * and "killall -STOP cat" */
8810 if (G_interactive_fd) {
8811#if ENABLE_HUSH_JOB
8812 if (fg_pipe->alive_cmds != 0)
Denys Vlasenko16096292017-07-10 10:00:28 +02008813 insert_job_into_table(fg_pipe);
Denys Vlasenko7e675362016-10-28 21:57:31 +02008814#endif
8815 return rcode;
8816 }
8817 if (fg_pipe->alive_cmds == 0)
8818 return rcode;
8819 }
8820 /* There are still running processes in the fg_pipe */
8821 return -1;
8822 }
Denys Vlasenko10ad6222017-04-17 16:13:32 +02008823 /* It wasn't in fg_pipe, look for process in bg pipes */
Denys Vlasenko7e675362016-10-28 21:57:31 +02008824 }
8825
8826#if ENABLE_HUSH_JOB
8827 /* We were asked to wait for bg or orphaned children */
8828 /* No need to remember exitcode in this case */
8829 for (pi = G.job_list; pi; pi = pi->next) {
8830 for (i = 0; i < pi->num_cmds; i++) {
8831 if (pi->cmds[i].pid == childpid)
8832 goto found_pi_and_prognum;
8833 }
8834 }
8835 /* Happens when shell is used as init process (init=/bin/sh) */
8836 debug_printf("checkjobs: pid %d was not in our list!\n", childpid);
8837 return -1; /* this wasn't a process from fg_pipe */
8838
8839 found_pi_and_prognum:
8840 if (dead) {
8841 /* child exited */
Denys Vlasenko840a4352017-07-07 22:56:02 +02008842 int rcode = WEXITSTATUS(status);
Denys Vlasenko7e675362016-10-28 21:57:31 +02008843 if (WIFSIGNALED(status))
Denys Vlasenko93e2a222020-12-23 12:23:21 +01008844 /* NB: not 128 + sig, MIPS has sig 128 */
8845 rcode = 128 | WTERMSIG(status);
Denys Vlasenko840a4352017-07-07 22:56:02 +02008846 pi->cmds[i].cmd_exitcode = rcode;
8847 if (G.last_bg_pid == pi->cmds[i].pid)
8848 G.last_bg_pid_exitcode = rcode;
8849 pi->cmds[i].pid = 0;
Denys Vlasenko7e675362016-10-28 21:57:31 +02008850 pi->alive_cmds--;
8851 if (!pi->alive_cmds) {
Denys Vlasenko259747c2019-11-28 10:28:14 +01008852# if ENABLE_HUSH_BASH_COMPAT
Denys Vlasenkoe6f51ac2019-03-27 18:34:10 +01008853 G.dead_job_exitcode = job_exited_or_stopped(pi);
Denys Vlasenko259747c2019-11-28 10:28:14 +01008854# endif
Denys Vlasenko2ed74e22017-07-14 19:58:46 +02008855 if (G_interactive_fd) {
Denys Vlasenko7e675362016-10-28 21:57:31 +02008856 printf(JOB_STATUS_FORMAT, pi->jobid,
8857 "Done", pi->cmdtext);
Denys Vlasenko2ed74e22017-07-14 19:58:46 +02008858 delete_finished_job(pi);
8859 } else {
8860/*
8861 * bash deletes finished jobs from job table only in interactive mode,
8862 * after "jobs" cmd, or if pid of a new process matches one of the old ones
8863 * (see cleanup_dead_jobs(), delete_old_job(), J_NOTIFIED in bash source).
8864 * Testcase script: "(exit 3) & sleep 1; wait %1; echo $?" prints 3 in bash.
8865 * We only retain one "dead" job, if it's the single job on the list.
8866 * This covers most of real-world scenarios where this is useful.
8867 */
8868 if (pi != G.job_list)
8869 delete_finished_job(pi);
8870 }
Denys Vlasenko7e675362016-10-28 21:57:31 +02008871 }
8872 } else {
8873 /* child stopped */
8874 pi->stopped_cmds++;
8875 }
8876#endif
8877 return -1; /* this wasn't a process from fg_pipe */
8878}
8879
8880/* Check to see if any processes have exited -- if they have,
8881 * figure out why and see if a job has completed.
Denys Vlasenko62b717b2016-11-07 22:12:18 +01008882 *
8883 * If non-NULL fg_pipe: wait for its completion or stop.
8884 * Return its exitcode or zero if stopped.
8885 *
8886 * Alternatively (fg_pipe == NULL, waitfor_pid != 0):
8887 * waitpid(WNOHANG), if waitfor_pid exits or stops, return exitcode+1,
8888 * else return <0 if waitpid errors out (e.g. ECHILD: nothing to wait for)
8889 * or 0 if no children changed status.
8890 *
8891 * Alternatively (fg_pipe == NULL, waitfor_pid == 0),
8892 * return <0 if waitpid errors out (e.g. ECHILD: nothing to wait for)
8893 * or 0 if no children changed status.
Denys Vlasenko7e675362016-10-28 21:57:31 +02008894 */
8895static int checkjobs(struct pipe *fg_pipe, pid_t waitfor_pid)
8896{
8897 int attributes;
8898 int status;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008899 int rcode = 0;
8900
8901 debug_printf_jobs("checkjobs %p\n", fg_pipe);
8902
8903 attributes = WUNTRACED;
8904 if (fg_pipe == NULL)
8905 attributes |= WNOHANG;
8906
8907 errno = 0;
8908#if ENABLE_HUSH_FAST
8909 if (G.handled_SIGCHLD == G.count_SIGCHLD) {
8910//bb_error_msg("[%d] checkjobs: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d children?:%d fg_pipe:%p",
8911//getpid(), G.count_SIGCHLD, G.handled_SIGCHLD, G.we_have_children, fg_pipe);
8912 /* There was neither fork nor SIGCHLD since last waitpid */
8913 /* Avoid doing waitpid syscall if possible */
8914 if (!G.we_have_children) {
8915 errno = ECHILD;
8916 return -1;
8917 }
8918 if (fg_pipe == NULL) { /* is WNOHANG set? */
8919 /* We have children, but they did not exit
8920 * or stop yet (we saw no SIGCHLD) */
8921 return 0;
8922 }
8923 /* else: !WNOHANG, waitpid will block, can't short-circuit */
8924 }
8925#endif
8926
8927/* Do we do this right?
8928 * bash-3.00# sleep 20 | false
8929 * <ctrl-Z pressed>
8930 * [3]+ Stopped sleep 20 | false
8931 * bash-3.00# echo $?
8932 * 1 <========== bg pipe is not fully done, but exitcode is already known!
8933 * [hush 1.14.0: yes we do it right]
8934 */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008935 while (1) {
Denys Vlasenko7e675362016-10-28 21:57:31 +02008936 pid_t childpid;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008937#if ENABLE_HUSH_FAST
Denys Vlasenko7e675362016-10-28 21:57:31 +02008938 int i;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008939 i = G.count_SIGCHLD;
8940#endif
8941 childpid = waitpid(-1, &status, attributes);
8942 if (childpid <= 0) {
8943 if (childpid && errno != ECHILD)
James Byrne69374872019-07-02 11:35:03 +02008944 bb_simple_perror_msg("waitpid");
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008945#if ENABLE_HUSH_FAST
8946 else { /* Until next SIGCHLD, waitpid's are useless */
8947 G.we_have_children = (childpid == 0);
8948 G.handled_SIGCHLD = i;
8949//bb_error_msg("[%d] checkjobs: waitpid returned <= 0, G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
8950 }
8951#endif
Denys Vlasenko7e675362016-10-28 21:57:31 +02008952 /* ECHILD (no children), or 0 (no change in children status) */
8953 rcode = childpid;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008954 break;
8955 }
Denys Vlasenko7e675362016-10-28 21:57:31 +02008956 rcode = process_wait_result(fg_pipe, childpid, status);
8957 if (rcode >= 0) {
8958 /* fg_pipe exited or stopped */
8959 break;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008960 }
Denys Vlasenkoe6f51ac2019-03-27 18:34:10 +01008961 if (childpid == waitfor_pid) { /* "wait PID" */
Denys Vlasenko62b717b2016-11-07 22:12:18 +01008962 debug_printf_exec("childpid==waitfor_pid:%d status:0x%08x\n", childpid, status);
Denys Vlasenko7e675362016-10-28 21:57:31 +02008963 rcode = WEXITSTATUS(status);
8964 if (WIFSIGNALED(status))
Denys Vlasenko93e2a222020-12-23 12:23:21 +01008965 rcode = 128 | WTERMSIG(status);
Denys Vlasenko62b717b2016-11-07 22:12:18 +01008966 if (WIFSTOPPED(status))
Denys Vlasenko93e2a222020-12-23 12:23:21 +01008967 /* bash: "cmd & wait $!" and cmd stops: $? = 128 | stopsig */
8968 rcode = 128 | WSTOPSIG(status);
Denys Vlasenko7e675362016-10-28 21:57:31 +02008969 rcode++;
8970 break; /* "wait PID" called us, give it exitcode+1 */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008971 }
Denys Vlasenkoe6f51ac2019-03-27 18:34:10 +01008972#if ENABLE_HUSH_BASH_COMPAT
8973 if (-1 == waitfor_pid /* "wait -n" (wait for any one job) */
8974 && G.dead_job_exitcode >= 0 /* some job did finish */
8975 ) {
8976 debug_printf_exec("waitfor_pid:-1\n");
8977 rcode = G.dead_job_exitcode + 1;
8978 break;
8979 }
8980#endif
Denys Vlasenko7e675362016-10-28 21:57:31 +02008981 /* This wasn't one of our processes, or */
8982 /* fg_pipe still has running processes, do waitpid again */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008983 } /* while (waitpid succeeds)... */
8984
8985 return rcode;
8986}
8987
8988#if ENABLE_HUSH_JOB
Denys Vlasenkoda463fb2010-09-07 09:53:50 +02008989static int checkjobs_and_fg_shell(struct pipe *fg_pipe)
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008990{
8991 pid_t p;
Denys Vlasenko7e675362016-10-28 21:57:31 +02008992 int rcode = checkjobs(fg_pipe, 0 /*(no pid to wait for)*/);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02008993 if (G_saved_tty_pgrp) {
8994 /* Job finished, move the shell to the foreground */
8995 p = getpgrp(); /* our process group id */
8996 debug_printf_jobs("fg'ing ourself: getpgrp()=%d\n", (int)p);
8997 tcsetpgrp(G_interactive_fd, p);
8998 }
8999 return rcode;
9000}
9001#endif
9002
9003/* Start all the jobs, but don't wait for anything to finish.
9004 * See checkjobs().
9005 *
9006 * Return code is normally -1, when the caller has to wait for children
9007 * to finish to determine the exit status of the pipe. If the pipe
9008 * is a simple builtin command, however, the action is done by the
9009 * time run_pipe returns, and the exit code is provided as the
9010 * return value.
9011 *
9012 * Returns -1 only if started some children. IOW: we have to
9013 * mask out retvals of builtins etc with 0xff!
9014 *
9015 * The only case when we do not need to [v]fork is when the pipe
9016 * is single, non-backgrounded, non-subshell command. Examples:
9017 * cmd ; ... { list } ; ...
9018 * cmd && ... { list } && ...
9019 * cmd || ... { list } || ...
Denys Vlasenkob72baeb2011-02-02 18:38:57 +01009020 * If it is, then we can run cmd as a builtin, NOFORK,
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009021 * or (if SH_STANDALONE) an applet, and we can run the { list }
9022 * with run_list. If it isn't one of these, we fork and exec cmd.
9023 *
9024 * Cases when we must fork:
9025 * non-single: cmd | cmd
9026 * backgrounded: cmd & { list } &
9027 * subshell: ( list ) [&]
9028 */
9029#if !ENABLE_HUSH_MODE_X
Denys Vlasenko945e9b02018-07-24 18:01:22 +02009030#define redirect_and_varexp_helper(command, sqp, argv_expanded) \
9031 redirect_and_varexp_helper(command, sqp)
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009032#endif
Denys Vlasenkod358b0b2018-04-05 00:51:55 +02009033static int redirect_and_varexp_helper(
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009034 struct command *command,
Denys Vlasenko2db74612017-07-07 22:07:28 +02009035 struct squirrel **sqp,
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009036 char **argv_expanded)
9037{
Denys Vlasenko41d8f102018-04-05 14:41:21 +02009038 /* Assignments occur before redirects. Try:
9039 * a=`sleep 1` sleep 2 3>/qwe/rty
9040 */
9041
9042 char **new_env = expand_assignments(command->argv, command->assignment_cnt);
9043 dump_cmd_in_x_mode(new_env);
9044 dump_cmd_in_x_mode(argv_expanded);
9045 /* this takes ownership of new_env[i] elements, and frees new_env: */
9046 set_vars_and_save_old(new_env);
9047
Denys Vlasenko41d8f102018-04-05 14:41:21 +02009048 return setup_redirects(command, sqp);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009049}
9050static NOINLINE int run_pipe(struct pipe *pi)
9051{
9052 static const char *const null_ptr = NULL;
9053
9054 int cmd_no;
9055 int next_infd;
9056 struct command *command;
9057 char **argv_expanded;
9058 char **argv;
Denys Vlasenko2db74612017-07-07 22:07:28 +02009059 struct squirrel *squirrel = NULL;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009060 int rcode;
9061
9062 debug_printf_exec("run_pipe start: members:%d\n", pi->num_cmds);
9063 debug_enter();
9064
Denys Vlasenko1fd3d942010-09-08 13:31:53 +02009065 /* Testcase: set -- q w e; (IFS='' echo "$*"; IFS=''; echo "$*"); echo "$*"
9066 * Result should be 3 lines: q w e, qwe, q w e
9067 */
Denys Vlasenko96786362018-04-11 16:02:58 +02009068 if (G.ifs_whitespace != G.ifs)
9069 free(G.ifs_whitespace);
Denys Vlasenko1fd3d942010-09-08 13:31:53 +02009070 G.ifs = get_local_var_value("IFS");
Denys Vlasenko96786362018-04-11 16:02:58 +02009071 if (G.ifs) {
9072 char *p;
9073 G.ifs_whitespace = (char*)G.ifs;
9074 p = skip_whitespace(G.ifs);
9075 if (*p) {
9076 /* Not all $IFS is whitespace */
9077 char *d;
9078 int len = p - G.ifs;
9079 p = skip_non_whitespace(p);
9080 G.ifs_whitespace = xmalloc(len + strlen(p) + 1); /* can overestimate */
9081 d = mempcpy(G.ifs_whitespace, G.ifs, len);
9082 while (*p) {
9083 if (isspace(*p))
9084 *d++ = *p;
9085 p++;
9086 }
9087 *d = '\0';
9088 }
9089 } else {
Denys Vlasenko1fd3d942010-09-08 13:31:53 +02009090 G.ifs = defifs;
Denys Vlasenko96786362018-04-11 16:02:58 +02009091 G.ifs_whitespace = (char*)G.ifs;
9092 }
Denys Vlasenko1fd3d942010-09-08 13:31:53 +02009093
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009094 IF_HUSH_JOB(pi->pgrp = -1;)
9095 pi->stopped_cmds = 0;
9096 command = &pi->cmds[0];
9097 argv_expanded = NULL;
9098
9099 if (pi->num_cmds != 1
9100 || pi->followup == PIPE_BG
9101 || command->cmd_type == CMD_SUBSHELL
9102 ) {
9103 goto must_fork;
9104 }
9105
9106 pi->alive_cmds = 1;
9107
9108 debug_printf_exec(": group:%p argv:'%s'\n",
9109 command->group, command->argv ? command->argv[0] : "NONE");
9110
9111 if (command->group) {
9112#if ENABLE_HUSH_FUNCTIONS
9113 if (command->cmd_type == CMD_FUNCDEF) {
9114 /* "executing" func () { list } */
9115 struct function *funcp;
9116
9117 funcp = new_function(command->argv[0]);
9118 /* funcp->name is already set to argv[0] */
9119 funcp->body = command->group;
9120# if !BB_MMU
9121 funcp->body_as_string = command->group_as_string;
9122 command->group_as_string = NULL;
9123# endif
9124 command->group = NULL;
9125 command->argv[0] = NULL;
9126 debug_printf_exec("cmd %p has child func at %p\n", command, funcp);
9127 funcp->parent_cmd = command;
9128 command->child_func = funcp;
9129
9130 debug_printf_exec("run_pipe: return EXIT_SUCCESS\n");
9131 debug_leave();
9132 return EXIT_SUCCESS;
9133 }
9134#endif
9135 /* { list } */
Denys Vlasenko41ef41b2018-07-24 16:54:41 +02009136 debug_printf_exec("non-subshell group\n");
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009137 rcode = 1; /* exitcode if redir failed */
Denys Vlasenko2db74612017-07-07 22:07:28 +02009138 if (setup_redirects(command, &squirrel) == 0) {
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009139 debug_printf_exec(": run_list\n");
Denys Vlasenkod1b84572018-03-28 18:42:54 +02009140//FIXME: we need to pass squirrel down into run_list()
9141//for SH_STANDALONE case, or else this construct:
9142// { find /proc/self/fd; true; } >FILE; cmd2
9143//has no way of closing saved fd#1 for "find",
9144//and in SH_STANDALONE mode, "find" is not execed,
9145//therefore CLOEXEC on saved fd does not help.
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009146 rcode = run_list(command->group) & 0xff;
9147 }
9148 restore_redirects(squirrel);
9149 IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;)
9150 debug_leave();
9151 debug_printf_exec("run_pipe: return %d\n", rcode);
9152 return rcode;
9153 }
9154
9155 argv = command->argv ? command->argv : (char **) &null_ptr;
9156 {
9157 const struct built_in_command *x;
Denys Vlasenkod358b0b2018-04-05 00:51:55 +02009158 IF_HUSH_FUNCTIONS(const struct function *funcp;)
9159 IF_NOT_HUSH_FUNCTIONS(enum { funcp = 0 };)
Denys Vlasenko929a41d2018-04-05 14:09:14 +02009160 struct variable **sv_shadowed;
Denys Vlasenkod358b0b2018-04-05 00:51:55 +02009161 struct variable *old_vars;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009162
Denys Vlasenko5807e182018-02-08 19:19:04 +01009163#if ENABLE_HUSH_LINENO_VAR
Denys Vlasenko08fb82c2019-05-19 15:26:05 +02009164 G.execute_lineno = command->lineno;
Denys Vlasenkob8d076b2018-01-19 16:00:57 +01009165#endif
Denys Vlasenko6aad1dd2018-01-19 15:37:04 +01009166
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009167 if (argv[command->assignment_cnt] == NULL) {
Denys Vlasenko5fa05052018-04-03 11:21:13 +02009168 /* Assignments, but no command.
9169 * Ensure redirects take effect (that is, create files).
9170 * Try "a=t >file"
9171 */
Denys Vlasenko21b7f1b2018-04-05 15:15:53 +02009172 unsigned i;
Denys Vlasenko5fa05052018-04-03 11:21:13 +02009173 G.expand_exitcode = 0;
Denys Vlasenko21b7f1b2018-04-05 15:15:53 +02009174 only_assignments:
Denys Vlasenko2db74612017-07-07 22:07:28 +02009175 rcode = setup_redirects(command, &squirrel);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009176 restore_redirects(squirrel);
Denys Vlasenko21b7f1b2018-04-05 15:15:53 +02009177
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009178 /* Set shell variables */
Denys Vlasenko21b7f1b2018-04-05 15:15:53 +02009179 i = 0;
9180 while (i < command->assignment_cnt) {
Denys Vlasenko34179952018-04-11 13:47:59 +02009181 char *p = expand_string_to_string(argv[i],
9182 EXP_FLAG_ESC_GLOB_CHARS,
9183 /*unbackslash:*/ 1
9184 );
Denys Vlasenko9dda9272018-07-27 14:12:05 +02009185#if ENABLE_HUSH_MODE_X
9186 if (G_x_mode) {
Denys Vlasenko4b70c922018-07-27 17:42:38 +02009187 char *eq;
Denys Vlasenkoaa449c92018-07-28 12:13:58 +02009188 if (i == 0)
9189 x_mode_prefix();
9190 x_mode_addchr(' ');
Denys Vlasenko4b70c922018-07-27 17:42:38 +02009191 eq = strchrnul(p, '=');
Denys Vlasenkoaa449c92018-07-28 12:13:58 +02009192 if (*eq) eq++;
9193 x_mode_addblock(p, (eq - p));
9194 x_mode_print_optionally_squoted(eq);
9195 x_mode_flush();
Denys Vlasenko9dda9272018-07-27 14:12:05 +02009196 }
9197#endif
Denys Vlasenko21b7f1b2018-04-05 15:15:53 +02009198 debug_printf_env("set shell var:'%s'->'%s'\n", *argv, p);
Denys Vlasenko38ef39a2017-07-18 01:40:01 +02009199 if (set_local_var(p, /*flag:*/ 0)) {
9200 /* assignment to readonly var / putenv error? */
9201 rcode = 1;
9202 }
Denys Vlasenko21b7f1b2018-04-05 15:15:53 +02009203 i++;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009204 }
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009205 /* Redirect error sets $? to 1. Otherwise,
9206 * if evaluating assignment value set $?, retain it.
Denys Vlasenko5fa05052018-04-03 11:21:13 +02009207 * Else, clear $?:
9208 * false; q=`exit 2`; echo $? - should print 2
9209 * false; x=1; echo $? - should print 0
9210 * Because of the 2nd case, we can't just use G.last_exitcode.
9211 */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009212 if (rcode == 0)
Denys Vlasenko5fa05052018-04-03 11:21:13 +02009213 rcode = G.expand_exitcode;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009214 IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;)
9215 debug_leave();
9216 debug_printf_exec("run_pipe: return %d\n", rcode);
9217 return rcode;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009218 }
9219
9220 /* Expand the rest into (possibly) many strings each */
Denys Vlasenkod2241f52020-10-31 03:34:07 +01009221#if defined(CMD_TEST2_SINGLEWORD_NOGLOB)
9222 if (command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB)
9223 argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt);
9224 else
9225#endif
Denys Vlasenko11752d42018-04-03 08:20:58 +02009226#if defined(CMD_SINGLEWORD_NOGLOB)
Denys Vlasenko929a41d2018-04-05 14:09:14 +02009227 if (command->cmd_type == CMD_SINGLEWORD_NOGLOB)
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009228 argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt);
Denys Vlasenko929a41d2018-04-05 14:09:14 +02009229 else
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009230#endif
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009231 argv_expanded = expand_strvec_to_strvec(argv + command->assignment_cnt);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009232
Denys Vlasenko41d8f102018-04-05 14:41:21 +02009233 /* If someone gives us an empty string: `cmd with empty output` */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009234 if (!argv_expanded[0]) {
9235 free(argv_expanded);
Denys Vlasenko21b7f1b2018-04-05 15:15:53 +02009236 /* `false` still has to set exitcode 1 */
9237 G.expand_exitcode = G.last_exitcode;
Denys Vlasenko41d8f102018-04-05 14:41:21 +02009238 goto only_assignments;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009239 }
9240
Denys Vlasenko929a41d2018-04-05 14:09:14 +02009241 old_vars = NULL;
9242 sv_shadowed = G.shadowed_vars_pp;
9243
Denys Vlasenko75481d32017-07-31 05:27:09 +02009244 /* Check if argv[0] matches any functions (this goes before bltins) */
Denys Vlasenko929a41d2018-04-05 14:09:14 +02009245 IF_HUSH_FUNCTIONS(funcp = find_function(argv_expanded[0]);)
9246 IF_HUSH_FUNCTIONS(x = NULL;)
9247 IF_HUSH_FUNCTIONS(if (!funcp))
Denys Vlasenko75481d32017-07-31 05:27:09 +02009248 x = find_builtin(argv_expanded[0]);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009249 if (x || funcp) {
Denys Vlasenko34f6b122018-04-05 11:30:17 +02009250 if (x && x->b_function == builtin_exec && argv_expanded[1] == NULL) {
9251 debug_printf("exec with redirects only\n");
Denys Vlasenko41d8f102018-04-05 14:41:21 +02009252 /*
9253 * Variable assignments are executed, but then "forgotten":
9254 * a=`sleep 1;echo A` exec 3>&-; echo $a
9255 * sleeps, but prints nothing.
9256 */
9257 enter_var_nest_level();
9258 G.shadowed_vars_pp = &old_vars;
Denys Vlasenko945e9b02018-07-24 18:01:22 +02009259 rcode = redirect_and_varexp_helper(command,
9260 /*squirrel:*/ ERR_PTR,
9261 argv_expanded
9262 );
Denys Vlasenko41d8f102018-04-05 14:41:21 +02009263 G.shadowed_vars_pp = sv_shadowed;
Denys Vlasenko34f6b122018-04-05 11:30:17 +02009264 /* rcode=1 can be if redir file can't be opened */
Denys Vlasenko41d8f102018-04-05 14:41:21 +02009265
Denys Vlasenko34f6b122018-04-05 11:30:17 +02009266 goto clean_up_and_ret1;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009267 }
Denys Vlasenkod358b0b2018-04-05 00:51:55 +02009268
Denys Vlasenko34f6b122018-04-05 11:30:17 +02009269 /* Bump var nesting, or this will leak exported $a:
Denys Vlasenkod358b0b2018-04-05 00:51:55 +02009270 * a=b true; env | grep ^a=
9271 */
9272 enter_var_nest_level();
Denys Vlasenko929a41d2018-04-05 14:09:14 +02009273 /* Collect all variables "shadowed" by helper
9274 * (IOW: old vars overridden by "var1=val1 var2=val2 cmd..." syntax)
9275 * into old_vars list:
9276 */
9277 G.shadowed_vars_pp = &old_vars;
9278 rcode = redirect_and_varexp_helper(command, &squirrel, argv_expanded);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009279 if (rcode == 0) {
9280 if (!funcp) {
Denys Vlasenko929a41d2018-04-05 14:09:14 +02009281 /* Do not collect *to old_vars list* vars shadowed
9282 * by e.g. "local VAR" builtin (collect them
9283 * in the previously nested list instead):
9284 * don't want them to be restored immediately
9285 * after "local" completes.
9286 */
9287 G.shadowed_vars_pp = sv_shadowed;
9288
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009289 debug_printf_exec(": builtin '%s' '%s'...\n",
9290 x->b_cmd, argv_expanded[1]);
Denys Vlasenko8ee2ada2011-02-07 02:03:51 +01009291 fflush_all();
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009292 rcode = x->b_function(argv_expanded) & 0xff;
9293 fflush_all();
9294 }
9295#if ENABLE_HUSH_FUNCTIONS
9296 else {
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009297 debug_printf_exec(": function '%s' '%s'...\n",
9298 funcp->name, argv_expanded[1]);
9299 rcode = run_function(funcp, argv_expanded) & 0xff;
Denys Vlasenko929a41d2018-04-05 14:09:14 +02009300 /*
9301 * But do collect *to old_vars list* vars shadowed
9302 * within function execution. To that end, restore
9303 * this pointer _after_ function run:
9304 */
9305 G.shadowed_vars_pp = sv_shadowed;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009306 }
9307#endif
9308 }
Denys Vlasenko34f6b122018-04-05 11:30:17 +02009309 } else
Denys Vlasenko82d1c1f2017-12-31 17:30:02 +01009310 if (ENABLE_FEATURE_SH_NOFORK && NUM_APPLETS > 1) {
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009311 int n = find_applet_by_name(argv_expanded[0]);
Denys Vlasenko34f6b122018-04-05 11:30:17 +02009312 if (n < 0 || !APPLET_IS_NOFORK(n))
9313 goto must_fork;
9314
9315 enter_var_nest_level();
Denys Vlasenko929a41d2018-04-05 14:09:14 +02009316 /* Collect all variables "shadowed" by helper into old_vars list */
9317 G.shadowed_vars_pp = &old_vars;
9318 rcode = redirect_and_varexp_helper(command, &squirrel, argv_expanded);
9319 G.shadowed_vars_pp = sv_shadowed;
9320
Denys Vlasenko34f6b122018-04-05 11:30:17 +02009321 if (rcode == 0) {
9322 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n",
9323 argv_expanded[0], argv_expanded[1]);
9324 /*
9325 * Note: signals (^C) can't interrupt here.
9326 * We remember them and they will be acted upon
9327 * after applet returns.
9328 * This makes applets which can run for a long time
9329 * and/or wait for user input ineligible for NOFORK:
9330 * for example, "yes" or "rm" (rm -i waits for input).
9331 */
9332 rcode = run_nofork_applet(n, argv_expanded);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009333 }
Denys Vlasenko4e1dc532018-04-05 13:10:34 +02009334 } else
9335 goto must_fork;
Denys Vlasenko34f6b122018-04-05 11:30:17 +02009336
Denys Vlasenko41d8f102018-04-05 14:41:21 +02009337 restore_redirects(squirrel);
9338 clean_up_and_ret1:
Denys Vlasenko34f6b122018-04-05 11:30:17 +02009339 leave_var_nest_level();
9340 add_vars(old_vars);
Denys Vlasenko34f6b122018-04-05 11:30:17 +02009341
9342 /*
9343 * Try "usleep 99999999" + ^C + "echo $?"
9344 * with FEATURE_SH_NOFORK=y.
9345 */
9346 if (!funcp) {
9347 /* It was builtin or nofork.
9348 * if this would be a real fork/execed program,
9349 * it should have died if a fatal sig was received.
9350 * But OTOH, there was no separate process,
9351 * the sig was sent to _shell_, not to non-existing
9352 * child.
9353 * Let's just handle ^C only, this one is obvious:
9354 * we aren't ok with exitcode 0 when ^C was pressed
9355 * during builtin/nofork.
9356 */
9357 if (sigismember(&G.pending_set, SIGINT))
Denys Vlasenko93e2a222020-12-23 12:23:21 +01009358 rcode = 128 | SIGINT;
Denys Vlasenko34f6b122018-04-05 11:30:17 +02009359 }
Denys Vlasenko34f6b122018-04-05 11:30:17 +02009360 free(argv_expanded);
9361 IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;)
9362 debug_leave();
9363 debug_printf_exec("run_pipe return %d\n", rcode);
9364 return rcode;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009365 }
9366
9367 must_fork:
9368 /* NB: argv_expanded may already be created, and that
9369 * might include `cmd` runs! Do not rerun it! We *must*
9370 * use argv_expanded if it's non-NULL */
9371
9372 /* Going to fork a child per each pipe member */
9373 pi->alive_cmds = 0;
9374 next_infd = 0;
9375
9376 cmd_no = 0;
9377 while (cmd_no < pi->num_cmds) {
9378 struct fd_pair pipefds;
9379#if !BB_MMU
Denys Vlasenko9db344a2018-04-09 19:05:11 +02009380 int sv_var_nest_level = G.var_nest_level;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009381 volatile nommu_save_t nommu_save;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009382 nommu_save.old_vars = NULL;
9383 nommu_save.argv = NULL;
9384 nommu_save.argv_from_re_execing = NULL;
9385#endif
9386 command = &pi->cmds[cmd_no];
9387 cmd_no++;
9388 if (command->argv) {
9389 debug_printf_exec(": pipe member '%s' '%s'...\n",
9390 command->argv[0], command->argv[1]);
9391 } else {
9392 debug_printf_exec(": pipe member with no argv\n");
9393 }
9394
9395 /* pipes are inserted between pairs of commands */
9396 pipefds.rd = 0;
9397 pipefds.wr = 1;
9398 if (cmd_no < pi->num_cmds)
9399 xpiped_pair(pipefds);
9400
Denys Vlasenko5807e182018-02-08 19:19:04 +01009401#if ENABLE_HUSH_LINENO_VAR
Denys Vlasenko08fb82c2019-05-19 15:26:05 +02009402 G.execute_lineno = command->lineno;
Denys Vlasenkob8d076b2018-01-19 16:00:57 +01009403#endif
Denys Vlasenko6aad1dd2018-01-19 15:37:04 +01009404
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009405 command->pid = BB_MMU ? fork() : vfork();
9406 if (!command->pid) { /* child */
9407#if ENABLE_HUSH_JOB
9408 disable_restore_tty_pgrp_on_exit();
9409 CLEAR_RANDOM_T(&G.random_gen); /* or else $RANDOM repeats in child */
9410
9411 /* Every child adds itself to new process group
9412 * with pgid == pid_of_first_child_in_pipe */
9413 if (G.run_list_level == 1 && G_interactive_fd) {
9414 pid_t pgrp;
9415 pgrp = pi->pgrp;
9416 if (pgrp < 0) /* true for 1st process only */
9417 pgrp = getpid();
9418 if (setpgid(0, pgrp) == 0
9419 && pi->followup != PIPE_BG
9420 && G_saved_tty_pgrp /* we have ctty */
9421 ) {
9422 /* We do it in *every* child, not just first,
9423 * to avoid races */
9424 tcsetpgrp(G_interactive_fd, pgrp);
9425 }
9426 }
9427#endif
9428 if (pi->alive_cmds == 0 && pi->followup == PIPE_BG) {
9429 /* 1st cmd in backgrounded pipe
9430 * should have its stdin /dev/null'ed */
9431 close(0);
9432 if (open(bb_dev_null, O_RDONLY))
9433 xopen("/", O_RDONLY);
9434 } else {
9435 xmove_fd(next_infd, 0);
9436 }
9437 xmove_fd(pipefds.wr, 1);
9438 if (pipefds.rd > 1)
9439 close(pipefds.rd);
9440 /* Like bash, explicit redirects override pipes,
Denys Vlasenko869994c2016-08-20 15:16:00 +02009441 * and the pipe fd (fd#1) is available for dup'ing:
9442 * "cmd1 2>&1 | cmd2": fd#1 is duped to fd#2, thus stderr
9443 * of cmd1 goes into pipe.
9444 */
9445 if (setup_redirects(command, NULL)) {
9446 /* Happens when redir file can't be opened:
9447 * $ hush -c 'echo FOO >&2 | echo BAR 3>/qwe/rty; echo BAZ'
9448 * FOO
9449 * hush: can't open '/qwe/rty': No such file or directory
9450 * BAZ
9451 * (echo BAR is not executed, it hits _exit(1) below)
9452 */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009453 _exit(1);
Denys Vlasenko869994c2016-08-20 15:16:00 +02009454 }
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009455
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009456 /* Stores to nommu_save list of env vars putenv'ed
9457 * (NOMMU, on MMU we don't need that) */
9458 /* cast away volatility... */
9459 pseudo_exec((nommu_save_t*) &nommu_save, command, argv_expanded);
9460 /* pseudo_exec() does not return */
9461 }
9462
9463 /* parent or error */
9464#if ENABLE_HUSH_FAST
9465 G.count_SIGCHLD++;
9466//bb_error_msg("[%d] fork in run_pipe: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
9467#endif
9468 enable_restore_tty_pgrp_on_exit();
9469#if !BB_MMU
9470 /* Clean up after vforked child */
9471 free(nommu_save.argv);
9472 free(nommu_save.argv_from_re_execing);
Denys Vlasenko9db344a2018-04-09 19:05:11 +02009473 G.var_nest_level = sv_var_nest_level;
9474 remove_nested_vars();
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009475 add_vars(nommu_save.old_vars);
9476#endif
9477 free(argv_expanded);
9478 argv_expanded = NULL;
9479 if (command->pid < 0) { /* [v]fork failed */
9480 /* Clearly indicate, was it fork or vfork */
James Byrne69374872019-07-02 11:35:03 +02009481 bb_simple_perror_msg(BB_MMU ? "vfork"+1 : "vfork");
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009482 } else {
9483 pi->alive_cmds++;
9484#if ENABLE_HUSH_JOB
9485 /* Second and next children need to know pid of first one */
9486 if (pi->pgrp < 0)
9487 pi->pgrp = command->pid;
9488#endif
9489 }
9490
9491 if (cmd_no > 1)
9492 close(next_infd);
9493 if (cmd_no < pi->num_cmds)
9494 close(pipefds.wr);
9495 /* Pass read (output) pipe end to next iteration */
9496 next_infd = pipefds.rd;
9497 }
9498
9499 if (!pi->alive_cmds) {
9500 debug_leave();
9501 debug_printf_exec("run_pipe return 1 (all forks failed, no children)\n");
9502 return 1;
9503 }
9504
9505 debug_leave();
9506 debug_printf_exec("run_pipe return -1 (%u children started)\n", pi->alive_cmds);
9507 return -1;
9508}
9509
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009510/* NB: called by pseudo_exec, and therefore must not modify any
9511 * global data until exec/_exit (we can be a child after vfork!) */
9512static int run_list(struct pipe *pi)
9513{
9514#if ENABLE_HUSH_CASE
9515 char *case_word = NULL;
9516#endif
9517#if ENABLE_HUSH_LOOPS
9518 struct pipe *loop_top = NULL;
9519 char **for_lcur = NULL;
9520 char **for_list = NULL;
9521#endif
9522 smallint last_followup;
9523 smalluint rcode;
9524#if ENABLE_HUSH_IF || ENABLE_HUSH_CASE
9525 smalluint cond_code = 0;
9526#else
9527 enum { cond_code = 0 };
9528#endif
9529#if HAS_KEYWORDS
Denys Vlasenko9b782552010-09-08 13:33:26 +02009530 smallint rword; /* RES_foo */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009531 smallint last_rword; /* ditto */
9532#endif
9533
9534 debug_printf_exec("run_list start lvl %d\n", G.run_list_level);
9535 debug_enter();
9536
9537#if ENABLE_HUSH_LOOPS
9538 /* Check syntax for "for" */
Denys Vlasenko0d6a4ec2010-12-18 01:34:49 +01009539 {
9540 struct pipe *cpipe;
9541 for (cpipe = pi; cpipe; cpipe = cpipe->next) {
9542 if (cpipe->res_word != RES_FOR && cpipe->res_word != RES_IN)
9543 continue;
9544 /* current word is FOR or IN (BOLD in comments below) */
9545 if (cpipe->next == NULL) {
9546 syntax_error("malformed for");
9547 debug_leave();
9548 debug_printf_exec("run_list lvl %d return 1\n", G.run_list_level);
9549 return 1;
9550 }
9551 /* "FOR v; do ..." and "for v IN a b; do..." are ok */
9552 if (cpipe->next->res_word == RES_DO)
9553 continue;
9554 /* next word is not "do". It must be "in" then ("FOR v in ...") */
9555 if (cpipe->res_word == RES_IN /* "for v IN a b; not_do..."? */
9556 || cpipe->next->res_word != RES_IN /* FOR v not_do_and_not_in..."? */
9557 ) {
9558 syntax_error("malformed for");
9559 debug_leave();
9560 debug_printf_exec("run_list lvl %d return 1\n", G.run_list_level);
9561 return 1;
9562 }
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009563 }
9564 }
9565#endif
9566
9567 /* Past this point, all code paths should jump to ret: label
9568 * in order to return, no direct "return" statements please.
9569 * This helps to ensure that no memory is leaked. */
9570
9571#if ENABLE_HUSH_JOB
9572 G.run_list_level++;
9573#endif
9574
9575#if HAS_KEYWORDS
9576 rword = RES_NONE;
9577 last_rword = RES_XXXX;
9578#endif
9579 last_followup = PIPE_SEQ;
9580 rcode = G.last_exitcode;
9581
9582 /* Go through list of pipes, (maybe) executing them. */
9583 for (; pi; pi = IF_HUSH_LOOPS(rword == RES_DONE ? loop_top : ) pi->next) {
Denys Vlasenko5cc9bf62016-11-08 17:34:44 +01009584 int r;
Denys Vlasenko9fda6092017-07-14 13:36:48 +02009585 int sv_errexit_depth;
Denys Vlasenko5cc9bf62016-11-08 17:34:44 +01009586
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009587 if (G.flag_SIGINT)
9588 break;
Denys Vlasenko04b46bc2016-10-01 22:28:03 +02009589 if (G_flag_return_in_progress == 1)
9590 break;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009591
9592 IF_HAS_KEYWORDS(rword = pi->res_word;)
9593 debug_printf_exec(": rword=%d cond_code=%d last_rword=%d\n",
9594 rword, cond_code, last_rword);
Denys Vlasenko9fda6092017-07-14 13:36:48 +02009595
9596 sv_errexit_depth = G.errexit_depth;
Denys Vlasenko82d1c1f2017-12-31 17:30:02 +01009597 if (
9598#if ENABLE_HUSH_IF
9599 rword == RES_IF || rword == RES_ELIF ||
9600#endif
Denys Vlasenko9fda6092017-07-14 13:36:48 +02009601 pi->followup != PIPE_SEQ
9602 ) {
9603 G.errexit_depth++;
9604 }
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009605#if ENABLE_HUSH_LOOPS
9606 if ((rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR)
9607 && loop_top == NULL /* avoid bumping G.depth_of_loop twice */
9608 ) {
9609 /* start of a loop: remember where loop starts */
9610 loop_top = pi;
9611 G.depth_of_loop++;
9612 }
9613#endif
9614 /* Still in the same "if...", "then..." or "do..." branch? */
9615 if (IF_HAS_KEYWORDS(rword == last_rword &&) 1) {
9616 if ((rcode == 0 && last_followup == PIPE_OR)
9617 || (rcode != 0 && last_followup == PIPE_AND)
9618 ) {
9619 /* It is "<true> || CMD" or "<false> && CMD"
9620 * and we should not execute CMD */
9621 debug_printf_exec("skipped cmd because of || or &&\n");
9622 last_followup = pi->followup;
Denys Vlasenko3beab832013-04-07 18:16:58 +02009623 goto dont_check_jobs_but_continue;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009624 }
9625 }
9626 last_followup = pi->followup;
9627 IF_HAS_KEYWORDS(last_rword = rword;)
9628#if ENABLE_HUSH_IF
9629 if (cond_code) {
9630 if (rword == RES_THEN) {
9631 /* if false; then ... fi has exitcode 0! */
9632 G.last_exitcode = rcode = EXIT_SUCCESS;
9633 /* "if <false> THEN cmd": skip cmd */
9634 continue;
9635 }
9636 } else {
9637 if (rword == RES_ELSE || rword == RES_ELIF) {
9638 /* "if <true> then ... ELSE/ELIF cmd":
9639 * skip cmd and all following ones */
9640 break;
9641 }
9642 }
9643#endif
9644#if ENABLE_HUSH_LOOPS
9645 if (rword == RES_FOR) { /* && pi->num_cmds - always == 1 */
9646 if (!for_lcur) {
9647 /* first loop through for */
9648
9649 static const char encoded_dollar_at[] ALIGN1 = {
9650 SPECIAL_VAR_SYMBOL, '@' | 0x80, SPECIAL_VAR_SYMBOL, '\0'
9651 }; /* encoded representation of "$@" */
9652 static const char *const encoded_dollar_at_argv[] = {
9653 encoded_dollar_at, NULL
9654 }; /* argv list with one element: "$@" */
9655 char **vals;
9656
Denys Vlasenkoa5db1d72018-07-28 12:42:08 +02009657 G.last_exitcode = rcode = EXIT_SUCCESS;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009658 vals = (char**)encoded_dollar_at_argv;
9659 if (pi->next->res_word == RES_IN) {
9660 /* if no variable values after "in" we skip "for" */
9661 if (!pi->next->cmds[0].argv) {
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009662 debug_printf_exec(": null FOR: exitcode EXIT_SUCCESS\n");
9663 break;
9664 }
9665 vals = pi->next->cmds[0].argv;
9666 } /* else: "for var; do..." -> assume "$@" list */
9667 /* create list of variable values */
9668 debug_print_strings("for_list made from", vals);
9669 for_list = expand_strvec_to_strvec(vals);
9670 for_lcur = for_list;
9671 debug_print_strings("for_list", for_list);
9672 }
9673 if (!*for_lcur) {
9674 /* "for" loop is over, clean up */
9675 free(for_list);
9676 for_list = NULL;
9677 for_lcur = NULL;
9678 break;
9679 }
9680 /* Insert next value from for_lcur */
9681 /* note: *for_lcur already has quotes removed, $var expanded, etc */
Denys Vlasenko3bab36b2017-07-18 01:05:24 +02009682 set_local_var(xasprintf("%s=%s", pi->cmds[0].argv[0], *for_lcur++), /*flag:*/ 0);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009683 continue;
9684 }
9685 if (rword == RES_IN) {
9686 continue; /* "for v IN list;..." - "in" has no cmds anyway */
9687 }
9688 if (rword == RES_DONE) {
9689 continue; /* "done" has no cmds too */
9690 }
9691#endif
9692#if ENABLE_HUSH_CASE
9693 if (rword == RES_CASE) {
Denys Vlasenkoaeaee432016-11-04 20:14:04 +01009694 debug_printf_exec("CASE cond_code:%d\n", cond_code);
Denys Vlasenko34179952018-04-11 13:47:59 +02009695 case_word = expand_string_to_string(pi->cmds->argv[0],
9696 EXP_FLAG_ESC_GLOB_CHARS, /*unbackslash:*/ 1);
Denys Vlasenkoabf75562018-04-02 17:25:18 +02009697 debug_printf_exec("CASE word1:'%s'\n", case_word);
9698 //unbackslash(case_word);
9699 //debug_printf_exec("CASE word2:'%s'\n", case_word);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009700 continue;
9701 }
9702 if (rword == RES_MATCH) {
9703 char **argv;
9704
Denys Vlasenkoaeaee432016-11-04 20:14:04 +01009705 debug_printf_exec("MATCH cond_code:%d\n", cond_code);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009706 if (!case_word) /* "case ... matched_word) ... WORD)": we executed selected branch, stop */
9707 break;
9708 /* all prev words didn't match, does this one match? */
9709 argv = pi->cmds->argv;
9710 while (*argv) {
Denys Vlasenko34179952018-04-11 13:47:59 +02009711 char *pattern;
9712 debug_printf_exec("expand_string_to_string('%s')\n", *argv);
9713 pattern = expand_string_to_string(*argv,
9714 EXP_FLAG_ESC_GLOB_CHARS,
9715 /*unbackslash:*/ 0
9716 );
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009717 /* TODO: which FNM_xxx flags to use? */
9718 cond_code = (fnmatch(pattern, case_word, /*flags:*/ 0) != 0);
Denys Vlasenko34179952018-04-11 13:47:59 +02009719 debug_printf_exec("fnmatch(pattern:'%s',str:'%s'):%d\n",
9720 pattern, case_word, cond_code);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009721 free(pattern);
Denys Vlasenko34179952018-04-11 13:47:59 +02009722 if (cond_code == 0) {
9723 /* match! we will execute this branch */
Denys Vlasenkoaeaee432016-11-04 20:14:04 +01009724 free(case_word);
9725 case_word = NULL; /* make future "word)" stop */
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009726 break;
9727 }
9728 argv++;
9729 }
9730 continue;
9731 }
9732 if (rword == RES_CASE_BODY) { /* inside of a case branch */
Denys Vlasenkoaeaee432016-11-04 20:14:04 +01009733 debug_printf_exec("CASE_BODY cond_code:%d\n", cond_code);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009734 if (cond_code != 0)
9735 continue; /* not matched yet, skip this pipe */
9736 }
Denys Vlasenkoaeaee432016-11-04 20:14:04 +01009737 if (rword == RES_ESAC) {
9738 debug_printf_exec("ESAC cond_code:%d\n", cond_code);
9739 if (case_word) {
9740 /* "case" did not match anything: still set $? (to 0) */
9741 G.last_exitcode = rcode = EXIT_SUCCESS;
9742 }
9743 }
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009744#endif
9745 /* Just pressing <enter> in shell should check for jobs.
9746 * OTOH, in non-interactive shell this is useless
9747 * and only leads to extra job checks */
9748 if (pi->num_cmds == 0) {
9749 if (G_interactive_fd)
9750 goto check_jobs_and_continue;
9751 continue;
9752 }
9753
9754 /* After analyzing all keywords and conditions, we decided
9755 * to execute this pipe. NB: have to do checkjobs(NULL)
9756 * after run_pipe to collect any background children,
9757 * even if list execution is to be stopped. */
9758 debug_printf_exec(": run_pipe with %d members\n", pi->num_cmds);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009759#if ENABLE_HUSH_LOOPS
Denys Vlasenko5cc9bf62016-11-08 17:34:44 +01009760 G.flag_break_continue = 0;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009761#endif
Denys Vlasenko5cc9bf62016-11-08 17:34:44 +01009762 rcode = r = run_pipe(pi); /* NB: rcode is a smalluint, r is int */
9763 if (r != -1) {
9764 /* We ran a builtin, function, or group.
9765 * rcode is already known
9766 * and we don't need to wait for anything. */
9767 debug_printf_exec(": builtin/func exitcode %d\n", rcode);
9768 G.last_exitcode = rcode;
9769 check_and_run_traps();
Denys Vlasenkobb095f42020-02-20 16:37:59 +01009770#if ENABLE_HUSH_TRAP && ENABLE_HUSH_FUNCTIONS
9771 rcode = G.last_exitcode; /* "return" in trap can change it, read back */
9772#endif
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009773#if ENABLE_HUSH_LOOPS
Denys Vlasenko5cc9bf62016-11-08 17:34:44 +01009774 /* Was it "break" or "continue"? */
9775 if (G.flag_break_continue) {
9776 smallint fbc = G.flag_break_continue;
9777 /* We might fall into outer *loop*,
9778 * don't want to break it too */
9779 if (loop_top) {
9780 G.depth_break_continue--;
9781 if (G.depth_break_continue == 0)
9782 G.flag_break_continue = 0;
9783 /* else: e.g. "continue 2" should *break* once, *then* continue */
9784 } /* else: "while... do... { we are here (innermost list is not a loop!) };...done" */
9785 if (G.depth_break_continue != 0 || fbc == BC_BREAK) {
Denys Vlasenko7e675362016-10-28 21:57:31 +02009786 checkjobs(NULL, 0 /*(no pid to wait for)*/);
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009787 break;
9788 }
Denys Vlasenko5cc9bf62016-11-08 17:34:44 +01009789 /* "continue": simulate end of loop */
9790 rword = RES_DONE;
9791 continue;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009792 }
Denys Vlasenko5cc9bf62016-11-08 17:34:44 +01009793#endif
9794 if (G_flag_return_in_progress == 1) {
9795 checkjobs(NULL, 0 /*(no pid to wait for)*/);
9796 break;
9797 }
9798 } else if (pi->followup == PIPE_BG) {
9799 /* What does bash do with attempts to background builtins? */
9800 /* even bash 3.2 doesn't do that well with nested bg:
9801 * try "{ { sleep 10; echo DEEP; } & echo HERE; } &".
9802 * I'm NOT treating inner &'s as jobs */
9803#if ENABLE_HUSH_JOB
9804 if (G.run_list_level == 1)
Denys Vlasenko16096292017-07-10 10:00:28 +02009805 insert_job_into_table(pi);
Denys Vlasenko5cc9bf62016-11-08 17:34:44 +01009806#endif
9807 /* Last command's pid goes to $! */
9808 G.last_bg_pid = pi->cmds[pi->num_cmds - 1].pid;
Denys Vlasenko840a4352017-07-07 22:56:02 +02009809 G.last_bg_pid_exitcode = 0;
Denys Vlasenko5cc9bf62016-11-08 17:34:44 +01009810 debug_printf_exec(": cmd&: exitcode EXIT_SUCCESS\n");
Denys Vlasenko7c40ddd2017-08-02 16:37:39 +02009811/* Check pi->pi_inverted? "! sleep 1 & echo $?": bash says 1. dash and ash say 0 */
Denys Vlasenko6c635d62016-11-08 20:26:11 +01009812 rcode = EXIT_SUCCESS;
9813 goto check_traps;
Denys Vlasenko5cc9bf62016-11-08 17:34:44 +01009814 } else {
9815#if ENABLE_HUSH_JOB
9816 if (G.run_list_level == 1 && G_interactive_fd) {
9817 /* Waits for completion, then fg's main shell */
9818 rcode = checkjobs_and_fg_shell(pi);
9819 debug_printf_exec(": checkjobs_and_fg_shell exitcode %d\n", rcode);
Denys Vlasenko6c635d62016-11-08 20:26:11 +01009820 goto check_traps;
Denys Vlasenko5cc9bf62016-11-08 17:34:44 +01009821 }
Denys Vlasenko6c635d62016-11-08 20:26:11 +01009822#endif
9823 /* This one just waits for completion */
9824 rcode = checkjobs(pi, 0 /*(no pid to wait for)*/);
9825 debug_printf_exec(": checkjobs exitcode %d\n", rcode);
9826 check_traps:
Denys Vlasenko5cc9bf62016-11-08 17:34:44 +01009827 G.last_exitcode = rcode;
9828 check_and_run_traps();
Denys Vlasenkobb095f42020-02-20 16:37:59 +01009829#if ENABLE_HUSH_TRAP && ENABLE_HUSH_FUNCTIONS
9830 rcode = G.last_exitcode; /* "return" in trap can change it, read back */
9831#endif
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009832 }
9833
Denys Vlasenko9fda6092017-07-14 13:36:48 +02009834 /* Handle "set -e" */
9835 if (rcode != 0 && G.o_opt[OPT_O_ERREXIT]) {
9836 debug_printf_exec("ERREXIT:1 errexit_depth:%d\n", G.errexit_depth);
9837 if (G.errexit_depth == 0)
9838 hush_exit(rcode);
9839 }
9840 G.errexit_depth = sv_errexit_depth;
9841
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009842 /* Analyze how result affects subsequent commands */
9843#if ENABLE_HUSH_IF
9844 if (rword == RES_IF || rword == RES_ELIF)
9845 cond_code = rcode;
9846#endif
Denys Vlasenko3beab832013-04-07 18:16:58 +02009847 check_jobs_and_continue:
Denys Vlasenko7e675362016-10-28 21:57:31 +02009848 checkjobs(NULL, 0 /*(no pid to wait for)*/);
Denys Vlasenko3beab832013-04-07 18:16:58 +02009849 dont_check_jobs_but_continue: ;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009850#if ENABLE_HUSH_LOOPS
9851 /* Beware of "while false; true; do ..."! */
Denys Vlasenko00ae9892011-05-31 17:35:45 +02009852 if (pi->next
9853 && (pi->next->res_word == RES_DO || pi->next->res_word == RES_DONE)
Denys Vlasenko56a3b822011-06-01 12:47:07 +02009854 /* check for RES_DONE is needed for "while ...; do \n done" case */
Denys Vlasenko00ae9892011-05-31 17:35:45 +02009855 ) {
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009856 if (rword == RES_WHILE) {
9857 if (rcode) {
9858 /* "while false; do...done" - exitcode 0 */
9859 G.last_exitcode = rcode = EXIT_SUCCESS;
9860 debug_printf_exec(": while expr is false: breaking (exitcode:EXIT_SUCCESS)\n");
Denys Vlasenko3beab832013-04-07 18:16:58 +02009861 break;
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009862 }
9863 }
9864 if (rword == RES_UNTIL) {
9865 if (!rcode) {
9866 debug_printf_exec(": until expr is true: breaking\n");
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009867 break;
9868 }
9869 }
9870 }
9871#endif
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009872 } /* for (pi) */
9873
9874#if ENABLE_HUSH_JOB
9875 G.run_list_level--;
9876#endif
9877#if ENABLE_HUSH_LOOPS
9878 if (loop_top)
9879 G.depth_of_loop--;
9880 free(for_list);
9881#endif
9882#if ENABLE_HUSH_CASE
9883 free(case_word);
9884#endif
9885 debug_leave();
9886 debug_printf_exec("run_list lvl %d return %d\n", G.run_list_level + 1, rcode);
9887 return rcode;
9888}
9889
9890/* Select which version we will use */
9891static int run_and_free_list(struct pipe *pi)
9892{
9893 int rcode = 0;
9894 debug_printf_exec("run_and_free_list entered\n");
Dan Fandrich85c62472010-11-20 13:05:17 -08009895 if (!G.o_opt[OPT_O_NOEXEC]) {
Denys Vlasenkob36abf22010-09-05 14:50:59 +02009896 debug_printf_exec(": run_list: 1st pipe with %d cmds\n", pi->num_cmds);
9897 rcode = run_list(pi);
9898 }
9899 /* free_pipe_list has the side effect of clearing memory.
9900 * In the long run that function can be merged with run_list,
9901 * but doing that now would hobble the debugging effort. */
9902 free_pipe_list(pi);
9903 debug_printf_exec("run_and_free_list return %d\n", rcode);
9904 return rcode;
9905}
9906
9907
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02009908static void install_sighandlers(unsigned mask)
Eric Andersen52a97ca2001-06-22 06:49:26 +00009909{
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02009910 sighandler_t old_handler;
9911 unsigned sig = 0;
9912 while ((mask >>= 1) != 0) {
9913 sig++;
9914 if (!(mask & 1))
9915 continue;
Denys Vlasenko0806e402011-05-12 23:06:20 +02009916 old_handler = install_sighandler(sig, pick_sighandler(sig));
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02009917 /* POSIX allows shell to re-enable SIGCHLD
9918 * even if it was SIG_IGN on entry.
9919 * Therefore we skip IGN check for it:
9920 */
9921 if (sig == SIGCHLD)
9922 continue;
Denys Vlasenko23bc5622020-02-18 16:46:01 +01009923 /* Interactive bash re-enables SIGHUP which is SIG_IGNed on entry.
9924 * Try:
9925 * trap '' hup; bash; echo RET # type "kill -hup $$", see SIGHUP having effect
9926 * trap '' hup; bash -c 'kill -hup $$; echo ALIVE' # here SIGHUP is SIG_IGNed
Denys Vlasenko49e6bf22017-08-04 14:28:16 +02009927 */
Denys Vlasenko23bc5622020-02-18 16:46:01 +01009928 if (sig == SIGHUP && G_interactive_fd)
9929 continue;
9930 /* Unless one of the above signals, is it SIG_IGN? */
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02009931 if (old_handler == SIG_IGN) {
9932 /* oops... restore back to IGN, and record this fact */
Denys Vlasenko0806e402011-05-12 23:06:20 +02009933 install_sighandler(sig, old_handler);
Denys Vlasenko7a85c602017-01-08 17:40:18 +01009934#if ENABLE_HUSH_TRAP
9935 if (!G_traps)
9936 G_traps = xzalloc(sizeof(G_traps[0]) * NSIG);
9937 free(G_traps[sig]);
9938 G_traps[sig] = xzalloc(1); /* == xstrdup(""); */
9939#endif
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02009940 }
9941 }
9942}
9943
9944/* Called a few times only (or even once if "sh -c") */
9945static void install_special_sighandlers(void)
9946{
Denis Vlasenkof9375282009-04-05 19:13:39 +00009947 unsigned mask;
Denys Vlasenkoe89a2412010-01-12 15:19:31 +01009948
Denys Vlasenko54e9e122011-05-09 00:52:15 +02009949 /* Which signals are shell-special? */
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02009950 mask = (1 << SIGQUIT) | (1 << SIGCHLD);
Denys Vlasenko54e9e122011-05-09 00:52:15 +02009951 if (G_interactive_fd) {
9952 mask |= SPECIAL_INTERACTIVE_SIGS;
9953 if (G_saved_tty_pgrp) /* we have ctty, job control sigs work */
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02009954 mask |= SPECIAL_JOBSTOP_SIGS;
Denys Vlasenko54e9e122011-05-09 00:52:15 +02009955 }
Denys Vlasenkof58f7052011-05-12 02:10:33 +02009956 /* Careful, do not re-install handlers we already installed */
9957 if (G.special_sig_mask != mask) {
9958 unsigned diff = mask & ~G.special_sig_mask;
9959 G.special_sig_mask = mask;
9960 install_sighandlers(diff);
9961 }
Denis Vlasenkof9375282009-04-05 19:13:39 +00009962}
9963
9964#if ENABLE_HUSH_JOB
9965/* helper */
Denys Vlasenko54e9e122011-05-09 00:52:15 +02009966/* Set handlers to restore tty pgrp and exit */
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02009967static void install_fatal_sighandlers(void)
Denis Vlasenkof9375282009-04-05 19:13:39 +00009968{
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02009969 unsigned mask;
Denys Vlasenko54e9e122011-05-09 00:52:15 +02009970
9971 /* We will restore tty pgrp on these signals */
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02009972 mask = 0
Denys Vlasenko830ea352016-11-08 04:59:11 +01009973 /*+ (1 << SIGILL ) * HUSH_DEBUG*/
9974 /*+ (1 << SIGFPE ) * HUSH_DEBUG*/
Denys Vlasenko54e9e122011-05-09 00:52:15 +02009975 + (1 << SIGBUS ) * HUSH_DEBUG
9976 + (1 << SIGSEGV) * HUSH_DEBUG
Denys Vlasenko830ea352016-11-08 04:59:11 +01009977 /*+ (1 << SIGTRAP) * HUSH_DEBUG*/
Denys Vlasenko54e9e122011-05-09 00:52:15 +02009978 + (1 << SIGABRT)
9979 /* bash 3.2 seems to handle these just like 'fatal' ones */
9980 + (1 << SIGPIPE)
9981 + (1 << SIGALRM)
Denys Vlasenkof58f7052011-05-12 02:10:33 +02009982 /* if we are interactive, SIGHUP, SIGTERM and SIGINT are special sigs.
Denys Vlasenko54e9e122011-05-09 00:52:15 +02009983 * if we aren't interactive... but in this case
Denys Vlasenkof58f7052011-05-12 02:10:33 +02009984 * we never want to restore pgrp on exit, and this fn is not called
9985 */
Denys Vlasenko54e9e122011-05-09 00:52:15 +02009986 /*+ (1 << SIGHUP )*/
9987 /*+ (1 << SIGTERM)*/
9988 /*+ (1 << SIGINT )*/
9989 ;
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02009990 G_fatal_sig_mask = mask;
Denys Vlasenko54e9e122011-05-09 00:52:15 +02009991
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +02009992 install_sighandlers(mask);
Denis Vlasenkof9375282009-04-05 19:13:39 +00009993}
Denis Vlasenkob81b3df2007-04-28 16:48:04 +00009994#endif
Eric Andersenada18ff2001-05-21 16:18:22 +00009995
Denys Vlasenko6696eac2010-11-14 02:01:50 +01009996static int set_mode(int state, char mode, const char *o_opt)
Denis Vlasenkod5762932009-03-31 11:22:57 +00009997{
Denys Vlasenko6696eac2010-11-14 02:01:50 +01009998 int idx;
Denis Vlasenkod5762932009-03-31 11:22:57 +00009999 switch (mode) {
Denys Vlasenko6696eac2010-11-14 02:01:50 +010010000 case 'n':
Dan Fandrich85c62472010-11-20 13:05:17 -080010001 G.o_opt[OPT_O_NOEXEC] = state;
Denys Vlasenko6696eac2010-11-14 02:01:50 +010010002 break;
10003 case 'x':
10004 IF_HUSH_MODE_X(G_x_mode = state;)
Denys Vlasenkoaa449c92018-07-28 12:13:58 +020010005 IF_HUSH_MODE_X(if (G.x_mode_fd <= 0) G.x_mode_fd = dup_CLOEXEC(2, 10);)
Denys Vlasenko6696eac2010-11-14 02:01:50 +010010006 break;
Denys Vlasenko18a90ec2019-09-05 14:07:14 +020010007 case 'e':
10008 G.o_opt[OPT_O_ERREXIT] = state;
10009 break;
Denys Vlasenko6696eac2010-11-14 02:01:50 +010010010 case 'o':
10011 if (!o_opt) {
Denys Vlasenko18a90ec2019-09-05 14:07:14 +020010012 /* "set -o" or "set +o" without parameter.
Denys Vlasenko6696eac2010-11-14 02:01:50 +010010013 * in bash, set -o produces this output:
10014 * pipefail off
10015 * and set +o:
10016 * set +o pipefail
10017 * We always use the second form.
10018 */
10019 const char *p = o_opt_strings;
10020 idx = 0;
10021 while (*p) {
10022 printf("set %co %s\n", (G.o_opt[idx] ? '-' : '+'), p);
10023 idx++;
10024 p += strlen(p) + 1;
10025 }
10026 break;
10027 }
10028 idx = index_in_strings(o_opt_strings, o_opt);
10029 if (idx >= 0) {
10030 G.o_opt[idx] = state;
10031 break;
10032 }
Denys Vlasenko18a90ec2019-09-05 14:07:14 +020010033 /* fall through to error */
Denys Vlasenko6696eac2010-11-14 02:01:50 +010010034 default:
10035 return EXIT_FAILURE;
Denis Vlasenkod5762932009-03-31 11:22:57 +000010036 }
10037 return EXIT_SUCCESS;
10038}
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000010039
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000010040int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Matt Kraai2d91deb2001-08-01 17:21:35 +000010041int hush_main(int argc, char **argv)
Eric Andersen25f27032001-04-26 23:22:31 +000010042{
Denys Vlasenkobb4e32b2020-12-20 16:36:00 +010010043 pid_t cached_getpid;
Denys Vlasenkof58f7052011-05-12 02:10:33 +020010044 enum {
10045 OPT_login = (1 << 0),
10046 };
10047 unsigned flags;
Denys Vlasenko63139b52020-12-13 22:00:56 +010010048#if !BB_MMU
10049 unsigned builtin_argc = 0;
10050#endif
Denis Vlasenkofbf6dea2007-04-13 19:56:56 +000010051 char **e;
Denis Vlasenkod76c0492007-05-25 02:16:25 +000010052 struct variable *cur_var;
Denys Vlasenko75eb9d22010-12-21 21:18:12 +010010053 struct variable *shell_ver;
Eric Andersenbc604a22001-05-16 05:24:03 +000010054
Denis Vlasenko574f2f42008-02-27 18:41:59 +000010055 INIT_G();
Denys Vlasenko10c01312011-05-11 11:49:21 +020010056 if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */
Denis Vlasenkoab2b0642009-04-06 18:42:11 +000010057 G.last_exitcode = EXIT_SUCCESS;
Denys Vlasenkocc9ecd92020-02-21 02:18:06 +010010058#if ENABLE_HUSH_TRAP
10059# if ENABLE_HUSH_FUNCTIONS
Denys Vlasenkobb095f42020-02-20 16:37:59 +010010060 G.return_exitcode = -1;
Denys Vlasenkocc9ecd92020-02-21 02:18:06 +010010061# endif
10062 G.pre_trap_exitcode = -1;
Denys Vlasenkobb095f42020-02-20 16:37:59 +010010063#endif
Denys Vlasenkoe9abe752016-08-19 20:15:26 +020010064
Denys Vlasenko10c01312011-05-11 11:49:21 +020010065#if ENABLE_HUSH_FAST
10066 G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */
10067#endif
Denis Vlasenko46f9b6d2009-04-05 10:39:03 +000010068#if !BB_MMU
10069 G.argv0_for_re_execing = argv[0];
10070#endif
Denys Vlasenko6aad1dd2018-01-19 15:37:04 +010010071
Denys Vlasenkobb4e32b2020-12-20 16:36:00 +010010072 cached_getpid = getpid(); /* for tcsetpgrp() during init */
Denys Vlasenko46a71dc2020-12-25 18:49:29 +010010073 G.root_pid = cached_getpid; /* for $PID (NOMMU can override via -$HEXPID:HEXPPID:...) */
10074 G.root_ppid = getppid(); /* for $PPID (NOMMU can override) */
Denys Vlasenkobb4e32b2020-12-20 16:36:00 +010010075
Denis Vlasenko0a83fc32007-05-25 11:12:32 +000010076 /* Deal with HUSH_VERSION */
Denys Vlasenko6aad1dd2018-01-19 15:37:04 +010010077 debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION");
10078 unsetenv("HUSH_VERSION"); /* in case it exists in initial env */
Denys Vlasenko75eb9d22010-12-21 21:18:12 +010010079 shell_ver = xzalloc(sizeof(*shell_ver));
10080 shell_ver->flg_export = 1;
10081 shell_ver->flg_read_only = 1;
Denys Vlasenko4f870492010-09-10 11:06:01 +020010082 /* Code which handles ${var<op>...} needs writable values for all variables,
Denys Vlasenko36f774a2010-09-05 14:45:38 +020010083 * therefore we xstrdup: */
Denys Vlasenko75eb9d22010-12-21 21:18:12 +010010084 shell_ver->varstr = xstrdup(hush_version_str);
Denys Vlasenko6aad1dd2018-01-19 15:37:04 +010010085
Denys Vlasenko605067b2010-09-06 12:10:51 +020010086 /* Create shell local variables from the values
10087 * currently living in the environment */
Denys Vlasenko75eb9d22010-12-21 21:18:12 +010010088 G.top_var = shell_ver;
Denis Vlasenko87a86552008-07-29 19:43:10 +000010089 cur_var = G.top_var;
Denis Vlasenko0a83fc32007-05-25 11:12:32 +000010090 e = environ;
Denis Vlasenkod76c0492007-05-25 02:16:25 +000010091 if (e) while (*e) {
10092 char *value = strchr(*e, '=');
10093 if (value) { /* paranoia */
10094 cur_var->next = xzalloc(sizeof(*cur_var));
10095 cur_var = cur_var->next;
Denis Vlasenko28c0f0f2007-05-25 02:46:01 +000010096 cur_var->varstr = *e;
Denis Vlasenkod76c0492007-05-25 02:16:25 +000010097 cur_var->max_len = strlen(*e);
10098 cur_var->flg_export = 1;
10099 }
10100 e++;
10101 }
Denys Vlasenko605067b2010-09-06 12:10:51 +020010102 /* (Re)insert HUSH_VERSION into env (AFTER we scanned the env!) */
Denys Vlasenko75eb9d22010-12-21 21:18:12 +010010103 debug_printf_env("putenv '%s'\n", shell_ver->varstr);
10104 putenv(shell_ver->varstr);
Denys Vlasenko6db47842009-09-05 20:15:17 +020010105
10106 /* Export PWD */
Denys Vlasenko3bab36b2017-07-18 01:05:24 +020010107 set_pwd_var(SETFLAG_EXPORT);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020010108
Kang-Che Sung027d3ab2017-01-11 14:18:15 +010010109#if BASH_HOSTNAME_VAR
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020010110 /* Set (but not export) HOSTNAME unless already set */
10111 if (!get_local_var_value("HOSTNAME")) {
10112 struct utsname uts;
10113 uname(&uts);
10114 set_local_var_from_halves("HOSTNAME", uts.nodename);
10115 }
Denys Vlasenkofd6f2952018-08-05 15:13:08 +020010116#endif
10117 /* IFS is not inherited from the parent environment */
10118 set_local_var_from_halves("IFS", defifs);
10119
Denys Vlasenkoef8985c2019-05-19 16:29:09 +020010120 if (!get_local_var_value("PATH"))
10121 set_local_var_from_halves("PATH", bb_default_root_path);
10122
Denys Vlasenko0c360192019-05-19 15:37:50 +020010123 /* PS1/PS2 are set later, if we determine that we are interactive */
10124
Denys Vlasenko6db47842009-09-05 20:15:17 +020010125 /* bash also exports SHLVL and _,
10126 * and sets (but doesn't export) the following variables:
10127 * BASH=/bin/bash
10128 * BASH_VERSINFO=([0]="3" [1]="2" [2]="0" [3]="1" [4]="release" [5]="i386-pc-linux-gnu")
10129 * BASH_VERSION='3.2.0(1)-release'
10130 * HOSTTYPE=i386
10131 * MACHTYPE=i386-pc-linux-gnu
10132 * OSTYPE=linux-gnu
Denys Vlasenkodea47882009-10-09 15:40:49 +020010133 * PPID=<NNNNN> - we also do it elsewhere
Denys Vlasenko6db47842009-09-05 20:15:17 +020010134 * EUID=<NNNNN>
10135 * UID=<NNNNN>
10136 * GROUPS=()
10137 * LINES=<NNN>
10138 * COLUMNS=<NNN>
10139 * BASH_ARGC=()
10140 * BASH_ARGV=()
10141 * BASH_LINENO=()
10142 * BASH_SOURCE=()
10143 * DIRSTACK=()
10144 * PIPESTATUS=([0]="0")
10145 * HISTFILE=/<xxx>/.bash_history
10146 * HISTFILESIZE=500
10147 * HISTSIZE=500
10148 * MAILCHECK=60
10149 * PATH=/usr/gnu/bin:/usr/local/bin:/bin:/usr/bin:.
10150 * SHELL=/bin/bash
10151 * SHELLOPTS=braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor
10152 * TERM=dumb
10153 * OPTERR=1
10154 * OPTIND=1
Denys Vlasenko6db47842009-09-05 20:15:17 +020010155 * PS4='+ '
10156 */
10157
Denys Vlasenko9cabd172020-12-13 18:24:11 +010010158#if NUM_SCRIPTS > 0
10159 if (argc < 0) {
10160 char *script = get_script_content(-argc - 1);
10161 G.global_argv = argv;
10162 G.global_argc = string_array_len(argv);
Denys Vlasenko9cabd172020-12-13 18:24:11 +010010163 //install_special_sighandlers(); - needed?
10164 parse_and_run_string(script);
10165 goto final_return;
10166 }
10167#endif
10168
Eric Andersen94ac2442001-05-22 19:05:18 +000010169 /* Initialize some more globals to non-zero values */
Denys Vlasenkoe9abe752016-08-19 20:15:26 +020010170 die_func = restore_ttypgrp_and__exit;
Denis Vlasenkoed782372009-04-10 00:45:02 +000010171
Denis Vlasenkoc4a7af52009-04-05 20:33:27 +000010172 /* Shell is non-interactive at first. We need to call
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +020010173 * install_special_sighandlers() if we are going to execute "sh <script>",
Denis Vlasenkod3f973e2009-04-06 10:21:42 +000010174 * "sh -c <cmds>" or login shell's /etc/profile and friends.
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +020010175 * If we later decide that we are interactive, we run install_special_sighandlers()
Denis Vlasenkoc4a7af52009-04-05 20:33:27 +000010176 * in order to intercept (more) signals.
10177 */
10178
10179 /* Parse options */
Mike Frysinger19a7ea12009-03-28 13:02:11 +000010180 /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */
Denys Vlasenkof58f7052011-05-12 02:10:33 +020010181 flags = (argv[0] && argv[0][0] == '-') ? OPT_login : 0;
Denis Vlasenko0bb4a232009-04-05 01:42:59 +000010182 while (1) {
Denys Vlasenko3b053052021-01-04 03:05:34 +010010183 int opt = getopt(argc, argv, "+" /* stop at 1st non-option */
10184 "cexinsl"
Denis Vlasenko0bb4a232009-04-05 01:42:59 +000010185#if !BB_MMU
Denis Vlasenkobc569742009-04-12 20:35:19 +000010186 "<:$:R:V:"
10187# if ENABLE_HUSH_FUNCTIONS
10188 "F:"
10189# endif
Denis Vlasenko0bb4a232009-04-05 01:42:59 +000010190#endif
10191 );
10192 if (opt <= 0)
10193 break;
Eric Andersen25f27032001-04-26 23:22:31 +000010194 switch (opt) {
Denis Vlasenkofbf6dea2007-04-13 19:56:56 +000010195 case 'c':
Denys Vlasenko0ab2dd42020-12-23 02:22:08 +010010196 /* Note: -c is not an option with param!
Denys Vlasenko9cabd172020-12-13 18:24:11 +010010197 * "hush -c -l SCRIPT" is valid. "hush -cSCRIPT" is not.
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020010198 */
Denys Vlasenkof3634582019-06-03 12:21:04 +020010199 G.opt_c = 1;
Denys Vlasenko9cabd172020-12-13 18:24:11 +010010200 break;
Denis Vlasenkofbf6dea2007-04-13 19:56:56 +000010201 case 'i':
Denis Vlasenkoc666f712007-05-16 22:18:54 +000010202 /* Well, we cannot just declare interactiveness,
10203 * we have to have some stuff (ctty, etc) */
Denis Vlasenko60b392f2009-04-03 19:14:32 +000010204 /* G_interactive_fd++; */
Denis Vlasenkofbf6dea2007-04-13 19:56:56 +000010205 break;
Mike Frysinger19a7ea12009-03-28 13:02:11 +000010206 case 's':
Denys Vlasenkof3634582019-06-03 12:21:04 +020010207 G.opt_s = 1;
Mike Frysinger19a7ea12009-03-28 13:02:11 +000010208 break;
Denys Vlasenkof58f7052011-05-12 02:10:33 +020010209 case 'l':
10210 flags |= OPT_login;
10211 break;
Denis Vlasenko0bb4a232009-04-05 01:42:59 +000010212#if !BB_MMU
Denis Vlasenko50f3aa42009-04-07 10:52:40 +000010213 case '<': /* "big heredoc" support */
Denys Vlasenko729ecb82010-06-07 14:14:26 +020010214 full_write1_str(optarg);
Denis Vlasenko50f3aa42009-04-07 10:52:40 +000010215 _exit(0);
Denys Vlasenkoe89a2412010-01-12 15:19:31 +010010216 case '$': {
10217 unsigned long long empty_trap_mask;
10218
Denis Vlasenko34e573d2009-04-06 12:56:28 +000010219 G.root_pid = bb_strtou(optarg, &optarg, 16);
10220 optarg++;
Denys Vlasenkodea47882009-10-09 15:40:49 +020010221 G.root_ppid = bb_strtou(optarg, &optarg, 16);
10222 optarg++;
Denis Vlasenko34e573d2009-04-06 12:56:28 +000010223 G.last_bg_pid = bb_strtou(optarg, &optarg, 16);
10224 optarg++;
Denis Vlasenkoab2b0642009-04-06 18:42:11 +000010225 G.last_exitcode = bb_strtou(optarg, &optarg, 16);
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020010226 optarg++;
10227 builtin_argc = bb_strtou(optarg, &optarg, 16);
Denys Vlasenkoe89a2412010-01-12 15:19:31 +010010228 optarg++;
10229 empty_trap_mask = bb_strtoull(optarg, &optarg, 16);
10230 if (empty_trap_mask != 0) {
Denys Vlasenko4ee824f2017-07-03 01:22:13 +020010231 IF_HUSH_TRAP(int sig;)
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +020010232 install_special_sighandlers();
Denys Vlasenko4ee824f2017-07-03 01:22:13 +020010233# if ENABLE_HUSH_TRAP
Denys Vlasenko7a85c602017-01-08 17:40:18 +010010234 G_traps = xzalloc(sizeof(G_traps[0]) * NSIG);
Denys Vlasenkoe89a2412010-01-12 15:19:31 +010010235 for (sig = 1; sig < NSIG; sig++) {
10236 if (empty_trap_mask & (1LL << sig)) {
Denys Vlasenko7a85c602017-01-08 17:40:18 +010010237 G_traps[sig] = xzalloc(1); /* == xstrdup(""); */
Denys Vlasenko0806e402011-05-12 23:06:20 +020010238 install_sighandler(sig, SIG_IGN);
Denys Vlasenkoe89a2412010-01-12 15:19:31 +010010239 }
10240 }
Denys Vlasenko4ee824f2017-07-03 01:22:13 +020010241# endif
Denys Vlasenkoe89a2412010-01-12 15:19:31 +010010242 }
Denis Vlasenkod3f973e2009-04-06 10:21:42 +000010243# if ENABLE_HUSH_LOOPS
Denis Vlasenko34e573d2009-04-06 12:56:28 +000010244 optarg++;
10245 G.depth_of_loop = bb_strtou(optarg, &optarg, 16);
Denis Vlasenkod3f973e2009-04-06 10:21:42 +000010246# endif
Denys Vlasenko49142d42020-12-13 18:44:07 +010010247 /* Suppress "killed by signal" message, -$ hack is used
10248 * for subshells: echo `sh -c 'kill -9 $$'`
10249 * should be silent.
10250 */
10251 IF_HUSH_JOB(G.run_list_level = 1;)
Denys Vlasenkoeb0de052018-04-09 17:54:07 +020010252# if ENABLE_HUSH_FUNCTIONS
10253 /* nommu uses re-exec trick for "... | func | ...",
10254 * should allow "return".
10255 * This accidentally allows returns in subshells.
10256 */
10257 G_flag_return_in_progress = -1;
10258# endif
Denis Vlasenko34e573d2009-04-06 12:56:28 +000010259 break;
Denys Vlasenkoe89a2412010-01-12 15:19:31 +010010260 }
Denis Vlasenko0bb4a232009-04-05 01:42:59 +000010261 case 'R':
10262 case 'V':
Denys Vlasenko3bab36b2017-07-18 01:05:24 +020010263 set_local_var(xstrdup(optarg), opt == 'R' ? SETFLAG_MAKE_RO : 0);
Denis Vlasenko0bb4a232009-04-05 01:42:59 +000010264 break;
Denis Vlasenkobc569742009-04-12 20:35:19 +000010265# if ENABLE_HUSH_FUNCTIONS
10266 case 'F': {
10267 struct function *funcp = new_function(optarg);
10268 /* funcp->name is already set to optarg */
10269 /* funcp->body is set to NULL. It's a special case. */
10270 funcp->body_as_string = argv[optind];
10271 optind++;
10272 break;
10273 }
10274# endif
Denis Vlasenko0bb4a232009-04-05 01:42:59 +000010275#endif
Denys Vlasenko3b053052021-01-04 03:05:34 +010010276 /*case '?': invalid option encountered (set_mode('?') will fail) */
10277 /*case 'n':*/
10278 /*case 'x':*/
10279 /*case 'e':*/
10280 default:
Denys Vlasenko6696eac2010-11-14 02:01:50 +010010281 if (set_mode(1, opt, NULL) == 0) /* no error */
Mike Frysingerad88d5a2009-03-28 13:44:51 +000010282 break;
Denis Vlasenkofbf6dea2007-04-13 19:56:56 +000010283 bb_show_usage();
Eric Andersen25f27032001-04-26 23:22:31 +000010284 }
Denis Vlasenkof9375282009-04-05 19:13:39 +000010285 } /* option parsing loop */
Denis Vlasenko46f9b6d2009-04-05 10:39:03 +000010286
Denys Vlasenkof58f7052011-05-12 02:10:33 +020010287 /* Skip options. Try "hush -l": $1 should not be "-l"! */
10288 G.global_argc = argc - (optind - 1);
10289 G.global_argv = argv + (optind - 1);
10290 G.global_argv[0] = argv[0];
10291
Denis Vlasenkof9375282009-04-05 19:13:39 +000010292 /* If we are login shell... */
Denys Vlasenkof58f7052011-05-12 02:10:33 +020010293 if (flags & OPT_login) {
Denys Vlasenko63139b52020-12-13 22:00:56 +010010294 const char *hp = NULL;
Denys Vlasenko41ef41b2018-07-24 16:54:41 +020010295 HFILE *input;
Denys Vlasenko63139b52020-12-13 22:00:56 +010010296
Denis Vlasenko46f9b6d2009-04-05 10:39:03 +000010297 debug_printf("sourcing /etc/profile\n");
Denys Vlasenko41ef41b2018-07-24 16:54:41 +020010298 input = hfopen("/etc/profile");
Denys Vlasenko63139b52020-12-13 22:00:56 +010010299 run_profile:
Denis Vlasenko46f9b6d2009-04-05 10:39:03 +000010300 if (input != NULL) {
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +020010301 install_special_sighandlers();
Denis Vlasenko46f9b6d2009-04-05 10:39:03 +000010302 parse_and_run_file(input);
Denys Vlasenko41ef41b2018-07-24 16:54:41 +020010303 hfclose(input);
Denis Vlasenko46f9b6d2009-04-05 10:39:03 +000010304 }
Denis Vlasenkof9375282009-04-05 19:13:39 +000010305 /* bash: after sourcing /etc/profile,
10306 * tries to source (in the given order):
10307 * ~/.bash_profile, ~/.bash_login, ~/.profile,
Denys Vlasenko28a105d2009-06-01 11:26:30 +020010308 * stopping on first found. --noprofile turns this off.
Denis Vlasenkof9375282009-04-05 19:13:39 +000010309 * bash also sources ~/.bash_logout on exit.
10310 * If called as sh, skips .bash_XXX files.
10311 */
Denys Vlasenko63139b52020-12-13 22:00:56 +010010312 if (!hp) { /* unless we looped on the "goto" already */
10313 hp = get_local_var_value("HOME");
10314 if (hp && hp[0]) {
10315 debug_printf("sourcing ~/.profile\n");
10316 hp = concat_path_file(hp, ".profile");
10317 input = hfopen(hp);
10318 free((char*)hp);
10319 goto run_profile;
10320 }
10321 }
Denis Vlasenko46f9b6d2009-04-05 10:39:03 +000010322 }
10323
Denys Vlasenko9cabd172020-12-13 18:24:11 +010010324 /* -c takes effect *after* -l */
10325 if (G.opt_c) {
10326 /* Possibilities:
10327 * sh ... -c 'script'
10328 * sh ... -c 'script' ARG0 [ARG1...]
10329 * On NOMMU, if builtin_argc != 0,
10330 * sh ... -c 'builtin' BARGV... "" ARG0 [ARG1...]
10331 * "" needs to be replaced with NULL
10332 * and BARGV vector fed to builtin function.
10333 * Note: the form without ARG0 never happens:
10334 * sh ... -c 'builtin' BARGV... ""
10335 */
10336 char *script;
10337
10338 install_special_sighandlers();
10339
10340 G.global_argc--;
10341 G.global_argv++;
Denys Vlasenko49142d42020-12-13 18:44:07 +010010342#if !BB_MMU
Denys Vlasenko9cabd172020-12-13 18:24:11 +010010343 if (builtin_argc) {
10344 /* -c 'builtin' [BARGV...] "" ARG0 [ARG1...] */
10345 const struct built_in_command *x;
10346 x = find_builtin(G.global_argv[0]);
10347 if (x) { /* paranoia */
10348 argv = G.global_argv;
10349 G.global_argc -= builtin_argc + 1; /* skip [BARGV...] "" */
10350 G.global_argv += builtin_argc + 1;
10351 G.global_argv[-1] = NULL; /* replace "" */
10352 G.last_exitcode = x->b_function(argv);
10353 }
10354 goto final_return;
10355 }
Denys Vlasenko49142d42020-12-13 18:44:07 +010010356#endif
Denys Vlasenko9cabd172020-12-13 18:24:11 +010010357
10358 script = G.global_argv[0];
10359 if (!script)
10360 bb_error_msg_and_die(bb_msg_requires_arg, "-c");
10361 if (!G.global_argv[1]) {
10362 /* -c 'script' (no params): prevent empty $0 */
10363 G.global_argv[0] = argv[0];
10364 } else { /* else -c 'script' ARG0 [ARG1...]: $0 is ARG0 */
10365 G.global_argc--;
10366 G.global_argv++;
10367 }
10368 parse_and_run_string(script);
10369 goto final_return;
10370 }
10371
Denys Vlasenkof2ed39b2018-04-05 16:46:49 +020010372 /* -s is: hush -s ARGV1 ARGV2 (no SCRIPT) */
Denys Vlasenkof3634582019-06-03 12:21:04 +020010373 if (!G.opt_s && G.global_argv[1]) {
Denys Vlasenko41ef41b2018-07-24 16:54:41 +020010374 HFILE *input;
Denis Vlasenkof9375282009-04-05 19:13:39 +000010375 /*
Denis Vlasenkod3f973e2009-04-06 10:21:42 +000010376 * "bash <script>" (which is never interactive (unless -i?))
10377 * sources $BASH_ENV here (without scanning $PATH).
Denis Vlasenkof9375282009-04-05 19:13:39 +000010378 * If called as sh, does the same but with $ENV.
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020010379 * Also NB, per POSIX, $ENV should undergo parameter expansion.
Denis Vlasenkof9375282009-04-05 19:13:39 +000010380 */
Denys Vlasenkof58f7052011-05-12 02:10:33 +020010381 G.global_argc--;
10382 G.global_argv++;
10383 debug_printf("running script '%s'\n", G.global_argv[0]);
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010384 xfunc_error_retval = 127; /* for "hush /does/not/exist" case */
Denys Vlasenko41ef41b2018-07-24 16:54:41 +020010385 input = hfopen(G.global_argv[0]);
10386 if (!input) {
10387 bb_simple_perror_msg_and_die(G.global_argv[0]);
10388 }
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010389 xfunc_error_retval = 1;
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +020010390 install_special_sighandlers();
Denis Vlasenkof9375282009-04-05 19:13:39 +000010391 parse_and_run_file(input);
10392#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenko41ef41b2018-07-24 16:54:41 +020010393 hfclose(input);
Denis Vlasenkof9375282009-04-05 19:13:39 +000010394#endif
10395 goto final_return;
10396 }
Denys Vlasenkof3634582019-06-03 12:21:04 +020010397 /* "implicit" -s: bare interactive hush shows 's' in $- */
Denys Vlasenkod8740b22019-05-19 19:11:21 +020010398 G.opt_s = 1;
Denis Vlasenkof9375282009-04-05 19:13:39 +000010399
Denis Vlasenkoc4a7af52009-04-05 20:33:27 +000010400 /* Up to here, shell was non-interactive. Now it may become one.
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +020010401 * NB: don't forget to (re)run install_special_sighandlers() as needed.
Denis Vlasenkoc4a7af52009-04-05 20:33:27 +000010402 */
Denis Vlasenkof9375282009-04-05 19:13:39 +000010403
Denys Vlasenko28a105d2009-06-01 11:26:30 +020010404 /* A shell is interactive if the '-i' flag was given,
10405 * or if all of the following conditions are met:
Denis Vlasenko55b2de72007-04-18 17:21:28 +000010406 * no -c command
Eric Andersen25f27032001-04-26 23:22:31 +000010407 * no arguments remaining or the -s flag given
10408 * standard input is a terminal
10409 * standard output is a terminal
Denis Vlasenkof9375282009-04-05 19:13:39 +000010410 * Refer to Posix.2, the description of the 'sh' utility.
10411 */
10412#if ENABLE_HUSH_JOB
10413 if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) {
Mike Frysinger38478a62009-05-20 04:48:06 -040010414 G_saved_tty_pgrp = tcgetpgrp(STDIN_FILENO);
10415 debug_printf("saved_tty_pgrp:%d\n", G_saved_tty_pgrp);
10416 if (G_saved_tty_pgrp < 0)
10417 G_saved_tty_pgrp = 0;
Denis Vlasenkoc8653f62009-04-27 23:29:14 +000010418
10419 /* try to dup stdin to high fd#, >= 255 */
Denys Vlasenko9acd63c2018-03-28 18:35:07 +020010420 G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254);
Denis Vlasenkoc8653f62009-04-27 23:29:14 +000010421 if (G_interactive_fd < 0) {
10422 /* try to dup to any fd */
10423 G_interactive_fd = dup(STDIN_FILENO);
Denis Vlasenko60b392f2009-04-03 19:14:32 +000010424 if (G_interactive_fd < 0) {
Denis Vlasenkoc8653f62009-04-27 23:29:14 +000010425 /* give up */
10426 G_interactive_fd = 0;
Mike Frysinger38478a62009-05-20 04:48:06 -040010427 G_saved_tty_pgrp = 0;
Denis Vlasenko54e7ffb2007-04-21 00:03:36 +000010428 }
10429 }
Eric Andersen25f27032001-04-26 23:22:31 +000010430 }
Denis Vlasenkof9375282009-04-05 19:13:39 +000010431 debug_printf("interactive_fd:%d\n", G_interactive_fd);
Denis Vlasenko60b392f2009-04-03 19:14:32 +000010432 if (G_interactive_fd) {
Denis Vlasenkof9375282009-04-05 19:13:39 +000010433 close_on_exec_on(G_interactive_fd);
Denis Vlasenkoc8653f62009-04-27 23:29:14 +000010434
Mike Frysinger38478a62009-05-20 04:48:06 -040010435 if (G_saved_tty_pgrp) {
Denis Vlasenkoc8653f62009-04-27 23:29:14 +000010436 /* If we were run as 'hush &', sleep until we are
10437 * in the foreground (tty pgrp == our pgrp).
10438 * If we get started under a job aware app (like bash),
10439 * make sure we are now in charge so we don't fight over
10440 * who gets the foreground */
10441 while (1) {
10442 pid_t shell_pgrp = getpgrp();
Mike Frysinger38478a62009-05-20 04:48:06 -040010443 G_saved_tty_pgrp = tcgetpgrp(G_interactive_fd);
10444 if (G_saved_tty_pgrp == shell_pgrp)
Denis Vlasenkoc8653f62009-04-27 23:29:14 +000010445 break;
10446 /* send TTIN to ourself (should stop us) */
10447 kill(- shell_pgrp, SIGTTIN);
10448 }
Denis Vlasenkof9375282009-04-05 19:13:39 +000010449 }
Denis Vlasenkoc8653f62009-04-27 23:29:14 +000010450
Denys Vlasenkof58f7052011-05-12 02:10:33 +020010451 /* Install more signal handlers */
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +020010452 install_special_sighandlers();
Denis Vlasenkoc8653f62009-04-27 23:29:14 +000010453
Mike Frysinger38478a62009-05-20 04:48:06 -040010454 if (G_saved_tty_pgrp) {
Denis Vlasenkoc8653f62009-04-27 23:29:14 +000010455 /* Set other signals to restore saved_tty_pgrp */
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +020010456 install_fatal_sighandlers();
Denis Vlasenkoc8653f62009-04-27 23:29:14 +000010457 /* Put ourselves in our own process group
10458 * (bash, too, does this only if ctty is available) */
10459 bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */
10460 /* Grab control of the terminal */
Denys Vlasenkobb4e32b2020-12-20 16:36:00 +010010461 tcsetpgrp(G_interactive_fd, cached_getpid);
Denis Vlasenkoc8653f62009-04-27 23:29:14 +000010462 }
Denys Vlasenko550bf5b2015-10-09 16:42:57 +020010463 enable_restore_tty_pgrp_on_exit();
Denys Vlasenko4840ae82011-09-04 15:28:03 +020010464
Denys Vlasenko76a4e832019-05-19 18:24:52 +020010465# if ENABLE_FEATURE_EDITING
10466 G.line_input_state = new_line_input_t(FOR_SHELL);
Ron Yorston9e2a5662020-01-21 16:01:58 +000010467# if EDITING_HAS_get_exe_name
10468 G.line_input_state->get_exe_name = get_builtin_name;
10469# endif
Denys Vlasenko76a4e832019-05-19 18:24:52 +020010470# endif
Denys Vlasenko4840ae82011-09-04 15:28:03 +020010471# if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0
10472 {
10473 const char *hp = get_local_var_value("HISTFILE");
10474 if (!hp) {
10475 hp = get_local_var_value("HOME");
10476 if (hp)
10477 hp = concat_path_file(hp, ".hush_history");
10478 } else {
10479 hp = xstrdup(hp);
10480 }
10481 if (hp) {
10482 G.line_input_state->hist_file = hp;
Denys Vlasenko4840ae82011-09-04 15:28:03 +020010483 //set_local_var(xasprintf("HISTFILE=%s", ...));
10484 }
10485# if ENABLE_FEATURE_SH_HISTFILESIZE
10486 hp = get_local_var_value("HISTFILESIZE");
10487 G.line_input_state->max_history = size_from_HISTFILESIZE(hp);
10488# endif
10489 }
10490# endif
Denys Vlasenkoe89a2412010-01-12 15:19:31 +010010491 } else {
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +020010492 install_special_sighandlers();
Denys Vlasenkoe89a2412010-01-12 15:19:31 +010010493 }
Denis Vlasenkoe3f2f892007-04-28 16:48:27 +000010494#elif ENABLE_HUSH_INTERACTIVE
Denis Vlasenkof9375282009-04-05 19:13:39 +000010495 /* No job control compiled in, only prompt/line editing */
10496 if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) {
Denys Vlasenko9acd63c2018-03-28 18:35:07 +020010497 G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254);
Denis Vlasenko60b392f2009-04-03 19:14:32 +000010498 if (G_interactive_fd < 0) {
Denis Vlasenkoe3f2f892007-04-28 16:48:27 +000010499 /* try to dup to any fd */
Denys Vlasenkod1a83232018-06-26 15:50:33 +020010500 G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, -1);
Denis Vlasenko60b392f2009-04-03 19:14:32 +000010501 if (G_interactive_fd < 0)
Denis Vlasenkoe3f2f892007-04-28 16:48:27 +000010502 /* give up */
Denis Vlasenko60b392f2009-04-03 19:14:32 +000010503 G_interactive_fd = 0;
Denis Vlasenkoe3f2f892007-04-28 16:48:27 +000010504 }
10505 }
Denis Vlasenko60b392f2009-04-03 19:14:32 +000010506 if (G_interactive_fd) {
Denis Vlasenkof9375282009-04-05 19:13:39 +000010507 close_on_exec_on(G_interactive_fd);
Denis Vlasenkof9375282009-04-05 19:13:39 +000010508 }
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +020010509 install_special_sighandlers();
Denis Vlasenkof9375282009-04-05 19:13:39 +000010510#else
10511 /* We have interactiveness code disabled */
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +020010512 install_special_sighandlers();
Denis Vlasenkof9375282009-04-05 19:13:39 +000010513#endif
10514 /* bash:
10515 * if interactive but not a login shell, sources ~/.bashrc
10516 * (--norc turns this off, --rcfile <file> overrides)
10517 */
10518
Denys Vlasenko0c360192019-05-19 15:37:50 +020010519 if (G_interactive_fd) {
10520#if ENABLE_HUSH_INTERACTIVE && ENABLE_FEATURE_EDITING_FANCY_PROMPT
10521 /* Set (but not export) PS1/2 unless already set */
10522 if (!get_local_var_value("PS1"))
10523 set_local_var_from_halves("PS1", "\\w \\$ ");
10524 if (!get_local_var_value("PS2"))
10525 set_local_var_from_halves("PS2", "> ");
10526#endif
10527 if (!ENABLE_FEATURE_SH_EXTRA_QUIET) {
10528 /* note: ash and hush share this string */
10529 printf("\n\n%s %s\n"
10530 IF_HUSH_HELP("Enter 'help' for a list of built-in commands.\n")
10531 "\n",
10532 bb_banner,
10533 "hush - the humble shell"
10534 );
10535 }
Mike Frysingerb2705e12009-03-23 08:44:02 +000010536 }
10537
Denys Vlasenko41ef41b2018-07-24 16:54:41 +020010538 parse_and_run_file(hfopen(NULL)); /* stdin */
Eric Andersen25f27032001-04-26 23:22:31 +000010539
Denis Vlasenkod76c0492007-05-25 02:16:25 +000010540 final_return:
Denis Vlasenkoab2b0642009-04-06 18:42:11 +000010541 hush_exit(G.last_exitcode);
Eric Andersen25f27032001-04-26 23:22:31 +000010542}
Denis Vlasenko96702ca2007-11-23 23:28:55 +000010543
10544
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000010545/*
10546 * Built-ins
10547 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010548static int FAST_FUNC builtin_true(char **argv UNUSED_PARAM)
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000010549{
10550 return 0;
10551}
10552
Denys Vlasenko265062d2017-01-10 15:13:30 +010010553#if ENABLE_HUSH_TEST || ENABLE_HUSH_ECHO || ENABLE_HUSH_PRINTF || ENABLE_HUSH_KILL
Denys Vlasenkoa8e19602020-12-14 03:52:54 +010010554static NOINLINE int run_applet_main(char **argv, int (*applet_main_func)(int argc, char **argv))
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000010555{
Denys Vlasenkod4e4fdb2017-07-03 21:31:16 +020010556 int argc = string_array_len(argv);
10557 return applet_main_func(argc, argv);
Mike Frysingerccb19592009-10-15 03:31:15 -040010558}
Denys Vlasenko265062d2017-01-10 15:13:30 +010010559#endif
Kang-Che Sung027d3ab2017-01-11 14:18:15 +010010560#if ENABLE_HUSH_TEST || BASH_TEST2
Mike Frysingerccb19592009-10-15 03:31:15 -040010561static int FAST_FUNC builtin_test(char **argv)
10562{
Denys Vlasenkoc0836532009-10-19 13:13:06 +020010563 return run_applet_main(argv, test_main);
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000010564}
Denys Vlasenko265062d2017-01-10 15:13:30 +010010565#endif
Denys Vlasenko1cc68042017-01-09 17:10:04 +010010566#if ENABLE_HUSH_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010567static int FAST_FUNC builtin_echo(char **argv)
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000010568{
Denys Vlasenkoc0836532009-10-19 13:13:06 +020010569 return run_applet_main(argv, echo_main);
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000010570}
Denys Vlasenko1cc68042017-01-09 17:10:04 +010010571#endif
Denys Vlasenko1125d7d2017-01-08 17:19:38 +010010572#if ENABLE_HUSH_PRINTF
Mike Frysinger4ebc76c2009-10-15 03:32:39 -040010573static int FAST_FUNC builtin_printf(char **argv)
10574{
Denys Vlasenkoc0836532009-10-19 13:13:06 +020010575 return run_applet_main(argv, printf_main);
Mike Frysinger4ebc76c2009-10-15 03:32:39 -040010576}
10577#endif
10578
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010010579#if ENABLE_HUSH_HELP
10580static int FAST_FUNC builtin_help(char **argv UNUSED_PARAM)
10581{
10582 const struct built_in_command *x;
10583
10584 printf(
10585 "Built-in commands:\n"
10586 "------------------\n");
10587 for (x = bltins1; x != &bltins1[ARRAY_SIZE(bltins1)]; x++) {
10588 if (x->b_descr)
10589 printf("%-10s%s\n", x->b_cmd, x->b_descr);
10590 }
10591 return EXIT_SUCCESS;
10592}
10593#endif
10594
10595#if MAX_HISTORY && ENABLE_FEATURE_EDITING
10596static int FAST_FUNC builtin_history(char **argv UNUSED_PARAM)
10597{
Ron Yorston9f3b4102019-12-16 09:31:10 +000010598 show_history(G.line_input_state);
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010010599 return EXIT_SUCCESS;
10600}
10601#endif
10602
Denys Vlasenkob131cce2010-05-20 03:39:43 +020010603static char **skip_dash_dash(char **argv)
10604{
10605 argv++;
10606 if (argv[0] && argv[0][0] == '-' && argv[0][1] == '-' && argv[0][2] == '\0')
10607 argv++;
10608 return argv;
10609}
10610
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010611static int FAST_FUNC builtin_cd(char **argv)
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000010612{
Denys Vlasenkob131cce2010-05-20 03:39:43 +020010613 const char *newdir;
10614
10615 argv = skip_dash_dash(argv);
10616 newdir = argv[0];
Denis Vlasenkobfbc9712009-04-06 12:04:42 +000010617 if (newdir == NULL) {
Denis Vlasenkob6e65562009-04-03 16:49:04 +000010618 /* bash does nothing (exitcode 0) if HOME is ""; if it's unset,
Denis Vlasenko0b677d82009-04-10 13:49:10 +000010619 * bash says "bash: cd: HOME not set" and does nothing
10620 * (exitcode 1)
Denis Vlasenkob6e65562009-04-03 16:49:04 +000010621 */
Denys Vlasenko90a99042009-09-06 02:36:23 +020010622 const char *home = get_local_var_value("HOME");
10623 newdir = home ? home : "/";
Denis Vlasenkob0a64782009-04-06 11:33:07 +000010624 }
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000010625 if (chdir(newdir)) {
Denis Vlasenkobfbc9712009-04-06 12:04:42 +000010626 /* Mimic bash message exactly */
10627 bb_perror_msg("cd: %s", newdir);
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000010628 return EXIT_FAILURE;
10629 }
Denys Vlasenko6db47842009-09-05 20:15:17 +020010630 /* Read current dir (get_cwd(1) is inside) and set PWD.
10631 * Note: do not enforce exporting. If PWD was unset or unexported,
10632 * set it again, but do not export. bash does the same.
10633 */
Denys Vlasenko3bab36b2017-07-18 01:05:24 +020010634 set_pwd_var(/*flag:*/ 0);
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000010635 return EXIT_SUCCESS;
10636}
10637
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010010638static int FAST_FUNC builtin_pwd(char **argv UNUSED_PARAM)
10639{
10640 puts(get_cwd(0));
10641 return EXIT_SUCCESS;
10642}
10643
10644static int FAST_FUNC builtin_eval(char **argv)
10645{
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010010646 argv = skip_dash_dash(argv);
Denys Vlasenko1f191122018-01-11 13:17:30 +010010647
Denys Vlasenkob0441a72018-07-15 18:03:56 +020010648 if (!argv[0])
10649 return EXIT_SUCCESS;
Denys Vlasenko1f191122018-01-11 13:17:30 +010010650
Denys Vlasenko7c5f18a2018-07-26 15:21:50 +020010651 IF_HUSH_MODE_X(G.x_mode_depth++;)
Denys Vlasenko9dda9272018-07-27 14:12:05 +020010652 //bb_error_msg("%s: ++x_mode_depth=%d", __func__, G.x_mode_depth);
Denys Vlasenkob0441a72018-07-15 18:03:56 +020010653 if (!argv[1]) {
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010010654 /* bash:
10655 * eval "echo Hi; done" ("done" is syntax error):
10656 * "echo Hi" will not execute too.
10657 */
Denys Vlasenkob0441a72018-07-15 18:03:56 +020010658 parse_and_run_string(argv[0]);
10659 } else {
10660 /* "The eval utility shall construct a command by
10661 * concatenating arguments together, separating
10662 * each with a <space> character."
10663 */
10664 char *str, *p;
10665 unsigned len = 0;
10666 char **pp = argv;
10667 do
10668 len += strlen(*pp) + 1;
10669 while (*++pp);
10670 str = p = xmalloc(len);
10671 pp = argv;
10672 for (;;) {
10673 p = stpcpy(p, *pp);
10674 pp++;
10675 if (!*pp)
10676 break;
10677 *p++ = ' ';
10678 }
10679 parse_and_run_string(str);
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010010680 free(str);
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010010681 }
Denys Vlasenko7c5f18a2018-07-26 15:21:50 +020010682 IF_HUSH_MODE_X(G.x_mode_depth--;)
Denys Vlasenko9dda9272018-07-27 14:12:05 +020010683 //bb_error_msg("%s: --x_mode_depth=%d", __func__, G.x_mode_depth);
Denys Vlasenkob0441a72018-07-15 18:03:56 +020010684 return G.last_exitcode;
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010010685}
10686
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010687static int FAST_FUNC builtin_exec(char **argv)
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000010688{
Denys Vlasenkob131cce2010-05-20 03:39:43 +020010689 argv = skip_dash_dash(argv);
10690 if (argv[0] == NULL)
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000010691 return EXIT_SUCCESS; /* bash does this */
Denys Vlasenkof37eb392009-10-18 11:46:35 +020010692
Denys Vlasenkof37eb392009-10-18 11:46:35 +020010693 /* Careful: we can end up here after [v]fork. Do not restore
10694 * tty pgrp then, only top-level shell process does that */
10695 if (G_saved_tty_pgrp && getpid() == G.root_pid)
10696 tcsetpgrp(G_interactive_fd, G_saved_tty_pgrp);
10697
Denys Vlasenko5b3d2eb2017-07-31 18:02:28 +020010698 /* Saved-redirect fds, script fds and G_interactive_fd are still
10699 * open here. However, they are all CLOEXEC, and execv below
10700 * closes them. Try interactive "exec ls -l /proc/self/fd",
10701 * it should show no extra open fds in the "ls" process.
10702 * If we'd try to run builtins/NOEXECs, this would need improving.
10703 */
10704 //close_saved_fds_and_FILE_fds();
10705
Denys Vlasenko3ef4f772009-10-19 23:09:06 +020010706 /* TODO: if exec fails, bash does NOT exit! We do.
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +020010707 * We'll need to undo trap cleanup (it's inside execvp_or_die)
Denys Vlasenko3ef4f772009-10-19 23:09:06 +020010708 * and tcsetpgrp, and this is inherently racy.
10709 */
10710 execvp_or_die(argv);
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000010711}
10712
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010713static int FAST_FUNC builtin_exit(char **argv)
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000010714{
Denis Vlasenkocd418a22009-04-06 18:08:35 +000010715 debug_printf_exec("%s()\n", __func__);
Denis Vlasenko40e84372009-04-18 11:23:38 +000010716
10717 /* interactive bash:
10718 * # trap "echo EEE" EXIT
10719 * # exit
10720 * exit
10721 * There are stopped jobs.
10722 * (if there are _stopped_ jobs, running ones don't count)
10723 * # exit
10724 * exit
Denys Vlasenko6830ade2013-01-15 13:58:01 +010010725 * EEE (then bash exits)
Denis Vlasenko40e84372009-04-18 11:23:38 +000010726 *
Denys Vlasenkoa110c902010-09-12 15:38:04 +020010727 * TODO: we can use G.exiting = -1 as indicator "last cmd was exit"
Denis Vlasenko40e84372009-04-18 11:23:38 +000010728 */
Denis Vlasenkoefea9d22009-04-09 13:43:11 +000010729
10730 /* note: EXIT trap is run by hush_exit */
Denys Vlasenkob131cce2010-05-20 03:39:43 +020010731 argv = skip_dash_dash(argv);
Denys Vlasenkocc9ecd92020-02-21 02:18:06 +010010732 if (argv[0] == NULL) {
10733#if ENABLE_HUSH_TRAP
10734 if (G.pre_trap_exitcode >= 0) /* "exit" in trap uses $? from before the trap */
10735 hush_exit(G.pre_trap_exitcode);
10736#endif
Denis Vlasenkoab2b0642009-04-06 18:42:11 +000010737 hush_exit(G.last_exitcode);
Denys Vlasenkocc9ecd92020-02-21 02:18:06 +010010738 }
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000010739 /* mimic bash: exit 123abc == exit 255 + error msg */
10740 xfunc_error_retval = 255;
10741 /* bash: exit -2 == exit 254, no error msg */
Denys Vlasenkob131cce2010-05-20 03:39:43 +020010742 hush_exit(xatoi(argv[0]) & 0xff);
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000010743}
10744
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010010745#if ENABLE_HUSH_TYPE
10746/* http://www.opengroup.org/onlinepubs/9699919799/utilities/type.html */
10747static int FAST_FUNC builtin_type(char **argv)
10748{
10749 int ret = EXIT_SUCCESS;
10750
10751 while (*++argv) {
10752 const char *type;
10753 char *path = NULL;
10754
10755 if (0) {} /* make conditional compile easier below */
10756 /*else if (find_alias(*argv))
10757 type = "an alias";*/
Denys Vlasenko259747c2019-11-28 10:28:14 +010010758# if ENABLE_HUSH_FUNCTIONS
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010010759 else if (find_function(*argv))
10760 type = "a function";
Denys Vlasenko259747c2019-11-28 10:28:14 +010010761# endif
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010010762 else if (find_builtin(*argv))
10763 type = "a shell builtin";
10764 else if ((path = find_in_path(*argv)) != NULL)
10765 type = path;
10766 else {
10767 bb_error_msg("type: %s: not found", *argv);
10768 ret = EXIT_FAILURE;
10769 continue;
10770 }
10771
10772 printf("%s is %s\n", *argv, type);
10773 free(path);
10774 }
10775
10776 return ret;
10777}
10778#endif
10779
10780#if ENABLE_HUSH_READ
10781/* Interruptibility of read builtin in bash
10782 * (tested on bash-4.2.8 by sending signals (not by ^C)):
10783 *
10784 * Empty trap makes read ignore corresponding signal, for any signal.
10785 *
10786 * SIGINT:
10787 * - terminates non-interactive shell;
10788 * - interrupts read in interactive shell;
10789 * if it has non-empty trap:
10790 * - executes trap and returns to command prompt in interactive shell;
10791 * - executes trap and returns to read in non-interactive shell;
10792 * SIGTERM:
10793 * - is ignored (does not interrupt) read in interactive shell;
10794 * - terminates non-interactive shell;
10795 * if it has non-empty trap:
10796 * - executes trap and returns to read;
10797 * SIGHUP:
10798 * - terminates shell (regardless of interactivity);
10799 * if it has non-empty trap:
10800 * - executes trap and returns to read;
Denys Vlasenkof5470412017-05-22 19:34:45 +020010801 * SIGCHLD from children:
10802 * - does not interrupt read regardless of interactivity:
10803 * try: sleep 1 & read x; echo $x
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010010804 */
10805static int FAST_FUNC builtin_read(char **argv)
10806{
10807 const char *r;
Denys Vlasenko19358cc2018-08-05 15:42:29 +020010808 struct builtin_read_params params;
10809
10810 memset(&params, 0, sizeof(params));
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010010811
10812 /* "!": do not abort on errors.
10813 * Option string must start with "sr" to match BUILTIN_READ_xxx
10814 */
Denys Vlasenko19358cc2018-08-05 15:42:29 +020010815 params.read_flags = getopt32(argv,
Denys Vlasenko259747c2019-11-28 10:28:14 +010010816# if BASH_READ_D
Denys Vlasenko457825f2021-06-06 12:07:11 +020010817 IF_NOT_HUSH_BASH_COMPAT("^")
10818 "!srn:p:t:u:d:" IF_NOT_HUSH_BASH_COMPAT("\0" "-1"/*min 1 arg*/),
10819 &params.opt_n, &params.opt_p, &params.opt_t, &params.opt_u, &params.opt_d
Denys Vlasenko259747c2019-11-28 10:28:14 +010010820# else
Denys Vlasenko457825f2021-06-06 12:07:11 +020010821 IF_NOT_HUSH_BASH_COMPAT("^")
10822 "!srn:p:t:u:" IF_NOT_HUSH_BASH_COMPAT("\0" "-1"/*min 1 arg*/),
10823 &params.opt_n, &params.opt_p, &params.opt_t, &params.opt_u
Denys Vlasenko259747c2019-11-28 10:28:14 +010010824# endif
Denys Vlasenko457825f2021-06-06 12:07:11 +020010825//TODO: print "read: need variable name"
10826//for the case of !BASH "read" with no args (now it fails silently)
10827//(or maybe extend getopt32() to emit a message if "-1" fails)
Denys Vlasenko1f41c882017-08-09 13:52:36 +020010828 );
Denys Vlasenko19358cc2018-08-05 15:42:29 +020010829 if ((uint32_t)params.read_flags == (uint32_t)-1)
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010010830 return EXIT_FAILURE;
10831 argv += optind;
Denys Vlasenko19358cc2018-08-05 15:42:29 +020010832 params.argv = argv;
10833 params.setvar = set_local_var_from_halves;
10834 params.ifs = get_local_var_value("IFS"); /* can be NULL */
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010010835
10836 again:
Denys Vlasenko19358cc2018-08-05 15:42:29 +020010837 r = shell_builtin_read(&params);
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010010838
10839 if ((uintptr_t)r == 1 && errno == EINTR) {
10840 unsigned sig = check_and_run_traps();
Denys Vlasenkof5470412017-05-22 19:34:45 +020010841 if (sig != SIGINT)
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010010842 goto again;
10843 }
10844
10845 if ((uintptr_t)r > 1) {
James Byrne69374872019-07-02 11:35:03 +020010846 bb_simple_error_msg(r);
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010010847 r = (char*)(uintptr_t)1;
10848 }
10849
10850 return (uintptr_t)r;
10851}
10852#endif
10853
10854#if ENABLE_HUSH_UMASK
10855static int FAST_FUNC builtin_umask(char **argv)
10856{
10857 int rc;
10858 mode_t mask;
10859
10860 rc = 1;
10861 mask = umask(0);
10862 argv = skip_dash_dash(argv);
10863 if (argv[0]) {
10864 mode_t old_mask = mask;
10865
10866 /* numeric umasks are taken as-is */
10867 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
10868 if (!isdigit(argv[0][0]))
10869 mask ^= 0777;
10870 mask = bb_parse_mode(argv[0], mask);
10871 if (!isdigit(argv[0][0]))
10872 mask ^= 0777;
10873 if ((unsigned)mask > 0777) {
10874 mask = old_mask;
10875 /* bash messages:
10876 * bash: umask: 'q': invalid symbolic mode operator
10877 * bash: umask: 999: octal number out of range
10878 */
10879 bb_error_msg("%s: invalid mode '%s'", "umask", argv[0]);
10880 rc = 0;
10881 }
10882 } else {
10883 /* Mimic bash */
10884 printf("%04o\n", (unsigned) mask);
10885 /* fall through and restore mask which we set to 0 */
10886 }
10887 umask(mask);
10888
10889 return !rc; /* rc != 0 - success */
10890}
10891#endif
10892
Denys Vlasenko41ade052017-01-08 18:56:24 +010010893#if ENABLE_HUSH_EXPORT || ENABLE_HUSH_TRAP
Denis Vlasenko38e626d2009-04-18 12:58:19 +000010894static void print_escaped(const char *s)
10895{
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020010896 if (*s == '\'')
10897 goto squote;
Denis Vlasenko38e626d2009-04-18 12:58:19 +000010898 do {
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020010899 const char *p = strchrnul(s, '\'');
10900 /* print 'xxxx', possibly just '' */
10901 printf("'%.*s'", (int)(p - s), s);
10902 if (*p == '\0')
10903 break;
10904 s = p;
10905 squote:
Denis Vlasenko38e626d2009-04-18 12:58:19 +000010906 /* s points to '; print "'''...'''" */
10907 putchar('"');
10908 do putchar('\''); while (*++s == '\'');
10909 putchar('"');
10910 } while (*s);
10911}
Denys Vlasenko41ade052017-01-08 18:56:24 +010010912#endif
Denis Vlasenko38e626d2009-04-18 12:58:19 +000010913
Denys Vlasenko1e660422017-07-17 21:10:50 +020010914#if ENABLE_HUSH_EXPORT || ENABLE_HUSH_LOCAL || ENABLE_HUSH_READONLY
Denys Vlasenko3bab36b2017-07-18 01:05:24 +020010915static int helper_export_local(char **argv, unsigned flags)
Denys Vlasenko295fef82009-06-03 12:47:26 +020010916{
10917 do {
10918 char *name = *argv;
Denys Vlasenkod8bd7012019-05-14 18:53:24 +020010919 const char *name_end = endofname(name);
Denys Vlasenko295fef82009-06-03 12:47:26 +020010920
Denys Vlasenko27c56f12010-09-07 09:56:34 +020010921 if (*name_end == '\0') {
10922 struct variable *var, **vpp;
Denys Vlasenko295fef82009-06-03 12:47:26 +020010923
Denys Vlasenko27c56f12010-09-07 09:56:34 +020010924 vpp = get_ptr_to_local_var(name, name_end - name);
10925 var = vpp ? *vpp : NULL;
10926
Denys Vlasenko3bab36b2017-07-18 01:05:24 +020010927 if (flags & SETFLAG_UNEXPORT) {
Denys Vlasenko295fef82009-06-03 12:47:26 +020010928 /* export -n NAME (without =VALUE) */
10929 if (var) {
10930 var->flg_export = 0;
10931 debug_printf_env("%s: unsetenv '%s'\n", __func__, name);
10932 unsetenv(name);
10933 } /* else: export -n NOT_EXISTING_VAR: no-op */
10934 continue;
10935 }
Denys Vlasenko3bab36b2017-07-18 01:05:24 +020010936 if (flags & SETFLAG_EXPORT) {
Denys Vlasenko295fef82009-06-03 12:47:26 +020010937 /* export NAME (without =VALUE) */
10938 if (var) {
10939 var->flg_export = 1;
10940 debug_printf_env("%s: putenv '%s'\n", __func__, var->varstr);
10941 putenv(var->varstr);
10942 continue;
10943 }
10944 }
Denys Vlasenko38ef39a2017-07-18 01:40:01 +020010945 if (flags & SETFLAG_MAKE_RO) {
10946 /* readonly NAME (without =VALUE) */
10947 if (var) {
10948 var->flg_read_only = 1;
10949 continue;
10950 }
10951 }
Denys Vlasenko6ec76d82017-01-08 18:40:41 +010010952# if ENABLE_HUSH_LOCAL
Denys Vlasenkob95ee962017-07-17 21:19:53 +020010953 /* Is this "local" bltin? */
Denys Vlasenko3bab36b2017-07-18 01:05:24 +020010954 if (!(flags & (SETFLAG_EXPORT|SETFLAG_UNEXPORT|SETFLAG_MAKE_RO))) {
Denys Vlasenko332e4112018-04-04 22:32:59 +020010955 unsigned lvl = flags >> SETFLAG_VARLVL_SHIFT;
10956 if (var && var->var_nest_level == lvl) {
Denys Vlasenkob95ee962017-07-17 21:19:53 +020010957 /* "local x=abc; ...; local x" - ignore second local decl */
10958 continue;
10959 }
Denys Vlasenko61508d92016-10-02 21:12:02 +020010960 }
Denys Vlasenko6ec76d82017-01-08 18:40:41 +010010961# endif
Denys Vlasenko295fef82009-06-03 12:47:26 +020010962 /* Exporting non-existing variable.
10963 * bash does not put it in environment,
10964 * but remembers that it is exported,
10965 * and does put it in env when it is set later.
Denys Vlasenko1e660422017-07-17 21:10:50 +020010966 * We just set it to "" and export.
10967 */
Denys Vlasenko295fef82009-06-03 12:47:26 +020010968 /* Or, it's "local NAME" (without =VALUE).
Denys Vlasenko1e660422017-07-17 21:10:50 +020010969 * bash sets the value to "".
10970 */
10971 /* Or, it's "readonly NAME" (without =VALUE).
10972 * bash remembers NAME and disallows its creation
10973 * in the future.
10974 */
Denys Vlasenko295fef82009-06-03 12:47:26 +020010975 name = xasprintf("%s=", name);
10976 } else {
Denys Vlasenkod8bd7012019-05-14 18:53:24 +020010977 if (*name_end != '=') {
10978 bb_error_msg("'%s': bad variable name", name);
10979 /* do not parse following argv[]s: */
10980 return 1;
10981 }
Denys Vlasenko295fef82009-06-03 12:47:26 +020010982 /* (Un)exporting/making local NAME=VALUE */
10983 name = xstrdup(name);
Denys Vlasenkod8bd7012019-05-14 18:53:24 +020010984 /* Testcase: export PS1='\w \$ ' */
10985 unbackslash(name);
Denys Vlasenko295fef82009-06-03 12:47:26 +020010986 }
Denys Vlasenko21b7f1b2018-04-05 15:15:53 +020010987 debug_printf_env("%s: set_local_var('%s')\n", __func__, name);
Denys Vlasenko38ef39a2017-07-18 01:40:01 +020010988 if (set_local_var(name, flags))
10989 return EXIT_FAILURE;
Denys Vlasenko295fef82009-06-03 12:47:26 +020010990 } while (*++argv);
Denys Vlasenko1e660422017-07-17 21:10:50 +020010991 return EXIT_SUCCESS;
Denys Vlasenko295fef82009-06-03 12:47:26 +020010992}
Denys Vlasenko6ec76d82017-01-08 18:40:41 +010010993#endif
Denys Vlasenko295fef82009-06-03 12:47:26 +020010994
Denys Vlasenko6ec76d82017-01-08 18:40:41 +010010995#if ENABLE_HUSH_EXPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010996static int FAST_FUNC builtin_export(char **argv)
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000010997{
Denis Vlasenkoad4bd052009-04-20 22:04:21 +000010998 unsigned opt_unexport;
10999
Denys Vlasenko259747c2019-11-28 10:28:14 +010011000# if ENABLE_HUSH_EXPORT_N
Denys Vlasenkodf5131c2009-06-07 16:04:17 +020011001 /* "!": do not abort on errors */
11002 opt_unexport = getopt32(argv, "!n");
11003 if (opt_unexport == (uint32_t)-1)
11004 return EXIT_FAILURE;
11005 argv += optind;
Denys Vlasenko259747c2019-11-28 10:28:14 +010011006# else
Denys Vlasenkodf5131c2009-06-07 16:04:17 +020011007 opt_unexport = 0;
11008 argv++;
Denys Vlasenko259747c2019-11-28 10:28:14 +010011009# endif
Denys Vlasenkodf5131c2009-06-07 16:04:17 +020011010
11011 if (argv[0] == NULL) {
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000011012 char **e = environ;
Denis Vlasenko0b677d82009-04-10 13:49:10 +000011013 if (e) {
11014 while (*e) {
Denys Vlasenko259747c2019-11-28 10:28:14 +010011015# if 0
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000011016 puts(*e++);
Denys Vlasenko259747c2019-11-28 10:28:14 +010011017# else
Denis Vlasenko0b677d82009-04-10 13:49:10 +000011018 /* ash emits: export VAR='VAL'
11019 * bash: declare -x VAR="VAL"
11020 * we follow ash example */
11021 const char *s = *e++;
11022 const char *p = strchr(s, '=');
11023
11024 if (!p) /* wtf? take next variable */
11025 continue;
11026 /* export var= */
11027 printf("export %.*s", (int)(p - s) + 1, s);
Denis Vlasenko38e626d2009-04-18 12:58:19 +000011028 print_escaped(p + 1);
Denis Vlasenko0b677d82009-04-10 13:49:10 +000011029 putchar('\n');
Denys Vlasenko259747c2019-11-28 10:28:14 +010011030# endif
Denis Vlasenko0b677d82009-04-10 13:49:10 +000011031 }
Denys Vlasenko8131eea2009-11-02 14:19:51 +010011032 /*fflush_all(); - done after each builtin anyway */
Denis Vlasenko0b677d82009-04-10 13:49:10 +000011033 }
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000011034 return EXIT_SUCCESS;
11035 }
11036
Denys Vlasenko3bab36b2017-07-18 01:05:24 +020011037 return helper_export_local(argv, opt_unexport ? SETFLAG_UNEXPORT : SETFLAG_EXPORT);
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000011038}
Denys Vlasenko6ec76d82017-01-08 18:40:41 +010011039#endif
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000011040
Denys Vlasenko295fef82009-06-03 12:47:26 +020011041#if ENABLE_HUSH_LOCAL
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011042static int FAST_FUNC builtin_local(char **argv)
Denys Vlasenko295fef82009-06-03 12:47:26 +020011043{
11044 if (G.func_nest_level == 0) {
11045 bb_error_msg("%s: not in a function", argv[0]);
11046 return EXIT_FAILURE; /* bash compat */
11047 }
Denys Vlasenko1e660422017-07-17 21:10:50 +020011048 argv++;
Denys Vlasenkod358b0b2018-04-05 00:51:55 +020011049 /* Since all builtins run in a nested variable level,
11050 * need to use level - 1 here. Or else the variable will be removed at once
11051 * after builtin returns.
11052 */
11053 return helper_export_local(argv, (G.var_nest_level - 1) << SETFLAG_VARLVL_SHIFT);
Denys Vlasenko295fef82009-06-03 12:47:26 +020011054}
11055#endif
11056
Denys Vlasenko1e660422017-07-17 21:10:50 +020011057#if ENABLE_HUSH_READONLY
11058static int FAST_FUNC builtin_readonly(char **argv)
11059{
Denys Vlasenko3bab36b2017-07-18 01:05:24 +020011060 argv++;
11061 if (*argv == NULL) {
Denys Vlasenko1e660422017-07-17 21:10:50 +020011062 /* bash: readonly [-p]: list all readonly VARs
11063 * (-p has no effect in bash)
11064 */
11065 struct variable *e;
11066 for (e = G.top_var; e; e = e->next) {
11067 if (e->flg_read_only) {
11068//TODO: quote value: readonly VAR='VAL'
11069 printf("readonly %s\n", e->varstr);
11070 }
11071 }
11072 return EXIT_SUCCESS;
11073 }
Denys Vlasenko3bab36b2017-07-18 01:05:24 +020011074 return helper_export_local(argv, SETFLAG_MAKE_RO);
Denys Vlasenko1e660422017-07-17 21:10:50 +020011075}
11076#endif
11077
Denys Vlasenko10d5ece2017-01-08 18:28:43 +010011078#if ENABLE_HUSH_UNSET
Denys Vlasenko61508d92016-10-02 21:12:02 +020011079/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#unset */
11080static int FAST_FUNC builtin_unset(char **argv)
11081{
11082 int ret;
11083 unsigned opts;
11084
11085 /* "!": do not abort on errors */
11086 /* "+": stop at 1st non-option */
11087 opts = getopt32(argv, "!+vf");
11088 if (opts == (unsigned)-1)
11089 return EXIT_FAILURE;
11090 if (opts == 3) {
James Byrne69374872019-07-02 11:35:03 +020011091 bb_simple_error_msg("unset: -v and -f are exclusive");
Denys Vlasenko61508d92016-10-02 21:12:02 +020011092 return EXIT_FAILURE;
11093 }
11094 argv += optind;
11095
11096 ret = EXIT_SUCCESS;
11097 while (*argv) {
11098 if (!(opts & 2)) { /* not -f */
11099 if (unset_local_var(*argv)) {
11100 /* unset <nonexistent_var> doesn't fail.
11101 * Error is when one tries to unset RO var.
11102 * Message was printed by unset_local_var. */
11103 ret = EXIT_FAILURE;
11104 }
11105 }
Denys Vlasenko10d5ece2017-01-08 18:28:43 +010011106# if ENABLE_HUSH_FUNCTIONS
Denys Vlasenko61508d92016-10-02 21:12:02 +020011107 else {
11108 unset_func(*argv);
11109 }
Denys Vlasenko10d5ece2017-01-08 18:28:43 +010011110# endif
Denys Vlasenko61508d92016-10-02 21:12:02 +020011111 argv++;
11112 }
11113 return ret;
11114}
Denys Vlasenko10d5ece2017-01-08 18:28:43 +010011115#endif
Denys Vlasenko61508d92016-10-02 21:12:02 +020011116
Denys Vlasenko10d5ece2017-01-08 18:28:43 +010011117#if ENABLE_HUSH_SET
Denys Vlasenko61508d92016-10-02 21:12:02 +020011118/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set
11119 * built-in 'set' handler
11120 * SUSv3 says:
11121 * set [-abCefhmnuvx] [-o option] [argument...]
11122 * set [+abCefhmnuvx] [+o option] [argument...]
11123 * set -- [argument...]
11124 * set -o
11125 * set +o
11126 * Implementations shall support the options in both their hyphen and
11127 * plus-sign forms. These options can also be specified as options to sh.
11128 * Examples:
11129 * Write out all variables and their values: set
11130 * Set $1, $2, and $3 and set "$#" to 3: set c a b
11131 * Turn on the -x and -v options: set -xv
11132 * Unset all positional parameters: set --
11133 * Set $1 to the value of x, even if it begins with '-' or '+': set -- "$x"
11134 * Set the positional parameters to the expansion of x, even if x expands
11135 * with a leading '-' or '+': set -- $x
11136 *
11137 * So far, we only support "set -- [argument...]" and some of the short names.
11138 */
11139static int FAST_FUNC builtin_set(char **argv)
11140{
11141 int n;
11142 char **pp, **g_argv;
11143 char *arg = *++argv;
11144
11145 if (arg == NULL) {
11146 struct variable *e;
11147 for (e = G.top_var; e; e = e->next)
11148 puts(e->varstr);
11149 return EXIT_SUCCESS;
11150 }
11151
11152 do {
11153 if (strcmp(arg, "--") == 0) {
11154 ++argv;
11155 goto set_argv;
11156 }
11157 if (arg[0] != '+' && arg[0] != '-')
11158 break;
11159 for (n = 1; arg[n]; ++n) {
Denys Vlasenko18a90ec2019-09-05 14:07:14 +020011160 if (set_mode((arg[0] == '-'), arg[n], argv[1])) {
11161 bb_error_msg("%s: %s: invalid option", "set", arg);
11162 return EXIT_FAILURE;
11163 }
Denys Vlasenko61508d92016-10-02 21:12:02 +020011164 if (arg[n] == 'o' && argv[1])
11165 argv++;
11166 }
11167 } while ((arg = *++argv) != NULL);
11168 /* Now argv[0] is 1st argument */
11169
11170 if (arg == NULL)
11171 return EXIT_SUCCESS;
11172 set_argv:
11173
11174 /* NB: G.global_argv[0] ($0) is never freed/changed */
11175 g_argv = G.global_argv;
11176 if (G.global_args_malloced) {
11177 pp = g_argv;
11178 while (*++pp)
11179 free(*pp);
11180 g_argv[1] = NULL;
11181 } else {
11182 G.global_args_malloced = 1;
11183 pp = xzalloc(sizeof(pp[0]) * 2);
11184 pp[0] = g_argv[0]; /* retain $0 */
11185 g_argv = pp;
11186 }
11187 /* This realloc's G.global_argv */
11188 G.global_argv = pp = add_strings_to_strings(g_argv, argv, /*dup:*/ 1);
11189
Denys Vlasenkod4e4fdb2017-07-03 21:31:16 +020011190 G.global_argc = 1 + string_array_len(pp + 1);
Denys Vlasenko61508d92016-10-02 21:12:02 +020011191
11192 return EXIT_SUCCESS;
Denys Vlasenko61508d92016-10-02 21:12:02 +020011193}
Denys Vlasenko10d5ece2017-01-08 18:28:43 +010011194#endif
Denys Vlasenko61508d92016-10-02 21:12:02 +020011195
11196static int FAST_FUNC builtin_shift(char **argv)
11197{
11198 int n = 1;
11199 argv = skip_dash_dash(argv);
11200 if (argv[0]) {
Denys Vlasenkoe59591a2017-07-06 20:12:44 +020011201 n = bb_strtou(argv[0], NULL, 10);
11202 if (errno || n < 0) {
11203 /* shared string with ash.c */
11204 bb_error_msg("Illegal number: %s", argv[0]);
11205 /*
11206 * ash aborts in this case.
11207 * bash prints error message and set $? to 1.
11208 * Interestingly, for "shift 99999" bash does not
11209 * print error message, but does set $? to 1
11210 * (and does no shifting at all).
11211 */
11212 }
Denys Vlasenko61508d92016-10-02 21:12:02 +020011213 }
11214 if (n >= 0 && n < G.global_argc) {
Denys Vlasenko4e4f88e2017-01-09 07:57:38 +010011215 if (G_global_args_malloced) {
Denys Vlasenko61508d92016-10-02 21:12:02 +020011216 int m = 1;
11217 while (m <= n)
11218 free(G.global_argv[m++]);
11219 }
11220 G.global_argc -= n;
11221 memmove(&G.global_argv[1], &G.global_argv[n+1],
11222 G.global_argc * sizeof(G.global_argv[0]));
11223 return EXIT_SUCCESS;
11224 }
11225 return EXIT_FAILURE;
11226}
11227
Denys Vlasenko74d40582017-08-11 01:32:46 +020011228#if ENABLE_HUSH_GETOPTS
11229static int FAST_FUNC builtin_getopts(char **argv)
11230{
Denys Vlasenko9a7d0a02017-08-11 02:37:48 +020011231/* http://pubs.opengroup.org/onlinepubs/9699919799/utilities/getopts.html
11232
Denys Vlasenko74d40582017-08-11 01:32:46 +020011233TODO:
Denys Vlasenko74d40582017-08-11 01:32:46 +020011234If a required argument is not found, and getopts is not silent,
11235a question mark (?) is placed in VAR, OPTARG is unset, and a
11236diagnostic message is printed. If getopts is silent, then a
11237colon (:) is placed in VAR and OPTARG is set to the option
11238character found.
11239
11240Test that VAR is a valid variable name?
Denys Vlasenko9a7d0a02017-08-11 02:37:48 +020011241
11242"Whenever the shell is invoked, OPTIND shall be initialized to 1"
Denys Vlasenko74d40582017-08-11 01:32:46 +020011243*/
11244 char cbuf[2];
11245 const char *cp, *optstring, *var;
Denys Vlasenko238ff982017-08-29 13:38:30 +020011246 int c, n, exitcode, my_opterr;
11247 unsigned count;
Denys Vlasenko74d40582017-08-11 01:32:46 +020011248
11249 optstring = *++argv;
11250 if (!optstring || !(var = *++argv)) {
James Byrne69374872019-07-02 11:35:03 +020011251 bb_simple_error_msg("usage: getopts OPTSTRING VAR [ARGS]");
Denys Vlasenko74d40582017-08-11 01:32:46 +020011252 return EXIT_FAILURE;
11253 }
11254
Denys Vlasenko238ff982017-08-29 13:38:30 +020011255 if (argv[1])
11256 argv[0] = G.global_argv[0]; /* for error messages in getopt() */
11257 else
11258 argv = G.global_argv;
11259 cbuf[1] = '\0';
11260
11261 my_opterr = 0;
Denys Vlasenko048491f2017-08-17 12:36:39 +020011262 if (optstring[0] != ':') {
Denys Vlasenko419db032017-08-11 17:21:14 +020011263 cp = get_local_var_value("OPTERR");
Denys Vlasenko048491f2017-08-17 12:36:39 +020011264 /* 0 if "OPTERR=0", 1 otherwise */
Denys Vlasenko238ff982017-08-29 13:38:30 +020011265 my_opterr = (!cp || NOT_LONE_CHAR(cp, '0'));
Denys Vlasenko419db032017-08-11 17:21:14 +020011266 }
Denys Vlasenko74d40582017-08-11 01:32:46 +020011267
11268 /* getopts stops on first non-option. Add "+" to force that */
11269 /*if (optstring[0] != '+')*/ {
11270 char *s = alloca(strlen(optstring) + 2);
11271 sprintf(s, "+%s", optstring);
11272 optstring = s;
11273 }
11274
Denys Vlasenko238ff982017-08-29 13:38:30 +020011275 /* Naively, now we should just
11276 * cp = get_local_var_value("OPTIND");
11277 * optind = cp ? atoi(cp) : 0;
11278 * optarg = NULL;
11279 * opterr = my_opterr;
11280 * c = getopt(string_array_len(argv), argv, optstring);
11281 * and be done? Not so fast...
11282 * Unlike normal getopt() usage in C programs, here
11283 * each successive call will (usually) have the same argv[] CONTENTS,
11284 * but not the ADDRESSES. Worse yet, it's possible that between
11285 * invocations of "getopts", there will be calls to shell builtins
11286 * which use getopt() internally. Example:
11287 * while getopts "abc" RES -a -bc -abc de; do
11288 * unset -ff func
11289 * done
11290 * This would not work correctly: getopt() call inside "unset"
11291 * modifies internal libc state which is tracking position in
11292 * multi-option strings ("-abc"). At best, it can skip options
11293 * or return the same option infinitely. With glibc implementation
11294 * of getopt(), it would use outright invalid pointers and return
11295 * garbage even _without_ "unset" mangling internal state.
11296 *
11297 * We resort to resetting getopt() state and calling it N times,
11298 * until we get Nth result (or failure).
11299 * (N == G.getopt_count is reset to 0 whenever OPTIND is [un]set).
11300 */
Denys Vlasenko60161812017-08-29 14:32:17 +020011301 GETOPT_RESET();
Denys Vlasenko238ff982017-08-29 13:38:30 +020011302 count = 0;
11303 n = string_array_len(argv);
11304 do {
11305 optarg = NULL;
11306 opterr = (count < G.getopt_count) ? 0 : my_opterr;
11307 c = getopt(n, argv, optstring);
11308 if (c < 0)
11309 break;
11310 count++;
11311 } while (count <= G.getopt_count);
11312
11313 /* Set OPTIND. Prevent resetting of the magic counter! */
11314 set_local_var_from_halves("OPTIND", utoa(optind));
11315 G.getopt_count = count; /* "next time, give me N+1'th result" */
Denys Vlasenko60161812017-08-29 14:32:17 +020011316 GETOPT_RESET(); /* just in case */
Denys Vlasenko419db032017-08-11 17:21:14 +020011317
11318 /* Set OPTARG */
11319 /* Always set or unset, never left as-is, even on exit/error:
11320 * "If no option was found, or if the option that was found
11321 * does not have an option-argument, OPTARG shall be unset."
11322 */
11323 cp = optarg;
11324 if (c == '?') {
11325 /* If ":optstring" and unknown option is seen,
11326 * it is stored to OPTARG.
11327 */
11328 if (optstring[1] == ':') {
11329 cbuf[0] = optopt;
11330 cp = cbuf;
11331 }
11332 }
11333 if (cp)
11334 set_local_var_from_halves("OPTARG", cp);
11335 else
11336 unset_local_var("OPTARG");
11337
11338 /* Convert -1 to "?" */
Denys Vlasenko74d40582017-08-11 01:32:46 +020011339 exitcode = EXIT_SUCCESS;
11340 if (c < 0) { /* -1: end of options */
11341 exitcode = EXIT_FAILURE;
11342 c = '?';
11343 }
Denys Vlasenko419db032017-08-11 17:21:14 +020011344
Denys Vlasenko238ff982017-08-29 13:38:30 +020011345 /* Set VAR */
Denys Vlasenko74d40582017-08-11 01:32:46 +020011346 cbuf[0] = c;
Denys Vlasenko74d40582017-08-11 01:32:46 +020011347 set_local_var_from_halves(var, cbuf);
Denys Vlasenko9a7d0a02017-08-11 02:37:48 +020011348
Denys Vlasenko74d40582017-08-11 01:32:46 +020011349 return exitcode;
11350}
11351#endif
11352
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010011353static int FAST_FUNC builtin_source(char **argv)
Denys Vlasenko61508d92016-10-02 21:12:02 +020011354{
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010011355 char *arg_path, *filename;
Denys Vlasenko41ef41b2018-07-24 16:54:41 +020011356 HFILE *input;
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010011357 save_arg_t sv;
11358 char *args_need_save;
11359#if ENABLE_HUSH_FUNCTIONS
11360 smallint sv_flg;
Denys Vlasenko7a85c602017-01-08 17:40:18 +010011361#endif
Denys Vlasenko61508d92016-10-02 21:12:02 +020011362
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010011363 argv = skip_dash_dash(argv);
11364 filename = argv[0];
11365 if (!filename) {
11366 /* bash says: "bash: .: filename argument required" */
11367 return 2; /* bash compat */
11368 }
11369 arg_path = NULL;
11370 if (!strchr(filename, '/')) {
11371 arg_path = find_in_path(filename);
11372 if (arg_path)
11373 filename = arg_path;
Denys Vlasenko54c21112018-01-27 20:46:45 +010011374 else if (!ENABLE_HUSH_BASH_SOURCE_CURDIR) {
Denys Vlasenkof7e0fea2018-01-27 19:05:59 +010011375 errno = ENOENT;
11376 bb_simple_perror_msg(filename);
11377 return EXIT_FAILURE;
11378 }
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010011379 }
Denys Vlasenko41ef41b2018-07-24 16:54:41 +020011380 input = hfopen(filename);
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010011381 free(arg_path);
11382 if (!input) {
Denys Vlasenko41ef41b2018-07-24 16:54:41 +020011383 bb_perror_msg("%s", filename);
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010011384 /* POSIX: non-interactive shell should abort here,
11385 * not merely fail. So far no one complained :)
11386 */
11387 return EXIT_FAILURE;
11388 }
11389
11390#if ENABLE_HUSH_FUNCTIONS
11391 sv_flg = G_flag_return_in_progress;
11392 /* "we are inside sourced file, ok to use return" */
11393 G_flag_return_in_progress = -1;
11394#endif
11395 args_need_save = argv[1]; /* used as a boolean variable */
11396 if (args_need_save)
11397 save_and_replace_G_args(&sv, argv);
11398
11399 /* "false; . ./empty_line; echo Zero:$?" should print 0 */
11400 G.last_exitcode = 0;
11401 parse_and_run_file(input);
Denys Vlasenko41ef41b2018-07-24 16:54:41 +020011402 hfclose(input);
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010011403
11404 if (args_need_save) /* can't use argv[1] instead: "shift" can mangle it */
11405 restore_G_args(&sv, argv);
11406#if ENABLE_HUSH_FUNCTIONS
11407 G_flag_return_in_progress = sv_flg;
11408#endif
11409
11410 return G.last_exitcode;
11411}
11412
Denys Vlasenko7a85c602017-01-08 17:40:18 +010011413#if ENABLE_HUSH_TRAP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011414static int FAST_FUNC builtin_trap(char **argv)
Denis Vlasenko38e626d2009-04-18 12:58:19 +000011415{
Denis Vlasenko38e626d2009-04-18 12:58:19 +000011416 int sig;
11417 char *new_cmd;
11418
Denys Vlasenko7a85c602017-01-08 17:40:18 +010011419 if (!G_traps)
11420 G_traps = xzalloc(sizeof(G_traps[0]) * NSIG);
Denis Vlasenko38e626d2009-04-18 12:58:19 +000011421
11422 argv++;
11423 if (!*argv) {
Denis Vlasenko6008d8a2009-04-18 13:05:10 +000011424 int i;
Denis Vlasenko38e626d2009-04-18 12:58:19 +000011425 /* No args: print all trapped */
11426 for (i = 0; i < NSIG; ++i) {
Denys Vlasenko7a85c602017-01-08 17:40:18 +010011427 if (G_traps[i]) {
Denis Vlasenko38e626d2009-04-18 12:58:19 +000011428 printf("trap -- ");
Denys Vlasenko7a85c602017-01-08 17:40:18 +010011429 print_escaped(G_traps[i]);
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020011430 /* note: bash adds "SIG", but only if invoked
11431 * as "bash". If called as "sh", or if set -o posix,
11432 * then it prints short signal names.
11433 * We are printing short names: */
11434 printf(" %s\n", get_signame(i));
Denis Vlasenko38e626d2009-04-18 12:58:19 +000011435 }
11436 }
Denys Vlasenko8131eea2009-11-02 14:19:51 +010011437 /*fflush_all(); - done after each builtin anyway */
Denis Vlasenko38e626d2009-04-18 12:58:19 +000011438 return EXIT_SUCCESS;
11439 }
11440
11441 new_cmd = NULL;
Denis Vlasenko38e626d2009-04-18 12:58:19 +000011442 /* If first arg is a number: reset all specified signals */
11443 sig = bb_strtou(*argv, NULL, 10);
11444 if (errno == 0) {
11445 int ret;
11446 process_sig_list:
11447 ret = EXIT_SUCCESS;
11448 while (*argv) {
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +020011449 sighandler_t handler;
11450
Denis Vlasenko38e626d2009-04-18 12:58:19 +000011451 sig = get_signum(*argv++);
Denys Vlasenko86981e32017-07-25 20:06:17 +020011452 if (sig < 0) {
Denis Vlasenko38e626d2009-04-18 12:58:19 +000011453 ret = EXIT_FAILURE;
11454 /* Mimic bash message exactly */
Denys Vlasenko74562982017-07-06 18:40:45 +020011455 bb_error_msg("trap: %s: invalid signal specification", argv[-1]);
Denis Vlasenko38e626d2009-04-18 12:58:19 +000011456 continue;
11457 }
11458
Denys Vlasenko7a85c602017-01-08 17:40:18 +010011459 free(G_traps[sig]);
11460 G_traps[sig] = xstrdup(new_cmd);
Denis Vlasenko38e626d2009-04-18 12:58:19 +000011461
Denys Vlasenkoe89a2412010-01-12 15:19:31 +010011462 debug_printf("trap: setting SIG%s (%i) to '%s'\n",
Denys Vlasenko7a85c602017-01-08 17:40:18 +010011463 get_signame(sig), sig, G_traps[sig]);
Denis Vlasenko38e626d2009-04-18 12:58:19 +000011464
11465 /* There is no signal for 0 (EXIT) */
11466 if (sig == 0)
11467 continue;
11468
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +020011469 if (new_cmd)
11470 handler = (new_cmd[0] ? record_pending_signo : SIG_IGN);
11471 else
11472 /* We are removing trap handler */
11473 handler = pick_sighandler(sig);
Denys Vlasenko0806e402011-05-12 23:06:20 +020011474 install_sighandler(sig, handler);
Denis Vlasenko38e626d2009-04-18 12:58:19 +000011475 }
11476 return ret;
11477 }
11478
11479 if (!argv[1]) { /* no second arg */
James Byrne69374872019-07-02 11:35:03 +020011480 bb_simple_error_msg("trap: invalid arguments");
Denis Vlasenko38e626d2009-04-18 12:58:19 +000011481 return EXIT_FAILURE;
11482 }
11483
11484 /* First arg is "-": reset all specified to default */
11485 /* First arg is "--": skip it, the rest is "handler SIGs..." */
11486 /* Everything else: set arg as signal handler
11487 * (includes "" case, which ignores signal) */
11488 if (argv[0][0] == '-') {
11489 if (argv[0][1] == '\0') { /* "-" */
11490 /* new_cmd remains NULL: "reset these sigs" */
11491 goto reset_traps;
11492 }
11493 if (argv[0][1] == '-' && argv[0][2] == '\0') { /* "--" */
11494 argv++;
11495 }
11496 /* else: "-something", no special meaning */
11497 }
11498 new_cmd = *argv;
11499 reset_traps:
11500 argv++;
11501 goto process_sig_list;
11502}
Denys Vlasenko7a85c602017-01-08 17:40:18 +010011503#endif
Denis Vlasenko38e626d2009-04-18 12:58:19 +000011504
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000011505#if ENABLE_HUSH_JOB
Denys Vlasenko4e1c8b42016-11-07 20:06:40 +010011506static struct pipe *parse_jobspec(const char *str)
11507{
11508 struct pipe *pi;
Denys Vlasenkod5b5c2f2017-01-08 15:46:04 +010011509 unsigned jobnum;
Denys Vlasenko4e1c8b42016-11-07 20:06:40 +010011510
Denys Vlasenkod5b5c2f2017-01-08 15:46:04 +010011511 if (sscanf(str, "%%%u", &jobnum) != 1) {
11512 if (str[0] != '%'
11513 || (str[1] != '%' && str[1] != '+' && str[1] != '\0')
11514 ) {
11515 bb_error_msg("bad argument '%s'", str);
11516 return NULL;
11517 }
11518 /* It is "%%", "%+" or "%" - current job */
11519 jobnum = G.last_jobid;
11520 if (jobnum == 0) {
James Byrne69374872019-07-02 11:35:03 +020011521 bb_simple_error_msg("no current job");
Denys Vlasenkod5b5c2f2017-01-08 15:46:04 +010011522 return NULL;
11523 }
Denys Vlasenko4e1c8b42016-11-07 20:06:40 +010011524 }
11525 for (pi = G.job_list; pi; pi = pi->next) {
11526 if (pi->jobid == jobnum) {
11527 return pi;
11528 }
11529 }
Denys Vlasenkofd68f1e2017-01-09 05:47:57 +010011530 bb_error_msg("%u: no such job", jobnum);
Denys Vlasenko4e1c8b42016-11-07 20:06:40 +010011531 return NULL;
11532}
11533
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010011534static int FAST_FUNC builtin_jobs(char **argv UNUSED_PARAM)
11535{
11536 struct pipe *job;
11537 const char *status_string;
11538
11539 checkjobs(NULL, 0 /*(no pid to wait for)*/);
11540 for (job = G.job_list; job; job = job->next) {
11541 if (job->alive_cmds == job->stopped_cmds)
11542 status_string = "Stopped";
11543 else
11544 status_string = "Running";
11545
11546 printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->cmdtext);
11547 }
Denys Vlasenko2ed74e22017-07-14 19:58:46 +020011548
11549 clean_up_last_dead_job();
11550
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010011551 return EXIT_SUCCESS;
11552}
11553
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000011554/* built-in 'fg' and 'bg' handler */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011555static int FAST_FUNC builtin_fg_bg(char **argv)
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000011556{
Denys Vlasenko4e1c8b42016-11-07 20:06:40 +010011557 int i;
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000011558 struct pipe *pi;
11559
Denis Vlasenko60b392f2009-04-03 19:14:32 +000011560 if (!G_interactive_fd)
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000011561 return EXIT_FAILURE;
Denis Vlasenkoc8653f62009-04-27 23:29:14 +000011562
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000011563 /* If they gave us no args, assume they want the last backgrounded task */
11564 if (!argv[1]) {
Denis Vlasenko87a86552008-07-29 19:43:10 +000011565 for (pi = G.job_list; pi; pi = pi->next) {
11566 if (pi->jobid == G.last_jobid) {
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000011567 goto found;
11568 }
11569 }
11570 bb_error_msg("%s: no current job", argv[0]);
11571 return EXIT_FAILURE;
11572 }
Denys Vlasenko4e1c8b42016-11-07 20:06:40 +010011573
11574 pi = parse_jobspec(argv[1]);
11575 if (!pi)
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000011576 return EXIT_FAILURE;
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000011577 found:
Denis Vlasenko6b9e0532009-04-18 01:23:21 +000011578 /* TODO: bash prints a string representation
11579 * of job being foregrounded (like "sleep 1 | cat") */
Mike Frysinger38478a62009-05-20 04:48:06 -040011580 if (argv[0][0] == 'f' && G_saved_tty_pgrp) {
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000011581 /* Put the job into the foreground. */
Denis Vlasenko60b392f2009-04-03 19:14:32 +000011582 tcsetpgrp(G_interactive_fd, pi->pgrp);
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000011583 }
11584
11585 /* Restart the processes in the job */
Denis Vlasenko9af22c72008-10-09 12:54:58 +000011586 debug_printf_jobs("reviving %d procs, pgrp %d\n", pi->num_cmds, pi->pgrp);
11587 for (i = 0; i < pi->num_cmds; i++) {
11588 debug_printf_jobs("reviving pid %d\n", pi->cmds[i].pid);
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000011589 }
Denis Vlasenko9af22c72008-10-09 12:54:58 +000011590 pi->stopped_cmds = 0;
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000011591
11592 i = kill(- pi->pgrp, SIGCONT);
11593 if (i < 0) {
11594 if (errno == ESRCH) {
Denys Vlasenko16096292017-07-10 10:00:28 +020011595 delete_finished_job(pi);
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000011596 return EXIT_SUCCESS;
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000011597 }
James Byrne69374872019-07-02 11:35:03 +020011598 bb_simple_perror_msg("kill (SIGCONT)");
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000011599 }
11600
Denis Vlasenko34d4d892009-04-04 20:24:37 +000011601 if (argv[0][0] == 'f') {
Denys Vlasenko16096292017-07-10 10:00:28 +020011602 remove_job_from_table(pi); /* FG job shouldn't be in job table */
Denis Vlasenkoc7985b72008-06-17 05:43:38 +000011603 return checkjobs_and_fg_shell(pi);
11604 }
11605 return EXIT_SUCCESS;
11606}
11607#endif
11608
Denys Vlasenko1125d7d2017-01-08 17:19:38 +010011609#if ENABLE_HUSH_KILL
11610static int FAST_FUNC builtin_kill(char **argv)
11611{
11612 int ret = 0;
11613
Denys Vlasenkofd68f1e2017-01-09 05:47:57 +010011614# if ENABLE_HUSH_JOB
11615 if (argv[1] && strcmp(argv[1], "-l") != 0) {
11616 int i = 1;
Denys Vlasenko1125d7d2017-01-08 17:19:38 +010011617
11618 do {
11619 struct pipe *pi;
11620 char *dst;
11621 int j, n;
11622
11623 if (argv[i][0] != '%')
11624 continue;
11625 /*
11626 * "kill %N" - job kill
11627 * Converting to pgrp / pid kill
11628 */
11629 pi = parse_jobspec(argv[i]);
11630 if (!pi) {
11631 /* Eat bad jobspec */
11632 j = i;
11633 do {
11634 j++;
11635 argv[j - 1] = argv[j];
11636 } while (argv[j]);
11637 ret = 1;
11638 i--;
11639 continue;
11640 }
11641 /*
11642 * In jobs started under job control, we signal
11643 * entire process group by kill -PGRP_ID.
11644 * This happens, f.e., in interactive shell.
11645 *
11646 * Otherwise, we signal each child via
11647 * kill PID1 PID2 PID3.
11648 * Testcases:
11649 * sh -c 'sleep 1|sleep 1 & kill %1'
11650 * sh -c 'true|sleep 2 & sleep 1; kill %1'
11651 * sh -c 'true|sleep 1 & sleep 2; kill %1'
11652 */
Denys Vlasenko5362cc42017-01-09 05:57:13 +010011653 n = G_interactive_fd ? 1 : pi->num_cmds;
Denys Vlasenko1125d7d2017-01-08 17:19:38 +010011654 dst = alloca(n * sizeof(int)*4);
11655 argv[i] = dst;
Denys Vlasenko1125d7d2017-01-08 17:19:38 +010011656 if (G_interactive_fd)
11657 dst += sprintf(dst, " -%u", (int)pi->pgrp);
Denys Vlasenkofd68f1e2017-01-09 05:47:57 +010011658 else for (j = 0; j < n; j++) {
Denys Vlasenko1125d7d2017-01-08 17:19:38 +010011659 struct command *cmd = &pi->cmds[j];
11660 /* Skip exited members of the job */
11661 if (cmd->pid == 0)
11662 continue;
11663 /*
11664 * kill_main has matching code to expect
11665 * leading space. Needed to not confuse
11666 * negative pids with "kill -SIGNAL_NO" syntax
11667 */
11668 dst += sprintf(dst, " %u", (int)cmd->pid);
11669 }
11670 *dst = '\0';
11671 } while (argv[++i]);
11672 }
Denys Vlasenkofd68f1e2017-01-09 05:47:57 +010011673# endif
Denys Vlasenko1125d7d2017-01-08 17:19:38 +010011674
Denys Vlasenkofd68f1e2017-01-09 05:47:57 +010011675 if (argv[1] || ret == 0) {
Denys Vlasenko1125d7d2017-01-08 17:19:38 +010011676 ret = run_applet_main(argv, kill_main);
11677 }
Denys Vlasenkofd68f1e2017-01-09 05:47:57 +010011678 /* else: ret = 1, "kill %bad_jobspec" case */
Denys Vlasenko1125d7d2017-01-08 17:19:38 +010011679 return ret;
11680}
11681#endif
11682
11683#if ENABLE_HUSH_WAIT
Mike Frysinger56bdea12009-03-28 20:01:58 +000011684/* http://www.opengroup.org/onlinepubs/9699919799/utilities/wait.html */
Denys Vlasenko259747c2019-11-28 10:28:14 +010011685# if !ENABLE_HUSH_JOB
11686# define wait_for_child_or_signal(pipe,pid) wait_for_child_or_signal(pid)
11687# endif
Denys Vlasenko62b717b2016-11-07 22:12:18 +010011688static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid)
Denys Vlasenko7e675362016-10-28 21:57:31 +020011689{
11690 int ret = 0;
11691 for (;;) {
11692 int sig;
Denys Vlasenko62b717b2016-11-07 22:12:18 +010011693 sigset_t oldset;
Denys Vlasenko7e675362016-10-28 21:57:31 +020011694
Denys Vlasenko830ea352016-11-08 04:59:11 +010011695 if (!sigisemptyset(&G.pending_set))
11696 goto check_sig;
11697
Denys Vlasenko7e675362016-10-28 21:57:31 +020011698 /* waitpid is not interruptible by SA_RESTARTed
11699 * signals which we use. Thus, this ugly dance:
11700 */
11701
11702 /* Make sure possible SIGCHLD is stored in kernel's
11703 * pending signal mask before we call waitpid.
11704 * Or else we may race with SIGCHLD, lose it,
Denys Vlasenko62b717b2016-11-07 22:12:18 +010011705 * and get stuck in sigsuspend...
Denys Vlasenko7e675362016-10-28 21:57:31 +020011706 */
Denys Vlasenko62b717b2016-11-07 22:12:18 +010011707 sigfillset(&oldset); /* block all signals, remember old set */
Denys Vlasenkob437df12018-12-08 15:35:24 +010011708 sigprocmask2(SIG_SETMASK, &oldset);
Denys Vlasenko7e675362016-10-28 21:57:31 +020011709
11710 if (!sigisemptyset(&G.pending_set)) {
11711 /* Crap! we raced with some signal! */
Denys Vlasenko7e675362016-10-28 21:57:31 +020011712 goto restore;
11713 }
11714
11715 /*errno = 0; - checkjobs does this */
Denys Vlasenko62b717b2016-11-07 22:12:18 +010011716/* Can't pass waitfor_pipe into checkjobs(): it won't be interruptible */
Denys Vlasenko7e675362016-10-28 21:57:31 +020011717 ret = checkjobs(NULL, waitfor_pid); /* waitpid(WNOHANG) inside */
Denys Vlasenko62b717b2016-11-07 22:12:18 +010011718 debug_printf_exec("checkjobs:%d\n", ret);
Denys Vlasenko259747c2019-11-28 10:28:14 +010011719# if ENABLE_HUSH_JOB
Denys Vlasenko62b717b2016-11-07 22:12:18 +010011720 if (waitfor_pipe) {
11721 int rcode = job_exited_or_stopped(waitfor_pipe);
11722 debug_printf_exec("job_exited_or_stopped:%d\n", rcode);
11723 if (rcode >= 0) {
11724 ret = rcode;
11725 sigprocmask(SIG_SETMASK, &oldset, NULL);
11726 break;
11727 }
11728 }
Denys Vlasenko259747c2019-11-28 10:28:14 +010011729# endif
Denys Vlasenko7e675362016-10-28 21:57:31 +020011730 /* if ECHILD, there are no children (ret is -1 or 0) */
11731 /* if ret == 0, no children changed state */
11732 /* if ret != 0, it's exitcode+1 of exited waitfor_pid child */
Denys Vlasenko62b717b2016-11-07 22:12:18 +010011733 if (errno == ECHILD || ret) {
11734 ret--;
11735 if (ret < 0) /* if ECHILD, may need to fix "ret" */
Denys Vlasenko7e675362016-10-28 21:57:31 +020011736 ret = 0;
Denys Vlasenko259747c2019-11-28 10:28:14 +010011737# if ENABLE_HUSH_BASH_COMPAT
Denys Vlasenko4d1c5142019-03-26 18:34:06 +010011738 if (waitfor_pid == -1 && errno == ECHILD) {
11739 /* exitcode of "wait -n" with no children is 127, not 0 */
11740 ret = 127;
11741 }
Denys Vlasenko259747c2019-11-28 10:28:14 +010011742# endif
Denys Vlasenko7e675362016-10-28 21:57:31 +020011743 sigprocmask(SIG_SETMASK, &oldset, NULL);
11744 break;
11745 }
Denys Vlasenko7e675362016-10-28 21:57:31 +020011746 /* Wait for SIGCHLD or any other signal */
Denys Vlasenko7e675362016-10-28 21:57:31 +020011747 /* It is vitally important for sigsuspend that SIGCHLD has non-DFL handler! */
11748 /* Note: sigsuspend invokes signal handler */
11749 sigsuspend(&oldset);
Denys Vlasenko23bc5622020-02-18 16:46:01 +010011750 /* ^^^ add "sigdelset(&oldset, SIGCHLD)" before sigsuspend
11751 * to make sure SIGCHLD is not masked off?
11752 * It was reported that this:
11753 * fn() { : | return; }
11754 * shopt -s lastpipe
11755 * fn
11756 * exec hush SCRIPT
11757 * under bash 4.4.23 runs SCRIPT with SIGCHLD masked,
11758 * making "wait" commands in SCRIPT block forever.
11759 */
Denys Vlasenko7e675362016-10-28 21:57:31 +020011760 restore:
11761 sigprocmask(SIG_SETMASK, &oldset, NULL);
Denys Vlasenko830ea352016-11-08 04:59:11 +010011762 check_sig:
Denys Vlasenko7e675362016-10-28 21:57:31 +020011763 /* So, did we get a signal? */
Denys Vlasenko7e675362016-10-28 21:57:31 +020011764 sig = check_and_run_traps();
11765 if (sig /*&& sig != SIGCHLD - always true */) {
Denys Vlasenko7c40ddd2017-08-02 16:37:39 +020011766 /* Do this for any (non-ignored) signal, not only for ^C */
Denys Vlasenko93e2a222020-12-23 12:23:21 +010011767 ret = 128 | sig;
Denys Vlasenko7e675362016-10-28 21:57:31 +020011768 break;
11769 }
11770 /* SIGCHLD, or no signal, or ignored one, such as SIGQUIT. Repeat */
11771 }
11772 return ret;
11773}
11774
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011775static int FAST_FUNC builtin_wait(char **argv)
Mike Frysinger56bdea12009-03-28 20:01:58 +000011776{
Denys Vlasenko7e675362016-10-28 21:57:31 +020011777 int ret;
Denys Vlasenko9d6cbaf2011-05-11 23:56:11 +020011778 int status;
Mike Frysinger56bdea12009-03-28 20:01:58 +000011779
Denys Vlasenkob131cce2010-05-20 03:39:43 +020011780 argv = skip_dash_dash(argv);
Denys Vlasenko259747c2019-11-28 10:28:14 +010011781# if ENABLE_HUSH_BASH_COMPAT
Denys Vlasenkoe6f51ac2019-03-27 18:34:10 +010011782 if (argv[0] && strcmp(argv[0], "-n") == 0) {
Denys Vlasenko4d1c5142019-03-26 18:34:06 +010011783 /* wait -n */
Denys Vlasenkoe6f51ac2019-03-27 18:34:10 +010011784 /* (bash accepts "wait -n PID" too and ignores PID) */
11785 G.dead_job_exitcode = -1;
11786 return wait_for_child_or_signal(NULL, -1 /*no job, wait for one job*/);
Denys Vlasenko4d1c5142019-03-26 18:34:06 +010011787 }
Denys Vlasenko259747c2019-11-28 10:28:14 +010011788# endif
Denys Vlasenkob131cce2010-05-20 03:39:43 +020011789 if (argv[0] == NULL) {
Denis Vlasenko7566bae2009-03-31 17:24:49 +000011790 /* Don't care about wait results */
11791 /* Note 1: must wait until there are no more children */
11792 /* Note 2: must be interruptible */
11793 /* Examples:
11794 * $ sleep 3 & sleep 6 & wait
11795 * [1] 30934 sleep 3
11796 * [2] 30935 sleep 6
11797 * [1] Done sleep 3
11798 * [2] Done sleep 6
11799 * $ sleep 3 & sleep 6 & wait
11800 * [1] 30936 sleep 3
11801 * [2] 30937 sleep 6
11802 * [1] Done sleep 3
11803 * ^C <-- after ~4 sec from keyboard
11804 * $
11805 */
Denys Vlasenkoe6f51ac2019-03-27 18:34:10 +010011806 return wait_for_child_or_signal(NULL, 0 /*no job and no pid to wait for*/);
Denis Vlasenko7566bae2009-03-31 17:24:49 +000011807 }
Mike Frysinger56bdea12009-03-28 20:01:58 +000011808
Denys Vlasenko7e675362016-10-28 21:57:31 +020011809 do {
Denis Vlasenkod5762932009-03-31 11:22:57 +000011810 pid_t pid = bb_strtou(*argv, NULL, 10);
Denys Vlasenko7e675362016-10-28 21:57:31 +020011811 if (errno || pid <= 0) {
Denys Vlasenko259747c2019-11-28 10:28:14 +010011812# if ENABLE_HUSH_JOB
Denys Vlasenko62b717b2016-11-07 22:12:18 +010011813 if (argv[0][0] == '%') {
Denys Vlasenko02affb42016-11-08 00:59:29 +010011814 struct pipe *wait_pipe;
Denys Vlasenkod5b5c2f2017-01-08 15:46:04 +010011815 ret = 127; /* bash compat for bad jobspecs */
Denys Vlasenko62b717b2016-11-07 22:12:18 +010011816 wait_pipe = parse_jobspec(*argv);
11817 if (wait_pipe) {
Denys Vlasenko02affb42016-11-08 00:59:29 +010011818 ret = job_exited_or_stopped(wait_pipe);
Denys Vlasenko2ed74e22017-07-14 19:58:46 +020011819 if (ret < 0) {
Denys Vlasenko02affb42016-11-08 00:59:29 +010011820 ret = wait_for_child_or_signal(wait_pipe, 0);
Denys Vlasenko2ed74e22017-07-14 19:58:46 +020011821 } else {
11822 /* waiting on "last dead job" removes it */
11823 clean_up_last_dead_job();
Denys Vlasenko13102632017-07-08 00:24:32 +020011824 }
Denys Vlasenko62b717b2016-11-07 22:12:18 +010011825 }
Denys Vlasenkod5b5c2f2017-01-08 15:46:04 +010011826 /* else: parse_jobspec() already emitted error msg */
11827 continue;
Denys Vlasenko62b717b2016-11-07 22:12:18 +010011828 }
Denys Vlasenko259747c2019-11-28 10:28:14 +010011829# endif
Denis Vlasenkod5762932009-03-31 11:22:57 +000011830 /* mimic bash message */
11831 bb_error_msg("wait: '%s': not a pid or valid job spec", *argv);
Denys Vlasenko9db74e42016-10-28 22:39:12 +020011832 ret = EXIT_FAILURE;
11833 continue; /* bash checks all argv[] */
Denis Vlasenkod5762932009-03-31 11:22:57 +000011834 }
Denys Vlasenko02affb42016-11-08 00:59:29 +010011835
Denys Vlasenko7e675362016-10-28 21:57:31 +020011836 /* Do we have such child? */
11837 ret = waitpid(pid, &status, WNOHANG);
11838 if (ret < 0) {
11839 /* No */
Denys Vlasenko840a4352017-07-07 22:56:02 +020011840 ret = 127;
Denys Vlasenko7e675362016-10-28 21:57:31 +020011841 if (errno == ECHILD) {
Denys Vlasenko0c5657e2017-07-14 19:27:03 +020011842 if (pid == G.last_bg_pid) {
Denys Vlasenko9db74e42016-10-28 22:39:12 +020011843 /* "wait $!" but last bg task has already exited. Try:
11844 * (sleep 1; exit 3) & sleep 2; echo $?; wait $!; echo $?
11845 * In bash it prints exitcode 0, then 3.
Denys Vlasenko26ad94b2016-11-07 23:07:21 +010011846 * In dash, it is 127.
Denys Vlasenko9db74e42016-10-28 22:39:12 +020011847 */
Denys Vlasenko840a4352017-07-07 22:56:02 +020011848 ret = G.last_bg_pid_exitcode;
Denys Vlasenko26ad94b2016-11-07 23:07:21 +010011849 } else {
11850 /* Example: "wait 1". mimic bash message */
Denys Vlasenko259747c2019-11-28 10:28:14 +010011851 bb_error_msg("wait: pid %u is not a child of this shell", (unsigned)pid);
Denys Vlasenko9db74e42016-10-28 22:39:12 +020011852 }
Denys Vlasenko7e675362016-10-28 21:57:31 +020011853 } else {
11854 /* ??? */
11855 bb_perror_msg("wait %s", *argv);
11856 }
Denys Vlasenko9db74e42016-10-28 22:39:12 +020011857 continue; /* bash checks all argv[] */
11858 }
11859 if (ret == 0) {
Denys Vlasenko7e675362016-10-28 21:57:31 +020011860 /* Yes, and it still runs */
Denys Vlasenko02affb42016-11-08 00:59:29 +010011861 ret = wait_for_child_or_signal(NULL, pid);
Denys Vlasenko7e675362016-10-28 21:57:31 +020011862 } else {
11863 /* Yes, and it just exited */
Denys Vlasenko02affb42016-11-08 00:59:29 +010011864 process_wait_result(NULL, pid, status);
Denys Vlasenko85378cd2015-10-11 21:47:11 +020011865 ret = WEXITSTATUS(status);
Mike Frysinger56bdea12009-03-28 20:01:58 +000011866 if (WIFSIGNALED(status))
Denys Vlasenko93e2a222020-12-23 12:23:21 +010011867 ret = 128 | WTERMSIG(status);
Mike Frysinger56bdea12009-03-28 20:01:58 +000011868 }
Denys Vlasenko9db74e42016-10-28 22:39:12 +020011869 } while (*++argv);
Mike Frysinger56bdea12009-03-28 20:01:58 +000011870
11871 return ret;
11872}
Denys Vlasenko1125d7d2017-01-08 17:19:38 +010011873#endif
Mike Frysinger56bdea12009-03-28 20:01:58 +000011874
Denis Vlasenko3d40d8e2009-04-17 23:44:18 +000011875#if ENABLE_HUSH_LOOPS || ENABLE_HUSH_FUNCTIONS
11876static unsigned parse_numeric_argv1(char **argv, unsigned def, unsigned def_min)
11877{
11878 if (argv[1]) {
11879 def = bb_strtou(argv[1], NULL, 10);
11880 if (errno || def < def_min || argv[2]) {
11881 bb_error_msg("%s: bad arguments", argv[0]);
11882 def = UINT_MAX;
11883 }
11884 }
11885 return def;
11886}
11887#endif
11888
Denis Vlasenkodadfb492008-07-29 10:16:05 +000011889#if ENABLE_HUSH_LOOPS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011890static int FAST_FUNC builtin_break(char **argv)
Denis Vlasenkobcb25532008-07-28 23:04:34 +000011891{
Denis Vlasenko3d40d8e2009-04-17 23:44:18 +000011892 unsigned depth;
Denis Vlasenko87a86552008-07-29 19:43:10 +000011893 if (G.depth_of_loop == 0) {
Denis Vlasenko4f504a92008-07-29 19:48:30 +000011894 bb_error_msg("%s: only meaningful in a loop", argv[0]);
Denys Vlasenko49117b42016-07-21 14:40:08 +020011895 /* if we came from builtin_continue(), need to undo "= 1" */
11896 G.flag_break_continue = 0;
Denis Vlasenkofcf37c32008-07-29 11:37:15 +000011897 return EXIT_SUCCESS; /* bash compat */
11898 }
Denys Vlasenko49117b42016-07-21 14:40:08 +020011899 G.flag_break_continue++; /* BC_BREAK = 1, or BC_CONTINUE = 2 */
Denis Vlasenko3d40d8e2009-04-17 23:44:18 +000011900
11901 G.depth_break_continue = depth = parse_numeric_argv1(argv, 1, 1);
11902 if (depth == UINT_MAX)
11903 G.flag_break_continue = BC_BREAK;
11904 if (G.depth_of_loop < depth)
Denis Vlasenko87a86552008-07-29 19:43:10 +000011905 G.depth_break_continue = G.depth_of_loop;
Denis Vlasenko3d40d8e2009-04-17 23:44:18 +000011906
Denis Vlasenkobcb25532008-07-28 23:04:34 +000011907 return EXIT_SUCCESS;
11908}
11909
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011910static int FAST_FUNC builtin_continue(char **argv)
Denis Vlasenkobcb25532008-07-28 23:04:34 +000011911{
Denis Vlasenko4f504a92008-07-29 19:48:30 +000011912 G.flag_break_continue = 1; /* BC_CONTINUE = 2 = 1+1 */
11913 return builtin_break(argv);
Denis Vlasenkobcb25532008-07-28 23:04:34 +000011914}
Denis Vlasenkodadfb492008-07-29 10:16:05 +000011915#endif
Denis Vlasenko3d40d8e2009-04-17 23:44:18 +000011916
11917#if ENABLE_HUSH_FUNCTIONS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011918static int FAST_FUNC builtin_return(char **argv)
Denis Vlasenko3d40d8e2009-04-17 23:44:18 +000011919{
11920 int rc;
11921
Denys Vlasenko04b46bc2016-10-01 22:28:03 +020011922 if (G_flag_return_in_progress != -1) {
Denis Vlasenko3d40d8e2009-04-17 23:44:18 +000011923 bb_error_msg("%s: not in a function or sourced script", argv[0]);
11924 return EXIT_FAILURE; /* bash compat */
11925 }
11926
Denys Vlasenko04b46bc2016-10-01 22:28:03 +020011927 G_flag_return_in_progress = 1;
Denis Vlasenko3d40d8e2009-04-17 23:44:18 +000011928
11929 /* bash:
11930 * out of range: wraps around at 256, does not error out
11931 * non-numeric param:
11932 * f() { false; return qwe; }; f; echo $?
11933 * bash: return: qwe: numeric argument required <== we do this
11934 * 255 <== we also do this
11935 */
11936 rc = parse_numeric_argv1(argv, G.last_exitcode, 0);
Denys Vlasenkobb095f42020-02-20 16:37:59 +010011937# if ENABLE_HUSH_TRAP
11938 if (argv[1]) { /* "return ARG" inside a running trap sets $? */
11939 debug_printf_exec("G.return_exitcode=%d\n", rc);
11940 G.return_exitcode = rc;
11941 }
11942# endif
Denis Vlasenko3d40d8e2009-04-17 23:44:18 +000011943 return rc;
11944}
11945#endif
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010011946
Denys Vlasenko11f2e992017-08-10 16:34:03 +020011947#if ENABLE_HUSH_TIMES
11948static int FAST_FUNC builtin_times(char **argv UNUSED_PARAM)
11949{
11950 static const uint8_t times_tbl[] ALIGN1 = {
11951 ' ', offsetof(struct tms, tms_utime),
11952 '\n', offsetof(struct tms, tms_stime),
11953 ' ', offsetof(struct tms, tms_cutime),
11954 '\n', offsetof(struct tms, tms_cstime),
11955 0
11956 };
11957 const uint8_t *p;
11958 unsigned clk_tck;
11959 struct tms buf;
11960
11961 clk_tck = bb_clk_tck();
11962
11963 times(&buf);
11964 p = times_tbl;
11965 do {
11966 unsigned sec, frac;
11967 unsigned long t;
11968 t = *(clock_t *)(((char *) &buf) + p[1]);
11969 sec = t / clk_tck;
11970 frac = t % clk_tck;
11971 printf("%um%u.%03us%c",
11972 sec / 60, sec % 60,
11973 (frac * 1000) / clk_tck,
11974 p[0]);
11975 p += 2;
11976 } while (*p);
11977
11978 return EXIT_SUCCESS;
11979}
11980#endif
11981
Denys Vlasenkoa1184af2017-01-10 15:58:02 +010011982#if ENABLE_HUSH_MEMLEAK
11983static int FAST_FUNC builtin_memleak(char **argv UNUSED_PARAM)
11984{
11985 void *p;
11986 unsigned long l;
11987
11988# ifdef M_TRIM_THRESHOLD
11989 /* Optional. Reduces probability of false positives */
11990 malloc_trim(0);
11991# endif
11992 /* Crude attempt to find where "free memory" starts,
11993 * sans fragmentation. */
11994 p = malloc(240);
11995 l = (unsigned long)p;
11996 free(p);
11997 p = malloc(3400);
11998 if (l < (unsigned long)p) l = (unsigned long)p;
11999 free(p);
12000
12001
12002# if 0 /* debug */
12003 {
12004 struct mallinfo mi = mallinfo();
12005 printf("top alloc:0x%lx malloced:%d+%d=%d\n", l,
12006 mi.arena, mi.hblkhd, mi.arena + mi.hblkhd);
12007 }
12008# endif
12009
12010 if (!G.memleak_value)
12011 G.memleak_value = l;
12012
12013 l -= G.memleak_value;
12014 if ((long)l < 0)
12015 l = 0;
12016 l /= 1024;
12017 if (l > 127)
12018 l = 127;
12019
12020 /* Exitcode is "how many kilobytes we leaked since 1st call" */
12021 return l;
12022}
12023#endif