aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2009-05-27 18:01:42 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2009-05-27 18:01:42 +0200
commit20cc390b9bb33cd0ab05c8bbfcd24babad7ec204 (patch)
tree876974f2abe0ae0213e5707fb551af70b73665cd
parentbae3abf2c7185f0a9145ed2c97abb2d2e7bc2b40 (diff)
downloadbusybox-w32-20cc390b9bb33cd0ab05c8bbfcd24babad7ec204.tar.gz
busybox-w32-20cc390b9bb33cd0ab05c8bbfcd24babad7ec204.tar.bz2
busybox-w32-20cc390b9bb33cd0ab05c8bbfcd24babad7ec204.zip
post-1.14.0 fixes
hush significantly updated. fixes for acpid, awk, depmod, dhcp, gzip, mdev, modprobe, sysctl. libbb fixes. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--archival/gzip.c68
-rw-r--r--editors/awk.c9
-rw-r--r--include/libbb.h6
-rw-r--r--include/platform.h5
-rw-r--r--libbb/pw_encrypt_des.c4
-rw-r--r--libbb/read.c4
-rw-r--r--modutils/depmod.c39
-rw-r--r--modutils/modprobe.c6
-rw-r--r--networking/udhcp/leases.c3
-rw-r--r--procps/sysctl.c8
-rw-r--r--scripts/defconfig2
-rw-r--r--shell/hush.c1818
-rw-r--r--util-linux/acpid.c4
-rw-r--r--util-linux/mdev.c3
14 files changed, 1201 insertions, 778 deletions
diff --git a/archival/gzip.c b/archival/gzip.c
index 43804b2e4..a76e1d3bd 100644
--- a/archival/gzip.c
+++ b/archival/gzip.c
@@ -389,19 +389,6 @@ static void put_32bit(ulg n)
389} 389}
390 390
391/* =========================================================================== 391/* ===========================================================================
392 * Clear input and output buffers
393 */
394static void clear_bufs(void)
395{
396 G1.outcnt = 0;
397#ifdef DEBUG
398 G1.insize = 0;
399#endif
400 G1.isize = 0;
401}
402
403
404/* ===========================================================================
405 * Run a set of bytes through the crc shift register. If s is a NULL 392 * Run a set of bytes through the crc shift register. If s is a NULL
406 * pointer, then initialize the crc shift register contents instead. 393 * pointer, then initialize the crc shift register contents instead.
407 * Return the current crc in either case. 394 * Return the current crc in either case.
@@ -2019,7 +2006,37 @@ USE_DESKTOP(long long) int pack_gzip(unpack_info_t *info UNUSED_PARAM)
2019{ 2006{
2020 struct stat s; 2007 struct stat s;
2021 2008
2022 clear_bufs(); 2009 /* Clear input and output buffers */
2010 G1.outcnt = 0;
2011#ifdef DEBUG
2012 G1.insize = 0;
2013#endif
2014 G1.isize = 0;
2015
2016 /* Reinit G2.xxx */
2017 memset(&G2, 0, sizeof(G2));
2018 G2.l_desc.dyn_tree = G2.dyn_ltree;
2019 G2.l_desc.static_tree = G2.static_ltree;
2020 G2.l_desc.extra_bits = extra_lbits;
2021 G2.l_desc.extra_base = LITERALS + 1;
2022 G2.l_desc.elems = L_CODES;
2023 G2.l_desc.max_length = MAX_BITS;
2024 //G2.l_desc.max_code = 0;
2025 G2.d_desc.dyn_tree = G2.dyn_dtree;
2026 G2.d_desc.static_tree = G2.static_dtree;
2027 G2.d_desc.extra_bits = extra_dbits;
2028 //G2.d_desc.extra_base = 0;
2029 G2.d_desc.elems = D_CODES;
2030 G2.d_desc.max_length = MAX_BITS;
2031 //G2.d_desc.max_code = 0;
2032 G2.bl_desc.dyn_tree = G2.bl_tree;
2033 //G2.bl_desc.static_tree = NULL;
2034 G2.bl_desc.extra_bits = extra_blbits,
2035 //G2.bl_desc.extra_base = 0;
2036 G2.bl_desc.elems = BL_CODES;
2037 G2.bl_desc.max_length = MAX_BL_BITS;
2038 //G2.bl_desc.max_code = 0;
2039
2023 s.st_ctime = 0; 2040 s.st_ctime = 0;
2024 fstat(STDIN_FILENO, &s); 2041 fstat(STDIN_FILENO, &s);
2025 zip(s.st_ctime); 2042 zip(s.st_ctime);
@@ -2064,29 +2081,6 @@ int gzip_main(int argc UNUSED_PARAM, char **argv)
2064 SET_PTR_TO_GLOBALS(xzalloc(sizeof(struct globals) + sizeof(struct globals2)) 2081 SET_PTR_TO_GLOBALS(xzalloc(sizeof(struct globals) + sizeof(struct globals2))
2065 + sizeof(struct globals)); 2082 + sizeof(struct globals));
2066 barrier(); 2083 barrier();
2067 G2.l_desc.dyn_tree = G2.dyn_ltree;
2068 G2.l_desc.static_tree = G2.static_ltree;
2069 G2.l_desc.extra_bits = extra_lbits;
2070 G2.l_desc.extra_base = LITERALS + 1;
2071 G2.l_desc.elems = L_CODES;
2072 G2.l_desc.max_length = MAX_BITS;
2073 //G2.l_desc.max_code = 0;
2074
2075 G2.d_desc.dyn_tree = G2.dyn_dtree;
2076 G2.d_desc.static_tree = G2.static_dtree;
2077 G2.d_desc.extra_bits = extra_dbits;
2078 //G2.d_desc.extra_base = 0;
2079 G2.d_desc.elems = D_CODES;
2080 G2.d_desc.max_length = MAX_BITS;
2081 //G2.d_desc.max_code = 0;
2082
2083 G2.bl_desc.dyn_tree = G2.bl_tree;
2084 //G2.bl_desc.static_tree = NULL;
2085 G2.bl_desc.extra_bits = extra_blbits,
2086 //G2.bl_desc.extra_base = 0;
2087 G2.bl_desc.elems = BL_CODES;
2088 G2.bl_desc.max_length = MAX_BL_BITS;
2089 //G2.bl_desc.max_code = 0;
2090 2084
2091 /* Allocate all global buffers (for DYN_ALLOC option) */ 2085 /* Allocate all global buffers (for DYN_ALLOC option) */
2092 ALLOC(uch, G1.l_buf, INBUFSIZ); 2086 ALLOC(uch, G1.l_buf, INBUFSIZ);
diff --git a/editors/awk.c b/editors/awk.c
index 89ce2cfc8..89ae503aa 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -1571,13 +1571,14 @@ static int awk_split(const char *s, node *spl, char **slist)
1571 n++; /* we saw yet another delimiter */ 1571 n++; /* we saw yet another delimiter */
1572 } else { 1572 } else {
1573 pmatch[0].rm_eo = l; 1573 pmatch[0].rm_eo = l;
1574 if (s[l]) pmatch[0].rm_eo++; 1574 if (s[l])
1575 pmatch[0].rm_eo++;
1575 } 1576 }
1576 memcpy(s1, s, l); 1577 memcpy(s1, s, l);
1577 /* make sure we remove *all* of the separator chars */ 1578 /* make sure we remove *all* of the separator chars */
1578 while (l < pmatch[0].rm_eo) { 1579 do {
1579 s1[l++] = '\0'; 1580 s1[l] = '\0';
1580 } 1581 } while (++l < pmatch[0].rm_eo);
1581 nextword(&s1); 1582 nextword(&s1);
1582 s += pmatch[0].rm_eo; 1583 s += pmatch[0].rm_eo;
1583 } while (*s); 1584 } while (*s);
diff --git a/include/libbb.h b/include/libbb.h
index 1faa9e9fd..2868eba03 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -965,6 +965,12 @@ enum {
965 /* How long the longest ESC sequence we know? */ 965 /* How long the longest ESC sequence we know? */
966 KEYCODE_BUFFER_SIZE = 4 966 KEYCODE_BUFFER_SIZE = 4
967}; 967};
968/* Note: fd may be in blocking or non-blocking mode, both make sense.
969 * For one, less uses non-blocking mode.
970 * Only the first read syscall inside read_key may block indefinitely
971 * (unless fd is in non-blocking mode),
972 * subsequent reads will time out after a few milliseconds.
973 */
968int read_key(int fd, smalluint *nbuffered, char *buffer) FAST_FUNC; 974int read_key(int fd, smalluint *nbuffered, char *buffer) FAST_FUNC;
969 975
970 976
diff --git a/include/platform.h b/include/platform.h
index 47fd5f63d..317349fed 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -173,7 +173,10 @@
173/* performs reasonably well (gcc usually inlines memcpy here) */ 173/* performs reasonably well (gcc usually inlines memcpy here) */
174#define move_from_unaligned16(v, u16p) (memcpy(&(v), (u16p), 2)) 174#define move_from_unaligned16(v, u16p) (memcpy(&(v), (u16p), 2))
175#define move_from_unaligned32(v, u32p) (memcpy(&(v), (u32p), 4)) 175#define move_from_unaligned32(v, u32p) (memcpy(&(v), (u32p), 4))
176#define move_to_unaligned32(u32p, v) (memcpy((u32p), &(v), 4)) 176#define move_to_unaligned32(u32p, v) do { \
177 uint32_t __t = (v); \
178 memcpy((u32p), &__t, 4); \
179} while (0)
177#endif 180#endif
178 181
179/* ---- Networking ------------------------------------------ */ 182/* ---- Networking ------------------------------------------ */
diff --git a/libbb/pw_encrypt_des.c b/libbb/pw_encrypt_des.c
index 52548d623..c8e02ddff 100644
--- a/libbb/pw_encrypt_des.c
+++ b/libbb/pw_encrypt_des.c
@@ -778,8 +778,10 @@ des_crypt(struct des_ctx *ctx, char output[DES_OUT_BUFSIZE],
778 to64_msb_first(output + 2, (r0 >> 8)); 778 to64_msb_first(output + 2, (r0 >> 8));
779 /* bits 7..0 of r0 and 31..16 of r1 */ 779 /* bits 7..0 of r0 and 31..16 of r1 */
780 to64_msb_first(output + 6, (r0 << 16) | (r1 >> 16)); 780 to64_msb_first(output + 6, (r0 << 16) | (r1 >> 16));
781 /* (bits 15..0 of r1 + 00) and NUL byte */ 781 /* bits 15..0 of r1 and two zero bits (plus extra zero byte) */
782 to64_msb_first(output + 10, (r1 << 8)); 782 to64_msb_first(output + 10, (r1 << 8));
783 /* extra zero byte is encoded as '.', fixing it */
784 output[13] = '\0';
783#endif 785#endif
784 786
785 return output; 787 return output;
diff --git a/libbb/read.c b/libbb/read.c
index 37503e84d..4654f737e 100644
--- a/libbb/read.c
+++ b/libbb/read.c
@@ -229,7 +229,7 @@ void* FAST_FUNC xmalloc_read(int fd, size_t *maxsz_p)
229 if (size > 64*1024) 229 if (size > 64*1024)
230 size = 64*1024; 230 size = 64*1024;
231 } 231 }
232 xrealloc(buf, total + 1); 232 buf = xrealloc(buf, total + 1);
233 buf[total] = '\0'; 233 buf[total] = '\0';
234 234
235 if (maxsz_p) 235 if (maxsz_p)
@@ -273,7 +273,7 @@ void* FAST_FUNC xmalloc_open_read_close(const char *filename, size_t *maxsz_p)
273 free(buf); 273 free(buf);
274 return NULL; 274 return NULL;
275 } 275 }
276 xrealloc(buf, size + 1); 276 buf = xrealloc(buf, size + 1);
277 buf[size] = '\0'; 277 buf[size] = '\0';
278 278
279 if (maxsz_p) 279 if (maxsz_p)
diff --git a/modutils/depmod.c b/modutils/depmod.c
index 405ba9e2a..5ec2a51dd 100644
--- a/modutils/depmod.c
+++ b/modutils/depmod.c
@@ -40,26 +40,28 @@ enum {
40 ARG_r = (1<<6) /* Compat dummy. Linux Makefile uses it */ 40 ARG_r = (1<<6) /* Compat dummy. Linux Makefile uses it */
41}; 41};
42 42
43static int FAST_FUNC parse_module(const char *fname, struct stat *sb, 43static int FAST_FUNC parse_module(const char *fname, struct stat *sb UNUSED_PARAM,
44 void *data, int UNUSED_PARAM depth) 44 void *data, int depth UNUSED_PARAM)
45{ 45{
46 char modname[MODULE_NAME_LEN];
46 module_info **first = (module_info **) data; 47 module_info **first = (module_info **) data;
47 char *image, *ptr; 48 char *image, *ptr;
48 module_info *info; 49 module_info *info;
49 size_t len = sb->st_size; 50 /* Arbitrary. Was sb->st_size, but that breaks .gz etc */
51 size_t len = (64*1024*1024 - 4096);
50 52
51 if (strrstr(fname, ".ko") == NULL) 53 if (strrstr(fname, ".ko") == NULL)
52 return TRUE; 54 return TRUE;
53 55
54 image = xmalloc_open_zipped_read_close(fname, &len); 56 image = xmalloc_open_zipped_read_close(fname, &len);
55 info = xzalloc(sizeof(module_info)); 57 info = xzalloc(sizeof(*info));
56 58
57 info->next = *first; 59 info->next = *first;
58 *first = info; 60 *first = info;
59 61
60 info->dnext = info->dprev = info; 62 info->dnext = info->dprev = info;
61 info->name = xasprintf("/%s", fname); 63 info->name = xasprintf("/%s", fname);
62 info->modname = filename2modname(fname, NULL); 64 info->modname = xstrdup(filename2modname(fname, modname));
63 for (ptr = image; ptr < image + len - 10; ptr++) { 65 for (ptr = image; ptr < image + len - 10; ptr++) {
64 if (strncmp(ptr, "depends=", 8) == 0) { 66 if (strncmp(ptr, "depends=", 8) == 0) {
65 char *u; 67 char *u;
@@ -69,12 +71,14 @@ static int FAST_FUNC parse_module(const char *fname, struct stat *sb,
69 if (*u == '-') 71 if (*u == '-')
70 *u = '_'; 72 *u = '_';
71 ptr += string_to_llist(ptr, &info->dependencies, ","); 73 ptr += string_to_llist(ptr, &info->dependencies, ",");
72 } else if (ENABLE_FEATURE_MODUTILS_ALIAS && 74 } else if (ENABLE_FEATURE_MODUTILS_ALIAS
73 strncmp(ptr, "alias=", 6) == 0) { 75 && strncmp(ptr, "alias=", 6) == 0
76 ) {
74 llist_add_to(&info->aliases, xstrdup(ptr + 6)); 77 llist_add_to(&info->aliases, xstrdup(ptr + 6));
75 ptr += strlen(ptr); 78 ptr += strlen(ptr);
76 } else if (ENABLE_FEATURE_MODUTILS_SYMBOLS && 79 } else if (ENABLE_FEATURE_MODUTILS_SYMBOLS
77 strncmp(ptr, "__ksymtab_", 10) == 0) { 80 && strncmp(ptr, "__ksymtab_", 10) == 0
81 ) {
78 ptr += 10; 82 ptr += 10;
79 if (strncmp(ptr, "gpl", 3) == 0 || 83 if (strncmp(ptr, "gpl", 3) == 0 ||
80 strcmp(ptr, "strings") == 0) 84 strcmp(ptr, "strings") == 0)
@@ -199,10 +203,17 @@ int depmod_main(int argc UNUSED_PARAM, char **argv)
199 if (!(option_mask32 & ARG_n)) 203 if (!(option_mask32 & ARG_n))
200 xfreopen_write("modules.alias", stdout); 204 xfreopen_write("modules.alias", stdout);
201 for (m = modules; m != NULL; m = m->next) { 205 for (m = modules; m != NULL; m = m->next) {
206 const char *fname = bb_basename(m->name);
207 int fnlen = strchrnul(fname, '.') - fname;
202 while (m->aliases) { 208 while (m->aliases) {
203 printf("alias %s %s\n", 209 /* Last word can well be m->modname instead,
210 * but depmod from module-init-tools 3.4
211 * uses module basename, i.e., no s/-/_/g.
212 * (pathname and .ko.* are still stripped)
213 * Mimicking that... */
214 printf("alias %s %.*s\n",
204 (char*)llist_pop(&m->aliases), 215 (char*)llist_pop(&m->aliases),
205 m->modname); 216 fnlen, fname);
206 } 217 }
207 } 218 }
208#endif 219#endif
@@ -210,10 +221,12 @@ int depmod_main(int argc UNUSED_PARAM, char **argv)
210 if (!(option_mask32 & ARG_n)) 221 if (!(option_mask32 & ARG_n))
211 xfreopen_write("modules.symbols", stdout); 222 xfreopen_write("modules.symbols", stdout);
212 for (m = modules; m != NULL; m = m->next) { 223 for (m = modules; m != NULL; m = m->next) {
224 const char *fname = bb_basename(m->name);
225 int fnlen = strchrnul(fname, '.') - fname;
213 while (m->symbols) { 226 while (m->symbols) {
214 printf("alias symbol:%s %s\n", 227 printf("alias symbol:%s %.*s\n",
215 (char*)llist_pop(&m->symbols), 228 (char*)llist_pop(&m->symbols),
216 m->modname); 229 fnlen, fname);
217 } 230 }
218 } 231 }
219#endif 232#endif
diff --git a/modutils/modprobe.c b/modutils/modprobe.c
index 218a898a8..0339ebb40 100644
--- a/modutils/modprobe.c
+++ b/modutils/modprobe.c
@@ -109,7 +109,9 @@ static void add_probe(const char *name)
109 struct module_entry *m; 109 struct module_entry *m;
110 110
111 m = get_or_add_modentry(name); 111 m = get_or_add_modentry(name);
112 if (m->flags & MODULE_FLAG_LOADED) { 112 if (!(option_mask32 & MODPROBE_OPT_REMOVE)
113 && (m->flags & MODULE_FLAG_LOADED)
114 ) {
113 DBG("skipping %s, it is already loaded", name); 115 DBG("skipping %s, it is already loaded", name);
114 return; 116 return;
115 } 117 }
@@ -339,7 +341,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
339 config_close(parser); 341 config_close(parser);
340 } 342 }
341 343
342 if (opt & MODPROBE_OPT_INSERT_ALL) { 344 if (opt & (MODPROBE_OPT_INSERT_ALL | MODPROBE_OPT_REMOVE)) {
343 /* Each argument is a module name */ 345 /* Each argument is a module name */
344 do { 346 do {
345 add_probe(*argv++); 347 add_probe(*argv++);
diff --git a/networking/udhcp/leases.c b/networking/udhcp/leases.c
index 6e1398d2f..e17fb9e3f 100644
--- a/networking/udhcp/leases.c
+++ b/networking/udhcp/leases.c
@@ -63,7 +63,8 @@ struct dhcpOfferedAddr* FAST_FUNC add_lease(
63 if (oldest) { 63 if (oldest) {
64 oldest->hostname[0] = '\0'; 64 oldest->hostname[0] = '\0';
65 if (hostname) { 65 if (hostname) {
66 hostname_length = hostname[-1]; /* look at option size byte */ 66 /* option size byte, + 1 for NUL */
67 hostname_length = hostname[-1] + 1;
67 if (hostname_length > sizeof(oldest->hostname)) 68 if (hostname_length > sizeof(oldest->hostname))
68 hostname_length = sizeof(oldest->hostname); 69 hostname_length = sizeof(oldest->hostname);
69 hostname = (uint8_t*) safe_strncpy((char*)oldest->hostname, (char*)hostname, hostname_length); 70 hostname = (uint8_t*) safe_strncpy((char*)oldest->hostname, (char*)hostname, hostname_length);
diff --git a/procps/sysctl.c b/procps/sysctl.c
index d0ff20ec7..c9063bf07 100644
--- a/procps/sysctl.c
+++ b/procps/sysctl.c
@@ -214,11 +214,11 @@ static int sysctl_handle_preload_file(const char *filename)
214// (but _whitespace_ from ends should be trimmed first (and we do it right)) 214// (but _whitespace_ from ends should be trimmed first (and we do it right))
215//TODO: "var==1" is mishandled (must use "=1" as a value, but uses "1") 215//TODO: "var==1" is mishandled (must use "=1" as a value, but uses "1")
216 while (config_read(parser, token, 2, 2, "# \t=", PARSE_NORMAL)) { 216 while (config_read(parser, token, 2, 2, "# \t=", PARSE_NORMAL)) {
217 char *tp;
217 sysctl_dots_to_slashes(token[0]); 218 sysctl_dots_to_slashes(token[0]);
218 /* Save ~4 bytes by using parser internals */ 219 tp = xasprintf("%s=%s", token[0], token[1]);
219 /* parser->line is big enough for sprintf */ 220 sysctl_act_recursive(tp);
220 sprintf(parser->line, "%s=%s", token[0], token[1]); 221 free(tp);
221 sysctl_act_recursive(parser->line);
222 } 222 }
223 if (ENABLE_FEATURE_CLEAN_UP) 223 if (ENABLE_FEATURE_CLEAN_UP)
224 config_close(parser); 224 config_close(parser);
diff --git a/scripts/defconfig b/scripts/defconfig
index a3ab58878..a863ecad5 100644
--- a/scripts/defconfig
+++ b/scripts/defconfig
@@ -579,7 +579,7 @@ CONFIG_DEVMEM=y
579CONFIG_EJECT=y 579CONFIG_EJECT=y
580CONFIG_FEATURE_EJECT_SCSI=y 580CONFIG_FEATURE_EJECT_SCSI=y
581CONFIG_FBSPLASH=y 581CONFIG_FBSPLASH=y
582CONFIG_FLASH_ERASEALL=y 582# CONFIG_FLASH_ERASEALL is not set
583CONFIG_IONICE=y 583CONFIG_IONICE=y
584# CONFIG_INOTIFYD is not set 584# CONFIG_INOTIFYD is not set
585CONFIG_LAST=y 585CONFIG_LAST=y
diff --git a/shell/hush.c b/shell/hush.c
index b6e49db99..8c3e7c551 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -50,19 +50,13 @@
50 * 50 *
51 * TODOs: 51 * TODOs:
52 * grep for "TODO" and fix (some of them are easy) 52 * grep for "TODO" and fix (some of them are easy)
53 * change { and } from special chars to reserved words 53 * $var refs in function do not pick up values set by "var=val func"
54 * builtins: return, ulimit 54 * builtins: ulimit
55 * follow IFS rules more precisely, including update semantics 55 * follow IFS rules more precisely, including update semantics
56 * figure out what to do with backslash-newline
57 * continuation lines, both explicit and implicit - done?
58 * SIGHUP handling
59 * ^Z handling (and explain it in comments for mere humans)
60 * separate job control from interactiveness
61 * (testcase: booting with init=/bin/hush does not show prompt (2009-04))
62 * 56 *
63 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. 57 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
64 */ 58 */
65#include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ 59#include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */
66#include <glob.h> 60#include <glob.h>
67/* #include <dmalloc.h> */ 61/* #include <dmalloc.h> */
68#if ENABLE_HUSH_CASE 62#if ENABLE_HUSH_CASE
@@ -71,11 +65,11 @@
71#include "math.h" 65#include "math.h"
72#include "match.h" 66#include "match.h"
73#ifndef PIPE_BUF 67#ifndef PIPE_BUF
74# define PIPE_BUF 4096 /* amount of buffering in a pipe */ 68# define PIPE_BUF 4096 /* amount of buffering in a pipe */
75#endif 69#endif
76 70
77 71
78/* Debug build knobs */ 72/* Build knobs */
79#define LEAK_HUNTING 0 73#define LEAK_HUNTING 0
80#define BUILD_AS_NOMMU 0 74#define BUILD_AS_NOMMU 0
81/* Enable/disable sanity checks. Ok to enable in production, 75/* Enable/disable sanity checks. Ok to enable in production,
@@ -83,6 +77,13 @@
83 * Keeping 1 for now even in released versions. 77 * Keeping 1 for now even in released versions.
84 */ 78 */
85#define HUSH_DEBUG 1 79#define HUSH_DEBUG 1
80/* Slightly bigger (+200 bytes), but faster hush.
81 * So far it only enables a trick with counting SIGCHLDs and forks,
82 * which allows us to do fewer waitpid's.
83 * (we can detect a case where neither forks were done nor SIGCHLDs happened
84 * and therefore waitpid will return the same result as last time)
85 */
86#define ENABLE_HUSH_FAST 0
86 87
87 88
88#if BUILD_AS_NOMMU 89#if BUILD_AS_NOMMU
@@ -99,10 +100,9 @@
99# undef CONFIG_FEATURE_SH_STANDALONE 100# undef CONFIG_FEATURE_SH_STANDALONE
100# undef ENABLE_FEATURE_SH_STANDALONE 101# undef ENABLE_FEATURE_SH_STANDALONE
101# undef USE_FEATURE_SH_STANDALONE 102# undef USE_FEATURE_SH_STANDALONE
102# define SKIP_FEATURE_SH_STANDALONE(...) __VA_ARGS__
103# define ENABLE_FEATURE_SH_STANDALONE 0
104# define USE_FEATURE_SH_STANDALONE(...) 103# define USE_FEATURE_SH_STANDALONE(...)
105# define SKIP_FEATURE_SH_STANDALONE(...) __VA_ARGS__ 104# define SKIP_FEATURE_SH_STANDALONE(...) __VA_ARGS__
105# define ENABLE_FEATURE_SH_STANDALONE 0
106#endif 106#endif
107 107
108#if !ENABLE_HUSH_INTERACTIVE 108#if !ENABLE_HUSH_INTERACTIVE
@@ -144,17 +144,19 @@
144 144
145#define SPECIAL_VAR_SYMBOL 3 145#define SPECIAL_VAR_SYMBOL 3
146 146
147struct variable;
148
147static const char hush_version_str[] ALIGN1 = "HUSH_VERSION="BB_VER; 149static const char hush_version_str[] ALIGN1 = "HUSH_VERSION="BB_VER;
148 150
149/* This supports saving pointers malloced in vfork child, 151/* This supports saving pointers malloced in vfork child,
150 * to be freed in the parent. One pointer is saved in 152 * to be freed in the parent.
151 * G.argv_from_re_execing global var instead. TODO: unify.
152 */ 153 */
153#if !BB_MMU 154#if !BB_MMU
154typedef struct nommu_save_t { 155typedef struct nommu_save_t {
155 char **new_env; 156 char **new_env;
156 char **old_env; 157 struct variable *old_vars;
157 char **argv; 158 char **argv;
159 char **argv_from_re_execing;
158} nommu_save_t; 160} nommu_save_t;
159#endif 161#endif
160 162
@@ -196,9 +198,10 @@ typedef enum reserved_style {
196#endif 198#endif
197#if ENABLE_HUSH_CASE 199#if ENABLE_HUSH_CASE
198 RES_CASE , 200 RES_CASE ,
199 /* two pseudo-keywords support contrived "case" syntax: */ 201 /* three pseudo-keywords support contrived "case" syntax: */
200 RES_MATCH , /* "word)" */ 202 RES_CASE_IN, /* "case ... IN", turns into RES_MATCH when IN is observed */
201 RES_CASEI , /* "this command is inside CASE" */ 203 RES_MATCH , /* "word)" */
204 RES_CASE_BODY, /* "this command is inside CASE" */
202 RES_ESAC , 205 RES_ESAC ,
203#endif 206#endif
204 RES_XXXX , 207 RES_XXXX ,
@@ -288,8 +291,8 @@ struct command {
288#if ENABLE_HUSH_FUNCTIONS 291#if ENABLE_HUSH_FUNCTIONS
289# define GRP_FUNCTION 2 292# define GRP_FUNCTION 2
290#endif 293#endif
291 struct pipe *group; /* if non-NULL, this "command" is { list }, 294 /* if non-NULL, this "command" is { list }, ( list ), or a compound statement */
292 * ( list ), or a compound statement */ 295 struct pipe *group;
293#if !BB_MMU 296#if !BB_MMU
294 char *group_as_string; 297 char *group_as_string;
295#endif 298#endif
@@ -319,6 +322,10 @@ struct command {
319 */ 322 */
320 struct redir_struct *redirects; /* I/O redirections */ 323 struct redir_struct *redirects; /* I/O redirections */
321}; 324};
325/* Is there anything in this command at all? */
326#define IS_NULL_CMD(cmd) \
327 (!(cmd)->group && !(cmd)->argv && !(cmd)->redirects)
328
322 329
323struct pipe { 330struct pipe {
324 struct pipe *next; 331 struct pipe *next;
@@ -341,6 +348,9 @@ typedef enum pipe_style {
341 PIPE_OR = 3, 348 PIPE_OR = 3,
342 PIPE_BG = 4, 349 PIPE_BG = 4,
343} pipe_style; 350} pipe_style;
351/* Is there anything in this pipe at all? */
352#define IS_NULL_PIPE(pi) \
353 ((pi)->num_cmds == 0 IF_HAS_KEYWORDS( && (pi)->res_word == RES_NONE))
344 354
345/* This holds pointers to the various results of parsing */ 355/* This holds pointers to the various results of parsing */
346struct parse_context { 356struct parse_context {
@@ -411,15 +421,26 @@ struct function {
411/* "Globals" within this file */ 421/* "Globals" within this file */
412/* Sorted roughly by size (smaller offsets == smaller code) */ 422/* Sorted roughly by size (smaller offsets == smaller code) */
413struct globals { 423struct globals {
424 /* interactive_fd != 0 means we are an interactive shell.
425 * If we are, then saved_tty_pgrp can also be != 0, meaning
426 * that controlling tty is available. With saved_tty_pgrp == 0,
427 * job control still works, but terminal signals
428 * (^C, ^Z, ^Y, ^\) won't work at all, and background
429 * process groups can only be created with "cmd &".
430 * With saved_tty_pgrp != 0, hush will use tcsetpgrp()
431 * to give tty to the foreground process group,
432 * and will take it back when the group is stopped (^Z)
433 * or killed (^C).
434 */
414#if ENABLE_HUSH_INTERACTIVE 435#if ENABLE_HUSH_INTERACTIVE
415 /* 'interactive_fd' is a fd# open to ctty, if we have one 436 /* 'interactive_fd' is a fd# open to ctty, if we have one
416 * _AND_ if we decided to act interactively */ 437 * _AND_ if we decided to act interactively */
417 int interactive_fd; 438 int interactive_fd;
418 const char *PS1; 439 const char *PS1;
419 const char *PS2; 440 const char *PS2;
420#define G_interactive_fd (G.interactive_fd) 441# define G_interactive_fd (G.interactive_fd)
421#else 442#else
422#define G_interactive_fd 0 443# define G_interactive_fd 0
423#endif 444#endif
424#if ENABLE_FEATURE_EDITING 445#if ENABLE_FEATURE_EDITING
425 line_input_t *line_input_state; 446 line_input_t *line_input_state;
@@ -428,16 +449,24 @@ struct globals {
428 pid_t last_bg_pid; 449 pid_t last_bg_pid;
429#if ENABLE_HUSH_JOB 450#if ENABLE_HUSH_JOB
430 int run_list_level; 451 int run_list_level;
431 pid_t saved_tty_pgrp;
432 int last_jobid; 452 int last_jobid;
453 pid_t saved_tty_pgrp;
433 struct pipe *job_list; 454 struct pipe *job_list;
434 struct pipe *toplevel_list; 455# define G_saved_tty_pgrp (G.saved_tty_pgrp)
435//// smallint ctrl_z_flag; 456#else
457# define G_saved_tty_pgrp 0
436#endif 458#endif
437 smallint flag_SIGINT; 459 smallint flag_SIGINT;
438#if ENABLE_HUSH_LOOPS 460#if ENABLE_HUSH_LOOPS
439 smallint flag_break_continue; 461 smallint flag_break_continue;
440#endif 462#endif
463#if ENABLE_HUSH_FUNCTIONS
464 /* 0: outside of a function (or sourced file)
465 * -1: inside of a function, ok to use return builtin
466 * 1: return is invoked, skip all till end of func
467 */
468 smallint flag_return_in_progress;
469#endif
441 smallint fake_mode; 470 smallint fake_mode;
442 smallint exiting; /* used to prevent EXIT trap recursion */ 471 smallint exiting; /* used to prevent EXIT trap recursion */
443 /* These four support $?, $#, and $1 */ 472 /* These four support $?, $#, and $1 */
@@ -449,7 +478,6 @@ struct globals {
449 char **global_argv; 478 char **global_argv;
450#if !BB_MMU 479#if !BB_MMU
451 char *argv0_for_re_execing; 480 char *argv0_for_re_execing;
452 char **argv_from_re_execing;
453#endif 481#endif
454#if ENABLE_HUSH_LOOPS 482#if ENABLE_HUSH_LOOPS
455 unsigned depth_break_continue; 483 unsigned depth_break_continue;
@@ -463,8 +491,11 @@ struct globals {
463 struct function *top_func; 491 struct function *top_func;
464#endif 492#endif
465 /* Signal and trap handling */ 493 /* Signal and trap handling */
466// unsigned count_SIGCHLD; 494#if ENABLE_HUSH_FAST
467// unsigned handled_SIGCHLD; 495 unsigned count_SIGCHLD;
496 unsigned handled_SIGCHLD;
497 smallint we_have_children;
498#endif
468 /* which signals have non-DFL handler (even with no traps set)? */ 499 /* which signals have non-DFL handler (even with no traps set)? */
469 unsigned non_DFL_mask; 500 unsigned non_DFL_mask;
470 char **traps; /* char *traps[NSIG] */ 501 char **traps; /* char *traps[NSIG] */
@@ -475,12 +506,6 @@ struct globals {
475 int debug_indent; 506 int debug_indent;
476#endif 507#endif
477 char user_input_buf[ENABLE_FEATURE_EDITING ? BUFSIZ : 2]; 508 char user_input_buf[ENABLE_FEATURE_EDITING ? BUFSIZ : 2];
478#if ENABLE_FEATURE_SH_STANDALONE
479 struct nofork_save_area nofork_save;
480#endif
481#if ENABLE_HUSH_JOB
482 sigjmp_buf toplevel_jb;
483#endif
484}; 509};
485#define G (*ptr_to_globals) 510#define G (*ptr_to_globals)
486/* Not #defining name to G.name - this quickly gets unwieldy 511/* Not #defining name to G.name - this quickly gets unwieldy
@@ -523,6 +548,9 @@ static int builtin_wait(char **argv);
523static int builtin_break(char **argv); 548static int builtin_break(char **argv);
524static int builtin_continue(char **argv); 549static int builtin_continue(char **argv);
525#endif 550#endif
551#if ENABLE_HUSH_FUNCTIONS
552static int builtin_return(char **argv);
553#endif
526 554
527/* Table of built-in functions. They can be forked or not, depending on 555/* Table of built-in functions. They can be forked or not, depending on
528 * context: within pipes, they fork. As simple commands, they do not. 556 * context: within pipes, they fork. As simple commands, they do not.
@@ -576,7 +604,9 @@ static const struct built_in_command bltins[] = {
576#endif 604#endif
577 BLTIN("pwd" , builtin_pwd , "Print current directory"), 605 BLTIN("pwd" , builtin_pwd , "Print current directory"),
578 BLTIN("read" , builtin_read , "Input environment variable"), 606 BLTIN("read" , builtin_read , "Input environment variable"),
579// BLTIN("return" , builtin_return , "Return from a function"), 607#if ENABLE_HUSH_FUNCTIONS
608 BLTIN("return" , builtin_return , "Return from a function"),
609#endif
580 BLTIN("set" , builtin_set , "Set/unset shell local variables"), 610 BLTIN("set" , builtin_set , "Set/unset shell local variables"),
581 BLTIN("shift" , builtin_shift , "Shift positional parameters"), 611 BLTIN("shift" , builtin_shift , "Shift positional parameters"),
582 BLTIN("test" , builtin_test , "Test condition"), 612 BLTIN("test" , builtin_test , "Test condition"),
@@ -760,12 +790,12 @@ static void syntax_error_unterm_str(unsigned lineno, const char *s)
760 die_if_script(lineno, "syntax error: unterminated %s", s); 790 die_if_script(lineno, "syntax error: unterminated %s", s);
761} 791}
762 792
763static void syntax_error_unexpected_ch(unsigned lineno, char ch) 793static void syntax_error_unexpected_ch(unsigned lineno, int ch)
764{ 794{
765 char msg[2]; 795 char msg[2];
766 msg[0] = ch; 796 msg[0] = ch;
767 msg[1] = '\0'; 797 msg[1] = '\0';
768 die_if_script(lineno, "syntax error: unexpected %s", msg); 798 die_if_script(lineno, "syntax error: unexpected %s", ch == EOF ? "EOF" : msg);
769} 799}
770 800
771#if HUSH_DEBUG < 2 801#if HUSH_DEBUG < 2
@@ -785,6 +815,13 @@ static void syntax_error_unexpected_ch(unsigned lineno, char ch)
785#endif 815#endif
786 816
787 817
818#if ENABLE_HUSH_INTERACTIVE
819static void cmdedit_update_prompt(void);
820#else
821# define cmdedit_update_prompt()
822#endif
823
824
788/* Utility functions 825/* Utility functions
789 */ 826 */
790static int glob_needed(const char *s) 827static int glob_needed(const char *s)
@@ -861,6 +898,7 @@ static char **xx_add_strings_to_strings(int lineno, char **strings, char **add,
861 xx_add_strings_to_strings(__LINE__, strings, add, need_to_dup) 898 xx_add_strings_to_strings(__LINE__, strings, add, need_to_dup)
862#endif 899#endif
863 900
901/* Note: takes ownership of "add" ptr (it is not strdup'ed) */
864static char **add_string_to_strings(char **strings, char *add) 902static char **add_string_to_strings(char **strings, char *add)
865{ 903{
866 char *v[2]; 904 char *v[2];
@@ -879,64 +917,64 @@ static char **xx_add_string_to_strings(int lineno, char **strings, char *add)
879 xx_add_string_to_strings(__LINE__, strings, add) 917 xx_add_string_to_strings(__LINE__, strings, add)
880#endif 918#endif
881 919
882static void putenv_all(char **strings) 920static void free_strings(char **strings)
883{ 921{
922 char **v;
923
884 if (!strings) 924 if (!strings)
885 return; 925 return;
886 while (*strings) { 926 v = strings;
887 debug_printf_env("putenv '%s'\n", *strings); 927 while (*v) {
888 putenv(*strings++); 928 free(*v);
929 v++;
889 } 930 }
931 free(strings);
890} 932}
891 933
892static char **putenv_all_and_save_old(char **strings)
893{
894 char **old = NULL;
895 char **s = strings;
896
897 if (!strings)
898 return old;
899 while (*strings) {
900 char *v, *eq;
901 934
902 eq = strchr(*strings, '='); 935/* Helpers for setting new $n and restoring them back
903 if (eq) { 936 */
904 *eq = '\0'; 937typedef struct save_arg_t {
905 v = getenv(*strings); 938 char *sv_argv0;
906 *eq = '='; 939 char **sv_g_argv;
907 if (v) { 940 int sv_g_argc;
908 /* v points to VAL in VAR=VAL, go back to VAR */ 941 smallint sv_g_malloced;
909 v -= (eq - *strings) + 1; 942} save_arg_t;
910 old = add_string_to_strings(old, v);
911 }
912 }
913 strings++;
914 }
915 putenv_all(s);
916 return old;
917}
918 943
919static void free_strings_and_unsetenv(char **strings, int unset) 944static void save_and_replace_G_args(save_arg_t *sv, char **argv)
920{ 945{
921 char **v; 946 int n;
922 947
923 if (!strings) 948 sv->sv_argv0 = argv[0];
924 return; 949 sv->sv_g_argv = G.global_argv;
950 sv->sv_g_argc = G.global_argc;
951 sv->sv_g_malloced = G.global_args_malloced;
925 952
926 v = strings; 953 argv[0] = G.global_argv[0]; /* retain $0 */
927 while (*v) { 954 G.global_argv = argv;
928 if (unset) { 955 G.global_args_malloced = 0;
929 debug_printf_env("unsetenv '%s'\n", *v); 956
930 bb_unsetenv(*v); 957 n = 1;
931 } 958 while (*++argv)
932 free(*v++); 959 n++;
933 } 960 G.global_argc = n;
934 free(strings);
935} 961}
936 962
937static void free_strings(char **strings) 963static void restore_G_args(save_arg_t *sv, char **argv)
938{ 964{
939 free_strings_and_unsetenv(strings, 0); 965 char **pp;
966
967 if (G.global_args_malloced) {
968 /* someone ran "set -- arg1 arg2 ...", undo */
969 pp = G.global_argv;
970 while (*++pp) /* note: does not free $0 */
971 free(*pp);
972 free(G.global_argv);
973 }
974 argv[0] = sv->sv_argv0;
975 G.global_argv = sv->sv_g_argv;
976 G.global_argc = sv->sv_g_argc;
977 G.global_args_malloced = sv->sv_g_malloced;
940} 978}
941 979
942 980
@@ -978,13 +1016,14 @@ static void free_strings(char **strings)
978 * SIGHUP (interactive): 1016 * SIGHUP (interactive):
979 * send SIGCONT to stopped jobs, send SIGHUP to all jobs and exit 1017 * send SIGCONT to stopped jobs, send SIGHUP to all jobs and exit
980 * SIGTTIN, SIGTTOU, SIGTSTP (if job control is on): ignore 1018 * SIGTTIN, SIGTTOU, SIGTSTP (if job control is on): ignore
981 * (note that ^Z is handled not by trapping SIGTSTP, but by seeing 1019 * Note that ^Z is handled not by trapping SIGTSTP, but by seeing
982 * that all pipe members are stopped) (right?) 1020 * that all pipe members are stopped. Try this in bash:
1021 * while :; do :; done - ^Z does not background it
1022 * (while :; do :; done) - ^Z backgrounds it
983 * SIGINT (interactive): wait for last pipe, ignore the rest 1023 * SIGINT (interactive): wait for last pipe, ignore the rest
984 * of the command line, show prompt. NB: ^C does not send SIGINT 1024 * of the command line, show prompt. NB: ^C does not send SIGINT
985 * to interactive shell while shell is waiting for a pipe, 1025 * to interactive shell while shell is waiting for a pipe,
986 * since shell is bg'ed (is not in foreground process group). 1026 * since shell is bg'ed (is not in foreground process group).
987 * (check/expand this)
988 * Example 1: this waits 5 sec, but does not execute ls: 1027 * Example 1: this waits 5 sec, but does not execute ls:
989 * "echo $$; sleep 5; ls -l" + "kill -INT <pid>" 1028 * "echo $$; sleep 5; ls -l" + "kill -INT <pid>"
990 * Example 2: this does not wait and does not execute ls: 1029 * Example 2: this does not wait and does not execute ls:
@@ -1012,66 +1051,38 @@ static void free_strings(char **strings)
1012 * "trap 'cmd' SIGxxx": 1051 * "trap 'cmd' SIGxxx":
1013 * set bit in blocked_set (even if 'cmd' is '') 1052 * set bit in blocked_set (even if 'cmd' is '')
1014 * after [v]fork, if we plan to be a shell: 1053 * after [v]fork, if we plan to be a shell:
1015 * nothing for {} child shell (say, "true | { true; true; } | true") 1054 * unblock signals with special interactive handling
1016 * unset all traps if () shell. 1055 * (child shell is not interactive),
1056 * unset all traps (note: regardless of child shell's type - {}, (), etc)
1017 * after [v]fork, if we plan to exec: 1057 * after [v]fork, if we plan to exec:
1018 * POSIX says pending signal mask is cleared in child - no need to clear it. 1058 * POSIX says pending signal mask is cleared in child - no need to clear it.
1019 * Restore blocked signal set to one inherited by shell just prior to exec. 1059 * Restore blocked signal set to one inherited by shell just prior to exec.
1020 * 1060 *
1021 * Note: as a result, we do not use signal handlers much. The only uses 1061 * Note: as a result, we do not use signal handlers much. The only uses
1022 * are to count SIGCHLDs [disabled - bug somewhere, + bloat] 1062 * are to count SIGCHLDs
1023 * and to restore tty pgrp on signal-induced exit. 1063 * and to restore tty pgrp on signal-induced exit.
1024 */ 1064 */
1065enum {
1066 SPECIAL_INTERACTIVE_SIGS = 0
1067 | (1 << SIGTERM)
1068 | (1 << SIGINT)
1069 | (1 << SIGHUP)
1070 ,
1071 SPECIAL_JOB_SIGS = 0
1072#if ENABLE_HUSH_JOB
1073 | (1 << SIGTTIN)
1074 | (1 << SIGTTOU)
1075 | (1 << SIGTSTP)
1076#endif
1077};
1025 1078
1026//static void SIGCHLD_handler(int sig UNUSED_PARAM) 1079#if ENABLE_HUSH_FAST
1027//{ 1080static void SIGCHLD_handler(int sig UNUSED_PARAM)
1028// G.count_SIGCHLD++;
1029//}
1030
1031static int check_and_run_traps(int sig)
1032{ 1081{
1033 static const struct timespec zero_timespec = { 0, 0 }; 1082 G.count_SIGCHLD++;
1034 smalluint save_rcode; 1083//bb_error_msg("[%d] SIGCHLD_handler: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
1035 int last_sig = 0;
1036
1037 if (sig)
1038 goto jump_in;
1039 while (1) {
1040 sig = sigtimedwait(&G.blocked_set, NULL, &zero_timespec);
1041 if (sig <= 0)
1042 break;
1043 jump_in:
1044 last_sig = sig;
1045 if (G.traps && G.traps[sig]) {
1046 if (G.traps[sig][0]) {
1047 /* We have user-defined handler */
1048 char *argv[] = { NULL, xstrdup(G.traps[sig]), NULL };
1049 save_rcode = G.last_exitcode;
1050 builtin_eval(argv);
1051 free(argv[1]);
1052 G.last_exitcode = save_rcode;
1053 } /* else: "" trap, ignoring signal */
1054 continue;
1055 }
1056 /* not a trap: special action */
1057 switch (sig) {
1058// case SIGCHLD:
1059// G.count_SIGCHLD++;
1060// break;
1061 case SIGINT:
1062 bb_putchar('\n');
1063 G.flag_SIGINT = 1;
1064 break;
1065//TODO
1066// case SIGHUP: ...
1067// break;
1068 default: /* ignored: */
1069 /* SIGTERM, SIGQUIT, SIGTTIN, SIGTTOU, SIGTSTP */
1070 break;
1071 }
1072 }
1073 return last_sig;
1074} 1084}
1085#endif
1075 1086
1076#if ENABLE_HUSH_JOB 1087#if ENABLE_HUSH_JOB
1077 1088
@@ -1082,7 +1093,7 @@ static int check_and_run_traps(int sig)
1082 1093
1083/* Restores tty foreground process group, and exits. 1094/* Restores tty foreground process group, and exits.
1084 * May be called as signal handler for fatal signal 1095 * May be called as signal handler for fatal signal
1085 * (will faithfully resend signal to itself, producing correct exit state) 1096 * (will resend signal to itself, producing correct exit state)
1086 * or called directly with -EXITCODE. 1097 * or called directly with -EXITCODE.
1087 * We also call it if xfunc is exiting. */ 1098 * We also call it if xfunc is exiting. */
1088static void sigexit(int sig) NORETURN; 1099static void sigexit(int sig) NORETURN;
@@ -1093,8 +1104,8 @@ static void sigexit(int sig)
1093 1104
1094 /* Careful: we can end up here after [v]fork. Do not restore 1105 /* Careful: we can end up here after [v]fork. Do not restore
1095 * tty pgrp then, only top-level shell process does that */ 1106 * tty pgrp then, only top-level shell process does that */
1096 if (G_interactive_fd && getpid() == G.root_pid) 1107 if (G_saved_tty_pgrp && getpid() == G.root_pid)
1097 tcsetpgrp(G_interactive_fd, G.saved_tty_pgrp); 1108 tcsetpgrp(G_interactive_fd, G_saved_tty_pgrp);
1098 1109
1099 /* Not a signal, just exit */ 1110 /* Not a signal, just exit */
1100 if (sig <= 0) 1111 if (sig <= 0)
@@ -1132,6 +1143,67 @@ static void hush_exit(int exitcode)
1132#endif 1143#endif
1133} 1144}
1134 1145
1146static int check_and_run_traps(int sig)
1147{
1148 static const struct timespec zero_timespec = { 0, 0 };
1149 smalluint save_rcode;
1150 int last_sig = 0;
1151
1152 if (sig)
1153 goto jump_in;
1154 while (1) {
1155 sig = sigtimedwait(&G.blocked_set, NULL, &zero_timespec);
1156 if (sig <= 0)
1157 break;
1158 jump_in:
1159 last_sig = sig;
1160 if (G.traps && G.traps[sig]) {
1161 if (G.traps[sig][0]) {
1162 /* We have user-defined handler */
1163 char *argv[] = { NULL, xstrdup(G.traps[sig]), NULL };
1164 save_rcode = G.last_exitcode;
1165 builtin_eval(argv);
1166 free(argv[1]);
1167 G.last_exitcode = save_rcode;
1168 } /* else: "" trap, ignoring signal */
1169 continue;
1170 }
1171 /* not a trap: special action */
1172 switch (sig) {
1173#if ENABLE_HUSH_FAST
1174 case SIGCHLD:
1175 G.count_SIGCHLD++;
1176//bb_error_msg("[%d] check_and_run_traps: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
1177 break;
1178#endif
1179 case SIGINT:
1180 /* Builtin was ^C'ed, make it look prettier: */
1181 bb_putchar('\n');
1182 G.flag_SIGINT = 1;
1183 break;
1184#if ENABLE_HUSH_JOB
1185 case SIGHUP: {
1186 struct pipe *job;
1187 /* bash is observed to signal whole process groups,
1188 * not individual processes */
1189 for (job = G.job_list; job; job = job->next) {
1190 if (job->pgrp <= 0)
1191 continue;
1192 debug_printf_exec("HUPing pgrp %d\n", job->pgrp);
1193 if (kill(- job->pgrp, SIGHUP) == 0)
1194 kill(- job->pgrp, SIGCONT);
1195 }
1196 sigexit(SIGHUP);
1197 }
1198#endif
1199 default: /* ignored: */
1200 /* SIGTERM, SIGQUIT, SIGTTIN, SIGTTOU, SIGTSTP */
1201 break;
1202 }
1203 }
1204 return last_sig;
1205}
1206
1135 1207
1136static const char *set_cwd(void) 1208static const char *set_cwd(void)
1137{ 1209{
@@ -1146,37 +1218,48 @@ static const char *set_cwd(void)
1146} 1218}
1147 1219
1148 1220
1149/* Get/check local shell variables */ 1221/*
1150static struct variable *get_local_var(const char *name) 1222 * Shell and environment variable support
1223 */
1224static struct variable **get_ptr_to_local_var(const char *name)
1151{ 1225{
1226 struct variable **pp;
1152 struct variable *cur; 1227 struct variable *cur;
1153 int len; 1228 int len;
1154 1229
1155 if (!name)
1156 return NULL;
1157 len = strlen(name); 1230 len = strlen(name);
1158 for (cur = G.top_var; cur; cur = cur->next) { 1231 pp = &G.top_var;
1232 while ((cur = *pp) != NULL) {
1159 if (strncmp(cur->varstr, name, len) == 0 && cur->varstr[len] == '=') 1233 if (strncmp(cur->varstr, name, len) == 0 && cur->varstr[len] == '=')
1160 return cur; 1234 return pp;
1235 pp = &cur->next;
1161 } 1236 }
1162 return NULL; 1237 return NULL;
1163} 1238}
1164 1239
1165static const char *get_local_var_value(const char *src) 1240static struct variable *get_local_var(const char *name)
1166{ 1241{
1167 struct variable *var = get_local_var(src); 1242 struct variable **pp = get_ptr_to_local_var(name);
1168 if (var) 1243 if (pp)
1169 return strchr(var->varstr, '=') + 1; 1244 return *pp;
1245 return NULL;
1246}
1247
1248static const char *get_local_var_value(const char *name)
1249{
1250 struct variable **pp = get_ptr_to_local_var(name);
1251 if (pp)
1252 return strchr((*pp)->varstr, '=') + 1;
1170 return NULL; 1253 return NULL;
1171} 1254}
1172 1255
1173/* str holds "NAME=VAL" and is expected to be malloced. 1256/* str holds "NAME=VAL" and is expected to be malloced.
1174 * We take ownership of it. 1257 * We take ownership of it.
1175 * flg_export: 1258 * flg_export:
1176 * 0: do not export 1259 * 0: do not change export flag
1177 * 1: export 1260 * (if creating new variable, flag will be 0)
1178 * -1: if NAME is set, leave export status alone 1261 * 1: set export flag and putenv the variable
1179 * if NAME is not set, do not export 1262 * -1: clear export flag and unsetenv the variable
1180 * flg_read_only is set only when we handle -R var=val 1263 * flg_read_only is set only when we handle -R var=val
1181 */ 1264 */
1182#if BB_MMU 1265#if BB_MMU
@@ -1186,16 +1269,16 @@ static const char *get_local_var_value(const char *src)
1186static int set_local_var(char *str, int flg_export, int flg_read_only) 1269static int set_local_var(char *str, int flg_export, int flg_read_only)
1187{ 1270{
1188 struct variable *cur; 1271 struct variable *cur;
1189 char *value; 1272 char *eq_sign;
1190 int name_len; 1273 int name_len;
1191 1274
1192 value = strchr(str, '='); 1275 eq_sign = strchr(str, '=');
1193 if (!value) { /* not expected to ever happen? */ 1276 if (!eq_sign) { /* not expected to ever happen? */
1194 free(str); 1277 free(str);
1195 return -1; 1278 return -1;
1196 } 1279 }
1197 1280
1198 name_len = value - str + 1; /* including '=' */ 1281 name_len = eq_sign - str + 1; /* including '=' */
1199 cur = G.top_var; /* cannot be NULL (we have HUSH_VERSION and it's RO) */ 1282 cur = G.top_var; /* cannot be NULL (we have HUSH_VERSION and it's RO) */
1200 while (1) { 1283 while (1) {
1201 if (strncmp(cur->varstr, str, name_len) != 0) { 1284 if (strncmp(cur->varstr, str, name_len) != 0) {
@@ -1208,7 +1291,6 @@ static int set_local_var(char *str, int flg_export, int flg_read_only)
1208 continue; 1291 continue;
1209 } 1292 }
1210 /* We found an existing var with this name */ 1293 /* We found an existing var with this name */
1211 *value = '\0';
1212 if (cur->flg_read_only) { 1294 if (cur->flg_read_only) {
1213#if !BB_MMU 1295#if !BB_MMU
1214 if (!flg_read_only) 1296 if (!flg_read_only)
@@ -1217,10 +1299,13 @@ static int set_local_var(char *str, int flg_export, int flg_read_only)
1217 free(str); 1299 free(str);
1218 return -1; 1300 return -1;
1219 } 1301 }
1220 debug_printf_env("%s: unsetenv '%s'\n", __func__, str); 1302 if (flg_export == -1) {
1221 unsetenv(str); /* just in case */ 1303 debug_printf_env("%s: unsetenv '%s'\n", __func__, str);
1222 *value = '='; 1304 *eq_sign = '\0';
1223 if (strcmp(cur->varstr, str) == 0) { 1305 unsetenv(str);
1306 *eq_sign = '=';
1307 }
1308 if (strcmp(cur->varstr + name_len, eq_sign + 1) == 0) {
1224 free_and_exp: 1309 free_and_exp:
1225 free(str); 1310 free(str);
1226 goto exp; 1311 goto exp;
@@ -1250,45 +1335,69 @@ static int set_local_var(char *str, int flg_export, int flg_read_only)
1250 exp: 1335 exp:
1251 if (flg_export == 1) 1336 if (flg_export == 1)
1252 cur->flg_export = 1; 1337 cur->flg_export = 1;
1338 if (name_len == 4 && cur->varstr[0] == 'P' && cur->varstr[1] == 'S')
1339 cmdedit_update_prompt();
1253 if (cur->flg_export) { 1340 if (cur->flg_export) {
1254 debug_printf_env("%s: putenv '%s'\n", __func__, cur->varstr); 1341 if (flg_export == -1) {
1255 return putenv(cur->varstr); 1342 cur->flg_export = 0;
1343 /* unsetenv was already done */
1344 } else {
1345 debug_printf_env("%s: putenv '%s'\n", __func__, cur->varstr);
1346 return putenv(cur->varstr);
1347 }
1256 } 1348 }
1257 return 0; 1349 return 0;
1258} 1350}
1259 1351
1260static int unset_local_var(const char *name) 1352static int unset_local_var_len(const char *name, int name_len)
1261{ 1353{
1262 struct variable *cur; 1354 struct variable *cur;
1263 struct variable *prev = prev; /* for gcc */ 1355 struct variable **var_pp;
1264 int name_len;
1265 1356
1266 if (!name) 1357 if (!name)
1267 return EXIT_SUCCESS; 1358 return EXIT_SUCCESS;
1268 name_len = strlen(name); 1359 var_pp = &G.top_var;
1269 cur = G.top_var; 1360 while ((cur = *var_pp) != NULL) {
1270 while (cur) {
1271 if (strncmp(cur->varstr, name, name_len) == 0 && cur->varstr[name_len] == '=') { 1361 if (strncmp(cur->varstr, name, name_len) == 0 && cur->varstr[name_len] == '=') {
1272 if (cur->flg_read_only) { 1362 if (cur->flg_read_only) {
1273 bb_error_msg("%s: readonly variable", name); 1363 bb_error_msg("%s: readonly variable", name);
1274 return EXIT_FAILURE; 1364 return EXIT_FAILURE;
1275 } 1365 }
1276 /* prev is ok to use here because 1st variable, HUSH_VERSION, 1366 *var_pp = cur->next;
1277 * is ro, and we cannot reach this code on the 1st pass */
1278 prev->next = cur->next;
1279 debug_printf_env("%s: unsetenv '%s'\n", __func__, cur->varstr); 1367 debug_printf_env("%s: unsetenv '%s'\n", __func__, cur->varstr);
1280 bb_unsetenv(cur->varstr); 1368 bb_unsetenv(cur->varstr);
1369 if (name_len == 3 && cur->varstr[0] == 'P' && cur->varstr[1] == 'S')
1370 cmdedit_update_prompt();
1281 if (!cur->max_len) 1371 if (!cur->max_len)
1282 free(cur->varstr); 1372 free(cur->varstr);
1283 free(cur); 1373 free(cur);
1284 return EXIT_SUCCESS; 1374 return EXIT_SUCCESS;
1285 } 1375 }
1286 prev = cur; 1376 var_pp = &cur->next;
1287 cur = cur->next;
1288 } 1377 }
1289 return EXIT_SUCCESS; 1378 return EXIT_SUCCESS;
1290} 1379}
1291 1380
1381static int unset_local_var(const char *name)
1382{
1383 return unset_local_var_len(name, strlen(name));
1384}
1385
1386static void unset_vars(char **strings)
1387{
1388 char **v;
1389
1390 if (!strings)
1391 return;
1392 v = strings;
1393 while (*v) {
1394 const char *eq = strchrnul(*v, '=');
1395 unset_local_var_len(*v, (int)(eq - *v));
1396 v++;
1397 }
1398 free(strings);
1399}
1400
1292#if ENABLE_SH_MATH_SUPPORT 1401#if ENABLE_SH_MATH_SUPPORT
1293#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) 1402#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
1294#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) 1403#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
@@ -1316,6 +1425,62 @@ static void arith_set_local_var(const char *name, const char *val, int flags)
1316 1425
1317 1426
1318/* 1427/*
1428 * Helpers for "var1=val1 var2=val2 cmd" feature
1429 */
1430static void add_vars(struct variable *var)
1431{
1432 struct variable *next;
1433
1434 while (var) {
1435 next = var->next;
1436 var->next = G.top_var;
1437 G.top_var = var;
1438 if (var->flg_export) {
1439 debug_printf_env("%s: restoring exported '%s'\n", __func__, var->varstr);
1440 putenv(var->varstr);
1441 } else {
1442 debug_printf_env("%s: restoring local '%s'\n", __func__, var->varstr);
1443 }
1444 var = next;
1445 }
1446}
1447
1448static struct variable *set_vars_and_save_old(char **strings)
1449{
1450 char **s;
1451 struct variable *old = NULL;
1452
1453 if (!strings)
1454 return old;
1455 s = strings;
1456 while (*s) {
1457 struct variable *var_p;
1458 struct variable **var_pp;
1459 char *eq;
1460
1461 eq = strchr(*s, '=');
1462 if (eq) {
1463 *eq = '\0';
1464 var_pp = get_ptr_to_local_var(*s);
1465 *eq = '=';
1466 if (var_pp) {
1467 /* Remove variable from global linked list */
1468 var_p = *var_pp;
1469 debug_printf_env("%s: removing '%s'\n", __func__, var_p->varstr);
1470 *var_pp = var_p->next;
1471 /* Add it to returned list */
1472 var_p->next = old;
1473 old = var_p;
1474 }
1475 set_local_var(*s, 1, 0);
1476 }
1477 s++;
1478 }
1479 return old;
1480}
1481
1482
1483/*
1319 * in_str support 1484 * in_str support
1320 */ 1485 */
1321static int static_get(struct in_str *i) 1486static int static_get(struct in_str *i)
@@ -1334,14 +1499,18 @@ static int static_peek(struct in_str *i)
1334 1499
1335#if ENABLE_HUSH_INTERACTIVE 1500#if ENABLE_HUSH_INTERACTIVE
1336 1501
1337static void cmdedit_set_initial_prompt(void) 1502static void cmdedit_update_prompt(void)
1338{ 1503{
1339 if (ENABLE_FEATURE_EDITING_FANCY_PROMPT) { 1504 if (ENABLE_FEATURE_EDITING_FANCY_PROMPT) {
1340 G.PS1 = getenv("PS1"); 1505 G.PS1 = get_local_var_value("PS1");
1341 if (G.PS1 == NULL) 1506 if (G.PS1 == NULL)
1342 G.PS1 = "\\w \\$ "; 1507 G.PS1 = "\\w \\$ ";
1343 } else 1508 G.PS2 = get_local_var_value("PS2");
1509 } else {
1344 G.PS1 = NULL; 1510 G.PS1 = NULL;
1511 }
1512 if (G.PS2 == NULL)
1513 G.PS2 = "> ";
1345} 1514}
1346 1515
1347static const char* setup_prompt_string(int promptmode) 1516static const char* setup_prompt_string(int promptmode)
@@ -1742,7 +1911,7 @@ static int o_glob(o_string *o, int n)
1742 goto literal; 1911 goto literal;
1743 } 1912 }
1744 if (gr != 0) { /* GLOB_ABORTED ? */ 1913 if (gr != 0) { /* GLOB_ABORTED ? */
1745//TODO: testcase for bad glob pattern behavior 1914 /* TODO: testcase for bad glob pattern behavior */
1746 bb_error_msg("glob(3) error %d on '%s'", gr, pattern); 1915 bb_error_msg("glob(3) error %d on '%s'", gr, pattern);
1747 } 1916 }
1748 if (globdata.gl_pathv && globdata.gl_pathv[0]) { 1917 if (globdata.gl_pathv && globdata.gl_pathv[0]) {
@@ -1889,12 +2058,9 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
1889 * (expansion of right-hand side of assignment == 1-element expand. 2058 * (expansion of right-hand side of assignment == 1-element expand.
1890 * It will also do no globbing, and thus we must not backslash-quote!) */ 2059 * It will also do no globbing, and thus we must not backslash-quote!) */
1891 2060
1892 char first_ch, ored_ch; 2061 char ored_ch;
1893 int i; 2062 char *p;
1894 const char *val;
1895 char *dyn_val, *p;
1896 2063
1897 dyn_val = NULL;
1898 ored_ch = 0; 2064 ored_ch = 0;
1899 2065
1900 debug_printf_expand("expand_vars_to_list: arg '%s'\n", arg); 2066 debug_printf_expand("expand_vars_to_list: arg '%s'\n", arg);
@@ -1903,6 +2069,10 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
1903 debug_print_list("expand_vars_to_list[0]", output, n); 2069 debug_print_list("expand_vars_to_list[0]", output, n);
1904 2070
1905 while ((p = strchr(arg, SPECIAL_VAR_SYMBOL)) != NULL) { 2071 while ((p = strchr(arg, SPECIAL_VAR_SYMBOL)) != NULL) {
2072 char first_ch;
2073 int i;
2074 char *dyn_val = NULL;
2075 const char *val = NULL;
1906#if ENABLE_HUSH_TICK 2076#if ENABLE_HUSH_TICK
1907 o_string subst_result = NULL_O_STRING; 2077 o_string subst_result = NULL_O_STRING;
1908#endif 2078#endif
@@ -1920,7 +2090,6 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
1920 if ((first_ch & 0x7f) != '@') 2090 if ((first_ch & 0x7f) != '@')
1921 ored_ch |= first_ch; 2091 ored_ch |= first_ch;
1922 2092
1923 val = NULL;
1924 switch (first_ch & 0x7f) { 2093 switch (first_ch & 0x7f) {
1925 /* Highest bit in first_ch indicates that var is double-quoted */ 2094 /* Highest bit in first_ch indicates that var is double-quoted */
1926 case '$': /* pid */ 2095 case '$': /* pid */
@@ -1992,7 +2161,9 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
1992 case '`': /* <SPECIAL_VAR_SYMBOL>`cmd<SPECIAL_VAR_SYMBOL> */ 2161 case '`': /* <SPECIAL_VAR_SYMBOL>`cmd<SPECIAL_VAR_SYMBOL> */
1993 *p = '\0'; 2162 *p = '\0';
1994 arg++; 2163 arg++;
1995//TODO: can we just stuff it into "output" directly? 2164 /* Can't just stuff it into output o_string,
2165 * expanded result may need to be globbed
2166 * and $IFS-splitted */
1996 debug_printf_subst("SUBST '%s' first_ch %x\n", arg, first_ch); 2167 debug_printf_subst("SUBST '%s' first_ch %x\n", arg, first_ch);
1997 process_command_subs(&subst_result, arg); 2168 process_command_subs(&subst_result, arg);
1998 debug_printf_subst("SUBST RES '%s'\n", subst_result.data); 2169 debug_printf_subst("SUBST RES '%s'\n", subst_result.data);
@@ -2091,16 +2262,16 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
2091 if (exp_op == '%' || exp_op == '#') { 2262 if (exp_op == '%' || exp_op == '#') {
2092 if (val) { 2263 if (val) {
2093 /* we need to do a pattern match */ 2264 /* we need to do a pattern match */
2094 bool zero; 2265 bool match_at_left;
2095 char *loc; 2266 char *loc;
2096 scan_t scan = pick_scan(exp_op, *exp_word, &zero); 2267 scan_t scan = pick_scan(exp_op, *exp_word, &match_at_left);
2097 if (exp_op == *exp_word) /* ## or %% */ 2268 if (exp_op == *exp_word) /* ## or %% */
2098 ++exp_word; 2269 ++exp_word;
2099 val = dyn_val = xstrdup(val); 2270 val = dyn_val = xstrdup(val);
2100 loc = scan(dyn_val, exp_word, zero); 2271 loc = scan(dyn_val, exp_word, match_at_left);
2101 if (zero) 2272 if (match_at_left) /* # or ## */
2102 val = loc; 2273 val = loc;
2103 else 2274 else if (loc) /* % or %% and match was found */
2104 *loc = '\0'; 2275 *loc = '\0';
2105 } 2276 }
2106 } else { 2277 } else {
@@ -2132,7 +2303,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
2132 val = NULL; 2303 val = NULL;
2133 } else { 2304 } else {
2134 char *new_var = xasprintf("%s=%s", var, val); 2305 char *new_var = xasprintf("%s=%s", var, val);
2135 set_local_var(new_var, -1, 0); 2306 set_local_var(new_var, 0, 0);
2136 } 2307 }
2137 } 2308 }
2138 } 2309 }
@@ -2160,11 +2331,11 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
2160 } 2331 }
2161 } /* default: */ 2332 } /* default: */
2162 } /* switch (char after <SPECIAL_VAR_SYMBOL>) */ 2333 } /* switch (char after <SPECIAL_VAR_SYMBOL>) */
2334
2163 if (val) { 2335 if (val) {
2164 o_addQstr(output, val, strlen(val)); 2336 o_addQstr(output, val, strlen(val));
2165 } 2337 }
2166 free(dyn_val); 2338 free(dyn_val);
2167 dyn_val = NULL;
2168 /* Do the check to avoid writing to a const string */ 2339 /* Do the check to avoid writing to a const string */
2169 if (*p != SPECIAL_VAR_SYMBOL) 2340 if (*p != SPECIAL_VAR_SYMBOL)
2170 *p = SPECIAL_VAR_SYMBOL; 2341 *p = SPECIAL_VAR_SYMBOL;
@@ -2257,7 +2428,8 @@ static char* expand_strvec_to_string(char **argv)
2257 if (HUSH_DEBUG) 2428 if (HUSH_DEBUG)
2258 if (list[n-1] + strlen(list[n-1]) + 1 != list[n]) 2429 if (list[n-1] + strlen(list[n-1]) + 1 != list[n])
2259 bb_error_msg_and_die("BUG in varexp3"); 2430 bb_error_msg_and_die("BUG in varexp3");
2260 list[n][-1] = ' '; /* TODO: or to G.ifs[0]? */ 2431 /* bash uses ' ' regardless of $IFS contents */
2432 list[n][-1] = ' ';
2261 n++; 2433 n++;
2262 } 2434 }
2263 } 2435 }
@@ -2280,19 +2452,39 @@ static char **expand_assignments(char **argv, int count)
2280 2452
2281#if BB_MMU 2453#if BB_MMU
2282/* never called */ 2454/* never called */
2283void re_execute_shell(const char *s, char *argv0, char **argv); 2455void re_execute_shell(char ***to_free, const char *s, char *argv0, char **argv);
2284
2285#define clean_up_after_re_execute() ((void)0)
2286 2456
2287static void reset_traps_to_defaults(void) 2457static void reset_traps_to_defaults(void)
2288{ 2458{
2459 /* This function is always called in a child shell
2460 * after fork (not vfork, NOMMU doesn't use this function).
2461 * Child shells are not interactive.
2462 * SIGTTIN/SIGTTOU/SIGTSTP should not have special handling.
2463 * Testcase: (while :; do :; done) + ^Z should background.
2464 * Same goes for SIGTERM, SIGHUP, SIGINT.
2465 */
2289 unsigned sig; 2466 unsigned sig;
2290 int dirty; 2467 unsigned mask;
2291 2468
2292 if (!G.traps) 2469 if (!G.traps && !(G.non_DFL_mask & SPECIAL_INTERACTIVE_SIGS))
2293 return; 2470 return;
2294 dirty = 0; 2471
2295 for (sig = 0; sig < NSIG; sig++) { 2472 /* Stupid. It can be done with *single* &= op, but we can't use
2473 * the fact that G.blocked_set is implemented as a bitmask... */
2474 mask = (SPECIAL_INTERACTIVE_SIGS >> 1);
2475 sig = 1;
2476 while (1) {
2477 if (mask & 1)
2478 sigdelset(&G.blocked_set, sig);
2479 mask >>= 1;
2480 if (!mask)
2481 break;
2482 sig++;
2483 }
2484
2485 G.non_DFL_mask &= ~SPECIAL_INTERACTIVE_SIGS;
2486 mask = G.non_DFL_mask;
2487 if (G.traps) for (sig = 0; sig < NSIG; sig++, mask >>= 1) {
2296 if (!G.traps[sig]) 2488 if (!G.traps[sig])
2297 continue; 2489 continue;
2298 free(G.traps[sig]); 2490 free(G.traps[sig]);
@@ -2300,22 +2492,20 @@ static void reset_traps_to_defaults(void)
2300 /* There is no signal for 0 (EXIT) */ 2492 /* There is no signal for 0 (EXIT) */
2301 if (sig == 0) 2493 if (sig == 0)
2302 continue; 2494 continue;
2303 /* there was a trap handler, we are removing it 2495 /* There was a trap handler, we are removing it.
2304 * (if sig has non-DFL handling, 2496 * But if sig still has non-DFL handling,
2305 * we don't need to do anything) */ 2497 * we should not unblock it. */
2306 if (sig < 32 && (G.non_DFL_mask & (1 << sig))) 2498 if (mask & 1)
2307 continue; 2499 continue;
2308 sigdelset(&G.blocked_set, sig); 2500 sigdelset(&G.blocked_set, sig);
2309 dirty = 1;
2310 } 2501 }
2311 if (dirty) 2502 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
2312 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
2313} 2503}
2314 2504
2315#else /* !BB_MMU */ 2505#else /* !BB_MMU */
2316 2506
2317static void re_execute_shell(const char *s, char *g_argv0, char **g_argv) NORETURN; 2507static void re_execute_shell(char ***to_free, const char *s, char *g_argv0, char **g_argv) NORETURN;
2318static void re_execute_shell(const char *s, char *g_argv0, char **g_argv) 2508static void re_execute_shell(char ***to_free, const char *s, char *g_argv0, char **g_argv)
2319{ 2509{
2320 char param_buf[sizeof("-$%x:%x:%x:%x") + sizeof(unsigned) * 4]; 2510 char param_buf[sizeof("-$%x:%x:%x:%x") + sizeof(unsigned) * 4];
2321 char *heredoc_argv[4]; 2511 char *heredoc_argv[4];
@@ -2357,7 +2547,7 @@ static void re_execute_shell(const char *s, char *g_argv0, char **g_argv)
2357 pp = g_argv; 2547 pp = g_argv;
2358 while (*pp++) 2548 while (*pp++)
2359 cnt++; 2549 cnt++;
2360 G.argv_from_re_execing = argv = pp = xzalloc(sizeof(argv[0]) * cnt); 2550 *to_free = argv = pp = xzalloc(sizeof(argv[0]) * cnt);
2361 *pp++ = (char *) G.argv0_for_re_execing; 2551 *pp++ = (char *) G.argv0_for_re_execing;
2362 *pp++ = param_buf; 2552 *pp++ = param_buf;
2363 for (cur = G.top_var; cur; cur = cur->next) { 2553 for (cur = G.top_var; cur; cur = cur->next) {
@@ -2415,16 +2605,6 @@ static void re_execute_shell(const char *s, char *g_argv0, char **g_argv)
2415 xfunc_error_retval = 127; 2605 xfunc_error_retval = 127;
2416 bb_error_msg_and_die("can't re-execute the shell"); 2606 bb_error_msg_and_die("can't re-execute the shell");
2417} 2607}
2418
2419static void clean_up_after_re_execute(void)
2420{
2421 char **pp = G.argv_from_re_execing;
2422 if (pp) {
2423 /* Must match re_execute_shell's allocations (if any) */
2424 free(pp);
2425 G.argv_from_re_execing = NULL;
2426 }
2427}
2428#endif /* !BB_MMU */ 2608#endif /* !BB_MMU */
2429 2609
2430 2610
@@ -2436,6 +2616,9 @@ static void setup_heredoc(struct redir_struct *redir)
2436 /* the _body_ of heredoc (misleading field name) */ 2616 /* the _body_ of heredoc (misleading field name) */
2437 const char *heredoc = redir->rd_filename; 2617 const char *heredoc = redir->rd_filename;
2438 char *expanded; 2618 char *expanded;
2619#if !BB_MMU
2620 char **to_free;
2621#endif
2439 2622
2440 expanded = NULL; 2623 expanded = NULL;
2441 if (!(redir->rd_dup & HEREDOC_QUOTED)) { 2624 if (!(redir->rd_dup & HEREDOC_QUOTED)) {
@@ -2471,11 +2654,15 @@ static void setup_heredoc(struct redir_struct *redir)
2471 * for the unsuspecting parent process. Child creates a grandchild 2654 * for the unsuspecting parent process. Child creates a grandchild
2472 * and exits before parent execs the process which consumes heredoc 2655 * and exits before parent execs the process which consumes heredoc
2473 * (that exec happens after we return from this function) */ 2656 * (that exec happens after we return from this function) */
2657#if !BB_MMU
2658 to_free = NULL;
2659#endif
2474 pid = vfork(); 2660 pid = vfork();
2475 if (pid < 0) 2661 if (pid < 0)
2476 bb_perror_msg_and_die("vfork"); 2662 bb_perror_msg_and_die("vfork");
2477 if (pid == 0) { 2663 if (pid == 0) {
2478 /* child */ 2664 /* child */
2665 disable_restore_tty_pgrp_on_exit();
2479 pid = BB_MMU ? fork() : vfork(); 2666 pid = BB_MMU ? fork() : vfork();
2480 if (pid < 0) 2667 if (pid < 0)
2481 bb_perror_msg_and_die(BB_MMU ? "fork" : "vfork"); 2668 bb_perror_msg_and_die(BB_MMU ? "fork" : "vfork");
@@ -2488,14 +2675,19 @@ static void setup_heredoc(struct redir_struct *redir)
2488 _exit(0); 2675 _exit(0);
2489#else 2676#else
2490 /* Delegate blocking writes to another process */ 2677 /* Delegate blocking writes to another process */
2491 disable_restore_tty_pgrp_on_exit();
2492 xmove_fd(pair.wr, STDOUT_FILENO); 2678 xmove_fd(pair.wr, STDOUT_FILENO);
2493 re_execute_shell(heredoc, NULL, NULL); 2679 re_execute_shell(&to_free, heredoc, NULL, NULL);
2494#endif 2680#endif
2495 } 2681 }
2496 /* parent */ 2682 /* parent */
2683#if ENABLE_HUSH_FAST
2684 G.count_SIGCHLD++;
2685//bb_error_msg("[%d] fork in setup_heredoc: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
2686#endif
2497 enable_restore_tty_pgrp_on_exit(); 2687 enable_restore_tty_pgrp_on_exit();
2498 clean_up_after_re_execute(); 2688#if !BB_MMU
2689 free(to_free);
2690#endif
2499 close(pair.wr); 2691 close(pair.wr);
2500 free(expanded); 2692 free(expanded);
2501 wait(NULL); /* wait till child has died */ 2693 wait(NULL); /* wait till child has died */
@@ -2511,7 +2703,9 @@ static int setup_redirects(struct command *prog, int squirrel[])
2511 for (redir = prog->redirects; redir; redir = redir->next) { 2703 for (redir = prog->redirects; redir; redir = redir->next) {
2512 if (redir->rd_type == REDIRECT_HEREDOC2) { 2704 if (redir->rd_type == REDIRECT_HEREDOC2) {
2513 /* rd_fd<<HERE case */ 2705 /* rd_fd<<HERE case */
2514 if (squirrel && redir->rd_fd < 3) { 2706 if (squirrel && redir->rd_fd < 3
2707 && squirrel[redir->rd_fd] < 0
2708 ) {
2515 squirrel[redir->rd_fd] = dup(redir->rd_fd); 2709 squirrel[redir->rd_fd] = dup(redir->rd_fd);
2516 } 2710 }
2517 /* for REDIRECT_HEREDOC2, rd_filename holds _contents_ 2711 /* for REDIRECT_HEREDOC2, rd_filename holds _contents_
@@ -2547,7 +2741,9 @@ static int setup_redirects(struct command *prog, int squirrel[])
2547 } 2741 }
2548 2742
2549 if (openfd != redir->rd_fd) { 2743 if (openfd != redir->rd_fd) {
2550 if (squirrel && redir->rd_fd < 3) { 2744 if (squirrel && redir->rd_fd < 3
2745 && squirrel[redir->rd_fd] < 0
2746 ) {
2551 squirrel[redir->rd_fd] = dup(redir->rd_fd); 2747 squirrel[redir->rd_fd] = dup(redir->rd_fd);
2552 } 2748 }
2553 if (openfd == REDIRFD_CLOSE) { 2749 if (openfd == REDIRFD_CLOSE) {
@@ -2692,7 +2888,8 @@ static const struct function *find_function(const char *name)
2692 } 2888 }
2693 funcp = funcp->next; 2889 funcp = funcp->next;
2694 } 2890 }
2695 debug_printf_exec("found function '%s'\n", name); 2891 if (funcp)
2892 debug_printf_exec("found function '%s'\n", name);
2696 return funcp; 2893 return funcp;
2697} 2894}
2698 2895
@@ -2720,21 +2917,21 @@ static struct function *new_function(char *name)
2720 * body_as_string was not malloced! */ 2917 * body_as_string was not malloced! */
2721 if (funcp->body) { 2918 if (funcp->body) {
2722 free_pipe_list(funcp->body); 2919 free_pipe_list(funcp->body);
2723#if !BB_MMU 2920# if !BB_MMU
2724 free(funcp->body_as_string); 2921 free(funcp->body_as_string);
2725#endif 2922# endif
2726 } 2923 }
2727 } else { 2924 } else {
2728 debug_printf_exec("reinserting in tree & replacing function '%s'\n", funcp->name); 2925 debug_printf_exec("reinserting in tree & replacing function '%s'\n", funcp->name);
2729 cmd->argv[0] = funcp->name; 2926 cmd->argv[0] = funcp->name;
2730 cmd->group = funcp->body; 2927 cmd->group = funcp->body;
2731#if !BB_MMU 2928# if !BB_MMU
2732 cmd->group_as_string = funcp->body_as_string; 2929 cmd->group_as_string = funcp->body_as_string;
2733#endif 2930# endif
2734 } 2931 }
2735 goto skip; 2932 goto skip;
2736 } 2933 }
2737 debug_printf_exec("remembering new function '%s'\n", command->argv[0]); 2934 debug_printf_exec("remembering new function '%s'\n", name);
2738 funcp = *funcpp = xzalloc(sizeof(*funcp)); 2935 funcp = *funcpp = xzalloc(sizeof(*funcp));
2739 /*funcp->next = NULL;*/ 2936 /*funcp->next = NULL;*/
2740 skip: 2937 skip:
@@ -2742,8 +2939,42 @@ static struct function *new_function(char *name)
2742 return funcp; 2939 return funcp;
2743} 2940}
2744 2941
2745static void exec_function(const struct function *funcp, char **argv) NORETURN; 2942static void unset_func(const char *name)
2746static void exec_function(const struct function *funcp, char **argv) 2943{
2944 struct function *funcp;
2945 struct function **funcpp = &G.top_func;
2946
2947 while ((funcp = *funcpp) != NULL) {
2948 if (strcmp(funcp->name, name) == 0) {
2949 *funcpp = funcp->next;
2950 /* funcp is unlinked now, deleting it.
2951 * Note: if !funcp->body, the function was created by
2952 * "-F name body", do not free ->body_as_string
2953 * and ->name as they were not malloced. */
2954 if (funcp->body) {
2955 free_pipe_list(funcp->body);
2956 free(funcp->name);
2957# if !BB_MMU
2958 free(funcp->body_as_string);
2959# endif
2960 }
2961 free(funcp);
2962 break;
2963 }
2964 funcpp = &funcp->next;
2965 }
2966}
2967
2968# if BB_MMU
2969#define exec_function(nommu_save, funcp, argv) \
2970 exec_function(funcp, argv)
2971# endif
2972static void exec_function(nommu_save_t *nommu_save,
2973 const struct function *funcp,
2974 char **argv) NORETURN;
2975static void exec_function(nommu_save_t *nommu_save,
2976 const struct function *funcp,
2977 char **argv)
2747{ 2978{
2748# if BB_MMU 2979# if BB_MMU
2749 int n = 1; 2980 int n = 1;
@@ -2758,62 +2989,42 @@ static void exec_function(const struct function *funcp, char **argv)
2758 fflush(NULL); 2989 fflush(NULL);
2759 _exit(n); 2990 _exit(n);
2760# else 2991# else
2761 re_execute_shell(funcp->body_as_string, G.global_argv[0], argv + 1); 2992 re_execute_shell(&nommu_save->argv_from_re_execing,
2993 funcp->body_as_string,
2994 G.global_argv[0],
2995 argv + 1);
2762# endif 2996# endif
2763} 2997}
2764 2998
2765static int run_function(const struct function *funcp, char **argv) 2999static int run_function(const struct function *funcp, char **argv)
2766{ 3000{
2767 int n; 3001 int rc;
2768 char **pp; 3002 save_arg_t sv;
2769 char *sv_argv0; 3003 smallint sv_flg;
2770 smallint sv_g_malloced;
2771 int sv_g_argc;
2772 char **sv_g_argv;
2773 3004
2774 sv_argv0 = argv[0]; 3005 save_and_replace_G_args(&sv, argv);
2775 sv_g_malloced = G.global_args_malloced; 3006 /* "we are in function, ok to use return" */
2776 sv_g_argc = G.global_argc; 3007 sv_flg = G.flag_return_in_progress;
2777 sv_g_argv = G.global_argv; 3008 G.flag_return_in_progress = -1;
2778
2779 pp = argv;
2780 n = 1;
2781 while (*++pp)
2782 n++;
2783
2784 argv[0] = G.global_argv[0]; /* retain $0 */
2785 G.global_args_malloced = 0;
2786 G.global_argc = n;
2787 G.global_argv = argv;
2788 3009
2789 /* On MMU, funcp->body is always non-NULL */ 3010 /* On MMU, funcp->body is always non-NULL */
2790#if !BB_MMU 3011# if !BB_MMU
2791 if (!funcp->body) { 3012 if (!funcp->body) {
2792 /* Function defined by -F */ 3013 /* Function defined by -F */
2793 parse_and_run_string(funcp->body_as_string); 3014 parse_and_run_string(funcp->body_as_string);
2794 n = G.last_exitcode; 3015 rc = G.last_exitcode;
2795 } else 3016 } else
2796#endif 3017# endif
2797 { 3018 {
2798 n = run_list(funcp->body); 3019 rc = run_list(funcp->body);
2799 }
2800
2801 if (G.global_args_malloced) {
2802 /* function ran "set -- arg1 arg2 ..." */
2803 pp = G.global_argv;
2804 while (*++pp)
2805 free(*pp);
2806 free(G.global_argv);
2807 } 3020 }
2808 3021
2809 argv[0] = sv_argv0; 3022 G.flag_return_in_progress = sv_flg;
2810 G.global_args_malloced = sv_g_malloced; 3023 restore_G_args(&sv, argv);
2811 G.global_argc = sv_g_argc;
2812 G.global_argv = sv_g_argv;
2813 3024
2814 return n; 3025 return rc;
2815} 3026}
2816#endif 3027#endif /* ENABLE_HUSH_FUNCTIONS */
2817 3028
2818 3029
2819#if BB_MMU 3030#if BB_MMU
@@ -2825,7 +3036,7 @@ static int run_function(const struct function *funcp, char **argv)
2825 3036
2826/* Called after [v]fork() in run_pipe, or from builtin_exec. 3037/* Called after [v]fork() in run_pipe, or from builtin_exec.
2827 * Never returns. 3038 * Never returns.
2828 * XXX no exit() here. If you don't exec, use _exit instead. 3039 * Don't exit() here. If you don't exec, use _exit instead.
2829 * The at_exit handlers apparently confuse the calling process, 3040 * The at_exit handlers apparently confuse the calling process,
2830 * in particular stdin handling. Not sure why? -- because of vfork! (vda) */ 3041 * in particular stdin handling. Not sure why? -- because of vfork! (vda) */
2831static void pseudo_exec_argv(nommu_save_t *nommu_save, 3042static void pseudo_exec_argv(nommu_save_t *nommu_save,
@@ -2843,11 +3054,13 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save,
2843 3054
2844 new_env = expand_assignments(argv, assignment_cnt); 3055 new_env = expand_assignments(argv, assignment_cnt);
2845#if BB_MMU 3056#if BB_MMU
2846 putenv_all(new_env); 3057 set_vars_and_save_old(new_env);
2847 free(new_env); /* optional */ 3058 free(new_env); /* optional */
3059 /* we can also destroy set_vars_and_save_old's return value,
3060 * to save memory */
2848#else 3061#else
2849 nommu_save->new_env = new_env; 3062 nommu_save->new_env = new_env;
2850 nommu_save->old_env = putenv_all_and_save_old(new_env); 3063 nommu_save->old_vars = set_vars_and_save_old(new_env);
2851#endif 3064#endif
2852 if (argv_expanded) { 3065 if (argv_expanded) {
2853 argv = argv_expanded; 3066 argv = argv_expanded;
@@ -2889,7 +3102,7 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save,
2889 { 3102 {
2890 const struct function *funcp = find_function(argv[0]); 3103 const struct function *funcp = find_function(argv[0]);
2891 if (funcp) { 3104 if (funcp) {
2892 exec_function(funcp, argv); 3105 exec_function(nommu_save, funcp, argv);
2893 } 3106 }
2894 } 3107 }
2895#endif 3108#endif
@@ -2921,7 +3134,7 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save,
2921 debug_printf_exec("execing '%s'\n", argv[0]); 3134 debug_printf_exec("execing '%s'\n", argv[0]);
2922 sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); 3135 sigprocmask(SIG_SETMASK, &G.inherited_set, NULL);
2923 execvp(argv[0], argv); 3136 execvp(argv[0], argv);
2924 bb_perror_msg("can't exec '%s'", argv[0]); 3137 bb_perror_msg("can't execute '%s'", argv[0]);
2925 _exit(EXIT_FAILURE); 3138 _exit(EXIT_FAILURE);
2926} 3139}
2927 3140
@@ -2955,7 +3168,8 @@ static void pseudo_exec(nommu_save_t *nommu_save,
2955 * since this process is about to exit */ 3168 * since this process is about to exit */
2956 _exit(rcode); 3169 _exit(rcode);
2957#else 3170#else
2958 re_execute_shell(command->group_as_string, 3171 re_execute_shell(&nommu_save->argv_from_re_execing,
3172 command->group_as_string,
2959 G.global_argv[0], 3173 G.global_argv[0],
2960 G.global_argv + 1); 3174 G.global_argv + 1);
2961#endif 3175#endif
@@ -2985,8 +3199,11 @@ static const char *get_cmdtext(struct pipe *pi)
2985 } 3199 }
2986 3200
2987 len = 0; 3201 len = 0;
2988 do len += strlen(*argv) + 1; while (*++argv); 3202 do {
2989 pi->cmdtext = p = xmalloc(len); 3203 len += strlen(*argv) + 1;
3204 } while (*++argv);
3205 p = xmalloc(len);
3206 pi->cmdtext = p;
2990 argv = pi->cmds[0].argv; 3207 argv = pi->cmds[0].argv;
2991 do { 3208 do {
2992 len = strlen(*argv); 3209 len = strlen(*argv);
@@ -3000,44 +3217,36 @@ static const char *get_cmdtext(struct pipe *pi)
3000 3217
3001static void insert_bg_job(struct pipe *pi) 3218static void insert_bg_job(struct pipe *pi)
3002{ 3219{
3003 struct pipe *thejob; 3220 struct pipe *job, **jobp;
3004 int i; 3221 int i;
3005 3222
3006 /* Linear search for the ID of the job to use */ 3223 /* Linear search for the ID of the job to use */
3007 pi->jobid = 1; 3224 pi->jobid = 1;
3008 for (thejob = G.job_list; thejob; thejob = thejob->next) 3225 for (job = G.job_list; job; job = job->next)
3009 if (thejob->jobid >= pi->jobid) 3226 if (job->jobid >= pi->jobid)
3010 pi->jobid = thejob->jobid + 1; 3227 pi->jobid = job->jobid + 1;
3011 3228
3012 /* Add thejob to the list of running jobs */ 3229 /* Add job to the list of running jobs */
3013 if (!G.job_list) { 3230 jobp = &G.job_list;
3014 thejob = G.job_list = xmalloc(sizeof(*thejob)); 3231 while ((job = *jobp) != NULL)
3015 } else { 3232 jobp = &job->next;
3016 for (thejob = G.job_list; thejob->next; thejob = thejob->next) 3233 job = *jobp = xmalloc(sizeof(*job));
3017 continue; 3234
3018 thejob->next = xmalloc(sizeof(*thejob)); 3235 *job = *pi; /* physical copy */
3019 thejob = thejob->next; 3236 job->next = NULL;
3020 } 3237 job->cmds = xzalloc(sizeof(pi->cmds[0]) * pi->num_cmds);
3021 3238 /* Cannot copy entire pi->cmds[] vector! This causes double frees */
3022 /* Physically copy the struct job */
3023 memcpy(thejob, pi, sizeof(struct pipe));
3024 thejob->cmds = xzalloc(sizeof(pi->cmds[0]) * pi->num_cmds);
3025 /* We cannot copy entire pi->cmds[] vector! Double free()s will happen */
3026 for (i = 0; i < pi->num_cmds; i++) { 3239 for (i = 0; i < pi->num_cmds; i++) {
3027// TODO: do we really need to have so many fields which are just dead weight 3240 job->cmds[i].pid = pi->cmds[i].pid;
3028// at execution stage?
3029 thejob->cmds[i].pid = pi->cmds[i].pid;
3030 /* all other fields are not used and stay zero */ 3241 /* all other fields are not used and stay zero */
3031 } 3242 }
3032 thejob->next = NULL; 3243 job->cmdtext = xstrdup(get_cmdtext(pi));
3033 thejob->cmdtext = xstrdup(get_cmdtext(pi));
3034 3244
3035 /* We don't wait for background thejobs to return -- append it
3036 to the list of backgrounded thejobs and leave it alone */
3037 if (G_interactive_fd) 3245 if (G_interactive_fd)
3038 printf("[%d] %d %s\n", thejob->jobid, thejob->cmds[0].pid, thejob->cmdtext); 3246 printf("[%d] %d %s\n", job->jobid, job->cmds[0].pid, job->cmdtext);
3039 G.last_bg_pid = thejob->cmds[0].pid; 3247 /* Last command's pid goes to $! */
3040 G.last_jobid = thejob->jobid; 3248 G.last_bg_pid = job->cmds[job->num_cmds - 1].pid;
3249 G.last_jobid = job->jobid;
3041} 3250}
3042 3251
3043static void remove_bg_job(struct pipe *pi) 3252static void remove_bg_job(struct pipe *pi)
@@ -3082,39 +3291,57 @@ static int checkjobs(struct pipe* fg_pipe)
3082 3291
3083 debug_printf_jobs("checkjobs %p\n", fg_pipe); 3292 debug_printf_jobs("checkjobs %p\n", fg_pipe);
3084 3293
3085 errno = 0;
3086// if (G.handled_SIGCHLD == G.count_SIGCHLD)
3087// /* avoid doing syscall, nothing there anyway */
3088// return rcode;
3089
3090 attributes = WUNTRACED; 3294 attributes = WUNTRACED;
3091 if (fg_pipe == NULL) 3295 if (fg_pipe == NULL)
3092 attributes |= WNOHANG; 3296 attributes |= WNOHANG;
3093 3297
3298 errno = 0;
3299#if ENABLE_HUSH_FAST
3300 if (G.handled_SIGCHLD == G.count_SIGCHLD) {
3301//bb_error_msg("[%d] checkjobs: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d children?:%d fg_pipe:%p",
3302//getpid(), G.count_SIGCHLD, G.handled_SIGCHLD, G.we_have_children, fg_pipe);
3303 /* There was neither fork nor SIGCHLD since last waitpid */
3304 /* Avoid doing waitpid syscall if possible */
3305 if (!G.we_have_children) {
3306 errno = ECHILD;
3307 return -1;
3308 }
3309 if (fg_pipe == NULL) { /* is WNOHANG set? */
3310 /* We have children, but they did not exit
3311 * or stop yet (we saw no SIGCHLD) */
3312 return 0;
3313 }
3314 /* else: !WNOHANG, waitpid will block, can't short-circuit */
3315 }
3316#endif
3317
3094/* Do we do this right? 3318/* Do we do this right?
3095 * bash-3.00# sleep 20 | false 3319 * bash-3.00# sleep 20 | false
3096 * <ctrl-Z pressed> 3320 * <ctrl-Z pressed>
3097 * [3]+ Stopped sleep 20 | false 3321 * [3]+ Stopped sleep 20 | false
3098 * bash-3.00# echo $? 3322 * bash-3.00# echo $?
3099 * 1 <========== bg pipe is not fully done, but exitcode is already known! 3323 * 1 <========== bg pipe is not fully done, but exitcode is already known!
3324 * [hush 1.14.0: yes we do it right]
3100 */ 3325 */
3101
3102//FIXME: non-interactive bash does not continue even if all processes in fg pipe
3103//are stopped. Testcase: "cat | cat" in a script (not on command line)
3104// + killall -STOP cat
3105
3106 wait_more: 3326 wait_more:
3107 while (1) { 3327 while (1) {
3108 int i; 3328 int i;
3109 int dead; 3329 int dead;
3110 3330
3111// i = G.count_SIGCHLD; 3331#if ENABLE_HUSH_FAST
3332 i = G.count_SIGCHLD;
3333#endif
3112 childpid = waitpid(-1, &status, attributes); 3334 childpid = waitpid(-1, &status, attributes);
3113 if (childpid <= 0) { 3335 if (childpid <= 0) {
3114 if (childpid && errno != ECHILD) 3336 if (childpid && errno != ECHILD)
3115 bb_perror_msg("waitpid"); 3337 bb_perror_msg("waitpid");
3116// else /* Until next SIGCHLD, waitpid's are useless */ 3338#if ENABLE_HUSH_FAST
3117// G.handled_SIGCHLD = i; 3339 else { /* Until next SIGCHLD, waitpid's are useless */
3340 G.we_have_children = (childpid == 0);
3341 G.handled_SIGCHLD = i;
3342//bb_error_msg("[%d] checkjobs: waitpid returned <= 0, G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
3343 }
3344#endif
3118 break; 3345 break;
3119 } 3346 }
3120 dead = WIFEXITED(status) || WIFSIGNALED(status); 3347 dead = WIFEXITED(status) || WIFSIGNALED(status);
@@ -3136,14 +3363,22 @@ static int checkjobs(struct pipe* fg_pipe)
3136 debug_printf_jobs("check pid %d\n", fg_pipe->cmds[i].pid); 3363 debug_printf_jobs("check pid %d\n", fg_pipe->cmds[i].pid);
3137 if (fg_pipe->cmds[i].pid != childpid) 3364 if (fg_pipe->cmds[i].pid != childpid)
3138 continue; 3365 continue;
3139 /* printf("process %d exit %d\n", i, WEXITSTATUS(status)); */
3140 if (dead) { 3366 if (dead) {
3141 fg_pipe->cmds[i].pid = 0; 3367 fg_pipe->cmds[i].pid = 0;
3142 fg_pipe->alive_cmds--; 3368 fg_pipe->alive_cmds--;
3143 if (i == fg_pipe->num_cmds - 1) { 3369 if (i == fg_pipe->num_cmds - 1) {
3144 /* last process gives overall exitstatus */ 3370 /* last process gives overall exitstatus */
3371 /* Note: is WIFSIGNALED, WEXITSTATUS = sig + 128 */
3145 rcode = WEXITSTATUS(status); 3372 rcode = WEXITSTATUS(status);
3146 IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;) 3373 IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;)
3374 /* bash prints killing signal's name for *last*
3375 * process in pipe (prints just newline for SIGINT).
3376 * Mimic this. Example: "sleep 5" + ^\
3377 */
3378 if (WIFSIGNALED(status)) {
3379 int sig = WTERMSIG(status);
3380 printf("%s\n", sig == SIGINT ? "" : get_signame(sig));
3381 }
3147 } 3382 }
3148 } else { 3383 } else {
3149 fg_pipe->cmds[i].is_stopped = 1; 3384 fg_pipe->cmds[i].is_stopped = 1;
@@ -3152,12 +3387,17 @@ static int checkjobs(struct pipe* fg_pipe)
3152 debug_printf_jobs("fg_pipe: alive_cmds %d stopped_cmds %d\n", 3387 debug_printf_jobs("fg_pipe: alive_cmds %d stopped_cmds %d\n",
3153 fg_pipe->alive_cmds, fg_pipe->stopped_cmds); 3388 fg_pipe->alive_cmds, fg_pipe->stopped_cmds);
3154 if (fg_pipe->alive_cmds - fg_pipe->stopped_cmds <= 0) { 3389 if (fg_pipe->alive_cmds - fg_pipe->stopped_cmds <= 0) {
3155 /* All processes in fg pipe have exited/stopped */ 3390 /* All processes in fg pipe have exited or stopped */
3391/* Note: *non-interactive* bash does not continue if all processes in fg pipe
3392 * are stopped. Testcase: "cat | cat" in a script (not on command line!)
3393 * and "killall -STOP cat" */
3394 if (G_interactive_fd) {
3156#if ENABLE_HUSH_JOB 3395#if ENABLE_HUSH_JOB
3157 if (fg_pipe->alive_cmds) 3396 if (fg_pipe->alive_cmds)
3158 insert_bg_job(fg_pipe); 3397 insert_bg_job(fg_pipe);
3159#endif 3398#endif
3160 return rcode; 3399 return rcode;
3400 }
3161 } 3401 }
3162 /* There are still running processes in the fg pipe */ 3402 /* There are still running processes in the fg pipe */
3163 goto wait_more; /* do waitpid again */ 3403 goto wait_more; /* do waitpid again */
@@ -3205,10 +3445,12 @@ static int checkjobs_and_fg_shell(struct pipe* fg_pipe)
3205{ 3445{
3206 pid_t p; 3446 pid_t p;
3207 int rcode = checkjobs(fg_pipe); 3447 int rcode = checkjobs(fg_pipe);
3208 /* Job finished, move the shell to the foreground */ 3448 if (G_saved_tty_pgrp) {
3209 p = getpgid(0); /* pgid of our process */ 3449 /* Job finished, move the shell to the foreground */
3210 debug_printf_jobs("fg'ing ourself: getpgid(0)=%d\n", (int)p); 3450 p = getpgrp(); /* our process group id */
3211 tcsetpgrp(G_interactive_fd, p); 3451 debug_printf_jobs("fg'ing ourself: getpgrp()=%d\n", (int)p);
3452 tcsetpgrp(G_interactive_fd, p);
3453 }
3212 return rcode; 3454 return rcode;
3213} 3455}
3214#endif 3456#endif
@@ -3232,7 +3474,7 @@ static int checkjobs_and_fg_shell(struct pipe* fg_pipe)
3232 * cmd || ... { list } || ... 3474 * cmd || ... { list } || ...
3233 * If it is, then we can run cmd as a builtin, NOFORK [do we do this?], 3475 * If it is, then we can run cmd as a builtin, NOFORK [do we do this?],
3234 * or (if SH_STANDALONE) an applet, and we can run the { list } 3476 * or (if SH_STANDALONE) an applet, and we can run the { list }
3235 * with run_list(). If it isn't one of these, we fork and exec cmd. 3477 * with run_list. If it isn't one of these, we fork and exec cmd.
3236 * 3478 *
3237 * Cases when we must fork: 3479 * Cases when we must fork:
3238 * non-single: cmd | cmd 3480 * non-single: cmd | cmd
@@ -3244,7 +3486,6 @@ static int run_pipe(struct pipe *pi)
3244 static const char *const null_ptr = NULL; 3486 static const char *const null_ptr = NULL;
3245 int i; 3487 int i;
3246 int nextin; 3488 int nextin;
3247 int pipefds[2]; /* pipefds[0] is for reading */
3248 struct command *command; 3489 struct command *command;
3249 char **argv_expanded; 3490 char **argv_expanded;
3250 char **argv; 3491 char **argv;
@@ -3282,10 +3523,10 @@ static int run_pipe(struct pipe *pi)
3282 funcp = new_function(command->argv[0]); 3523 funcp = new_function(command->argv[0]);
3283 /* funcp->name is already set to argv[0] */ 3524 /* funcp->name is already set to argv[0] */
3284 funcp->body = command->group; 3525 funcp->body = command->group;
3285#if !BB_MMU 3526# if !BB_MMU
3286 funcp->body_as_string = command->group_as_string; 3527 funcp->body_as_string = command->group_as_string;
3287 command->group_as_string = NULL; 3528 command->group_as_string = NULL;
3288#endif 3529# endif
3289 command->group = NULL; 3530 command->group = NULL;
3290 command->argv[0] = NULL; 3531 command->argv[0] = NULL;
3291 debug_printf_exec("cmd %p has child func at %p\n", command, funcp); 3532 debug_printf_exec("cmd %p has child func at %p\n", command, funcp);
@@ -3320,7 +3561,7 @@ static int run_pipe(struct pipe *pi)
3320 enum { funcp = 0 }; 3561 enum { funcp = 0 };
3321#endif 3562#endif
3322 char **new_env = NULL; 3563 char **new_env = NULL;
3323 char **old_env = NULL; 3564 struct variable *old_vars = NULL;
3324 3565
3325 if (argv[command->assignment_cnt] == NULL) { 3566 if (argv[command->assignment_cnt] == NULL) {
3326 /* Assignments, but no command */ 3567 /* Assignments, but no command */
@@ -3361,18 +3602,19 @@ static int run_pipe(struct pipe *pi)
3361 goto clean_up_and_ret1; 3602 goto clean_up_and_ret1;
3362 } 3603 }
3363 } 3604 }
3364 /* XXX setup_redirects acts on file descriptors, not FILEs. 3605 /* setup_redirects acts on file descriptors, not FILEs.
3365 * This is perfect for work that comes after exec(). 3606 * This is perfect for work that comes after exec().
3366 * Is it really safe for inline use? Experimentally, 3607 * Is it really safe for inline use? Experimentally,
3367 * things seem to work with glibc. */ 3608 * things seem to work. */
3368 rcode = setup_redirects(command, squirrel); 3609 rcode = setup_redirects(command, squirrel);
3369 if (rcode == 0) { 3610 if (rcode == 0) {
3370 new_env = expand_assignments(argv, command->assignment_cnt); 3611 new_env = expand_assignments(argv, command->assignment_cnt);
3371 old_env = putenv_all_and_save_old(new_env); 3612 old_vars = set_vars_and_save_old(new_env);
3372 if (!funcp) { 3613 if (!funcp) {
3373 debug_printf_exec(": builtin '%s' '%s'...\n", 3614 debug_printf_exec(": builtin '%s' '%s'...\n",
3374 x->cmd, argv_expanded[1]); 3615 x->cmd, argv_expanded[1]);
3375 rcode = x->function(argv_expanded) & 0xff; 3616 rcode = x->function(argv_expanded) & 0xff;
3617 fflush(NULL);
3376 } 3618 }
3377#if ENABLE_HUSH_FUNCTIONS 3619#if ENABLE_HUSH_FUNCTIONS
3378 else { 3620 else {
@@ -3386,11 +3628,8 @@ static int run_pipe(struct pipe *pi)
3386 clean_up_and_ret: 3628 clean_up_and_ret:
3387#endif 3629#endif
3388 restore_redirects(squirrel); 3630 restore_redirects(squirrel);
3389 free_strings_and_unsetenv(new_env, 1); 3631 unset_vars(new_env);
3390 putenv_all(old_env); 3632 add_vars(old_vars);
3391 /* Free the pointers, but the strings themselves
3392 * are in environ now, don't use free_strings! */
3393 free(old_env);
3394 clean_up_and_ret1: 3633 clean_up_and_ret1:
3395 free(argv_expanded); 3634 free(argv_expanded);
3396 IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) 3635 IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;)
@@ -3404,12 +3643,11 @@ static int run_pipe(struct pipe *pi)
3404 if (i >= 0 && APPLET_IS_NOFORK(i)) { 3643 if (i >= 0 && APPLET_IS_NOFORK(i)) {
3405 rcode = setup_redirects(command, squirrel); 3644 rcode = setup_redirects(command, squirrel);
3406 if (rcode == 0) { 3645 if (rcode == 0) {
3407 save_nofork_data(&G.nofork_save);
3408 new_env = expand_assignments(argv, command->assignment_cnt); 3646 new_env = expand_assignments(argv, command->assignment_cnt);
3409 old_env = putenv_all_and_save_old(new_env); 3647 old_vars = set_vars_and_save_old(new_env);
3410 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", 3648 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n",
3411 argv_expanded[0], argv_expanded[1]); 3649 argv_expanded[0], argv_expanded[1]);
3412 rcode = run_nofork_applet_prime(&G.nofork_save, i, argv_expanded); 3650 rcode = run_nofork_applet(i, argv_expanded);
3413 } 3651 }
3414 goto clean_up_and_ret; 3652 goto clean_up_and_ret;
3415 } 3653 }
@@ -3427,11 +3665,13 @@ static int run_pipe(struct pipe *pi)
3427 nextin = 0; 3665 nextin = 0;
3428 3666
3429 for (i = 0; i < pi->num_cmds; i++) { 3667 for (i = 0; i < pi->num_cmds; i++) {
3668 struct fd_pair pipefds;
3430#if !BB_MMU 3669#if !BB_MMU
3431 volatile nommu_save_t nommu_save; 3670 volatile nommu_save_t nommu_save;
3432 nommu_save.new_env = NULL; 3671 nommu_save.new_env = NULL;
3433 nommu_save.old_env = NULL; 3672 nommu_save.old_vars = NULL;
3434 nommu_save.argv = NULL; 3673 nommu_save.argv = NULL;
3674 nommu_save.argv_from_re_execing = NULL;
3435#endif 3675#endif
3436 command = &(pi->cmds[i]); 3676 command = &(pi->cmds[i]);
3437 if (command->argv) { 3677 if (command->argv) {
@@ -3442,10 +3682,10 @@ static int run_pipe(struct pipe *pi)
3442 } 3682 }
3443 3683
3444 /* pipes are inserted between pairs of commands */ 3684 /* pipes are inserted between pairs of commands */
3445 pipefds[0] = 0; 3685 pipefds.rd = 0;
3446 pipefds[1] = 1; 3686 pipefds.wr = 1;
3447 if ((i + 1) < pi->num_cmds) 3687 if ((i + 1) < pi->num_cmds)
3448 xpipe(pipefds); 3688 xpiped_pair(pipefds);
3449 3689
3450 command->pid = BB_MMU ? fork() : vfork(); 3690 command->pid = BB_MMU ? fork() : vfork();
3451 if (!command->pid) { /* child */ 3691 if (!command->pid) { /* child */
@@ -3459,17 +3699,28 @@ static int run_pipe(struct pipe *pi)
3459 pgrp = pi->pgrp; 3699 pgrp = pi->pgrp;
3460 if (pgrp < 0) /* true for 1st process only */ 3700 if (pgrp < 0) /* true for 1st process only */
3461 pgrp = getpid(); 3701 pgrp = getpid();
3462 if (setpgid(0, pgrp) == 0 && pi->followup != PIPE_BG) { 3702 if (setpgid(0, pgrp) == 0
3703 && pi->followup != PIPE_BG
3704 && G_saved_tty_pgrp /* we have ctty */
3705 ) {
3463 /* We do it in *every* child, not just first, 3706 /* We do it in *every* child, not just first,
3464 * to avoid races */ 3707 * to avoid races */
3465 tcsetpgrp(G_interactive_fd, pgrp); 3708 tcsetpgrp(G_interactive_fd, pgrp);
3466 } 3709 }
3467 } 3710 }
3468#endif 3711#endif
3469 xmove_fd(nextin, 0); 3712 if (pi->alive_cmds == 0 && pi->followup == PIPE_BG) {
3470 xmove_fd(pipefds[1], 1); /* write end */ 3713 /* 1st cmd in backgrounded pipe
3471 if (pipefds[0] > 1) 3714 * should have its stdin /dev/null'ed */
3472 close(pipefds[0]); /* read end */ 3715 close(0);
3716 if (open(bb_dev_null, O_RDONLY))
3717 xopen("/", O_RDONLY);
3718 } else {
3719 xmove_fd(nextin, 0);
3720 }
3721 xmove_fd(pipefds.wr, 1);
3722 if (pipefds.rd > 1)
3723 close(pipefds.rd);
3473 /* Like bash, explicit redirects override pipes, 3724 /* Like bash, explicit redirects override pipes,
3474 * and the pipe fd is available for dup'ing. */ 3725 * and the pipe fd is available for dup'ing. */
3475 if (setup_redirects(command, NULL)) 3726 if (setup_redirects(command, NULL))
@@ -3486,16 +3737,17 @@ static int run_pipe(struct pipe *pi)
3486 } 3737 }
3487 3738
3488 /* parent or error */ 3739 /* parent or error */
3740#if ENABLE_HUSH_FAST
3741 G.count_SIGCHLD++;
3742//bb_error_msg("[%d] fork in run_pipe: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
3743#endif
3489 enable_restore_tty_pgrp_on_exit(); 3744 enable_restore_tty_pgrp_on_exit();
3490#if !BB_MMU 3745#if !BB_MMU
3491 /* Clean up after vforked child */ 3746 /* Clean up after vforked child */
3492 clean_up_after_re_execute();
3493 free(nommu_save.argv); 3747 free(nommu_save.argv);
3494 free_strings_and_unsetenv(nommu_save.new_env, 1); 3748 free(nommu_save.argv_from_re_execing);
3495 putenv_all(nommu_save.old_env); 3749 unset_vars(nommu_save.new_env);
3496 /* Free the pointers, but the strings themselves 3750 add_vars(nommu_save.old_vars);
3497 * are in environ now, don't use free_strings! */
3498 free(nommu_save.old_env);
3499#endif 3751#endif
3500 free(argv_expanded); 3752 free(argv_expanded);
3501 argv_expanded = NULL; 3753 argv_expanded = NULL;
@@ -3514,9 +3766,9 @@ static int run_pipe(struct pipe *pi)
3514 if (i) 3766 if (i)
3515 close(nextin); 3767 close(nextin);
3516 if ((i + 1) < pi->num_cmds) 3768 if ((i + 1) < pi->num_cmds)
3517 close(pipefds[1]); /* write end */ 3769 close(pipefds.wr);
3518 /* Pass read (output) pipe end to next iteration */ 3770 /* Pass read (output) pipe end to next iteration */
3519 nextin = pipefds[0]; 3771 nextin = pipefds.rd;
3520 } 3772 }
3521 3773
3522 if (!pi->alive_cmds) { 3774 if (!pi->alive_cmds) {
@@ -3560,8 +3812,9 @@ static void debug_print_tree(struct pipe *pi, int lvl)
3560#endif 3812#endif
3561#if ENABLE_HUSH_CASE 3813#if ENABLE_HUSH_CASE
3562 [RES_CASE ] = "CASE" , 3814 [RES_CASE ] = "CASE" ,
3815 [RES_CASE_IN ] = "CASE_IN" ,
3563 [RES_MATCH] = "MATCH", 3816 [RES_MATCH] = "MATCH",
3564 [RES_CASEI] = "CASEI", 3817 [RES_CASE_BODY] = "CASE_BODY",
3565 [RES_ESAC ] = "ESAC" , 3818 [RES_ESAC ] = "ESAC" ,
3566#endif 3819#endif
3567 [RES_XXXX ] = "XXXX" , 3820 [RES_XXXX ] = "XXXX" ,
@@ -3635,7 +3888,7 @@ static int run_list(struct pipe *pi)
3635 smallint last_rword; /* ditto */ 3888 smallint last_rword; /* ditto */
3636#endif 3889#endif
3637 3890
3638 debug_printf_exec("run_list start lvl %d\n", G.run_list_level + 1); 3891 debug_printf_exec("run_list start lvl %d\n", G.run_list_level);
3639 debug_enter(); 3892 debug_enter();
3640 3893
3641#if ENABLE_HUSH_LOOPS 3894#if ENABLE_HUSH_LOOPS
@@ -3669,51 +3922,9 @@ static int run_list(struct pipe *pi)
3669 * in order to return, no direct "return" statements please. 3922 * in order to return, no direct "return" statements please.
3670 * This helps to ensure that no memory is leaked. */ 3923 * This helps to ensure that no memory is leaked. */
3671 3924
3672////TODO: ctrl-Z handling needs re-thinking and re-testing
3673
3674#if ENABLE_HUSH_JOB 3925#if ENABLE_HUSH_JOB
3675 /* Example of nested list: "while true; do { sleep 1 | exit 2; } done". 3926 G.run_list_level++;
3676 * We are saving state before entering outermost list ("while...done")
3677 * so that ctrl-Z will correctly background _entire_ outermost list,
3678 * not just a part of it (like "sleep 1 | exit 2") */
3679 if (++G.run_list_level == 1 && G_interactive_fd) {
3680 if (sigsetjmp(G.toplevel_jb, 1)) {
3681 /* ctrl-Z forked and we are parent; or ctrl-C.
3682 * Sighandler has longjmped us here */
3683 signal(SIGINT, SIG_IGN);
3684 signal(SIGTSTP, SIG_IGN);
3685 /* Restore level (we can be coming from deep inside
3686 * nested levels) */
3687 G.run_list_level = 1;
3688#if ENABLE_FEATURE_SH_STANDALONE
3689 if (G.nofork_save.saved) { /* if save area is valid */
3690 debug_printf_jobs("exiting nofork early\n");
3691 restore_nofork_data(&G.nofork_save);
3692 }
3693#endif 3927#endif
3694//// if (G.ctrl_z_flag) {
3695//// /* ctrl-Z has forked and stored pid of the child in pi->pid.
3696//// * Remember this child as background job */
3697//// insert_bg_job(pi);
3698//// } else {
3699 /* ctrl-C. We just stop doing whatever we were doing */
3700 bb_putchar('\n');
3701//// }
3702 USE_HUSH_LOOPS(loop_top = NULL;)
3703 USE_HUSH_LOOPS(G.depth_of_loop = 0;)
3704 rcode = 0;
3705 goto ret;
3706 }
3707//// /* ctrl-Z handler will store pid etc in pi */
3708//// G.toplevel_list = pi;
3709//// G.ctrl_z_flag = 0;
3710#if ENABLE_FEATURE_SH_STANDALONE
3711 G.nofork_save.saved = 0; /* in case we will run a nofork later */
3712#endif
3713//// signal_SA_RESTART_empty_mask(SIGTSTP, handler_ctrl_z);
3714//// signal(SIGINT, handler_ctrl_c);
3715 }
3716#endif /* JOB */
3717 3928
3718#if HAS_KEYWORDS 3929#if HAS_KEYWORDS
3719 rword = RES_NONE; 3930 rword = RES_NONE;
@@ -3847,7 +4058,7 @@ static int run_list(struct pipe *pi)
3847 } 4058 }
3848 continue; 4059 continue;
3849 } 4060 }
3850 if (rword == RES_CASEI) { /* inside of a case branch */ 4061 if (rword == RES_CASE_BODY) { /* inside of a case branch */
3851 if (cond_code != 0) 4062 if (cond_code != 0)
3852 continue; /* not matched yet, skip this pipe */ 4063 continue; /* not matched yet, skip this pipe */
3853 } 4064 }
@@ -3873,7 +4084,8 @@ static int run_list(struct pipe *pi)
3873#endif 4084#endif
3874 rcode = r = run_pipe(pi); /* NB: rcode is a smallint */ 4085 rcode = r = run_pipe(pi); /* NB: rcode is a smallint */
3875 if (r != -1) { 4086 if (r != -1) {
3876 /* We only ran a builtin: rcode is already known 4087 /* We ran a builtin, function, or group.
4088 * rcode is already known
3877 * and we don't need to wait for anything. */ 4089 * and we don't need to wait for anything. */
3878 G.last_exitcode = rcode; 4090 G.last_exitcode = rcode;
3879 debug_printf_exec(": builtin/func exitcode %d\n", rcode); 4091 debug_printf_exec(": builtin/func exitcode %d\n", rcode);
@@ -3897,6 +4109,10 @@ static int run_list(struct pipe *pi)
3897 continue; 4109 continue;
3898 } 4110 }
3899#endif 4111#endif
4112#if ENABLE_HUSH_FUNCTIONS
4113 if (G.flag_return_in_progress == 1)
4114 goto check_jobs_and_break;
4115#endif
3900 } else if (pi->followup == PIPE_BG) { 4116 } else if (pi->followup == PIPE_BG) {
3901 /* What does bash do with attempts to background builtins? */ 4117 /* What does bash do with attempts to background builtins? */
3902 /* even bash 3.2 doesn't do that well with nested bg: 4118 /* even bash 3.2 doesn't do that well with nested bg:
@@ -3959,18 +4175,7 @@ static int run_list(struct pipe *pi)
3959 } /* for (pi) */ 4175 } /* for (pi) */
3960 4176
3961#if ENABLE_HUSH_JOB 4177#if ENABLE_HUSH_JOB
3962//// if (G.ctrl_z_flag) {
3963//// /* ctrl-Z forked somewhere in the past, we are the child,
3964//// * and now we completed running the list. Exit. */
3965//////TODO: _exit?
3966//// exit(rcode);
3967//// }
3968 ret:
3969 G.run_list_level--; 4178 G.run_list_level--;
3970//// if (!G.run_list_level && G_interactive_fd) {
3971//// signal(SIGTSTP, SIG_IGN);
3972//// signal(SIGINT, SIG_IGN);
3973//// }
3974#endif 4179#endif
3975#if ENABLE_HUSH_LOOPS 4180#if ENABLE_HUSH_LOOPS
3976 if (loop_top) 4181 if (loop_top)
@@ -4012,8 +4217,10 @@ static struct pipe *new_pipe(void)
4012 return pi; 4217 return pi;
4013} 4218}
4014 4219
4015/* Command (member of a pipe) is complete. The only possible error here 4220/* Command (member of a pipe) is complete, or we start a new pipe
4016 * is out of memory, in which case xmalloc exits. */ 4221 * if ctx->command is NULL.
4222 * No errors possible here.
4223 */
4017static int done_command(struct parse_context *ctx) 4224static int done_command(struct parse_context *ctx)
4018{ 4225{
4019 /* The command is really already in the pipe structure, so 4226 /* The command is really already in the pipe structure, so
@@ -4022,13 +4229,9 @@ static int done_command(struct parse_context *ctx)
4022 struct command *command = ctx->command; 4229 struct command *command = ctx->command;
4023 4230
4024 if (command) { 4231 if (command) {
4025 if (command->group == NULL 4232 if (IS_NULL_CMD(command)) {
4026 && command->argv == NULL
4027 && command->redirects == NULL
4028 ) {
4029 debug_printf_parse("done_command: skipping null cmd, num_cmds=%d\n", pi->num_cmds); 4233 debug_printf_parse("done_command: skipping null cmd, num_cmds=%d\n", pi->num_cmds);
4030 memset(command, 0, sizeof(*command)); /* paranoia */ 4234 goto clear_and_ret;
4031 return pi->num_cmds;
4032 } 4235 }
4033 pi->num_cmds++; 4236 pi->num_cmds++;
4034 debug_printf_parse("done_command: ++num_cmds=%d\n", pi->num_cmds); 4237 debug_printf_parse("done_command: ++num_cmds=%d\n", pi->num_cmds);
@@ -4040,12 +4243,9 @@ static int done_command(struct parse_context *ctx)
4040 /* Only real trickiness here is that the uncommitted 4243 /* Only real trickiness here is that the uncommitted
4041 * command structure is not counted in pi->num_cmds. */ 4244 * command structure is not counted in pi->num_cmds. */
4042 pi->cmds = xrealloc(pi->cmds, sizeof(*pi->cmds) * (pi->num_cmds+1)); 4245 pi->cmds = xrealloc(pi->cmds, sizeof(*pi->cmds) * (pi->num_cmds+1));
4043 command = &pi->cmds[pi->num_cmds]; 4246 ctx->command = command = &pi->cmds[pi->num_cmds];
4247 clear_and_ret:
4044 memset(command, 0, sizeof(*command)); 4248 memset(command, 0, sizeof(*command));
4045
4046 ctx->command = command;
4047 /* but ctx->pipe and ctx->list_head remain unchanged */
4048
4049 return pi->num_cmds; /* used only for 0/nonzero check */ 4249 return pi->num_cmds; /* used only for 0/nonzero check */
4050} 4250}
4051 4251
@@ -4065,9 +4265,7 @@ static void done_pipe(struct parse_context *ctx, pipe_style type)
4065 4265
4066 /* Without this check, even just <enter> on command line generates 4266 /* Without this check, even just <enter> on command line generates
4067 * tree of three NOPs (!). Which is harmless but annoying. 4267 * tree of three NOPs (!). Which is harmless but annoying.
4068 * IOW: it is safe to do it unconditionally. 4268 * IOW: it is safe to do it unconditionally. */
4069 * RES_NONE case is for "for a in; do ..." (empty IN set)
4070 * and other cases to work. */
4071 if (not_null 4269 if (not_null
4072#if ENABLE_HUSH_IF 4270#if ENABLE_HUSH_IF
4073 || ctx->ctx_res_w == RES_FI 4271 || ctx->ctx_res_w == RES_FI
@@ -4089,7 +4287,7 @@ static void done_pipe(struct parse_context *ctx, pipe_style type)
4089 ctx->pipe->next = new_p; 4287 ctx->pipe->next = new_p;
4090 ctx->pipe = new_p; 4288 ctx->pipe = new_p;
4091 /* RES_THEN, RES_DO etc are "sticky" - 4289 /* RES_THEN, RES_DO etc are "sticky" -
4092 * they remain set for commands inside if/while. 4290 * they remain set for pipes inside if/while.
4093 * This is used to control execution. 4291 * This is used to control execution.
4094 * RES_FOR and RES_IN are NOT sticky (needed to support 4292 * RES_FOR and RES_IN are NOT sticky (needed to support
4095 * cases where variable or value happens to match a keyword): 4293 * cases where variable or value happens to match a keyword):
@@ -4101,7 +4299,9 @@ static void done_pipe(struct parse_context *ctx, pipe_style type)
4101#endif 4299#endif
4102#if ENABLE_HUSH_CASE 4300#if ENABLE_HUSH_CASE
4103 if (ctx->ctx_res_w == RES_MATCH) 4301 if (ctx->ctx_res_w == RES_MATCH)
4104 ctx->ctx_res_w = RES_CASEI; 4302 ctx->ctx_res_w = RES_CASE_BODY;
4303 if (ctx->ctx_res_w == RES_CASE)
4304 ctx->ctx_res_w = RES_CASE_IN;
4105#endif 4305#endif
4106 ctx->command = NULL; /* trick done_command below */ 4306 ctx->command = NULL; /* trick done_command below */
4107 /* Create the memory for command, roughly: 4307 /* Create the memory for command, roughly:
@@ -4196,6 +4396,8 @@ static const struct reserved_combo* match_reserved_word(o_string *word)
4196 } 4396 }
4197 return NULL; 4397 return NULL;
4198} 4398}
4399/* Return 0: not a keyword, 1: keyword
4400 */
4199static int reserved_word(o_string *word, struct parse_context *ctx) 4401static int reserved_word(o_string *word, struct parse_context *ctx)
4200{ 4402{
4201#if ENABLE_HUSH_CASE 4403#if ENABLE_HUSH_CASE
@@ -4205,27 +4407,30 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
4205#endif 4407#endif
4206 const struct reserved_combo *r; 4408 const struct reserved_combo *r;
4207 4409
4410 if (word->o_quoted)
4411 return 0;
4208 r = match_reserved_word(word); 4412 r = match_reserved_word(word);
4209 if (!r) 4413 if (!r)
4210 return 0; 4414 return 0;
4211 4415
4212 debug_printf("found reserved word %s, res %d\n", r->literal, r->res); 4416 debug_printf("found reserved word %s, res %d\n", r->literal, r->res);
4213#if ENABLE_HUSH_CASE 4417#if ENABLE_HUSH_CASE
4214 if (r->res == RES_IN && ctx->ctx_res_w == RES_CASE) 4418 if (r->res == RES_IN && ctx->ctx_res_w == RES_CASE_IN) {
4215 /* "case word IN ..." - IN part starts first match part */ 4419 /* "case word IN ..." - IN part starts first MATCH part */
4216 r = &reserved_match; 4420 r = &reserved_match;
4217 else 4421 } else
4218#endif 4422#endif
4219 if (r->flag == 0) { /* '!' */ 4423 if (r->flag == 0) { /* '!' */
4220 if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */ 4424 if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */
4221 syntax_error("! ! command"); 4425 syntax_error("! ! command");
4222 IF_HAS_KEYWORDS(ctx->ctx_res_w = RES_SNTX;) 4426 ctx->ctx_res_w = RES_SNTX;
4223 } 4427 }
4224 ctx->ctx_inverted = 1; 4428 ctx->ctx_inverted = 1;
4225 return 1; 4429 return 1;
4226 } 4430 }
4227 if (r->flag & FLAG_START) { 4431 if (r->flag & FLAG_START) {
4228 struct parse_context *old; 4432 struct parse_context *old;
4433
4229 old = xmalloc(sizeof(*old)); 4434 old = xmalloc(sizeof(*old));
4230 debug_printf_parse("push stack %p\n", old); 4435 debug_printf_parse("push stack %p\n", old);
4231 *old = *ctx; /* physical copy */ 4436 *old = *ctx; /* physical copy */
@@ -4235,11 +4440,21 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
4235 syntax_error_at(word->data); 4440 syntax_error_at(word->data);
4236 ctx->ctx_res_w = RES_SNTX; 4441 ctx->ctx_res_w = RES_SNTX;
4237 return 1; 4442 return 1;
4443 } else {
4444 /* "{...} fi" is ok. "{...} if" is not
4445 * Example:
4446 * if { echo foo; } then { echo bar; } fi */
4447 if (ctx->command->group)
4448 done_pipe(ctx, PIPE_SEQ);
4238 } 4449 }
4450
4239 ctx->ctx_res_w = r->res; 4451 ctx->ctx_res_w = r->res;
4240 ctx->old_flag = r->flag; 4452 ctx->old_flag = r->flag;
4453 word->o_assignment = r->assignment_flag;
4454
4241 if (ctx->old_flag & FLAG_END) { 4455 if (ctx->old_flag & FLAG_END) {
4242 struct parse_context *old; 4456 struct parse_context *old;
4457
4243 done_pipe(ctx, PIPE_SEQ); 4458 done_pipe(ctx, PIPE_SEQ);
4244 debug_printf_parse("pop stack %p\n", ctx->stack); 4459 debug_printf_parse("pop stack %p\n", ctx->stack);
4245 old = ctx->stack; 4460 old = ctx->stack;
@@ -4255,7 +4470,6 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
4255 *ctx = *old; /* physical copy */ 4470 *ctx = *old; /* physical copy */
4256 free(old); 4471 free(old);
4257 } 4472 }
4258 word->o_assignment = r->assignment_flag;
4259 return 1; 4473 return 1;
4260} 4474}
4261#endif 4475#endif
@@ -4315,19 +4529,6 @@ static int done_word(o_string *word, struct parse_context *ctx)
4315 word->o_assignment = MAYBE_ASSIGNMENT; 4529 word->o_assignment = MAYBE_ASSIGNMENT;
4316 } 4530 }
4317 4531
4318 if (command->group) {
4319 /* "{ echo foo; } echo bar" - bad */
4320 /* NB: bash allows e.g.:
4321 * if true; then { echo foo; } fi
4322 * while if false; then false; fi do break; done
4323 * and disallows:
4324 * while if false; then false; fi; do; break; done
4325 * TODO? */
4326 syntax_error_at(word->data);
4327 debug_printf_parse("done_word return 1: syntax error, "
4328 "groups and arglists don't mix\n");
4329 return 1;
4330 }
4331#if HAS_KEYWORDS 4532#if HAS_KEYWORDS
4332# if ENABLE_HUSH_CASE 4533# if ENABLE_HUSH_CASE
4333 if (ctx->ctx_dsemicolon 4534 if (ctx->ctx_dsemicolon
@@ -4343,8 +4544,11 @@ static int done_word(o_string *word, struct parse_context *ctx)
4343 && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */ 4544 && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */
4344 && ctx->ctx_res_w != RES_IN 4545 && ctx->ctx_res_w != RES_IN
4345# endif 4546# endif
4547# if ENABLE_HUSH_CASE
4548 && ctx->ctx_res_w != RES_CASE
4549# endif
4346 ) { 4550 ) {
4347 debug_printf_parse(": checking '%s' for reserved-ness\n", word->data); 4551 debug_printf_parse("checking '%s' for reserved-ness\n", word->data);
4348 if (reserved_word(word, ctx)) { 4552 if (reserved_word(word, ctx)) {
4349 o_reset_to_empty_unquoted(word); 4553 o_reset_to_empty_unquoted(word);
4350 debug_printf_parse("done_word return %d\n", 4554 debug_printf_parse("done_word return %d\n",
@@ -4353,6 +4557,13 @@ static int done_word(o_string *word, struct parse_context *ctx)
4353 } 4557 }
4354 } 4558 }
4355#endif 4559#endif
4560 if (command->group) {
4561 /* "{ echo foo; } echo bar" - bad */
4562 syntax_error_at(word->data);
4563 debug_printf_parse("done_word return 1: syntax error, "
4564 "groups and arglists don't mix\n");
4565 return 1;
4566 }
4356 if (word->o_quoted /* word had "xx" or 'xx' at least as part of it. */ 4567 if (word->o_quoted /* word had "xx" or 'xx' at least as part of it. */
4357 /* optimization: and if it's ("" or '') or ($v... or `cmd`...): */ 4568 /* optimization: and if it's ("" or '') or ($v... or `cmd`...): */
4358 && (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL) 4569 && (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL)
@@ -4376,10 +4587,6 @@ static int done_word(o_string *word, struct parse_context *ctx)
4376 } 4587 }
4377 } 4588 }
4378 command->argv = add_string_to_strings(command->argv, xstrdup(word->data)); 4589 command->argv = add_string_to_strings(command->argv, xstrdup(word->data));
4379//SEGV, but good idea.
4380// command->argv = add_string_to_strings(command->argv, word->data);
4381// word->data = NULL;
4382// word->length = 0;
4383 debug_print_strings("word appended to argv", command->argv); 4590 debug_print_strings("word appended to argv", command->argv);
4384 } 4591 }
4385 4592
@@ -4657,6 +4864,9 @@ static FILE *generate_stream_from_string(const char *s)
4657{ 4864{
4658 FILE *pf; 4865 FILE *pf;
4659 int pid, channel[2]; 4866 int pid, channel[2];
4867#if !BB_MMU
4868 char **to_free;
4869#endif
4660 4870
4661 xpipe(channel); 4871 xpipe(channel);
4662 pid = BB_MMU ? fork() : vfork(); 4872 pid = BB_MMU ? fork() : vfork();
@@ -4688,15 +4898,22 @@ static FILE *generate_stream_from_string(const char *s)
4688 * huge=`cat BIG` # was blocking here forever 4898 * huge=`cat BIG` # was blocking here forever
4689 * echo OK 4899 * echo OK
4690 */ 4900 */
4691 re_execute_shell(s, 4901 re_execute_shell(&to_free,
4902 s,
4692 G.global_argv[0], 4903 G.global_argv[0],
4693 G.global_argv + 1); 4904 G.global_argv + 1);
4694#endif 4905#endif
4695 } 4906 }
4696 4907
4697 /* parent */ 4908 /* parent */
4909#if ENABLE_HUSH_FAST
4910 G.count_SIGCHLD++;
4911//bb_error_msg("[%d] fork in generate_stream_from_string: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
4912#endif
4698 enable_restore_tty_pgrp_on_exit(); 4913 enable_restore_tty_pgrp_on_exit();
4699 clean_up_after_re_execute(); 4914#if !BB_MMU
4915 free(to_free);
4916#endif
4700 close(channel[1]); 4917 close(channel[1]);
4701 pf = fdopen(channel[0], "r"); 4918 pf = fdopen(channel[0], "r");
4702 return pf; 4919 return pf;
@@ -4756,7 +4973,8 @@ static int parse_group(o_string *dest, struct parse_context *ctx,
4756#if ENABLE_HUSH_FUNCTIONS 4973#if ENABLE_HUSH_FUNCTIONS
4757 if (ch == '(' && !dest->o_quoted) { 4974 if (ch == '(' && !dest->o_quoted) {
4758 if (dest->length) 4975 if (dest->length)
4759 done_word(dest, ctx); 4976 if (done_word(dest, ctx))
4977 return 1;
4760 if (!command->argv) 4978 if (!command->argv)
4761 goto skip; /* (... */ 4979 goto skip; /* (... */
4762 if (command->argv[1]) { /* word word ... (... */ 4980 if (command->argv[1]) { /* word word ... (... */
@@ -4801,6 +5019,14 @@ static int parse_group(o_string *dest, struct parse_context *ctx,
4801 if (ch == '(') { 5019 if (ch == '(') {
4802 endch = ')'; 5020 endch = ')';
4803 command->grp_type = GRP_SUBSHELL; 5021 command->grp_type = GRP_SUBSHELL;
5022 } else {
5023 /* bash does not allow "{echo...", requires whitespace */
5024 ch = i_getch(input);
5025 if (ch != ' ' && ch != '\t' && ch != '\n') {
5026 syntax_error_unexpected_ch(ch);
5027 return 1;
5028 }
5029 nommu_addchr(&ctx->as_string, ch);
4804 } 5030 }
4805 5031
4806 { 5032 {
@@ -4814,10 +5040,10 @@ static int parse_group(o_string *dest, struct parse_context *ctx,
4814#endif 5040#endif
4815 /* empty ()/{} or parse error? */ 5041 /* empty ()/{} or parse error? */
4816 if (!pipe_list || pipe_list == ERR_PTR) { 5042 if (!pipe_list || pipe_list == ERR_PTR) {
5043 /* parse_stream already emitted error msg */
4817#if !BB_MMU 5044#if !BB_MMU
4818 free(as_string); 5045 free(as_string);
4819#endif 5046#endif
4820 syntax_error(NULL);
4821 debug_printf_parse("parse_group return 1: " 5047 debug_printf_parse("parse_group return 1: "
4822 "parse_stream returned %p\n", pipe_list); 5048 "parse_stream returned %p\n", pipe_list);
4823 return 1; 5049 return 1;
@@ -5024,21 +5250,23 @@ static int handle_dollar(o_string *as_string,
5024 o_addchr(dest, SPECIAL_VAR_SYMBOL); 5250 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5025 ch = i_getch(input); 5251 ch = i_getch(input);
5026 nommu_addchr(as_string, ch); 5252 nommu_addchr(as_string, ch);
5027 /* XXX maybe someone will try to escape the '}' */ 5253 /* TODO: maybe someone will try to escape the '}' */
5028 expansion = 0; 5254 expansion = 0;
5029 first_char = true; 5255 first_char = true;
5030 all_digits = false; 5256 all_digits = false;
5031 while (1) { 5257 while (1) {
5032 ch = i_getch(input); 5258 ch = i_getch(input);
5033 nommu_addchr(as_string, ch); 5259 nommu_addchr(as_string, ch);
5034 if (ch == '}') 5260 if (ch == '}') {
5035 break; 5261 break;
5262 }
5036 5263
5037 if (first_char) { 5264 if (first_char) {
5038 if (ch == '#') 5265 if (ch == '#') {
5039 /* ${#var}: length of var contents */ 5266 /* ${#var}: length of var contents */
5040 goto char_ok; 5267 goto char_ok;
5041 else if (isdigit(ch)) { 5268 }
5269 if (isdigit(ch)) {
5042 all_digits = true; 5270 all_digits = true;
5043 goto char_ok; 5271 goto char_ok;
5044 } 5272 }
@@ -5089,7 +5317,7 @@ static int handle_dollar(o_string *as_string,
5089 o_addchr(dest, ch | quote_mask); 5317 o_addchr(dest, ch | quote_mask);
5090 quote_mask = 0; 5318 quote_mask = 0;
5091 first_char = false; 5319 first_char = false;
5092 } 5320 } /* while (1) */
5093 o_addchr(dest, SPECIAL_VAR_SYMBOL); 5321 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5094 break; 5322 break;
5095 } 5323 }
@@ -5202,10 +5430,15 @@ static int parse_stream_dquoted(o_string *as_string,
5202 * $, `, ", \, or <newline>. A double quote may be quoted 5430 * $, `, ", \, or <newline>. A double quote may be quoted
5203 * within double quotes by preceding it with a backslash. 5431 * within double quotes by preceding it with a backslash.
5204 */ 5432 */
5205 if (strchr("$`\"\\", next) != NULL) { 5433 if (strchr("$`\"\\\n", next) != NULL) {
5206 o_addqchr(dest, i_getch(input)); 5434 ch = i_getch(input);
5435 if (ch != '\n') {
5436 o_addqchr(dest, ch);
5437 nommu_addchr(as_string, ch);
5438 }
5207 } else { 5439 } else {
5208 o_addqchr(dest, '\\'); 5440 o_addqchr(dest, '\\');
5441 nommu_addchr(as_string, '\\');
5209 } 5442 }
5210 goto again; 5443 goto again;
5211 } 5444 }
@@ -5300,10 +5533,17 @@ static struct pipe *parse_stream(char **pstring,
5300 5533
5301 if (heredoc_cnt) { 5534 if (heredoc_cnt) {
5302 syntax_error_unterm_str("here document"); 5535 syntax_error_unterm_str("here document");
5303 xfunc_die(); 5536 goto parse_error;
5537 }
5538 /* end_trigger == '}' case errors out earlier,
5539 * checking only ')' */
5540 if (end_trigger == ')') {
5541 syntax_error_unterm_ch('('); /* exits */
5542 /* goto parse_error; */
5304 } 5543 }
5544
5305 if (done_word(&dest, &ctx)) { 5545 if (done_word(&dest, &ctx)) {
5306 xfunc_die(); 5546 goto parse_error;
5307 } 5547 }
5308 o_free(&dest); 5548 o_free(&dest);
5309 done_pipe(&ctx, PIPE_SEQ); 5549 done_pipe(&ctx, PIPE_SEQ);
@@ -5335,6 +5575,7 @@ static struct pipe *parse_stream(char **pstring,
5335 , ch); 5575 , ch);
5336 5576
5337 if (!is_special && !is_ifs) { /* ordinary char */ 5577 if (!is_special && !is_ifs) { /* ordinary char */
5578 ordinary_char:
5338 o_addQchr(&dest, ch); 5579 o_addQchr(&dest, ch);
5339 if ((dest.o_assignment == MAYBE_ASSIGNMENT 5580 if ((dest.o_assignment == MAYBE_ASSIGNMENT
5340 || dest.o_assignment == WORD_IS_KEYWORD) 5581 || dest.o_assignment == WORD_IS_KEYWORD)
@@ -5375,16 +5616,37 @@ static struct pipe *parse_stream(char **pstring,
5375 * will still trigger for us */ 5616 * will still trigger for us */
5376 } 5617 }
5377 } 5618 }
5619
5620 /* "cmd}" or "cmd }..." without semicolon or &:
5621 * } is an ordinary char in this case, even inside { cmd; }
5622 * Pathological example: { ""}; } should exec "}" cmd
5623 */
5624 if (ch == '}') {
5625 if (!IS_NULL_CMD(ctx.command) /* cmd } */
5626 || dest.length != 0 /* word} */
5627 || dest.o_quoted /* ""} */
5628 ) {
5629 goto ordinary_char;
5630 }
5631 if (!IS_NULL_PIPE(ctx.pipe)) /* cmd | } */
5632 goto skip_end_trigger;
5633 /* else: } does terminate a group */
5634 }
5635
5378 if (end_trigger && end_trigger == ch 5636 if (end_trigger && end_trigger == ch
5379 && (heredoc_cnt == 0 || end_trigger != ';') 5637 && (ch != ';' || heredoc_cnt == 0)
5638#if ENABLE_HUSH_CASE
5639 && (ch != ')'
5640 || ctx.ctx_res_w != RES_MATCH
5641 || (!dest.o_quoted && strcmp(dest.data, "esac") == 0)
5642 )
5643#endif
5380 ) { 5644 ) {
5381//TODO: disallow "{ cmd }" without semicolon
5382 if (heredoc_cnt) { 5645 if (heredoc_cnt) {
5383 /* This is technically valid: 5646 /* This is technically valid:
5384 * { cat <<HERE; }; echo Ok 5647 * { cat <<HERE; }; echo Ok
5385 * heredoc 5648 * heredoc
5386 * heredoc 5649 * heredoc
5387 * heredoc
5388 * HERE 5650 * HERE
5389 * but we don't support this. 5651 * but we don't support this.
5390 * We require heredoc to be in enclosing {}/(), 5652 * We require heredoc to be in enclosing {}/(),
@@ -5417,6 +5679,7 @@ static struct pipe *parse_stream(char **pstring,
5417 return ctx.list_head; 5679 return ctx.list_head;
5418 } 5680 }
5419 } 5681 }
5682 skip_end_trigger:
5420 if (is_ifs) 5683 if (is_ifs)
5421 continue; 5684 continue;
5422 5685
@@ -5505,13 +5768,16 @@ static struct pipe *parse_stream(char **pstring,
5505 syntax_error("\\<eof>"); 5768 syntax_error("\\<eof>");
5506 xfunc_die(); 5769 xfunc_die();
5507 } 5770 }
5508 o_addchr(&dest, '\\');
5509 ch = i_getch(input); 5771 ch = i_getch(input);
5510 nommu_addchr(&ctx.as_string, ch); 5772 if (ch != '\n') {
5511 o_addchr(&dest, ch); 5773 o_addchr(&dest, '\\');
5512 /* Example: echo Hello \2>file 5774 nommu_addchr(&ctx.as_string, '\\');
5513 * we need to know that word 2 is quoted */ 5775 o_addchr(&dest, ch);
5514 dest.o_quoted = 1; 5776 nommu_addchr(&ctx.as_string, ch);
5777 /* Example: echo Hello \2>file
5778 * we need to know that word 2 is quoted */
5779 dest.o_quoted = 1;
5780 }
5515 break; 5781 break;
5516 case '$': 5782 case '$':
5517 if (handle_dollar(&ctx.as_string, &dest, input) != 0) { 5783 if (handle_dollar(&ctx.as_string, &dest, input) != 0) {
@@ -5580,7 +5846,7 @@ static struct pipe *parse_stream(char **pstring,
5580 break; 5846 break;
5581 ch = i_getch(input); 5847 ch = i_getch(input);
5582 nommu_addchr(&ctx.as_string, ch); 5848 nommu_addchr(&ctx.as_string, ch);
5583 if (ctx.ctx_res_w == RES_CASEI) { 5849 if (ctx.ctx_res_w == RES_CASE_BODY) {
5584 ctx.ctx_dsemicolon = 1; 5850 ctx.ctx_dsemicolon = 1;
5585 ctx.ctx_res_w = RES_MATCH; 5851 ctx.ctx_res_w = RES_MATCH;
5586 break; 5852 break;
@@ -5752,15 +6018,9 @@ static void block_signals(int second_time)
5752 6018
5753 mask = (1 << SIGQUIT); 6019 mask = (1 << SIGQUIT);
5754 if (G_interactive_fd) { 6020 if (G_interactive_fd) {
5755 mask = 0 6021 mask = (1 << SIGQUIT) | SPECIAL_INTERACTIVE_SIGS;
5756 | (1 << SIGQUIT) 6022 if (G_saved_tty_pgrp) /* we have ctty, job control sigs work */
5757 | (1 << SIGTERM) 6023 mask |= SPECIAL_JOB_SIGS;
5758//TODO | (1 << SIGHUP)
5759#if ENABLE_HUSH_JOB
5760 | (1 << SIGTTIN) | (1 << SIGTTOU) | (1 << SIGTSTP)
5761#endif
5762 | (1 << SIGINT)
5763 ;
5764 } 6024 }
5765 G.non_DFL_mask = mask; 6025 G.non_DFL_mask = mask;
5766 6026
@@ -5779,9 +6039,14 @@ static void block_signals(int second_time)
5779 second_time ? NULL : &G.inherited_set); 6039 second_time ? NULL : &G.inherited_set);
5780 /* POSIX allows shell to re-enable SIGCHLD 6040 /* POSIX allows shell to re-enable SIGCHLD
5781 * even if it was SIG_IGN on entry */ 6041 * even if it was SIG_IGN on entry */
5782// G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ 6042#if ENABLE_HUSH_FAST
6043 G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */
6044 if (!second_time)
6045 signal(SIGCHLD, SIGCHLD_handler);
6046#else
5783 if (!second_time) 6047 if (!second_time)
5784 signal(SIGCHLD, SIG_DFL); // SIGCHLD_handler); 6048 signal(SIGCHLD, SIG_DFL);
6049#endif
5785} 6050}
5786 6051
5787#if ENABLE_HUSH_JOB 6052#if ENABLE_HUSH_JOB
@@ -5813,11 +6078,10 @@ static void set_fatal_handlers(void)
5813 /* bash 3.2 seems to handle these just like 'fatal' ones */ 6078 /* bash 3.2 seems to handle these just like 'fatal' ones */
5814 maybe_set_to_sigexit(SIGPIPE); 6079 maybe_set_to_sigexit(SIGPIPE);
5815 maybe_set_to_sigexit(SIGALRM); 6080 maybe_set_to_sigexit(SIGALRM);
5816//TODO: disable and move down when proper SIGHUP handling is added 6081 /* if we are interactive, SIGHUP, SIGTERM and SIGINT are masked.
5817 maybe_set_to_sigexit(SIGHUP );
5818 /* if we are interactive, [SIGHUP,] SIGTERM and SIGINT are masked.
5819 * if we aren't interactive... but in this case 6082 * if we aren't interactive... but in this case
5820 * we never want to restore pgrp on exit, and this fn is not called */ 6083 * we never want to restore pgrp on exit, and this fn is not called */
6084 /*maybe_set_to_sigexit(SIGHUP );*/
5821 /*maybe_set_to_sigexit(SIGTERM);*/ 6085 /*maybe_set_to_sigexit(SIGTERM);*/
5822 /*maybe_set_to_sigexit(SIGINT );*/ 6086 /*maybe_set_to_sigexit(SIGINT );*/
5823} 6087}
@@ -5884,11 +6148,7 @@ int hush_main(int argc, char **argv)
5884 G.global_argv = argv; 6148 G.global_argv = argv;
5885 /* Initialize some more globals to non-zero values */ 6149 /* Initialize some more globals to non-zero values */
5886 set_cwd(); 6150 set_cwd();
5887#if ENABLE_HUSH_INTERACTIVE 6151 cmdedit_update_prompt();
5888 if (ENABLE_FEATURE_EDITING)
5889 cmdedit_set_initial_prompt();
5890 G.PS2 = "> ";
5891#endif
5892 6152
5893 if (setjmp(die_jmp)) { 6153 if (setjmp(die_jmp)) {
5894 /* xfunc has failed! die die die */ 6154 /* xfunc has failed! die die die */
@@ -5992,7 +6252,6 @@ int hush_main(int argc, char **argv)
5992 /* If we are login shell... */ 6252 /* If we are login shell... */
5993 if (argv[0] && argv[0][0] == '-') { 6253 if (argv[0] && argv[0][0] == '-') {
5994 FILE *input; 6254 FILE *input;
5995 /* XXX what should argv be while sourcing /etc/profile? */
5996 debug_printf("sourcing /etc/profile\n"); 6255 debug_printf("sourcing /etc/profile\n");
5997 input = fopen_for_read("/etc/profile"); 6256 input = fopen_for_read("/etc/profile");
5998 if (input != NULL) { 6257 if (input != NULL) {
@@ -6046,54 +6305,57 @@ int hush_main(int argc, char **argv)
6046 */ 6305 */
6047#if ENABLE_HUSH_JOB 6306#if ENABLE_HUSH_JOB
6048 if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { 6307 if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) {
6049 G.saved_tty_pgrp = tcgetpgrp(STDIN_FILENO); 6308 G_saved_tty_pgrp = tcgetpgrp(STDIN_FILENO);
6050 debug_printf("saved_tty_pgrp:%d\n", G.saved_tty_pgrp); 6309 debug_printf("saved_tty_pgrp:%d\n", G_saved_tty_pgrp);
6051//TODO: "interactive" and "have job control" are two different things. 6310 if (G_saved_tty_pgrp < 0)
6052//If tcgetpgrp fails here, "have job control" is false, but "interactive" 6311 G_saved_tty_pgrp = 0;
6053//should stay on! Currently, we mix these into one. 6312
6054 if (G.saved_tty_pgrp >= 0) { 6313 /* try to dup stdin to high fd#, >= 255 */
6055 /* try to dup stdin to high fd#, >= 255 */ 6314 G_interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255);
6056 G_interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255); 6315 if (G_interactive_fd < 0) {
6316 /* try to dup to any fd */
6317 G_interactive_fd = dup(STDIN_FILENO);
6057 if (G_interactive_fd < 0) { 6318 if (G_interactive_fd < 0) {
6058 /* try to dup to any fd */ 6319 /* give up */
6059 G_interactive_fd = dup(STDIN_FILENO); 6320 G_interactive_fd = 0;
6060 if (G_interactive_fd < 0) 6321 G_saved_tty_pgrp = 0;
6061 /* give up */
6062 G_interactive_fd = 0;
6063 } 6322 }
6064// TODO: track & disallow any attempts of user
6065// to (inadvertently) close/redirect it
6066 } 6323 }
6324// TODO: track & disallow any attempts of user
6325// to (inadvertently) close/redirect G_interactive_fd
6067 } 6326 }
6068 debug_printf("interactive_fd:%d\n", G_interactive_fd); 6327 debug_printf("interactive_fd:%d\n", G_interactive_fd);
6069 if (G_interactive_fd) { 6328 if (G_interactive_fd) {
6070 pid_t shell_pgrp;
6071
6072 /* We are indeed interactive shell, and we will perform
6073 * job control. Setting up for that. */
6074
6075 close_on_exec_on(G_interactive_fd); 6329 close_on_exec_on(G_interactive_fd);
6076 /* If we were run as 'hush &', sleep until we are 6330
6077 * in the foreground (tty pgrp == our pgrp). 6331 if (G_saved_tty_pgrp) {
6078 * If we get started under a job aware app (like bash), 6332 /* If we were run as 'hush &', sleep until we are
6079 * make sure we are now in charge so we don't fight over 6333 * in the foreground (tty pgrp == our pgrp).
6080 * who gets the foreground */ 6334 * If we get started under a job aware app (like bash),
6081 while (1) { 6335 * make sure we are now in charge so we don't fight over
6082 shell_pgrp = getpgrp(); 6336 * who gets the foreground */
6083 G.saved_tty_pgrp = tcgetpgrp(G_interactive_fd); 6337 while (1) {
6084 if (G.saved_tty_pgrp == shell_pgrp) 6338 pid_t shell_pgrp = getpgrp();
6085 break; 6339 G_saved_tty_pgrp = tcgetpgrp(G_interactive_fd);
6086 /* send TTIN to ourself (should stop us) */ 6340 if (G_saved_tty_pgrp == shell_pgrp)
6087 kill(- shell_pgrp, SIGTTIN); 6341 break;
6342 /* send TTIN to ourself (should stop us) */
6343 kill(- shell_pgrp, SIGTTIN);
6344 }
6088 } 6345 }
6346
6089 /* Block some signals */ 6347 /* Block some signals */
6090 block_signals(signal_mask_is_inited); 6348 block_signals(signal_mask_is_inited);
6091 /* Set other signals to restore saved_tty_pgrp */ 6349
6092 set_fatal_handlers(); 6350 if (G_saved_tty_pgrp) {
6093 /* Put ourselves in our own process group */ 6351 /* Set other signals to restore saved_tty_pgrp */
6094 bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */ 6352 set_fatal_handlers();
6095 /* Grab control of the terminal */ 6353 /* Put ourselves in our own process group
6096 tcsetpgrp(G_interactive_fd, getpid()); 6354 * (bash, too, does this only if ctty is available) */
6355 bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */
6356 /* Grab control of the terminal */
6357 tcsetpgrp(G_interactive_fd, getpid());
6358 }
6097 /* -1 is special - makes xfuncs longjmp, not exit 6359 /* -1 is special - makes xfuncs longjmp, not exit
6098 * (we reset die_sleep = 0 whereever we [v]fork) */ 6360 * (we reset die_sleep = 0 whereever we [v]fork) */
6099 enable_restore_tty_pgrp_on_exit(); /* sets die_sleep = -1 */ 6361 enable_restore_tty_pgrp_on_exit(); /* sets die_sleep = -1 */
@@ -6131,7 +6393,9 @@ int hush_main(int argc, char **argv)
6131 6393
6132 if (!ENABLE_FEATURE_SH_EXTRA_QUIET && G_interactive_fd) { 6394 if (!ENABLE_FEATURE_SH_EXTRA_QUIET && G_interactive_fd) {
6133 printf("\n\n%s hush - the humble shell\n", bb_banner); 6395 printf("\n\n%s hush - the humble shell\n", bb_banner);
6134 printf("Enter 'help' for a list of built-in commands.\n\n"); 6396 if (ENABLE_HUSH_HELP)
6397 puts("Enter 'help' for a list of built-in commands.");
6398 puts("");
6135 } 6399 }
6136 6400
6137 parse_and_run_file(stdin); 6401 parse_and_run_file(stdin);
@@ -6166,81 +6430,6 @@ int lash_main(int argc, char **argv)
6166/* 6430/*
6167 * Built-ins 6431 * Built-ins
6168 */ 6432 */
6169static int builtin_trap(char **argv)
6170{
6171 int i;
6172 int sig;
6173 char *new_cmd;
6174
6175 if (!G.traps)
6176 G.traps = xzalloc(sizeof(G.traps[0]) * NSIG);
6177
6178 argv++;
6179 if (!*argv) {
6180 /* No args: print all trapped. This isn't 100% correct as we
6181 * should be escaping the cmd so that it can be pasted back in
6182 */
6183 for (i = 0; i < NSIG; ++i)
6184 if (G.traps[i])
6185 printf("trap -- '%s' %s\n", G.traps[i], get_signame(i));
6186 return EXIT_SUCCESS;
6187 }
6188
6189 new_cmd = NULL;
6190 i = 0;
6191 /* If first arg is decimal: reset all specified signals */
6192 sig = bb_strtou(*argv, NULL, 10);
6193 if (errno == 0) {
6194 int ret;
6195 set_all:
6196 ret = EXIT_SUCCESS;
6197 while (*argv) {
6198 sig = get_signum(*argv++);
6199 if (sig < 0 || sig >= NSIG) {
6200 ret = EXIT_FAILURE;
6201 /* Mimic bash message exactly */
6202 bb_perror_msg("trap: %s: invalid signal specification", argv[i]);
6203 continue;
6204 }
6205
6206 free(G.traps[sig]);
6207 G.traps[sig] = xstrdup(new_cmd);
6208
6209 debug_printf("trap: setting SIG%s (%i) to '%s'",
6210 get_signame(sig), sig, G.traps[sig]);
6211
6212 /* There is no signal for 0 (EXIT) */
6213 if (sig == 0)
6214 continue;
6215
6216 if (new_cmd) {
6217 sigaddset(&G.blocked_set, sig);
6218 } else {
6219 /* There was a trap handler, we are removing it
6220 * (if sig has non-DFL handling,
6221 * we don't need to do anything) */
6222 if (sig < 32 && (G.non_DFL_mask & (1 << sig)))
6223 continue;
6224 sigdelset(&G.blocked_set, sig);
6225 }
6226 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
6227 }
6228 return ret;
6229 }
6230
6231 /* First arg is "-": reset all specified to default */
6232 /* First arg is "": ignore all specified */
6233 /* Everything else: execute first arg upon signal */
6234 if (!argv[1]) {
6235 bb_error_msg("trap: invalid arguments");
6236 return EXIT_FAILURE;
6237 }
6238 if (NOT_LONE_DASH(*argv))
6239 new_cmd = *argv;
6240 argv++;
6241 goto set_all;
6242}
6243
6244static int builtin_true(char **argv UNUSED_PARAM) 6433static int builtin_true(char **argv UNUSED_PARAM)
6245{ 6434{
6246 return 0; 6435 return 0;
@@ -6291,7 +6480,7 @@ static int builtin_cd(char **argv)
6291 * bash says "bash: cd: HOME not set" and does nothing 6480 * bash says "bash: cd: HOME not set" and does nothing
6292 * (exitcode 1) 6481 * (exitcode 1)
6293 */ 6482 */
6294 newdir = getenv("HOME") ? : "/"; 6483 newdir = get_local_var_value("HOME") ? : "/";
6295 } 6484 }
6296 if (chdir(newdir)) { 6485 if (chdir(newdir)) {
6297 /* Mimic bash message exactly */ 6486 /* Mimic bash message exactly */
@@ -6310,7 +6499,7 @@ static int builtin_exec(char **argv)
6310#if !BB_MMU 6499#if !BB_MMU
6311 nommu_save_t dummy; 6500 nommu_save_t dummy;
6312#endif 6501#endif
6313// FIXME: if exec fails, bash does NOT exit! We do... 6502 /* TODO: if exec fails, bash does NOT exit! We do... */
6314 pseudo_exec_argv(&dummy, argv, 0, NULL); 6503 pseudo_exec_argv(&dummy, argv, 0, NULL);
6315 /* never returns */ 6504 /* never returns */
6316 } 6505 }
@@ -6319,11 +6508,19 @@ static int builtin_exec(char **argv)
6319static int builtin_exit(char **argv) 6508static int builtin_exit(char **argv)
6320{ 6509{
6321 debug_printf_exec("%s()\n", __func__); 6510 debug_printf_exec("%s()\n", __func__);
6322// TODO: bash does it ONLY on top-level sh exit (+interacive only?) 6511
6323 //puts("exit"); /* bash does it */ 6512 /* interactive bash:
6324// TODO: warn if we have background jobs: "There are stopped jobs" 6513 * # trap "echo EEE" EXIT
6325// On second consecutive 'exit', exit anyway. 6514 * # exit
6326// perhaps use G.exiting = -1 as indicator "last cmd was exit" 6515 * exit
6516 * There are stopped jobs.
6517 * (if there are _stopped_ jobs, running ones don't count)
6518 * # exit
6519 * exit
6520 # EEE (then bash exits)
6521 *
6522 * we can use G.exiting = -1 as indicator "last cmd was exit"
6523 */
6327 6524
6328 /* note: EXIT trap is run by hush_exit */ 6525 /* note: EXIT trap is run by hush_exit */
6329 if (*++argv == NULL) 6526 if (*++argv == NULL)
@@ -6334,9 +6531,31 @@ static int builtin_exit(char **argv)
6334 hush_exit(xatoi(*argv) & 0xff); 6531 hush_exit(xatoi(*argv) & 0xff);
6335} 6532}
6336 6533
6534static void print_escaped(const char *s)
6535{
6536 do {
6537 if (*s != '\'') {
6538 const char *p;
6539
6540 p = strchrnul(s, '\'');
6541 /* print 'xxxx', possibly just '' */
6542 printf("'%.*s'", (int)(p - s), s);
6543 if (*p == '\0')
6544 break;
6545 s = p;
6546 }
6547 /* s points to '; print "'''...'''" */
6548 putchar('"');
6549 do putchar('\''); while (*++s == '\'');
6550 putchar('"');
6551 } while (*s);
6552}
6553
6337static int builtin_export(char **argv) 6554static int builtin_export(char **argv)
6338{ 6555{
6339 if (*++argv == NULL) { 6556 unsigned opt_unexport;
6557
6558 if (argv[1] == NULL) {
6340 char **e = environ; 6559 char **e = environ;
6341 if (e) { 6560 if (e) {
6342 while (*e) { 6561 while (*e) {
@@ -6353,54 +6572,160 @@ static int builtin_export(char **argv)
6353 continue; 6572 continue;
6354 /* export var= */ 6573 /* export var= */
6355 printf("export %.*s", (int)(p - s) + 1, s); 6574 printf("export %.*s", (int)(p - s) + 1, s);
6356 s = p + 1; 6575 print_escaped(p + 1);
6357 while (*s) {
6358 if (*s != '\'') {
6359 p = strchrnul(s, '\'');
6360 /* print 'xxxx' */
6361 printf("'%.*s'", (int)(p - s), s);
6362 if (*p == '\0')
6363 break;
6364 s = p;
6365 }
6366 /* s points to '; print ''...'''" */
6367 putchar('"');
6368 do putchar('\''); while (*++s == '\'');
6369 putchar('"');
6370 }
6371 putchar('\n'); 6576 putchar('\n');
6372#endif 6577#endif
6373 } 6578 }
6374 fflush(stdout); 6579 /*fflush(stdout); - done after each builtin anyway */
6375 } 6580 }
6376 return EXIT_SUCCESS; 6581 return EXIT_SUCCESS;
6377 } 6582 }
6378 6583
6584#if ENABLE_HUSH_EXPORT_N
6585 /* "!": do not abort on errors */
6586 /* "+": stop at 1st non-option */
6587 opt_unexport = getopt32(argv, "!+n");
6588 if (opt_unexport == (unsigned)-1)
6589 return EXIT_FAILURE;
6590 argv += optind;
6591#else
6592 opt_unexport = 0;
6593 argv++;
6594#endif
6595
6379 do { 6596 do {
6380 const char *value;
6381 char *name = *argv; 6597 char *name = *argv;
6382 6598
6383 value = strchr(name, '='); 6599 /* So far we do not check that name is valid (TODO?) */
6384 if (!value) { 6600
6385 /* They are exporting something without a =VALUE */ 6601 if (strchr(name, '=') == NULL) {
6386 struct variable *var; 6602 struct variable *var;
6387 6603
6388 var = get_local_var(name); 6604 var = get_local_var(name);
6605 if (opt_unexport) {
6606 /* export -n NAME (without =VALUE) */
6607 if (var) {
6608 var->flg_export = 0;
6609 debug_printf_env("%s: unsetenv '%s'\n", __func__, name);
6610 unsetenv(name);
6611 } /* else: export -n NOT_EXISTING_VAR: no-op */
6612 continue;
6613 }
6614 /* export NAME (without =VALUE) */
6389 if (var) { 6615 if (var) {
6390 var->flg_export = 1; 6616 var->flg_export = 1;
6391 debug_printf_env("%s: putenv '%s'\n", __func__, var->varstr); 6617 debug_printf_env("%s: putenv '%s'\n", __func__, var->varstr);
6392 putenv(var->varstr); 6618 putenv(var->varstr);
6619 continue;
6393 } 6620 }
6394 /* bash does not return an error when trying to export 6621 /* Exporting non-existing variable.
6395 * an undefined variable. Do likewise. */ 6622 * bash does not put it in environment,
6396 continue; 6623 * but remembers that it is exported,
6624 * and does put it in env when it is set later.
6625 * We just set it to "" and export. */
6626 name = xasprintf("%s=", name);
6627 } else {
6628 /* (Un)exporting NAME=VALUE */
6629 name = xstrdup(name);
6397 } 6630 }
6398 set_local_var(xstrdup(name), 1, 0); 6631 set_local_var(name,
6632 /*export:*/ (opt_unexport ? -1 : 1),
6633 /*readonly:*/ 0
6634 );
6399 } while (*++argv); 6635 } while (*++argv);
6400 6636
6401 return EXIT_SUCCESS; 6637 return EXIT_SUCCESS;
6402} 6638}
6403 6639
6640static int builtin_trap(char **argv)
6641{
6642 int sig;
6643 char *new_cmd;
6644
6645 if (!G.traps)
6646 G.traps = xzalloc(sizeof(G.traps[0]) * NSIG);
6647
6648 argv++;
6649 if (!*argv) {
6650 int i;
6651 /* No args: print all trapped */
6652 for (i = 0; i < NSIG; ++i) {
6653 if (G.traps[i]) {
6654 printf("trap -- ");
6655 print_escaped(G.traps[i]);
6656 printf(" %s\n", get_signame(i));
6657 }
6658 }
6659 /*fflush(stdout); - done after each builtin anyway */
6660 return EXIT_SUCCESS;
6661 }
6662
6663 new_cmd = NULL;
6664 /* If first arg is a number: reset all specified signals */
6665 sig = bb_strtou(*argv, NULL, 10);
6666 if (errno == 0) {
6667 int ret;
6668 process_sig_list:
6669 ret = EXIT_SUCCESS;
6670 while (*argv) {
6671 sig = get_signum(*argv++);
6672 if (sig < 0 || sig >= NSIG) {
6673 ret = EXIT_FAILURE;
6674 /* Mimic bash message exactly */
6675 bb_perror_msg("trap: %s: invalid signal specification", argv[-1]);
6676 continue;
6677 }
6678
6679 free(G.traps[sig]);
6680 G.traps[sig] = xstrdup(new_cmd);
6681
6682 debug_printf("trap: setting SIG%s (%i) to '%s'",
6683 get_signame(sig), sig, G.traps[sig]);
6684
6685 /* There is no signal for 0 (EXIT) */
6686 if (sig == 0)
6687 continue;
6688
6689 if (new_cmd) {
6690 sigaddset(&G.blocked_set, sig);
6691 } else {
6692 /* There was a trap handler, we are removing it
6693 * (if sig has non-DFL handling,
6694 * we don't need to do anything) */
6695 if (sig < 32 && (G.non_DFL_mask & (1 << sig)))
6696 continue;
6697 sigdelset(&G.blocked_set, sig);
6698 }
6699 }
6700 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
6701 return ret;
6702 }
6703
6704 if (!argv[1]) { /* no second arg */
6705 bb_error_msg("trap: invalid arguments");
6706 return EXIT_FAILURE;
6707 }
6708
6709 /* First arg is "-": reset all specified to default */
6710 /* First arg is "--": skip it, the rest is "handler SIGs..." */
6711 /* Everything else: set arg as signal handler
6712 * (includes "" case, which ignores signal) */
6713 if (argv[0][0] == '-') {
6714 if (argv[0][1] == '\0') { /* "-" */
6715 /* new_cmd remains NULL: "reset these sigs" */
6716 goto reset_traps;
6717 }
6718 if (argv[0][1] == '-' && argv[0][2] == '\0') { /* "--" */
6719 argv++;
6720 }
6721 /* else: "-something", no special meaning */
6722 }
6723 new_cmd = *argv;
6724 reset_traps:
6725 argv++;
6726 goto process_sig_list;
6727}
6728
6404#if ENABLE_HUSH_JOB 6729#if ENABLE_HUSH_JOB
6405/* built-in 'fg' and 'bg' handler */ 6730/* built-in 'fg' and 'bg' handler */
6406static int builtin_fg_bg(char **argv) 6731static int builtin_fg_bg(char **argv)
@@ -6410,6 +6735,7 @@ static int builtin_fg_bg(char **argv)
6410 6735
6411 if (!G_interactive_fd) 6736 if (!G_interactive_fd)
6412 return EXIT_FAILURE; 6737 return EXIT_FAILURE;
6738
6413 /* If they gave us no args, assume they want the last backgrounded task */ 6739 /* If they gave us no args, assume they want the last backgrounded task */
6414 if (!argv[1]) { 6740 if (!argv[1]) {
6415 for (pi = G.job_list; pi; pi = pi->next) { 6741 for (pi = G.job_list; pi; pi = pi->next) {
@@ -6432,9 +6758,9 @@ static int builtin_fg_bg(char **argv)
6432 bb_error_msg("%s: %d: no such job", argv[0], jobnum); 6758 bb_error_msg("%s: %d: no such job", argv[0], jobnum);
6433 return EXIT_FAILURE; 6759 return EXIT_FAILURE;
6434 found: 6760 found:
6435 // TODO: bash prints a string representation 6761 /* TODO: bash prints a string representation
6436 // of job being foregrounded (like "sleep 1 | cat") 6762 * of job being foregrounded (like "sleep 1 | cat") */
6437 if (argv[0][0] == 'f') { 6763 if (argv[0][0] == 'f' && G_saved_tty_pgrp) {
6438 /* Put the job into the foreground. */ 6764 /* Put the job into the foreground. */
6439 tcsetpgrp(G_interactive_fd, pi->pgrp); 6765 tcsetpgrp(G_interactive_fd, pi->pgrp);
6440 } 6766 }
@@ -6658,78 +6984,117 @@ static int builtin_shift(char **argv)
6658 6984
6659static int builtin_source(char **argv) 6985static int builtin_source(char **argv)
6660{ 6986{
6987 const char *PATH;
6661 FILE *input; 6988 FILE *input;
6989 save_arg_t sv;
6990#if ENABLE_HUSH_FUNCTIONS
6991 smallint sv_flg;
6992#endif
6662 6993
6663 if (*++argv == NULL) 6994 if (*++argv == NULL)
6664 return EXIT_FAILURE; 6995 return EXIT_FAILURE;
6665 6996
6666 /* XXX search through $PATH is missing */ 6997 if (strchr(*argv, '/') == NULL
6998 && (PATH = get_local_var_value("PATH")) != NULL
6999 ) {
7000 /* Search through $PATH */
7001 while (1) {
7002 const char *end = strchrnul(PATH, ':');
7003 int sz = end - PATH; /* must be int! */
7004
7005 if (sz != 0) {
7006 char *tmp = xasprintf("%.*s/%s", sz, PATH, *argv);
7007 input = fopen_for_read(tmp);
7008 free(tmp);
7009 } else {
7010 /* We have xxx::yyyy in $PATH,
7011 * it means "use current dir" */
7012 input = fopen_for_read(*argv);
7013 }
7014 if (input)
7015 goto opened_ok;
7016 if (*end == '\0')
7017 break;
7018 PATH = end + 1;
7019 }
7020 }
6667 input = fopen_or_warn(*argv, "r"); 7021 input = fopen_or_warn(*argv, "r");
6668 if (!input) { 7022 if (!input) {
6669 /* bb_perror_msg("%s", *argv); - done by fopen_or_warn */ 7023 /* bb_perror_msg("%s", *argv); - done by fopen_or_warn */
6670 return EXIT_FAILURE; 7024 return EXIT_FAILURE;
6671 } 7025 }
7026 opened_ok:
6672 close_on_exec_on(fileno(input)); 7027 close_on_exec_on(fileno(input));
6673 7028
6674 /* Now run the file */ 7029#if ENABLE_HUSH_FUNCTIONS
6675//TODO: 7030 sv_flg = G.flag_return_in_progress;
6676 /* XXX argv and argc are broken; need to save old G.global_argv 7031 /* "we are inside sourced file, ok to use return" */
6677 * (pointer only is OK!) on this stack frame, 7032 G.flag_return_in_progress = -1;
6678 * set G.global_argv=argv+1, recurse, and restore. */ 7033#endif
7034 save_and_replace_G_args(&sv, argv);
7035
6679 parse_and_run_file(input); 7036 parse_and_run_file(input);
6680 fclose(input); 7037 fclose(input);
7038
7039 restore_G_args(&sv, argv);
7040#if ENABLE_HUSH_FUNCTIONS
7041 G.flag_return_in_progress = sv_flg;
7042#endif
7043
6681 return G.last_exitcode; 7044 return G.last_exitcode;
6682} 7045}
6683 7046
6684static int builtin_umask(char **argv) 7047static int builtin_umask(char **argv)
6685{ 7048{
6686 mode_t new_umask; 7049 int rc;
6687 const char *arg = argv[1]; 7050 mode_t mask;
6688 if (arg) { 7051
6689//TODO: umask may take chmod-like symbolic masks 7052 mask = umask(0);
6690 new_umask = bb_strtou(arg, NULL, 8); 7053 if (argv[1]) {
6691 if (errno) { 7054 mode_t old_mask = mask;
6692 //Message? bash examples: 7055
6693 //bash: umask: 'q': invalid symbolic mode operator 7056 mask ^= 0777;
6694 //bash: umask: 999: octal number out of range 7057 rc = bb_parse_mode(argv[1], &mask);
6695 return EXIT_FAILURE; 7058 mask ^= 0777;
7059 if (rc == 0) {
7060 mask = old_mask;
7061 /* bash messages:
7062 * bash: umask: 'q': invalid symbolic mode operator
7063 * bash: umask: 999: octal number out of range
7064 */
7065 bb_error_msg("%s: '%s' invalid mode", argv[0], argv[1]);
6696 } 7066 }
6697 } else { 7067 } else {
6698 new_umask = umask(0); 7068 rc = 1;
6699 printf("%.3o\n", (unsigned) new_umask); 7069 /* Mimic bash */
6700 /* fall through and restore new_umask which we set to 0 */ 7070 printf("%04o\n", (unsigned) mask);
7071 /* fall through and restore mask which we set to 0 */
6701 } 7072 }
6702 umask(new_umask); 7073 umask(mask);
6703 return EXIT_SUCCESS; 7074
7075 return !rc; /* rc != 0 - success */
6704} 7076}
6705 7077
6706/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#unset */ 7078/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#unset */
6707static int builtin_unset(char **argv) 7079static int builtin_unset(char **argv)
6708{ 7080{
6709 int ret; 7081 int ret;
6710 char var; 7082 unsigned opts;
6711 7083
6712 if (!*++argv) 7084 /* "!": do not abort on errors */
6713 return EXIT_SUCCESS; 7085 /* "+": stop at 1st non-option */
6714 7086 opts = getopt32(argv, "!+vf");
6715 var = 'v'; 7087 if (opts == (unsigned)-1)
6716 if (argv[0][0] == '-') { 7088 return EXIT_FAILURE;
6717 switch (argv[0][1]) { 7089 if (opts == 3) {
6718 case 'v': 7090 bb_error_msg("unset: -v and -f are exclusive");
6719 case 'f': 7091 return EXIT_FAILURE;
6720 var = argv[0][1];
6721 break;
6722 default:
6723 bb_error_msg("unset: %s: invalid option", *argv);
6724 return EXIT_FAILURE;
6725 }
6726//TODO: disallow "unset -vf ..." too
6727 argv++;
6728 } 7092 }
7093 argv += optind;
6729 7094
6730 ret = EXIT_SUCCESS; 7095 ret = EXIT_SUCCESS;
6731 while (*argv) { 7096 while (*argv) {
6732 if (var == 'v') { 7097 if (!(opts & 2)) { /* not -f */
6733 if (unset_local_var(*argv)) { 7098 if (unset_local_var(*argv)) {
6734 /* unset <nonexistent_var> doesn't fail. 7099 /* unset <nonexistent_var> doesn't fail.
6735 * Error is when one tries to unset RO var. 7100 * Error is when one tries to unset RO var.
@@ -6737,11 +7102,11 @@ static int builtin_unset(char **argv)
6737 ret = EXIT_FAILURE; 7102 ret = EXIT_FAILURE;
6738 } 7103 }
6739 } 7104 }
6740//#if ENABLE_HUSH_FUNCTIONS 7105#if ENABLE_HUSH_FUNCTIONS
6741// else { 7106 else {
6742// unset_local_func(*argv); 7107 unset_func(*argv);
6743// } 7108 }
6744//#endif 7109#endif
6745 argv++; 7110 argv++;
6746 } 7111 }
6747 return ret; 7112 return ret;
@@ -6817,25 +7182,36 @@ static int builtin_wait(char **argv)
6817 return ret; 7182 return ret;
6818} 7183}
6819 7184
7185#if ENABLE_HUSH_LOOPS || ENABLE_HUSH_FUNCTIONS
7186static unsigned parse_numeric_argv1(char **argv, unsigned def, unsigned def_min)
7187{
7188 if (argv[1]) {
7189 def = bb_strtou(argv[1], NULL, 10);
7190 if (errno || def < def_min || argv[2]) {
7191 bb_error_msg("%s: bad arguments", argv[0]);
7192 def = UINT_MAX;
7193 }
7194 }
7195 return def;
7196}
7197#endif
7198
6820#if ENABLE_HUSH_LOOPS 7199#if ENABLE_HUSH_LOOPS
6821static int builtin_break(char **argv) 7200static int builtin_break(char **argv)
6822{ 7201{
7202 unsigned depth;
6823 if (G.depth_of_loop == 0) { 7203 if (G.depth_of_loop == 0) {
6824 bb_error_msg("%s: only meaningful in a loop", argv[0]); 7204 bb_error_msg("%s: only meaningful in a loop", argv[0]);
6825 return EXIT_SUCCESS; /* bash compat */ 7205 return EXIT_SUCCESS; /* bash compat */
6826 } 7206 }
6827 G.flag_break_continue++; /* BC_BREAK = 1 */ 7207 G.flag_break_continue++; /* BC_BREAK = 1 */
6828 G.depth_break_continue = 1; 7208
6829 if (argv[1]) { 7209 G.depth_break_continue = depth = parse_numeric_argv1(argv, 1, 1);
6830 G.depth_break_continue = bb_strtou(argv[1], NULL, 10); 7210 if (depth == UINT_MAX)
6831 if (errno || !G.depth_break_continue || argv[2]) { 7211 G.flag_break_continue = BC_BREAK;
6832 bb_error_msg("%s: bad arguments", argv[0]); 7212 if (G.depth_of_loop < depth)
6833 G.flag_break_continue = BC_BREAK;
6834 G.depth_break_continue = UINT_MAX;
6835 }
6836 }
6837 if (G.depth_of_loop < G.depth_break_continue)
6838 G.depth_break_continue = G.depth_of_loop; 7213 G.depth_break_continue = G.depth_of_loop;
7214
6839 return EXIT_SUCCESS; 7215 return EXIT_SUCCESS;
6840} 7216}
6841 7217
@@ -6845,3 +7221,27 @@ static int builtin_continue(char **argv)
6845 return builtin_break(argv); 7221 return builtin_break(argv);
6846} 7222}
6847#endif 7223#endif
7224
7225#if ENABLE_HUSH_FUNCTIONS
7226static int builtin_return(char **argv)
7227{
7228 int rc;
7229
7230 if (G.flag_return_in_progress != -1) {
7231 bb_error_msg("%s: not in a function or sourced script", argv[0]);
7232 return EXIT_FAILURE; /* bash compat */
7233 }
7234
7235 G.flag_return_in_progress = 1;
7236
7237 /* bash:
7238 * out of range: wraps around at 256, does not error out
7239 * non-numeric param:
7240 * f() { false; return qwe; }; f; echo $?
7241 * bash: return: qwe: numeric argument required <== we do this
7242 * 255 <== we also do this
7243 */
7244 rc = parse_numeric_argv1(argv, G.last_exitcode, 0);
7245 return rc;
7246}
7247#endif
diff --git a/util-linux/acpid.c b/util-linux/acpid.c
index ef4e54d5d..49ea52d53 100644
--- a/util-linux/acpid.c
+++ b/util-linux/acpid.c
@@ -78,8 +78,8 @@ int acpid_main(int argc, char **argv)
78 // goto configuration directory 78 // goto configuration directory
79 xchdir(opt_conf); 79 xchdir(opt_conf);
80 80
81// // setup signals 81 // prevent zombies
82// bb_signals(BB_FATAL_SIGS, record_signo); 82 signal(SIGCHLD, SIG_IGN);
83 83
84 // no explicit evdev files given? -> use proc event interface 84 // no explicit evdev files given? -> use proc event interface
85 if (!*argv) { 85 if (!*argv) {
diff --git a/util-linux/mdev.c b/util-linux/mdev.c
index 2451cca05..3c4540cfb 100644
--- a/util-linux/mdev.c
+++ b/util-linux/mdev.c
@@ -181,7 +181,8 @@ static void make_device(char *path, int delete)
181 * the rest of fields unless keep_matching == 1 */ 181 * the rest of fields unless keep_matching == 1 */
182 182
183 /* 2nd field: uid:gid - device ownership */ 183 /* 2nd field: uid:gid - device ownership */
184 parse_chown_usergroup_or_die(&ugid, tokens[1]); 184 if (get_uidgid(&ugid, tokens[1], 1) == 0)
185 bb_error_msg("unknown user/group %s", tokens[1]);
185 186
186 /* 3rd field: mode - device permissions */ 187 /* 3rd field: mode - device permissions */
187 mode = strtoul(tokens[2], NULL, 8); 188 mode = strtoul(tokens[2], NULL, 8);