aboutsummaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/hush.c')
-rw-r--r--shell/hush.c739
1 files changed, 480 insertions, 259 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 125463a56..f6da826d3 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -41,14 +41,28 @@
41 * 41 *
42 * TODOs: 42 * TODOs:
43 * grep for "TODO" and fix (some of them are easy) 43 * grep for "TODO" and fix (some of them are easy)
44 * make complex ${var%...} constructs support optional
45 * make here documents optional
44 * special variables (done: PWD, PPID, RANDOM) 46 * special variables (done: PWD, PPID, RANDOM)
47 * follow IFS rules more precisely, including update semantics
45 * tilde expansion 48 * tilde expansion
46 * aliases 49 * aliases
47 * follow IFS rules more precisely, including update semantics
48 * builtins mandated by standards we don't support: 50 * builtins mandated by standards we don't support:
49 * [un]alias, command, fc, getopts, newgrp, readonly, times 51 * [un]alias, command, fc, getopts, times:
50 * make complex ${var%...} constructs support optional 52 * command -v CMD: print "/path/to/CMD"
51 * make here documents optional 53 * prints "CMD" for builtins
54 * prints "alias ALIAS='EXPANSION'" for aliases
55 * prints nothing and sets $? to 1 if not found
56 * command -V CMD: print "CMD is /path/CMD|a shell builtin|etc"
57 * command [-p] CMD: run CMD, even if a function CMD also exists
58 * (can use this to override standalone shell as well)
59 * -p: use default $PATH
60 * command BLTIN: disables special-ness (e.g. errors do not abort)
61 * getopts: getopt() for shells
62 * times: print getrusage(SELF/CHILDREN).ru_utime/ru_stime
63 * fc -l[nr] [BEG] [END]: list range of commands in history
64 * fc [-e EDITOR] [BEG] [END]: edit/rerun range of commands
65 * fc -s [PAT=REP] [CMD]: rerun CMD, replacing PAT with REP
52 * 66 *
53 * Bash compat TODO: 67 * Bash compat TODO:
54 * redirection of stdout+stderr: &> and >& 68 * redirection of stdout+stderr: &> and >&
@@ -64,8 +78,13 @@
64 * The EXPR is evaluated according to ARITHMETIC EVALUATION. 78 * The EXPR is evaluated according to ARITHMETIC EVALUATION.
65 * This is exactly equivalent to let "EXPR". 79 * This is exactly equivalent to let "EXPR".
66 * $[EXPR]: synonym for $((EXPR)) 80 * $[EXPR]: synonym for $((EXPR))
81 * indirect expansion: ${!VAR}
82 * substring op on @: ${@:n:m}
67 * 83 *
68 * Won't do: 84 * Won't do:
85 * Some builtins mandated by standards:
86 * newgrp [GRP]: not a builtin in bash but a suid binary
87 * which spawns a new shell with new group ID
69 * In bash, export builtin is special, its arguments are assignments 88 * In bash, export builtin is special, its arguments are assignments
70 * and therefore expansion of them should be "one-word" expansion: 89 * and therefore expansion of them should be "one-word" expansion:
71 * $ export i=`echo 'a b'` # export has one arg: "i=a b" 90 * $ export i=`echo 'a b'` # export has one arg: "i=a b"
@@ -219,6 +238,13 @@
219//config: help 238//config: help
220//config: export -n unexports variables. It is a bash extension. 239//config: export -n unexports variables. It is a bash extension.
221//config: 240//config:
241//config:config HUSH_READONLY
242//config: bool "readonly builtin"
243//config: default y
244//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH
245//config: help
246//config: Enable support for read-only variables.
247//config:
222//config:config HUSH_KILL 248//config:config HUSH_KILL
223//config: bool "kill builtin (supports kill %jobspec)" 249//config: bool "kill builtin (supports kill %jobspec)"
224//config: default y 250//config: default y
@@ -268,17 +294,9 @@
268//config: bool "memleak builtin (debugging)" 294//config: bool "memleak builtin (debugging)"
269//config: default n 295//config: default n
270//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 296//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH
271//config:
272//config:config MSH
273//config: bool "msh (deprecated: aliased to hush)"
274//config: default n
275//config: select HUSH
276//config: help
277//config: msh is deprecated and will be removed, please migrate to hush.
278 297
279//applet:IF_HUSH(APPLET(hush, BB_DIR_BIN, BB_SUID_DROP)) 298//applet:IF_HUSH(APPLET(hush, BB_DIR_BIN, BB_SUID_DROP))
280// APPLET_ODDNAME:name main location suid_type help 299// APPLET_ODDNAME:name main location suid_type help
281//applet:IF_MSH( APPLET_ODDNAME(msh, hush, BB_DIR_BIN, BB_SUID_DROP, hush))
282//applet:IF_SH_IS_HUSH( APPLET_ODDNAME(sh, hush, BB_DIR_BIN, BB_SUID_DROP, hush)) 300//applet:IF_SH_IS_HUSH( APPLET_ODDNAME(sh, hush, BB_DIR_BIN, BB_SUID_DROP, hush))
283//applet:IF_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, BB_DIR_BIN, BB_SUID_DROP, hush)) 301//applet:IF_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, BB_DIR_BIN, BB_SUID_DROP, hush))
284 302
@@ -293,7 +311,7 @@
293 * therefore we don't show them either. 311 * therefore we don't show them either.
294 */ 312 */
295//usage:#define hush_trivial_usage 313//usage:#define hush_trivial_usage
296//usage: "[-nxl] [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]" 314//usage: "[-enxl] [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
297//usage:#define hush_full_usage "\n\n" 315//usage:#define hush_full_usage "\n\n"
298//usage: "Unix shell interpreter" 316//usage: "Unix shell interpreter"
299 317
@@ -331,9 +349,9 @@
331/* Separate defines document which part of code implements what */ 349/* Separate defines document which part of code implements what */
332#define BASH_PATTERN_SUBST ENABLE_HUSH_BASH_COMPAT 350#define BASH_PATTERN_SUBST ENABLE_HUSH_BASH_COMPAT
333#define BASH_SUBSTR ENABLE_HUSH_BASH_COMPAT 351#define BASH_SUBSTR ENABLE_HUSH_BASH_COMPAT
334#define BASH_TEST2 ENABLE_HUSH_BASH_COMPAT
335#define BASH_SOURCE ENABLE_HUSH_BASH_COMPAT 352#define BASH_SOURCE ENABLE_HUSH_BASH_COMPAT
336#define BASH_HOSTNAME_VAR ENABLE_HUSH_BASH_COMPAT 353#define BASH_HOSTNAME_VAR ENABLE_HUSH_BASH_COMPAT
354#define BASH_TEST2 (ENABLE_HUSH_BASH_COMPAT && ENABLE_HUSH_TEST)
337 355
338 356
339/* Build knobs */ 357/* Build knobs */
@@ -410,6 +428,7 @@
410#define debug_printf_expand(...) do {} while (0) 428#define debug_printf_expand(...) do {} while (0)
411#define debug_printf_varexp(...) do {} while (0) 429#define debug_printf_varexp(...) do {} while (0)
412#define debug_printf_glob(...) do {} while (0) 430#define debug_printf_glob(...) do {} while (0)
431#define debug_printf_redir(...) do {} while (0)
413#define debug_printf_list(...) do {} while (0) 432#define debug_printf_list(...) do {} while (0)
414#define debug_printf_subst(...) do {} while (0) 433#define debug_printf_subst(...) do {} while (0)
415#define debug_printf_clean(...) do {} while (0) 434#define debug_printf_clean(...) do {} while (0)
@@ -753,6 +772,7 @@ struct function {
753static const char o_opt_strings[] ALIGN1 = 772static const char o_opt_strings[] ALIGN1 =
754 "pipefail\0" 773 "pipefail\0"
755 "noexec\0" 774 "noexec\0"
775 "errexit\0"
756#if ENABLE_HUSH_MODE_X 776#if ENABLE_HUSH_MODE_X
757 "xtrace\0" 777 "xtrace\0"
758#endif 778#endif
@@ -760,6 +780,7 @@ static const char o_opt_strings[] ALIGN1 =
760enum { 780enum {
761 OPT_O_PIPEFAIL, 781 OPT_O_PIPEFAIL,
762 OPT_O_NOEXEC, 782 OPT_O_NOEXEC,
783 OPT_O_ERREXIT,
763#if ENABLE_HUSH_MODE_X 784#if ENABLE_HUSH_MODE_X
764 OPT_O_XTRACE, 785 OPT_O_XTRACE,
765#endif 786#endif
@@ -816,6 +837,25 @@ struct globals {
816#else 837#else
817# define G_saved_tty_pgrp 0 838# define G_saved_tty_pgrp 0
818#endif 839#endif
840 /* How deeply are we in context where "set -e" is ignored */
841 int errexit_depth;
842 /* "set -e" rules (do we follow them correctly?):
843 * Exit if pipe, list, or compound command exits with a non-zero status.
844 * Shell does not exit if failed command is part of condition in
845 * if/while, part of && or || list except the last command, any command
846 * in a pipe but the last, or if the command's return value is being
847 * inverted with !. If a compound command other than a subshell returns a
848 * non-zero status because a command failed while -e was being ignored, the
849 * shell does not exit. A trap on ERR, if set, is executed before the shell
850 * exits [ERR is a bashism].
851 *
852 * If a compound command or function executes in a context where -e is
853 * ignored, none of the commands executed within are affected by the -e
854 * setting. If a compound command or function sets -e while executing in a
855 * context where -e is ignored, that setting does not have any effect until
856 * the compound command or the command containing the function call completes.
857 */
858
819 char o_opt[NUM_OPT_O]; 859 char o_opt[NUM_OPT_O];
820#if ENABLE_HUSH_MODE_X 860#if ENABLE_HUSH_MODE_X
821# define G_x_mode (G.o_opt[OPT_O_XTRACE]) 861# define G_x_mode (G.o_opt[OPT_O_XTRACE])
@@ -839,6 +879,7 @@ struct globals {
839 smallint exiting; /* used to prevent EXIT trap recursion */ 879 smallint exiting; /* used to prevent EXIT trap recursion */
840 /* These four support $?, $#, and $1 */ 880 /* These four support $?, $#, and $1 */
841 smalluint last_exitcode; 881 smalluint last_exitcode;
882 smalluint last_bg_pid_exitcode;
842#if ENABLE_HUSH_SET 883#if ENABLE_HUSH_SET
843 /* are global_argv and global_argv[1..n] malloced? (note: not [0]) */ 884 /* are global_argv and global_argv[1..n] malloced? (note: not [0]) */
844 smalluint global_args_malloced; 885 smalluint global_args_malloced;
@@ -929,6 +970,9 @@ static int builtin_exit(char **argv) FAST_FUNC;
929#if ENABLE_HUSH_EXPORT 970#if ENABLE_HUSH_EXPORT
930static int builtin_export(char **argv) FAST_FUNC; 971static int builtin_export(char **argv) FAST_FUNC;
931#endif 972#endif
973#if ENABLE_HUSH_READONLY
974static int builtin_readonly(char **argv) FAST_FUNC;
975#endif
932#if ENABLE_HUSH_JOB 976#if ENABLE_HUSH_JOB
933static int builtin_fg_bg(char **argv) FAST_FUNC; 977static int builtin_fg_bg(char **argv) FAST_FUNC;
934static int builtin_jobs(char **argv) FAST_FUNC; 978static int builtin_jobs(char **argv) FAST_FUNC;
@@ -1047,6 +1091,9 @@ static const struct built_in_command bltins1[] = {
1047#if ENABLE_HUSH_READ 1091#if ENABLE_HUSH_READ
1048 BLTIN("read" , builtin_read , "Input into variable"), 1092 BLTIN("read" , builtin_read , "Input into variable"),
1049#endif 1093#endif
1094#if ENABLE_HUSH_READONLY
1095 BLTIN("readonly" , builtin_readonly, "Make variables read-only"),
1096#endif
1050#if ENABLE_HUSH_FUNCTIONS 1097#if ENABLE_HUSH_FUNCTIONS
1051 BLTIN("return" , builtin_return , "Return from function"), 1098 BLTIN("return" , builtin_return , "Return from function"),
1052#endif 1099#endif
@@ -1154,6 +1201,10 @@ static const struct built_in_command bltins2[] = {
1154# define DEBUG_GLOB 0 1201# define DEBUG_GLOB 0
1155#endif 1202#endif
1156 1203
1204#ifndef debug_printf_redir
1205# define debug_printf_redir(...) (indent(), fdprintf(2, __VA_ARGS__))
1206#endif
1207
1157#ifndef debug_printf_list 1208#ifndef debug_printf_list
1158# define debug_printf_list(...) (indent(), fdprintf(2, __VA_ARGS__)) 1209# define debug_printf_list(...) (indent(), fdprintf(2, __VA_ARGS__))
1159#endif 1210#endif
@@ -1389,12 +1440,30 @@ static void free_strings(char **strings)
1389 free(strings); 1440 free(strings);
1390} 1441}
1391 1442
1443static int fcntl_F_DUPFD(int fd, int avoid_fd)
1444{
1445 int newfd;
1446 repeat:
1447 newfd = fcntl(fd, F_DUPFD, avoid_fd + 1);
1448 if (newfd < 0) {
1449 if (errno == EBUSY)
1450 goto repeat;
1451 if (errno == EINTR)
1452 goto repeat;
1453 }
1454 return newfd;
1455}
1392 1456
1393static int xdup_and_close(int fd, int F_DUPFD_maybe_CLOEXEC) 1457static int xdup_and_close(int fd, int F_DUPFD_maybe_CLOEXEC, int avoid_fd)
1394{ 1458{
1395 /* We avoid taking stdio fds. Mimicking ash: use fds above 9 */ 1459 int newfd;
1396 int newfd = fcntl(fd, F_DUPFD_maybe_CLOEXEC, 10); 1460 repeat:
1461 newfd = fcntl(fd, F_DUPFD_maybe_CLOEXEC, avoid_fd + 1);
1397 if (newfd < 0) { 1462 if (newfd < 0) {
1463 if (errno == EBUSY)
1464 goto repeat;
1465 if (errno == EINTR)
1466 goto repeat;
1398 /* fd was not open? */ 1467 /* fd was not open? */
1399 if (errno == EBADF) 1468 if (errno == EBADF)
1400 return fd; 1469 return fd;
@@ -1432,13 +1501,14 @@ static void fclose_and_forget(FILE *fp)
1432 } 1501 }
1433 fclose(fp); 1502 fclose(fp);
1434} 1503}
1435static int save_FILEs_on_redirect(int fd) 1504static int save_FILEs_on_redirect(int fd, int avoid_fd)
1436{ 1505{
1437 struct FILE_list *fl = G.FILE_list; 1506 struct FILE_list *fl = G.FILE_list;
1438 while (fl) { 1507 while (fl) {
1439 if (fd == fl->fd) { 1508 if (fd == fl->fd) {
1440 /* We use it only on script files, they are all CLOEXEC */ 1509 /* We use it only on script files, they are all CLOEXEC */
1441 fl->fd = xdup_and_close(fd, F_DUPFD_CLOEXEC); 1510 fl->fd = xdup_and_close(fd, F_DUPFD_CLOEXEC, avoid_fd);
1511 debug_printf_redir("redirect_fd %d: matches a script fd, moving it to %d\n", fd, fl->fd);
1442 return 1; 1512 return 1;
1443 } 1513 }
1444 fl = fl->next; 1514 fl = fl->next;
@@ -1451,13 +1521,14 @@ static void restore_redirected_FILEs(void)
1451 while (fl) { 1521 while (fl) {
1452 int should_be = fileno(fl->fp); 1522 int should_be = fileno(fl->fp);
1453 if (fl->fd != should_be) { 1523 if (fl->fd != should_be) {
1524 debug_printf_redir("restoring script fd from %d to %d\n", fl->fd, should_be);
1454 xmove_fd(fl->fd, should_be); 1525 xmove_fd(fl->fd, should_be);
1455 fl->fd = should_be; 1526 fl->fd = should_be;
1456 } 1527 }
1457 fl = fl->next; 1528 fl = fl->next;
1458 } 1529 }
1459} 1530}
1460#if ENABLE_FEATURE_SH_STANDALONE 1531#if ENABLE_FEATURE_SH_STANDALONE && BB_MMU
1461static void close_all_FILE_list(void) 1532static void close_all_FILE_list(void)
1462{ 1533{
1463 struct FILE_list *fl = G.FILE_list; 1534 struct FILE_list *fl = G.FILE_list;
@@ -1486,8 +1557,6 @@ typedef struct save_arg_t {
1486 1557
1487static void save_and_replace_G_args(save_arg_t *sv, char **argv) 1558static void save_and_replace_G_args(save_arg_t *sv, char **argv)
1488{ 1559{
1489 int n;
1490
1491 sv->sv_argv0 = argv[0]; 1560 sv->sv_argv0 = argv[0];
1492 sv->sv_g_argv = G.global_argv; 1561 sv->sv_g_argv = G.global_argv;
1493 sv->sv_g_argc = G.global_argc; 1562 sv->sv_g_argc = G.global_argc;
@@ -1497,10 +1566,7 @@ static void save_and_replace_G_args(save_arg_t *sv, char **argv)
1497 G.global_argv = argv; 1566 G.global_argv = argv;
1498 IF_HUSH_SET(G.global_args_malloced = 0;) 1567 IF_HUSH_SET(G.global_args_malloced = 0;)
1499 1568
1500 n = 1; 1569 G.global_argc = 1 + string_array_len(argv + 1);
1501 while (*++argv)
1502 n++;
1503 G.global_argc = n;
1504} 1570}
1505 1571
1506static void restore_G_args(save_arg_t *sv, char **argv) 1572static void restore_G_args(save_arg_t *sv, char **argv)
@@ -1991,32 +2057,19 @@ static const char* FAST_FUNC get_local_var_value(const char *name)
1991 2057
1992/* str holds "NAME=VAL" and is expected to be malloced. 2058/* str holds "NAME=VAL" and is expected to be malloced.
1993 * We take ownership of it. 2059 * We take ownership of it.
1994 * flg_export:
1995 * 0: do not change export flag
1996 * (if creating new variable, flag will be 0)
1997 * 1: set export flag and putenv the variable
1998 * -1: clear export flag and unsetenv the variable
1999 * flg_read_only is set only when we handle -R var=val
2000 */ 2060 */
2001#if !BB_MMU && ENABLE_HUSH_LOCAL 2061#define SETFLAG_EXPORT (1 << 0)
2002/* all params are used */ 2062#define SETFLAG_UNEXPORT (1 << 1)
2003#elif BB_MMU && ENABLE_HUSH_LOCAL 2063#define SETFLAG_MAKE_RO (1 << 2)
2004#define set_local_var(str, flg_export, local_lvl, flg_read_only) \ 2064#define SETFLAG_LOCAL_SHIFT 3
2005 set_local_var(str, flg_export, local_lvl) 2065static int set_local_var(char *str, unsigned flags)
2006#elif BB_MMU && !ENABLE_HUSH_LOCAL
2007#define set_local_var(str, flg_export, local_lvl, flg_read_only) \
2008 set_local_var(str, flg_export)
2009#elif !BB_MMU && !ENABLE_HUSH_LOCAL
2010#define set_local_var(str, flg_export, local_lvl, flg_read_only) \
2011 set_local_var(str, flg_export, flg_read_only)
2012#endif
2013static int set_local_var(char *str, int flg_export, int local_lvl, int flg_read_only)
2014{ 2066{
2015 struct variable **var_pp; 2067 struct variable **var_pp;
2016 struct variable *cur; 2068 struct variable *cur;
2017 char *free_me = NULL; 2069 char *free_me = NULL;
2018 char *eq_sign; 2070 char *eq_sign;
2019 int name_len; 2071 int name_len;
2072 IF_HUSH_LOCAL(unsigned local_lvl = (flags >> SETFLAG_LOCAL_SHIFT);)
2020 2073
2021 eq_sign = strchr(str, '='); 2074 eq_sign = strchr(str, '=');
2022 if (!eq_sign) { /* not expected to ever happen? */ 2075 if (!eq_sign) { /* not expected to ever happen? */
@@ -2034,14 +2087,13 @@ static int set_local_var(char *str, int flg_export, int local_lvl, int flg_read_
2034 2087
2035 /* We found an existing var with this name */ 2088 /* We found an existing var with this name */
2036 if (cur->flg_read_only) { 2089 if (cur->flg_read_only) {
2037#if !BB_MMU 2090 bb_error_msg("%s: readonly variable", str);
2038 if (!flg_read_only)
2039#endif
2040 bb_error_msg("%s: readonly variable", str);
2041 free(str); 2091 free(str);
2092//NOTE: in bash, assignment in "export READONLY_VAR=Z" fails, and sets $?=1,
2093//but export per se succeeds (does put the var in env). We don't mimic that.
2042 return -1; 2094 return -1;
2043 } 2095 }
2044 if (flg_export == -1) { // "&& cur->flg_export" ? 2096 if (flags & SETFLAG_UNEXPORT) { // && cur->flg_export ?
2045 debug_printf_env("%s: unsetenv '%s'\n", __func__, str); 2097 debug_printf_env("%s: unsetenv '%s'\n", __func__, str);
2046 *eq_sign = '\0'; 2098 *eq_sign = '\0';
2047 unsetenv(str); 2099 unsetenv(str);
@@ -2065,7 +2117,7 @@ static int set_local_var(char *str, int flg_export, int local_lvl, int flg_read_
2065 * z=z 2117 * z=z
2066 */ 2118 */
2067 if (cur->flg_export) 2119 if (cur->flg_export)
2068 flg_export = 1; 2120 flags |= SETFLAG_EXPORT;
2069 break; 2121 break;
2070 } 2122 }
2071#endif 2123#endif
@@ -2096,24 +2148,24 @@ static int set_local_var(char *str, int flg_export, int local_lvl, int flg_read_
2096 2148
2097 /* Not found - create new variable struct */ 2149 /* Not found - create new variable struct */
2098 cur = xzalloc(sizeof(*cur)); 2150 cur = xzalloc(sizeof(*cur));
2099#if ENABLE_HUSH_LOCAL 2151 IF_HUSH_LOCAL(cur->func_nest_level = local_lvl;)
2100 cur->func_nest_level = local_lvl;
2101#endif
2102 cur->next = *var_pp; 2152 cur->next = *var_pp;
2103 *var_pp = cur; 2153 *var_pp = cur;
2104 2154
2105 set_str_and_exp: 2155 set_str_and_exp:
2106 cur->varstr = str; 2156 cur->varstr = str;
2107#if !BB_MMU
2108 cur->flg_read_only = flg_read_only;
2109#endif
2110 exp: 2157 exp:
2111 if (flg_export == 1) 2158#if !BB_MMU || ENABLE_HUSH_READONLY
2159 if (flags & SETFLAG_MAKE_RO) {
2160 cur->flg_read_only = 1;
2161 }
2162#endif
2163 if (flags & SETFLAG_EXPORT)
2112 cur->flg_export = 1; 2164 cur->flg_export = 1;
2113 if (name_len == 4 && cur->varstr[0] == 'P' && cur->varstr[1] == 'S') 2165 if (name_len == 4 && cur->varstr[0] == 'P' && cur->varstr[1] == 'S')
2114 cmdedit_update_prompt(); 2166 cmdedit_update_prompt();
2115 if (cur->flg_export) { 2167 if (cur->flg_export) {
2116 if (flg_export == -1) { 2168 if (flags & SETFLAG_UNEXPORT) {
2117 cur->flg_export = 0; 2169 cur->flg_export = 0;
2118 /* unsetenv was already done */ 2170 /* unsetenv was already done */
2119 } else { 2171 } else {
@@ -2130,10 +2182,9 @@ static int set_local_var(char *str, int flg_export, int local_lvl, int flg_read_
2130} 2182}
2131 2183
2132/* Used at startup and after each cd */ 2184/* Used at startup and after each cd */
2133static void set_pwd_var(int exp) 2185static void set_pwd_var(unsigned flag)
2134{ 2186{
2135 set_local_var(xasprintf("PWD=%s", get_cwd(/*force:*/ 1)), 2187 set_local_var(xasprintf("PWD=%s", get_cwd(/*force:*/ 1)), flag);
2136 /*exp:*/ exp, /*lvl:*/ 0, /*ro:*/ 0);
2137} 2188}
2138 2189
2139static int unset_local_var_len(const char *name, int name_len) 2190static int unset_local_var_len(const char *name, int name_len)
@@ -2191,7 +2242,7 @@ static void unset_vars(char **strings)
2191static void FAST_FUNC set_local_var_from_halves(const char *name, const char *val) 2242static void FAST_FUNC set_local_var_from_halves(const char *name, const char *val)
2192{ 2243{
2193 char *var = xasprintf("%s=%s", name, val); 2244 char *var = xasprintf("%s=%s", name, val);
2194 set_local_var(var, /*flags:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); 2245 set_local_var(var, /*flag:*/ 0);
2195} 2246}
2196#endif 2247#endif
2197 2248
@@ -2234,16 +2285,32 @@ static struct variable *set_vars_and_save_old(char **strings)
2234 if (eq) { 2285 if (eq) {
2235 var_pp = get_ptr_to_local_var(*s, eq - *s); 2286 var_pp = get_ptr_to_local_var(*s, eq - *s);
2236 if (var_pp) { 2287 if (var_pp) {
2237 /* Remove variable from global linked list */
2238 var_p = *var_pp; 2288 var_p = *var_pp;
2289 if (var_p->flg_read_only) {
2290 char **p;
2291 bb_error_msg("%s: readonly variable", *s);
2292 /*
2293 * "VAR=V BLTIN" unsets VARs after BLTIN completes.
2294 * If VAR is readonly, leaving it in the list
2295 * after asssignment error (msg above)
2296 * causes doubled error message later, on unset.
2297 */
2298 debug_printf_env("removing/freeing '%s' element\n", *s);
2299 free(*s);
2300 p = s;
2301 do { *p = p[1]; p++; } while (*p);
2302 goto next;
2303 }
2304 /* Remove variable from global linked list */
2239 debug_printf_env("%s: removing '%s'\n", __func__, var_p->varstr); 2305 debug_printf_env("%s: removing '%s'\n", __func__, var_p->varstr);
2240 *var_pp = var_p->next; 2306 *var_pp = var_p->next;
2241 /* Add it to returned list */ 2307 /* Add it to returned list */
2242 var_p->next = old; 2308 var_p->next = old;
2243 old = var_p; 2309 old = var_p;
2244 } 2310 }
2245 set_local_var(*s, /*exp:*/ 1, /*lvl:*/ 0, /*ro:*/ 0); 2311 set_local_var(*s, SETFLAG_EXPORT);
2246 } 2312 }
2313 next:
2247 s++; 2314 s++;
2248 } 2315 }
2249 return old; 2316 return old;
@@ -3339,12 +3406,49 @@ static void done_pipe(struct parse_context *ctx, pipe_style type)
3339 debug_printf_parse("done_pipe entered, followup %d\n", type); 3406 debug_printf_parse("done_pipe entered, followup %d\n", type);
3340 /* Close previous command */ 3407 /* Close previous command */
3341 not_null = done_command(ctx); 3408 not_null = done_command(ctx);
3342 ctx->pipe->followup = type;
3343#if HAS_KEYWORDS 3409#if HAS_KEYWORDS
3344 ctx->pipe->pi_inverted = ctx->ctx_inverted; 3410 ctx->pipe->pi_inverted = ctx->ctx_inverted;
3345 ctx->ctx_inverted = 0; 3411 ctx->ctx_inverted = 0;
3346 ctx->pipe->res_word = ctx->ctx_res_w; 3412 ctx->pipe->res_word = ctx->ctx_res_w;
3347#endif 3413#endif
3414 if (type == PIPE_BG && ctx->list_head != ctx->pipe) {
3415 /* Necessary since && and || have precedence over &:
3416 * "cmd1 && cmd2 &" must spawn both cmds, not only cmd2,
3417 * in a backgrounded subshell.
3418 */
3419 struct pipe *pi;
3420 struct command *command;
3421
3422 /* Is this actually this construct, all pipes end with && or ||? */
3423 pi = ctx->list_head;
3424 while (pi != ctx->pipe) {
3425 if (pi->followup != PIPE_AND && pi->followup != PIPE_OR)
3426 goto no_conv;
3427 pi = pi->next;
3428 }
3429
3430 debug_printf_parse("BG with more than one pipe, converting to { p1 &&...pN; } &\n");
3431 pi->followup = PIPE_SEQ; /* close pN _not_ with "&"! */
3432 pi = xzalloc(sizeof(*pi));
3433 pi->followup = PIPE_BG;
3434 pi->num_cmds = 1;
3435 pi->cmds = xzalloc(sizeof(pi->cmds[0]));
3436 command = &pi->cmds[0];
3437 if (CMD_NORMAL != 0) /* "if xzalloc didn't do that already" */
3438 command->cmd_type = CMD_NORMAL;
3439 command->group = ctx->list_head;
3440#if !BB_MMU
3441 command->group_as_string = xstrndup(
3442 ctx->as_string.data,
3443 ctx->as_string.length - 1 /* do not copy last char, "&" */
3444 );
3445#endif
3446 /* Replace all pipes in ctx with one newly created */
3447 ctx->list_head = ctx->pipe = pi;
3448 } else {
3449 no_conv:
3450 ctx->pipe->followup = type;
3451 }
3348 3452
3349 /* Without this check, even just <enter> on command line generates 3453 /* Without this check, even just <enter> on command line generates
3350 * tree of three NOPs (!). Which is harmless but annoying. 3454 * tree of three NOPs (!). Which is harmless but annoying.
@@ -3514,9 +3618,8 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
3514 if (r->flag & FLAG_START) { 3618 if (r->flag & FLAG_START) {
3515 struct parse_context *old; 3619 struct parse_context *old;
3516 3620
3517 old = xmalloc(sizeof(*old)); 3621 old = xmemdup(ctx, sizeof(*ctx));
3518 debug_printf_parse("push stack %p\n", old); 3622 debug_printf_parse("push stack %p\n", old);
3519 *old = *ctx; /* physical copy */
3520 initialize_context(ctx); 3623 initialize_context(ctx);
3521 ctx->stack = old; 3624 ctx->stack = old;
3522 } else if (/*ctx->ctx_res_w == RES_NONE ||*/ !(ctx->old_flag & (1 << r->res))) { 3625 } else if (/*ctx->ctx_res_w == RES_NONE ||*/ !(ctx->old_flag & (1 << r->res))) {
@@ -4787,7 +4890,9 @@ static struct pipe *parse_stream(char **pstring,
4787 * Really, ask yourself, why 4890 * Really, ask yourself, why
4788 * "cmd && <newline>" doesn't start 4891 * "cmd && <newline>" doesn't start
4789 * cmd but waits for more input? 4892 * cmd but waits for more input?
4790 * No reason...) 4893 * The only reason is that it might be
4894 * a "cmd1 && <nl> cmd2 &" construct,
4895 * cmd1 may need to run in BG).
4791 */ 4896 */
4792 struct pipe *pi = ctx.list_head; 4897 struct pipe *pi = ctx.list_head;
4793 if (pi->num_cmds != 0 /* check #1 */ 4898 if (pi->num_cmds != 0 /* check #1 */
@@ -5146,7 +5251,7 @@ static struct pipe *parse_stream(char **pstring,
5146 * and it will match } earlier (not here). */ 5251 * and it will match } earlier (not here). */
5147 syntax_error_unexpected_ch(ch); 5252 syntax_error_unexpected_ch(ch);
5148 G.last_exitcode = 2; 5253 G.last_exitcode = 2;
5149 goto parse_error1; 5254 goto parse_error2;
5150 default: 5255 default:
5151 if (HUSH_DEBUG) 5256 if (HUSH_DEBUG)
5152 bb_error_msg_and_die("BUG: unexpected %c\n", ch); 5257 bb_error_msg_and_die("BUG: unexpected %c\n", ch);
@@ -5155,7 +5260,7 @@ static struct pipe *parse_stream(char **pstring,
5155 5260
5156 parse_error: 5261 parse_error:
5157 G.last_exitcode = 1; 5262 G.last_exitcode = 1;
5158 parse_error1: 5263 parse_error2:
5159 { 5264 {
5160 struct parse_context *pctx; 5265 struct parse_context *pctx;
5161 IF_HAS_KEYWORDS(struct parse_context *p2;) 5266 IF_HAS_KEYWORDS(struct parse_context *p2;)
@@ -5202,7 +5307,7 @@ static struct pipe *parse_stream(char **pstring,
5202/*** Execution routines ***/ 5307/*** Execution routines ***/
5203 5308
5204/* Expansion can recurse, need forward decls: */ 5309/* Expansion can recurse, need forward decls: */
5205#if !BASH_PATTERN_SUBST 5310#if !BASH_PATTERN_SUBST && !ENABLE_HUSH_CASE
5206/* only ${var/pattern/repl} (its pattern part) needs additional mode */ 5311/* only ${var/pattern/repl} (its pattern part) needs additional mode */
5207#define expand_string_to_string(str, do_unbackslash) \ 5312#define expand_string_to_string(str, do_unbackslash) \
5208 expand_string_to_string(str) 5313 expand_string_to_string(str)
@@ -5330,6 +5435,9 @@ static int expand_on_ifs(int *ended_with_ifs, o_string *output, int n, const cha
5330#endif 5435#endif
5331static char *encode_then_expand_string(const char *str, int process_bkslash, int do_unbackslash) 5436static char *encode_then_expand_string(const char *str, int process_bkslash, int do_unbackslash)
5332{ 5437{
5438#if !BASH_PATTERN_SUBST
5439 const int do_unbackslash = 1;
5440#endif
5333 char *exp_str; 5441 char *exp_str;
5334 struct in_str input; 5442 struct in_str input;
5335 o_string dest = NULL_O_STRING; 5443 o_string dest = NULL_O_STRING;
@@ -5628,27 +5736,34 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
5628 if (errmsg) 5736 if (errmsg)
5629 goto arith_err; 5737 goto arith_err;
5630 debug_printf_varexp("len:'%s'=%lld\n", exp_word, (long long)len); 5738 debug_printf_varexp("len:'%s'=%lld\n", exp_word, (long long)len);
5631 if (len >= 0) { /* bash compat: len < 0 is illegal */ 5739 if (beg < 0) {
5632 if (beg < 0) /* bash compat */ 5740 /* negative beg counts from the end */
5633 beg = 0; 5741 beg = (arith_t)strlen(val) + beg;
5634 debug_printf_varexp("from val:'%s'\n", val); 5742 if (beg < 0) /* ${v: -999999} is "" */
5635 if (len == 0 || !val || beg >= strlen(val)) { 5743 beg = len = 0;
5744 }
5745 debug_printf_varexp("from val:'%s'\n", val);
5746 if (len < 0) {
5747 /* in bash, len=-n means strlen()-n */
5748 len = (arith_t)strlen(val) - beg + len;
5749 if (len < 0) /* bash compat */
5750 die_if_script("%s: substring expression < 0", var);
5751 }
5752 if (len <= 0 || !val || beg >= strlen(val)) {
5636 arith_err: 5753 arith_err:
5637 val = NULL;
5638 } else {
5639 /* Paranoia. What if user entered 9999999999999
5640 * which fits in arith_t but not int? */
5641 if (len >= INT_MAX)
5642 len = INT_MAX;
5643 val = to_be_freed = xstrndup(val + beg, len);
5644 }
5645 debug_printf_varexp("val:'%s'\n", val);
5646 } else
5647#endif /* HUSH_SUBSTR_EXPANSION && FEATURE_SH_MATH */
5648 {
5649 die_if_script("malformed ${%s:...}", var);
5650 val = NULL; 5754 val = NULL;
5755 } else {
5756 /* Paranoia. What if user entered 9999999999999
5757 * which fits in arith_t but not int? */
5758 if (len >= INT_MAX)
5759 len = INT_MAX;
5760 val = to_be_freed = xstrndup(val + beg, len);
5651 } 5761 }
5762 debug_printf_varexp("val:'%s'\n", val);
5763#else /* not (HUSH_SUBSTR_EXPANSION && FEATURE_SH_MATH) */
5764 die_if_script("malformed ${%s:...}", var);
5765 val = NULL;
5766#endif
5652 } else { /* one of "-=+?" */ 5767 } else { /* one of "-=+?" */
5653 /* Standard-mandated substitution ops: 5768 /* Standard-mandated substitution ops:
5654 * ${var?word} - indicate error if unset 5769 * ${var?word} - indicate error if unset
@@ -5700,7 +5815,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
5700 val = NULL; 5815 val = NULL;
5701 } else { 5816 } else {
5702 char *new_var = xasprintf("%s=%s", var, val); 5817 char *new_var = xasprintf("%s=%s", var, val);
5703 set_local_var(new_var, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); 5818 set_local_var(new_var, /*flag:*/ 0);
5704 } 5819 }
5705 } 5820 }
5706 } 5821 }
@@ -5949,7 +6064,7 @@ static char **expand_strvec_to_strvec_singleword_noglob(char **argv)
5949 */ 6064 */
5950static char *expand_string_to_string(const char *str, int do_unbackslash) 6065static char *expand_string_to_string(const char *str, int do_unbackslash)
5951{ 6066{
5952#if !BASH_PATTERN_SUBST 6067#if !BASH_PATTERN_SUBST && !ENABLE_HUSH_CASE
5953 const int do_unbackslash = 1; 6068 const int do_unbackslash = 1;
5954#endif 6069#endif
5955 char *argv[2], **list; 6070 char *argv[2], **list;
@@ -5982,7 +6097,7 @@ static char *expand_string_to_string(const char *str, int do_unbackslash)
5982 return (char*)list; 6097 return (char*)list;
5983} 6098}
5984 6099
5985/* Used for "eval" builtin */ 6100/* Used for "eval" builtin and case string */
5986static char* expand_strvec_to_string(char **argv) 6101static char* expand_strvec_to_string(char **argv)
5987{ 6102{
5988 char **list; 6103 char **list;
@@ -6524,77 +6639,108 @@ static void setup_heredoc(struct redir_struct *redir)
6524 wait(NULL); /* wait till child has died */ 6639 wait(NULL); /* wait till child has died */
6525} 6640}
6526 6641
6527/* fd: redirect wants this fd to be used (e.g. 3>file). 6642struct squirrel {
6528 * Move all conflicting internally used fds, 6643 int orig_fd;
6529 * and remember them so that we can restore them later. 6644 int moved_to;
6530 */ 6645 /* moved_to = n: fd was moved to n; restore back to orig_fd after redir */
6531static int save_fds_on_redirect(int fd, int squirrel[3]) 6646 /* moved_to = -1: fd was opened by redirect; close orig_fd after redir */
6647};
6648
6649static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd)
6532{ 6650{
6533 if (squirrel) { 6651 int i = 0;
6534 /* Handle redirects of fds 0,1,2 */
6535 6652
6536 /* If we collide with an already moved stdio fd... */ 6653 if (sq) while (sq[i].orig_fd >= 0) {
6537 if (fd == squirrel[0]) { 6654 /* If we collide with an already moved fd... */
6538 squirrel[0] = xdup_and_close(squirrel[0], F_DUPFD); 6655 if (fd == sq[i].moved_to) {
6539 return 1; 6656 sq[i].moved_to = fcntl_F_DUPFD(sq[i].moved_to, avoid_fd);
6540 } 6657 debug_printf_redir("redirect_fd %d: already busy, moving to %d\n", fd, sq[i].moved_to);
6541 if (fd == squirrel[1]) { 6658 if (sq[i].moved_to < 0) /* what? */
6542 squirrel[1] = xdup_and_close(squirrel[1], F_DUPFD);
6543 return 1;
6544 }
6545 if (fd == squirrel[2]) {
6546 squirrel[2] = xdup_and_close(squirrel[2], F_DUPFD);
6547 return 1;
6548 }
6549 /* If we are about to redirect stdio fd, and did not yet move it... */
6550 if (fd <= 2 && squirrel[fd] < 0) {
6551 /* We avoid taking stdio fds */
6552 squirrel[fd] = fcntl(fd, F_DUPFD, 10);
6553 if (squirrel[fd] < 0 && errno != EBADF)
6554 xfunc_die(); 6659 xfunc_die();
6555 return 0; /* "we did not close fd" */ 6660 return sq;
6661 }
6662 if (fd == sq[i].orig_fd) {
6663 /* Example: echo Hello >/dev/null 1>&2 */
6664 debug_printf_redir("redirect_fd %d: already moved\n", fd);
6665 return sq;
6556 } 6666 }
6667 i++;
6557 } 6668 }
6558 6669
6670 sq = xrealloc(sq, (i + 2) * sizeof(sq[0]));
6671 sq[i].orig_fd = fd;
6672 /* If this fd is open, we move and remember it; if it's closed, moved_to = -1 */
6673 sq[i].moved_to = fcntl_F_DUPFD(fd, avoid_fd);
6674 debug_printf_redir("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, sq[i].moved_to);
6675 if (sq[i].moved_to < 0 && errno != EBADF)
6676 xfunc_die();
6677 sq[i+1].orig_fd = -1; /* end marker */
6678 return sq;
6679}
6680
6681/* fd: redirect wants this fd to be used (e.g. 3>file).
6682 * Move all conflicting internally used fds,
6683 * and remember them so that we can restore them later.
6684 */
6685static int save_fds_on_redirect(int fd, int avoid_fd, struct squirrel **sqp)
6686{
6687 if (avoid_fd < 9) /* the important case here is that it can be -1 */
6688 avoid_fd = 9;
6689
6559#if ENABLE_HUSH_INTERACTIVE 6690#if ENABLE_HUSH_INTERACTIVE
6560 if (fd != 0 && fd == G.interactive_fd) { 6691 if (fd != 0 && fd == G.interactive_fd) {
6561 G.interactive_fd = xdup_and_close(G.interactive_fd, F_DUPFD_CLOEXEC); 6692 G.interactive_fd = xdup_and_close(G.interactive_fd, F_DUPFD_CLOEXEC, avoid_fd);
6562 return 1; 6693 debug_printf_redir("redirect_fd %d: matches interactive_fd, moving it to %d\n", fd, G.interactive_fd);
6694 return 1; /* "we closed fd" */
6563 } 6695 }
6564#endif 6696#endif
6565
6566 /* Are we called from setup_redirects(squirrel==NULL)? Two cases: 6697 /* Are we called from setup_redirects(squirrel==NULL)? Two cases:
6567 * (1) Redirect in a forked child. No need to save FILEs' fds, 6698 * (1) Redirect in a forked child. No need to save FILEs' fds,
6568 * we aren't going to use them anymore, ok to trash. 6699 * we aren't going to use them anymore, ok to trash.
6569 * (2) "exec 3>FILE". Bummer. We can save FILEs' fds, 6700 * (2) "exec 3>FILE". Bummer. We can save script FILEs' fds,
6570 * but how are we doing to use them? 6701 * but how are we doing to restore them?
6571 * "fileno(fd) = new_fd" can't be done. 6702 * "fileno(fd) = new_fd" can't be done.
6572 */ 6703 */
6573 if (!squirrel) 6704 if (!sqp)
6574 return 0; 6705 return 0;
6575 6706
6576 return save_FILEs_on_redirect(fd); 6707 /* If this one of script's fds? */
6708 if (save_FILEs_on_redirect(fd, avoid_fd))
6709 return 1; /* yes. "we closed fd" */
6710
6711 /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */
6712 *sqp = add_squirrel(*sqp, fd, avoid_fd);
6713 return 0; /* "we did not close fd" */
6577} 6714}
6578 6715
6579static void restore_redirects(int squirrel[3]) 6716static void restore_redirects(struct squirrel *sq)
6580{ 6717{
6581 int i, fd; 6718
6582 for (i = 0; i <= 2; i++) { 6719 if (sq) {
6583 fd = squirrel[i]; 6720 int i = 0;
6584 if (fd != -1) { 6721 while (sq[i].orig_fd >= 0) {
6585 /* We simply die on error */ 6722 if (sq[i].moved_to >= 0) {
6586 xmove_fd(fd, i); 6723 /* We simply die on error */
6724 debug_printf_redir("restoring redirected fd from %d to %d\n", sq[i].moved_to, sq[i].orig_fd);
6725 xmove_fd(sq[i].moved_to, sq[i].orig_fd);
6726 } else {
6727 /* cmd1 9>FILE; cmd2_should_see_fd9_closed */
6728 debug_printf_redir("restoring redirected fd %d: closing it\n", sq[i].orig_fd);
6729 close(sq[i].orig_fd);
6730 }
6731 i++;
6587 } 6732 }
6733 free(sq);
6588 } 6734 }
6589 6735
6590 /* Moved G.interactive_fd stays on new fd, not doing anything for it */ 6736 /* If moved, G.interactive_fd stays on new fd, not restoring it */
6591 6737
6592 restore_redirected_FILEs(); 6738 restore_redirected_FILEs();
6593} 6739}
6594 6740
6595/* squirrel != NULL means we squirrel away copies of stdin, stdout, 6741/* squirrel != NULL means we squirrel away copies of stdin, stdout,
6596 * and stderr if they are redirected. */ 6742 * and stderr if they are redirected. */
6597static int setup_redirects(struct command *prog, int squirrel[]) 6743static int setup_redirects(struct command *prog, struct squirrel **sqp)
6598{ 6744{
6599 int openfd, mode; 6745 int openfd, mode;
6600 struct redir_struct *redir; 6746 struct redir_struct *redir;
@@ -6602,7 +6748,7 @@ static int setup_redirects(struct command *prog, int squirrel[])
6602 for (redir = prog->redirects; redir; redir = redir->next) { 6748 for (redir = prog->redirects; redir; redir = redir->next) {
6603 if (redir->rd_type == REDIRECT_HEREDOC2) { 6749 if (redir->rd_type == REDIRECT_HEREDOC2) {
6604 /* "rd_fd<<HERE" case */ 6750 /* "rd_fd<<HERE" case */
6605 save_fds_on_redirect(redir->rd_fd, squirrel); 6751 save_fds_on_redirect(redir->rd_fd, /*avoid:*/ 0, sqp);
6606 /* for REDIRECT_HEREDOC2, rd_filename holds _contents_ 6752 /* for REDIRECT_HEREDOC2, rd_filename holds _contents_
6607 * of the heredoc */ 6753 * of the heredoc */
6608 debug_printf_parse("set heredoc '%s'\n", 6754 debug_printf_parse("set heredoc '%s'\n",
@@ -6641,7 +6787,7 @@ static int setup_redirects(struct command *prog, int squirrel[])
6641 } 6787 }
6642 6788
6643 if (openfd != redir->rd_fd) { 6789 if (openfd != redir->rd_fd) {
6644 int closed = save_fds_on_redirect(redir->rd_fd, squirrel); 6790 int closed = save_fds_on_redirect(redir->rd_fd, /*avoid:*/ openfd, sqp);
6645 if (openfd == REDIRFD_CLOSE) { 6791 if (openfd == REDIRFD_CLOSE) {
6646 /* "rd_fd >&-" means "close me" */ 6792 /* "rd_fd >&-" means "close me" */
6647 if (!closed) { 6793 if (!closed) {
@@ -6817,13 +6963,11 @@ static void exec_function(char ***to_free,
6817 char **argv) 6963 char **argv)
6818{ 6964{
6819# if BB_MMU 6965# if BB_MMU
6820 int n = 1; 6966 int n;
6821 6967
6822 argv[0] = G.global_argv[0]; 6968 argv[0] = G.global_argv[0];
6823 G.global_argv = argv; 6969 G.global_argv = argv;
6824 while (*++argv) 6970 G.global_argc = n = 1 + string_array_len(argv + 1);
6825 n++;
6826 G.global_argc = n;
6827 /* On MMU, funcp->body is always non-NULL */ 6971 /* On MMU, funcp->body is always non-NULL */
6828 n = run_list(funcp->body); 6972 n = run_list(funcp->body);
6829 fflush_all(); 6973 fflush_all();
@@ -7071,7 +7215,7 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
7071 /* Do not leak open fds from opened script files etc */ 7215 /* Do not leak open fds from opened script files etc */
7072 close_all_FILE_list(); 7216 close_all_FILE_list();
7073 debug_printf_exec("running applet '%s'\n", argv[0]); 7217 debug_printf_exec("running applet '%s'\n", argv[0]);
7074 run_applet_no_and_exit(a, argv); 7218 run_applet_no_and_exit(a, argv[0], argv);
7075 } 7219 }
7076# endif 7220# endif
7077 /* Re-exec ourselves */ 7221 /* Re-exec ourselves */
@@ -7168,24 +7312,54 @@ static const char *get_cmdtext(struct pipe *pi)
7168 return pi->cmdtext; 7312 return pi->cmdtext;
7169} 7313}
7170 7314
7171static void insert_bg_job(struct pipe *pi) 7315static void remove_job_from_table(struct pipe *pi)
7316{
7317 struct pipe *prev_pipe;
7318
7319 if (pi == G.job_list) {
7320 G.job_list = pi->next;
7321 } else {
7322 prev_pipe = G.job_list;
7323 while (prev_pipe->next != pi)
7324 prev_pipe = prev_pipe->next;
7325 prev_pipe->next = pi->next;
7326 }
7327 G.last_jobid = 0;
7328 if (G.job_list)
7329 G.last_jobid = G.job_list->jobid;
7330}
7331
7332static void delete_finished_job(struct pipe *pi)
7333{
7334 remove_job_from_table(pi);
7335 free_pipe(pi);
7336}
7337
7338static void clean_up_last_dead_job(void)
7339{
7340 if (G.job_list && !G.job_list->alive_cmds)
7341 delete_finished_job(G.job_list);
7342}
7343
7344static void insert_job_into_table(struct pipe *pi)
7172{ 7345{
7173 struct pipe *job, **jobp; 7346 struct pipe *job, **jobp;
7174 int i; 7347 int i;
7175 7348
7176 /* Linear search for the ID of the job to use */ 7349 clean_up_last_dead_job();
7177 pi->jobid = 1;
7178 for (job = G.job_list; job; job = job->next)
7179 if (job->jobid >= pi->jobid)
7180 pi->jobid = job->jobid + 1;
7181 7350
7182 /* Add job to the list of running jobs */ 7351 /* Find the end of the list, and find next job ID to use */
7352 i = 0;
7183 jobp = &G.job_list; 7353 jobp = &G.job_list;
7184 while ((job = *jobp) != NULL) 7354 while ((job = *jobp) != NULL) {
7355 if (job->jobid > i)
7356 i = job->jobid;
7185 jobp = &job->next; 7357 jobp = &job->next;
7186 job = *jobp = xmalloc(sizeof(*job)); 7358 }
7359 pi->jobid = i + 1;
7187 7360
7188 *job = *pi; /* physical copy */ 7361 /* Create a new job struct at the end */
7362 job = *jobp = xmemdup(pi, sizeof(*pi));
7189 job->next = NULL; 7363 job->next = NULL;
7190 job->cmds = xzalloc(sizeof(pi->cmds[0]) * pi->num_cmds); 7364 job->cmds = xzalloc(sizeof(pi->cmds[0]) * pi->num_cmds);
7191 /* Cannot copy entire pi->cmds[] vector! This causes double frees */ 7365 /* Cannot copy entire pi->cmds[] vector! This causes double frees */
@@ -7199,31 +7373,6 @@ static void insert_bg_job(struct pipe *pi)
7199 printf("[%u] %u %s\n", job->jobid, (unsigned)job->cmds[0].pid, job->cmdtext); 7373 printf("[%u] %u %s\n", job->jobid, (unsigned)job->cmds[0].pid, job->cmdtext);
7200 G.last_jobid = job->jobid; 7374 G.last_jobid = job->jobid;
7201} 7375}
7202
7203static void remove_bg_job(struct pipe *pi)
7204{
7205 struct pipe *prev_pipe;
7206
7207 if (pi == G.job_list) {
7208 G.job_list = pi->next;
7209 } else {
7210 prev_pipe = G.job_list;
7211 while (prev_pipe->next != pi)
7212 prev_pipe = prev_pipe->next;
7213 prev_pipe->next = pi->next;
7214 }
7215 if (G.job_list)
7216 G.last_jobid = G.job_list->jobid;
7217 else
7218 G.last_jobid = 0;
7219}
7220
7221/* Remove a backgrounded job */
7222static void delete_finished_bg_job(struct pipe *pi)
7223{
7224 remove_bg_job(pi);
7225 free_pipe(pi);
7226}
7227#endif /* JOB */ 7376#endif /* JOB */
7228 7377
7229static int job_exited_or_stopped(struct pipe *pi) 7378static int job_exited_or_stopped(struct pipe *pi)
@@ -7310,7 +7459,7 @@ static int process_wait_result(struct pipe *fg_pipe, pid_t childpid, int status)
7310 if (G_interactive_fd) { 7459 if (G_interactive_fd) {
7311#if ENABLE_HUSH_JOB 7460#if ENABLE_HUSH_JOB
7312 if (fg_pipe->alive_cmds != 0) 7461 if (fg_pipe->alive_cmds != 0)
7313 insert_bg_job(fg_pipe); 7462 insert_job_into_table(fg_pipe);
7314#endif 7463#endif
7315 return rcode; 7464 return rcode;
7316 } 7465 }
@@ -7339,16 +7488,31 @@ static int process_wait_result(struct pipe *fg_pipe, pid_t childpid, int status)
7339 found_pi_and_prognum: 7488 found_pi_and_prognum:
7340 if (dead) { 7489 if (dead) {
7341 /* child exited */ 7490 /* child exited */
7342 pi->cmds[i].pid = 0; 7491 int rcode = WEXITSTATUS(status);
7343 pi->cmds[i].cmd_exitcode = WEXITSTATUS(status);
7344 if (WIFSIGNALED(status)) 7492 if (WIFSIGNALED(status))
7345 pi->cmds[i].cmd_exitcode = 128 + WTERMSIG(status); 7493 rcode = 128 + WTERMSIG(status);
7494 pi->cmds[i].cmd_exitcode = rcode;
7495 if (G.last_bg_pid == pi->cmds[i].pid)
7496 G.last_bg_pid_exitcode = rcode;
7497 pi->cmds[i].pid = 0;
7346 pi->alive_cmds--; 7498 pi->alive_cmds--;
7347 if (!pi->alive_cmds) { 7499 if (!pi->alive_cmds) {
7348 if (G_interactive_fd) 7500 if (G_interactive_fd) {
7349 printf(JOB_STATUS_FORMAT, pi->jobid, 7501 printf(JOB_STATUS_FORMAT, pi->jobid,
7350 "Done", pi->cmdtext); 7502 "Done", pi->cmdtext);
7351 delete_finished_bg_job(pi); 7503 delete_finished_job(pi);
7504 } else {
7505/*
7506 * bash deletes finished jobs from job table only in interactive mode,
7507 * after "jobs" cmd, or if pid of a new process matches one of the old ones
7508 * (see cleanup_dead_jobs(), delete_old_job(), J_NOTIFIED in bash source).
7509 * Testcase script: "(exit 3) & sleep 1; wait %1; echo $?" prints 3 in bash.
7510 * We only retain one "dead" job, if it's the single job on the list.
7511 * This covers most of real-world scenarios where this is useful.
7512 */
7513 if (pi != G.job_list)
7514 delete_finished_job(pi);
7515 }
7352 } 7516 }
7353 } else { 7517 } else {
7354 /* child stopped */ 7518 /* child stopped */
@@ -7505,14 +7669,14 @@ static int checkjobs_and_fg_shell(struct pipe *fg_pipe)
7505static int redirect_and_varexp_helper(char ***new_env_p, 7669static int redirect_and_varexp_helper(char ***new_env_p,
7506 struct variable **old_vars_p, 7670 struct variable **old_vars_p,
7507 struct command *command, 7671 struct command *command,
7508 int squirrel[3], 7672 struct squirrel **sqp,
7509 char **argv_expanded) 7673 char **argv_expanded)
7510{ 7674{
7511 /* setup_redirects acts on file descriptors, not FILEs. 7675 /* setup_redirects acts on file descriptors, not FILEs.
7512 * This is perfect for work that comes after exec(). 7676 * This is perfect for work that comes after exec().
7513 * Is it really safe for inline use? Experimentally, 7677 * Is it really safe for inline use? Experimentally,
7514 * things seem to work. */ 7678 * things seem to work. */
7515 int rcode = setup_redirects(command, squirrel); 7679 int rcode = setup_redirects(command, sqp);
7516 if (rcode == 0) { 7680 if (rcode == 0) {
7517 char **new_env = expand_assignments(command->argv, command->assignment_cnt); 7681 char **new_env = expand_assignments(command->argv, command->assignment_cnt);
7518 *new_env_p = new_env; 7682 *new_env_p = new_env;
@@ -7532,8 +7696,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
7532 struct command *command; 7696 struct command *command;
7533 char **argv_expanded; 7697 char **argv_expanded;
7534 char **argv; 7698 char **argv;
7535 /* it is not always needed, but we aim to smaller code */ 7699 struct squirrel *squirrel = NULL;
7536 int squirrel[] = { -1, -1, -1 };
7537 int rcode; 7700 int rcode;
7538 7701
7539 debug_printf_exec("run_pipe start: members:%d\n", pi->num_cmds); 7702 debug_printf_exec("run_pipe start: members:%d\n", pi->num_cmds);
@@ -7590,7 +7753,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
7590 /* { list } */ 7753 /* { list } */
7591 debug_printf("non-subshell group\n"); 7754 debug_printf("non-subshell group\n");
7592 rcode = 1; /* exitcode if redir failed */ 7755 rcode = 1; /* exitcode if redir failed */
7593 if (setup_redirects(command, squirrel) == 0) { 7756 if (setup_redirects(command, &squirrel) == 0) {
7594 debug_printf_exec(": run_list\n"); 7757 debug_printf_exec(": run_list\n");
7595 rcode = run_list(command->group) & 0xff; 7758 rcode = run_list(command->group) & 0xff;
7596 } 7759 }
@@ -7617,15 +7780,15 @@ static NOINLINE int run_pipe(struct pipe *pi)
7617 /* Ensure redirects take effect (that is, create files). 7780 /* Ensure redirects take effect (that is, create files).
7618 * Try "a=t >file" */ 7781 * Try "a=t >file" */
7619#if 0 /* A few cases in testsuite fail with this code. FIXME */ 7782#if 0 /* A few cases in testsuite fail with this code. FIXME */
7620 rcode = redirect_and_varexp_helper(&new_env, /*old_vars:*/ NULL, command, squirrel, /*argv_expanded:*/ NULL); 7783 rcode = redirect_and_varexp_helper(&new_env, /*old_vars:*/ NULL, command, &squirrel, /*argv_expanded:*/ NULL);
7621 /* Set shell variables */ 7784 /* Set shell variables */
7622 if (new_env) { 7785 if (new_env) {
7623 argv = new_env; 7786 argv = new_env;
7624 while (*argv) { 7787 while (*argv) {
7625 set_local_var(*argv, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); 7788 if (set_local_var(*argv, /*flag:*/ 0)) {
7626 /* Do we need to flag set_local_var() errors? 7789 /* assignment to readonly var / putenv error? */
7627 * "assignment to readonly var" and "putenv error" 7790 rcode = 1;
7628 */ 7791 }
7629 argv++; 7792 argv++;
7630 } 7793 }
7631 } 7794 }
@@ -7639,7 +7802,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
7639 7802
7640#else /* Older, bigger, but more correct code */ 7803#else /* Older, bigger, but more correct code */
7641 7804
7642 rcode = setup_redirects(command, squirrel); 7805 rcode = setup_redirects(command, &squirrel);
7643 restore_redirects(squirrel); 7806 restore_redirects(squirrel);
7644 /* Set shell variables */ 7807 /* Set shell variables */
7645 if (G_x_mode) 7808 if (G_x_mode)
@@ -7650,10 +7813,10 @@ static NOINLINE int run_pipe(struct pipe *pi)
7650 fprintf(stderr, " %s", p); 7813 fprintf(stderr, " %s", p);
7651 debug_printf_exec("set shell var:'%s'->'%s'\n", 7814 debug_printf_exec("set shell var:'%s'->'%s'\n",
7652 *argv, p); 7815 *argv, p);
7653 set_local_var(p, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); 7816 if (set_local_var(p, /*flag:*/ 0)) {
7654 /* Do we need to flag set_local_var() errors? 7817 /* assignment to readonly var / putenv error? */
7655 * "assignment to readonly var" and "putenv error" 7818 rcode = 1;
7656 */ 7819 }
7657 argv++; 7820 argv++;
7658 } 7821 }
7659 if (G_x_mode) 7822 if (G_x_mode)
@@ -7702,7 +7865,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
7702 goto clean_up_and_ret1; 7865 goto clean_up_and_ret1;
7703 } 7866 }
7704 } 7867 }
7705 rcode = redirect_and_varexp_helper(&new_env, &old_vars, command, squirrel, argv_expanded); 7868 rcode = redirect_and_varexp_helper(&new_env, &old_vars, command, &squirrel, argv_expanded);
7706 if (rcode == 0) { 7869 if (rcode == 0) {
7707 if (!funcp) { 7870 if (!funcp) {
7708 debug_printf_exec(": builtin '%s' '%s'...\n", 7871 debug_printf_exec(": builtin '%s' '%s'...\n",
@@ -7743,7 +7906,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
7743 if (ENABLE_FEATURE_SH_NOFORK) { 7906 if (ENABLE_FEATURE_SH_NOFORK) {
7744 int n = find_applet_by_name(argv_expanded[0]); 7907 int n = find_applet_by_name(argv_expanded[0]);
7745 if (n >= 0 && APPLET_IS_NOFORK(n)) { 7908 if (n >= 0 && APPLET_IS_NOFORK(n)) {
7746 rcode = redirect_and_varexp_helper(&new_env, &old_vars, command, squirrel, argv_expanded); 7909 rcode = redirect_and_varexp_helper(&new_env, &old_vars, command, &squirrel, argv_expanded);
7747 if (rcode == 0) { 7910 if (rcode == 0) {
7748 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", 7911 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n",
7749 argv_expanded[0], argv_expanded[1]); 7912 argv_expanded[0], argv_expanded[1]);
@@ -7968,6 +8131,7 @@ static int run_list(struct pipe *pi)
7968 /* Go through list of pipes, (maybe) executing them. */ 8131 /* Go through list of pipes, (maybe) executing them. */
7969 for (; pi; pi = IF_HUSH_LOOPS(rword == RES_DONE ? loop_top : ) pi->next) { 8132 for (; pi; pi = IF_HUSH_LOOPS(rword == RES_DONE ? loop_top : ) pi->next) {
7970 int r; 8133 int r;
8134 int sv_errexit_depth;
7971 8135
7972 if (G.flag_SIGINT) 8136 if (G.flag_SIGINT)
7973 break; 8137 break;
@@ -7977,6 +8141,13 @@ static int run_list(struct pipe *pi)
7977 IF_HAS_KEYWORDS(rword = pi->res_word;) 8141 IF_HAS_KEYWORDS(rword = pi->res_word;)
7978 debug_printf_exec(": rword=%d cond_code=%d last_rword=%d\n", 8142 debug_printf_exec(": rword=%d cond_code=%d last_rword=%d\n",
7979 rword, cond_code, last_rword); 8143 rword, cond_code, last_rword);
8144
8145 sv_errexit_depth = G.errexit_depth;
8146 if (IF_HAS_KEYWORDS(rword == RES_IF || rword == RES_ELIF ||)
8147 pi->followup != PIPE_SEQ
8148 ) {
8149 G.errexit_depth++;
8150 }
7980#if ENABLE_HUSH_LOOPS 8151#if ENABLE_HUSH_LOOPS
7981 if ((rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR) 8152 if ((rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR)
7982 && loop_top == NULL /* avoid bumping G.depth_of_loop twice */ 8153 && loop_top == NULL /* avoid bumping G.depth_of_loop twice */
@@ -8054,7 +8225,7 @@ static int run_list(struct pipe *pi)
8054 } 8225 }
8055 /* Insert next value from for_lcur */ 8226 /* Insert next value from for_lcur */
8056 /* note: *for_lcur already has quotes removed, $var expanded, etc */ 8227 /* note: *for_lcur already has quotes removed, $var expanded, etc */
8057 set_local_var(xasprintf("%s=%s", pi->cmds[0].argv[0], *for_lcur++), /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); 8228 set_local_var(xasprintf("%s=%s", pi->cmds[0].argv[0], *for_lcur++), /*flag:*/ 0);
8058 continue; 8229 continue;
8059 } 8230 }
8060 if (rword == RES_IN) { 8231 if (rword == RES_IN) {
@@ -8068,6 +8239,7 @@ static int run_list(struct pipe *pi)
8068 if (rword == RES_CASE) { 8239 if (rword == RES_CASE) {
8069 debug_printf_exec("CASE cond_code:%d\n", cond_code); 8240 debug_printf_exec("CASE cond_code:%d\n", cond_code);
8070 case_word = expand_strvec_to_string(pi->cmds->argv); 8241 case_word = expand_strvec_to_string(pi->cmds->argv);
8242 unbackslash(case_word);
8071 continue; 8243 continue;
8072 } 8244 }
8073 if (rword == RES_MATCH) { 8245 if (rword == RES_MATCH) {
@@ -8079,9 +8251,10 @@ static int run_list(struct pipe *pi)
8079 /* all prev words didn't match, does this one match? */ 8251 /* all prev words didn't match, does this one match? */
8080 argv = pi->cmds->argv; 8252 argv = pi->cmds->argv;
8081 while (*argv) { 8253 while (*argv) {
8082 char *pattern = expand_string_to_string(*argv, /*unbackslash:*/ 1); 8254 char *pattern = expand_string_to_string(*argv, /*unbackslash:*/ 0);
8083 /* TODO: which FNM_xxx flags to use? */ 8255 /* TODO: which FNM_xxx flags to use? */
8084 cond_code = (fnmatch(pattern, case_word, /*flags:*/ 0) != 0); 8256 cond_code = (fnmatch(pattern, case_word, /*flags:*/ 0) != 0);
8257 debug_printf_exec("fnmatch(pattern:'%s',str:'%s'):%d\n", pattern, case_word, cond_code);
8085 free(pattern); 8258 free(pattern);
8086 if (cond_code == 0) { /* match! we will execute this branch */ 8259 if (cond_code == 0) { /* match! we will execute this branch */
8087 free(case_word); 8260 free(case_word);
@@ -8162,10 +8335,11 @@ static int run_list(struct pipe *pi)
8162 * I'm NOT treating inner &'s as jobs */ 8335 * I'm NOT treating inner &'s as jobs */
8163#if ENABLE_HUSH_JOB 8336#if ENABLE_HUSH_JOB
8164 if (G.run_list_level == 1) 8337 if (G.run_list_level == 1)
8165 insert_bg_job(pi); 8338 insert_job_into_table(pi);
8166#endif 8339#endif
8167 /* Last command's pid goes to $! */ 8340 /* Last command's pid goes to $! */
8168 G.last_bg_pid = pi->cmds[pi->num_cmds - 1].pid; 8341 G.last_bg_pid = pi->cmds[pi->num_cmds - 1].pid;
8342 G.last_bg_pid_exitcode = 0;
8169 debug_printf_exec(": cmd&: exitcode EXIT_SUCCESS\n"); 8343 debug_printf_exec(": cmd&: exitcode EXIT_SUCCESS\n");
8170/* Check pi->pi_inverted? "! sleep 1 & echo $?": bash says 1. dash and ash says 0 */ 8344/* Check pi->pi_inverted? "! sleep 1 & echo $?": bash says 1. dash and ash says 0 */
8171 rcode = EXIT_SUCCESS; 8345 rcode = EXIT_SUCCESS;
@@ -8187,6 +8361,14 @@ static int run_list(struct pipe *pi)
8187 check_and_run_traps(); 8361 check_and_run_traps();
8188 } 8362 }
8189 8363
8364 /* Handle "set -e" */
8365 if (rcode != 0 && G.o_opt[OPT_O_ERREXIT]) {
8366 debug_printf_exec("ERREXIT:1 errexit_depth:%d\n", G.errexit_depth);
8367 if (G.errexit_depth == 0)
8368 hush_exit(rcode);
8369 }
8370 G.errexit_depth = sv_errexit_depth;
8371
8190 /* Analyze how result affects subsequent commands */ 8372 /* Analyze how result affects subsequent commands */
8191#if ENABLE_HUSH_IF 8373#if ENABLE_HUSH_IF
8192 if (rword == RES_IF || rword == RES_ELIF) 8374 if (rword == RES_IF || rword == RES_ELIF)
@@ -8366,6 +8548,9 @@ static int set_mode(int state, char mode, const char *o_opt)
8366 G.o_opt[idx] = state; 8548 G.o_opt[idx] = state;
8367 break; 8549 break;
8368 } 8550 }
8551 case 'e':
8552 G.o_opt[OPT_O_ERREXIT] = state;
8553 break;
8369 default: 8554 default:
8370 return EXIT_FAILURE; 8555 return EXIT_FAILURE;
8371 } 8556 }
@@ -8425,7 +8610,7 @@ int hush_main(int argc, char **argv)
8425 putenv(shell_ver->varstr); 8610 putenv(shell_ver->varstr);
8426 8611
8427 /* Export PWD */ 8612 /* Export PWD */
8428 set_pwd_var(/*exp:*/ 1); 8613 set_pwd_var(SETFLAG_EXPORT);
8429 8614
8430#if BASH_HOSTNAME_VAR 8615#if BASH_HOSTNAME_VAR
8431 /* Set (but not export) HOSTNAME unless already set */ 8616 /* Set (but not export) HOSTNAME unless already set */
@@ -8492,7 +8677,7 @@ int hush_main(int argc, char **argv)
8492 flags = (argv[0] && argv[0][0] == '-') ? OPT_login : 0; 8677 flags = (argv[0] && argv[0][0] == '-') ? OPT_login : 0;
8493 builtin_argc = 0; 8678 builtin_argc = 0;
8494 while (1) { 8679 while (1) {
8495 opt = getopt(argc, argv, "+c:xinsl" 8680 opt = getopt(argc, argv, "+c:exinsl"
8496#if !BB_MMU 8681#if !BB_MMU
8497 "<:$:R:V:" 8682 "<:$:R:V:"
8498# if ENABLE_HUSH_FUNCTIONS 8683# if ENABLE_HUSH_FUNCTIONS
@@ -8575,8 +8760,9 @@ int hush_main(int argc, char **argv)
8575 optarg++; 8760 optarg++;
8576 empty_trap_mask = bb_strtoull(optarg, &optarg, 16); 8761 empty_trap_mask = bb_strtoull(optarg, &optarg, 16);
8577 if (empty_trap_mask != 0) { 8762 if (empty_trap_mask != 0) {
8578 int sig; 8763 IF_HUSH_TRAP(int sig;)
8579 install_special_sighandlers(); 8764 install_special_sighandlers();
8765# if ENABLE_HUSH_TRAP
8580 G_traps = xzalloc(sizeof(G_traps[0]) * NSIG); 8766 G_traps = xzalloc(sizeof(G_traps[0]) * NSIG);
8581 for (sig = 1; sig < NSIG; sig++) { 8767 for (sig = 1; sig < NSIG; sig++) {
8582 if (empty_trap_mask & (1LL << sig)) { 8768 if (empty_trap_mask & (1LL << sig)) {
@@ -8584,6 +8770,7 @@ int hush_main(int argc, char **argv)
8584 install_sighandler(sig, SIG_IGN); 8770 install_sighandler(sig, SIG_IGN);
8585 } 8771 }
8586 } 8772 }
8773# endif
8587 } 8774 }
8588# if ENABLE_HUSH_LOOPS 8775# if ENABLE_HUSH_LOOPS
8589 optarg++; 8776 optarg++;
@@ -8593,7 +8780,7 @@ int hush_main(int argc, char **argv)
8593 } 8780 }
8594 case 'R': 8781 case 'R':
8595 case 'V': 8782 case 'V':
8596 set_local_var(xstrdup(optarg), /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ opt == 'R'); 8783 set_local_var(xstrdup(optarg), opt == 'R' ? SETFLAG_MAKE_RO : 0);
8597 break; 8784 break;
8598# if ENABLE_HUSH_FUNCTIONS 8785# if ENABLE_HUSH_FUNCTIONS
8599 case 'F': { 8786 case 'F': {
@@ -8608,6 +8795,7 @@ int hush_main(int argc, char **argv)
8608#endif 8795#endif
8609 case 'n': 8796 case 'n':
8610 case 'x': 8797 case 'x':
8798 case 'e':
8611 if (set_mode(1, opt, NULL) == 0) /* no error */ 8799 if (set_mode(1, opt, NULL) == 0) /* no error */
8612 break; 8800 break;
8613 default: 8801 default:
@@ -8694,7 +8882,7 @@ int hush_main(int argc, char **argv)
8694 G_saved_tty_pgrp = 0; 8882 G_saved_tty_pgrp = 0;
8695 8883
8696 /* try to dup stdin to high fd#, >= 255 */ 8884 /* try to dup stdin to high fd#, >= 255 */
8697 G_interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255); 8885 G_interactive_fd = fcntl_F_DUPFD(STDIN_FILENO, 254);
8698 if (G_interactive_fd < 0) { 8886 if (G_interactive_fd < 0) {
8699 /* try to dup to any fd */ 8887 /* try to dup to any fd */
8700 G_interactive_fd = dup(STDIN_FILENO); 8888 G_interactive_fd = dup(STDIN_FILENO);
@@ -8767,7 +8955,7 @@ int hush_main(int argc, char **argv)
8767#elif ENABLE_HUSH_INTERACTIVE 8955#elif ENABLE_HUSH_INTERACTIVE
8768 /* No job control compiled in, only prompt/line editing */ 8956 /* No job control compiled in, only prompt/line editing */
8769 if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { 8957 if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) {
8770 G_interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255); 8958 G_interactive_fd = fcntl_F_DUPFD(STDIN_FILENO, 254);
8771 if (G_interactive_fd < 0) { 8959 if (G_interactive_fd < 0) {
8772 /* try to dup to any fd */ 8960 /* try to dup to any fd */
8773 G_interactive_fd = dup(STDIN_FILENO); 8961 G_interactive_fd = dup(STDIN_FILENO);
@@ -8806,16 +8994,6 @@ int hush_main(int argc, char **argv)
8806} 8994}
8807 8995
8808 8996
8809#if ENABLE_MSH
8810int msh_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
8811int msh_main(int argc, char **argv)
8812{
8813 bb_error_msg("msh is deprecated, please use hush instead");
8814 return hush_main(argc, argv);
8815}
8816#endif
8817
8818
8819/* 8997/*
8820 * Built-ins 8998 * Built-ins
8821 */ 8999 */
@@ -8827,12 +9005,8 @@ static int FAST_FUNC builtin_true(char **argv UNUSED_PARAM)
8827#if ENABLE_HUSH_TEST || ENABLE_HUSH_ECHO || ENABLE_HUSH_PRINTF || ENABLE_HUSH_KILL 9005#if ENABLE_HUSH_TEST || ENABLE_HUSH_ECHO || ENABLE_HUSH_PRINTF || ENABLE_HUSH_KILL
8828static int run_applet_main(char **argv, int (*applet_main_func)(int argc, char **argv)) 9006static int run_applet_main(char **argv, int (*applet_main_func)(int argc, char **argv))
8829{ 9007{
8830 int argc = 0; 9008 int argc = string_array_len(argv);
8831 while (*argv) { 9009 return applet_main_func(argc, argv);
8832 argc++;
8833 argv++;
8834 }
8835 return applet_main_func(argc, argv - argc);
8836} 9010}
8837#endif 9011#endif
8838#if ENABLE_HUSH_TEST || BASH_TEST2 9012#if ENABLE_HUSH_TEST || BASH_TEST2
@@ -8909,7 +9083,7 @@ static int FAST_FUNC builtin_cd(char **argv)
8909 * Note: do not enforce exporting. If PWD was unset or unexported, 9083 * Note: do not enforce exporting. If PWD was unset or unexported,
8910 * set it again, but do not export. bash does the same. 9084 * set it again, but do not export. bash does the same.
8911 */ 9085 */
8912 set_pwd_var(/*exp:*/ 0); 9086 set_pwd_var(/*flag:*/ 0);
8913 return EXIT_SUCCESS; 9087 return EXIT_SUCCESS;
8914} 9088}
8915 9089
@@ -9147,12 +9321,8 @@ static void print_escaped(const char *s)
9147} 9321}
9148#endif 9322#endif
9149 9323
9150#if ENABLE_HUSH_EXPORT || ENABLE_HUSH_LOCAL 9324#if ENABLE_HUSH_EXPORT || ENABLE_HUSH_LOCAL || ENABLE_HUSH_READONLY
9151# if !ENABLE_HUSH_LOCAL 9325static int helper_export_local(char **argv, unsigned flags)
9152#define helper_export_local(argv, exp, lvl) \
9153 helper_export_local(argv, exp)
9154# endif
9155static void helper_export_local(char **argv, int exp, int lvl)
9156{ 9326{
9157 do { 9327 do {
9158 char *name = *argv; 9328 char *name = *argv;
@@ -9166,7 +9336,7 @@ static void helper_export_local(char **argv, int exp, int lvl)
9166 vpp = get_ptr_to_local_var(name, name_end - name); 9336 vpp = get_ptr_to_local_var(name, name_end - name);
9167 var = vpp ? *vpp : NULL; 9337 var = vpp ? *vpp : NULL;
9168 9338
9169 if (exp == -1) { /* unexporting? */ 9339 if (flags & SETFLAG_UNEXPORT) {
9170 /* export -n NAME (without =VALUE) */ 9340 /* export -n NAME (without =VALUE) */
9171 if (var) { 9341 if (var) {
9172 var->flg_export = 0; 9342 var->flg_export = 0;
@@ -9175,7 +9345,7 @@ static void helper_export_local(char **argv, int exp, int lvl)
9175 } /* else: export -n NOT_EXISTING_VAR: no-op */ 9345 } /* else: export -n NOT_EXISTING_VAR: no-op */
9176 continue; 9346 continue;
9177 } 9347 }
9178 if (exp == 1) { /* exporting? */ 9348 if (flags & SETFLAG_EXPORT) {
9179 /* export NAME (without =VALUE) */ 9349 /* export NAME (without =VALUE) */
9180 if (var) { 9350 if (var) {
9181 var->flg_export = 1; 9351 var->flg_export = 1;
@@ -9184,28 +9354,45 @@ static void helper_export_local(char **argv, int exp, int lvl)
9184 continue; 9354 continue;
9185 } 9355 }
9186 } 9356 }
9357 if (flags & SETFLAG_MAKE_RO) {
9358 /* readonly NAME (without =VALUE) */
9359 if (var) {
9360 var->flg_read_only = 1;
9361 continue;
9362 }
9363 }
9187# if ENABLE_HUSH_LOCAL 9364# if ENABLE_HUSH_LOCAL
9188 if (exp == 0 /* local? */ 9365 /* Is this "local" bltin? */
9189 && var && var->func_nest_level == lvl 9366 if (!(flags & (SETFLAG_EXPORT|SETFLAG_UNEXPORT|SETFLAG_MAKE_RO))) {
9190 ) { 9367 unsigned lvl = flags >> SETFLAG_LOCAL_SHIFT;
9191 /* "local x=abc; ...; local x" - ignore second local decl */ 9368 if (var && var->func_nest_level == lvl) {
9192 continue; 9369 /* "local x=abc; ...; local x" - ignore second local decl */
9370 continue;
9371 }
9193 } 9372 }
9194# endif 9373# endif
9195 /* Exporting non-existing variable. 9374 /* Exporting non-existing variable.
9196 * bash does not put it in environment, 9375 * bash does not put it in environment,
9197 * but remembers that it is exported, 9376 * but remembers that it is exported,
9198 * and does put it in env when it is set later. 9377 * and does put it in env when it is set later.
9199 * We just set it to "" and export. */ 9378 * We just set it to "" and export.
9379 */
9200 /* Or, it's "local NAME" (without =VALUE). 9380 /* Or, it's "local NAME" (without =VALUE).
9201 * bash sets the value to "". */ 9381 * bash sets the value to "".
9382 */
9383 /* Or, it's "readonly NAME" (without =VALUE).
9384 * bash remembers NAME and disallows its creation
9385 * in the future.
9386 */
9202 name = xasprintf("%s=", name); 9387 name = xasprintf("%s=", name);
9203 } else { 9388 } else {
9204 /* (Un)exporting/making local NAME=VALUE */ 9389 /* (Un)exporting/making local NAME=VALUE */
9205 name = xstrdup(name); 9390 name = xstrdup(name);
9206 } 9391 }
9207 set_local_var(name, /*exp:*/ exp, /*lvl:*/ lvl, /*ro:*/ 0); 9392 if (set_local_var(name, flags))
9393 return EXIT_FAILURE;
9208 } while (*++argv); 9394 } while (*++argv);
9395 return EXIT_SUCCESS;
9209} 9396}
9210#endif 9397#endif
9211 9398
@@ -9251,9 +9438,7 @@ static int FAST_FUNC builtin_export(char **argv)
9251 return EXIT_SUCCESS; 9438 return EXIT_SUCCESS;
9252 } 9439 }
9253 9440
9254 helper_export_local(argv, (opt_unexport ? -1 : 1), 0); 9441 return helper_export_local(argv, opt_unexport ? SETFLAG_UNEXPORT : SETFLAG_EXPORT);
9255
9256 return EXIT_SUCCESS;
9257} 9442}
9258#endif 9443#endif
9259 9444
@@ -9264,8 +9449,29 @@ static int FAST_FUNC builtin_local(char **argv)
9264 bb_error_msg("%s: not in a function", argv[0]); 9449 bb_error_msg("%s: not in a function", argv[0]);
9265 return EXIT_FAILURE; /* bash compat */ 9450 return EXIT_FAILURE; /* bash compat */
9266 } 9451 }
9267 helper_export_local(argv, 0, G.func_nest_level); 9452 argv++;
9268 return EXIT_SUCCESS; 9453 return helper_export_local(argv, G.func_nest_level << SETFLAG_LOCAL_SHIFT);
9454}
9455#endif
9456
9457#if ENABLE_HUSH_READONLY
9458static int FAST_FUNC builtin_readonly(char **argv)
9459{
9460 argv++;
9461 if (*argv == NULL) {
9462 /* bash: readonly [-p]: list all readonly VARs
9463 * (-p has no effect in bash)
9464 */
9465 struct variable *e;
9466 for (e = G.top_var; e; e = e->next) {
9467 if (e->flg_read_only) {
9468//TODO: quote value: readonly VAR='VAL'
9469 printf("readonly %s\n", e->varstr);
9470 }
9471 }
9472 return EXIT_SUCCESS;
9473 }
9474 return helper_export_local(argv, SETFLAG_MAKE_RO);
9269} 9475}
9270#endif 9476#endif
9271 9477
@@ -9379,10 +9585,7 @@ static int FAST_FUNC builtin_set(char **argv)
9379 /* This realloc's G.global_argv */ 9585 /* This realloc's G.global_argv */
9380 G.global_argv = pp = add_strings_to_strings(g_argv, argv, /*dup:*/ 1); 9586 G.global_argv = pp = add_strings_to_strings(g_argv, argv, /*dup:*/ 1);
9381 9587
9382 n = 1; 9588 G.global_argc = 1 + string_array_len(pp + 1);
9383 while (*++pp)
9384 n++;
9385 G.global_argc = n;
9386 9589
9387 return EXIT_SUCCESS; 9590 return EXIT_SUCCESS;
9388 9591
@@ -9398,7 +9601,18 @@ static int FAST_FUNC builtin_shift(char **argv)
9398 int n = 1; 9601 int n = 1;
9399 argv = skip_dash_dash(argv); 9602 argv = skip_dash_dash(argv);
9400 if (argv[0]) { 9603 if (argv[0]) {
9401 n = atoi(argv[0]); 9604 n = bb_strtou(argv[0], NULL, 10);
9605 if (errno || n < 0) {
9606 /* shared string with ash.c */
9607 bb_error_msg("Illegal number: %s", argv[0]);
9608 /*
9609 * ash aborts in this case.
9610 * bash prints error message and set $? to 1.
9611 * Interestingly, for "shift 99999" bash does not
9612 * print error message, but does set $? to 1
9613 * (and does no shifting at all).
9614 */
9615 }
9402 } 9616 }
9403 if (n >= 0 && n < G.global_argc) { 9617 if (n >= 0 && n < G.global_argc) {
9404 if (G_global_args_malloced) { 9618 if (G_global_args_malloced) {
@@ -9511,7 +9725,7 @@ static int FAST_FUNC builtin_trap(char **argv)
9511 if (sig < 0 || sig >= NSIG) { 9725 if (sig < 0 || sig >= NSIG) {
9512 ret = EXIT_FAILURE; 9726 ret = EXIT_FAILURE;
9513 /* Mimic bash message exactly */ 9727 /* Mimic bash message exactly */
9514 bb_perror_msg("trap: %s: invalid signal specification", argv[-1]); 9728 bb_error_msg("trap: %s: invalid signal specification", argv[-1]);
9515 continue; 9729 continue;
9516 } 9730 }
9517 9731
@@ -9604,6 +9818,9 @@ static int FAST_FUNC builtin_jobs(char **argv UNUSED_PARAM)
9604 9818
9605 printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->cmdtext); 9819 printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->cmdtext);
9606 } 9820 }
9821
9822 clean_up_last_dead_job();
9823
9607 return EXIT_SUCCESS; 9824 return EXIT_SUCCESS;
9608} 9825}
9609 9826
@@ -9648,14 +9865,14 @@ static int FAST_FUNC builtin_fg_bg(char **argv)
9648 i = kill(- pi->pgrp, SIGCONT); 9865 i = kill(- pi->pgrp, SIGCONT);
9649 if (i < 0) { 9866 if (i < 0) {
9650 if (errno == ESRCH) { 9867 if (errno == ESRCH) {
9651 delete_finished_bg_job(pi); 9868 delete_finished_job(pi);
9652 return EXIT_SUCCESS; 9869 return EXIT_SUCCESS;
9653 } 9870 }
9654 bb_perror_msg("kill (SIGCONT)"); 9871 bb_perror_msg("kill (SIGCONT)");
9655 } 9872 }
9656 9873
9657 if (argv[0][0] == 'f') { 9874 if (argv[0][0] == 'f') {
9658 remove_bg_job(pi); 9875 remove_job_from_table(pi); /* FG job shouldn't be in job table */
9659 return checkjobs_and_fg_shell(pi); 9876 return checkjobs_and_fg_shell(pi);
9660 } 9877 }
9661 return EXIT_SUCCESS; 9878 return EXIT_SUCCESS;
@@ -9847,8 +10064,12 @@ static int FAST_FUNC builtin_wait(char **argv)
9847 wait_pipe = parse_jobspec(*argv); 10064 wait_pipe = parse_jobspec(*argv);
9848 if (wait_pipe) { 10065 if (wait_pipe) {
9849 ret = job_exited_or_stopped(wait_pipe); 10066 ret = job_exited_or_stopped(wait_pipe);
9850 if (ret < 0) 10067 if (ret < 0) {
9851 ret = wait_for_child_or_signal(wait_pipe, 0); 10068 ret = wait_for_child_or_signal(wait_pipe, 0);
10069 } else {
10070 /* waiting on "last dead job" removes it */
10071 clean_up_last_dead_job();
10072 }
9852 } 10073 }
9853 /* else: parse_jobspec() already emitted error msg */ 10074 /* else: parse_jobspec() already emitted error msg */
9854 continue; 10075 continue;
@@ -9864,14 +10085,15 @@ static int FAST_FUNC builtin_wait(char **argv)
9864 ret = waitpid(pid, &status, WNOHANG); 10085 ret = waitpid(pid, &status, WNOHANG);
9865 if (ret < 0) { 10086 if (ret < 0) {
9866 /* No */ 10087 /* No */
10088 ret = 127;
9867 if (errno == ECHILD) { 10089 if (errno == ECHILD) {
9868 if (G.last_bg_pid > 0 && pid == G.last_bg_pid) { 10090 if (pid == G.last_bg_pid) {
9869 /* "wait $!" but last bg task has already exited. Try: 10091 /* "wait $!" but last bg task has already exited. Try:
9870 * (sleep 1; exit 3) & sleep 2; echo $?; wait $!; echo $? 10092 * (sleep 1; exit 3) & sleep 2; echo $?; wait $!; echo $?
9871 * In bash it prints exitcode 0, then 3. 10093 * In bash it prints exitcode 0, then 3.
9872 * In dash, it is 127. 10094 * In dash, it is 127.
9873 */ 10095 */
9874 /* ret = G.last_bg_pid_exitstatus - FIXME */ 10096 ret = G.last_bg_pid_exitcode;
9875 } else { 10097 } else {
9876 /* Example: "wait 1". mimic bash message */ 10098 /* Example: "wait 1". mimic bash message */
9877 bb_error_msg("wait: pid %d is not a child of this shell", (int)pid); 10099 bb_error_msg("wait: pid %d is not a child of this shell", (int)pid);
@@ -9880,7 +10102,6 @@ static int FAST_FUNC builtin_wait(char **argv)
9880 /* ??? */ 10102 /* ??? */
9881 bb_perror_msg("wait %s", *argv); 10103 bb_perror_msg("wait %s", *argv);
9882 } 10104 }
9883 ret = 127;
9884 continue; /* bash checks all argv[] */ 10105 continue; /* bash checks all argv[] */
9885 } 10106 }
9886 if (ret == 0) { 10107 if (ret == 0) {