aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2018-04-02 09:24:14 +0100
committerRon Yorston <rmy@pobox.com>2018-04-02 09:24:14 +0100
commit34a68d327b42c3c700e84cd475496985782290b1 (patch)
tree99bfe59cca420d26f01e81a7f41763f71b44d22c
parentaff3c5bd7b6bdcfb97f63153ab839c5f55f16a12 (diff)
parente84212f8346741a2d4a04b40639c44fe519cf5a7 (diff)
downloadbusybox-w32-34a68d327b42c3c700e84cd475496985782290b1.tar.gz
busybox-w32-34a68d327b42c3c700e84cd475496985782290b1.tar.bz2
busybox-w32-34a68d327b42c3c700e84cd475496985782290b1.zip
Merge branch 'busybox' into merge
-rw-r--r--archival/cpio.c2
-rw-r--r--archival/libarchive/data_extract_to_command.c2
-rw-r--r--archival/tar.c16
-rw-r--r--coreutils/stat.c2
-rw-r--r--editors/sed.c2
-rw-r--r--examples/var_service/README_distro_proposal.txt3
-rw-r--r--examples/var_service/dnsmasq/README10
-rw-r--r--examples/var_service/dnsmasq/dnsmasq.conf76
-rwxr-xr-xexamples/var_service/dnsmasq/log/run21
-rwxr-xr-xexamples/var_service/dnsmasq/p_log4
-rwxr-xr-xexamples/var_service/dnsmasq/run12
-rwxr-xr-xexamples/var_service/dnsmasq/w_log4
-rw-r--r--examples/var_service/fw/etc/dnsmasq_servers.conf38
-rwxr-xr-xexamples/var_service/ifplugd_if/run23
-rw-r--r--findutils/grep.c2
-rw-r--r--include/libbb.h31
-rw-r--r--libbb/get_line_from_file.c15
-rw-r--r--libbb/wfopen.c2
-rw-r--r--libbb/xfuncs.c7
-rw-r--r--libbb/xfuncs_printf.c15
-rw-r--r--miscutils/fbsplash.c21
-rw-r--r--networking/ifplugd.c2
-rw-r--r--networking/ifupdown.c6
-rw-r--r--networking/libiproute/iplink.c2
-rw-r--r--networking/netstat.c7
-rw-r--r--networking/route.c2
-rw-r--r--networking/ssl_client.c1
-rw-r--r--networking/udhcp/d6_socket.c2
-rw-r--r--networking/wget.c4
-rw-r--r--procps/top.c2
-rw-r--r--runit/sv.c57
-rw-r--r--shell/ash.c102
-rw-r--r--shell/ash_test/ash-heredoc/heredoc_backquote1.right5
-rwxr-xr-xshell/ash_test/ash-heredoc/heredoc_backquote1.tests10
-rw-r--r--shell/ash_test/ash-heredoc/heredoc_backslash1.right43
-rwxr-xr-xshell/ash_test/ash-heredoc/heredoc_backslash1.tests70
-rw-r--r--shell/ash_test/ash-heredoc/heredoc_bkslash_newline1.right8
-rwxr-xr-xshell/ash_test/ash-heredoc/heredoc_bkslash_newline1.tests25
-rw-r--r--shell/ash_test/ash-parsing/bkslash_newline1.right4
-rwxr-xr-xshell/ash_test/ash-parsing/bkslash_newline1.tests8
-rw-r--r--shell/ash_test/ash-parsing/bkslash_newline2.right4
-rwxr-xr-xshell/ash_test/ash-parsing/bkslash_newline2.tests4
-rw-r--r--shell/ash_test/ash-quoting/dollar_repl_slash_bash2.right1
-rwxr-xr-xshell/ash_test/ash-quoting/dollar_repl_slash_bash2.tests2
-rw-r--r--shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_1.right5
-rwxr-xr-xshell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_1.tests6
-rw-r--r--shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_2.right5
-rwxr-xr-xshell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_2.tests6
-rw-r--r--shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_3.right5
-rwxr-xr-xshell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_3.tests6
-rw-r--r--shell/ash_test/ash-vars/var_LINENO1.right8
-rwxr-xr-xshell/ash_test/ash-vars/var_LINENO1.tests6
-rw-r--r--shell/hush.c149
-rw-r--r--shell/hush_test/hush-heredoc/heredoc_bkslash_newline1.right8
-rwxr-xr-xshell/hush_test/hush-heredoc/heredoc_bkslash_newline1.tests25
-rw-r--r--shell/hush_test/hush-parsing/bkslash_newline1.right4
-rwxr-xr-xshell/hush_test/hush-parsing/bkslash_newline1.tests8
-rw-r--r--shell/hush_test/hush-parsing/bkslash_newline2.right4
-rwxr-xr-xshell/hush_test/hush-parsing/bkslash_newline2.tests4
-rw-r--r--shell/hush_test/hush-quoting/dollar_repl_slash_bash2.right1
-rwxr-xr-xshell/hush_test/hush-quoting/dollar_repl_slash_bash2.tests2
-rw-r--r--shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_1.right5
-rwxr-xr-xshell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_1.tests6
-rw-r--r--shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_2.right5
-rwxr-xr-xshell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_2.tests6
-rw-r--r--shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_3.right5
-rwxr-xr-xshell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_3.tests6
-rwxr-xr-xshell/hush_test/hush-vars/var_LINENO1.tests2
-rwxr-xr-xtestsuite/grep.tests6
-rw-r--r--util-linux/fstrim.c14
70 files changed, 799 insertions, 187 deletions
diff --git a/archival/cpio.c b/archival/cpio.c
index 1d6cbd1e2..308ec1b25 100644
--- a/archival/cpio.c
+++ b/archival/cpio.c
@@ -508,6 +508,8 @@ int cpio_main(int argc UNUSED_PARAM, char **argv)
508 while (get_header_cpio(archive_handle) == EXIT_SUCCESS) 508 while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
509 continue; 509 continue;
510 510
511 create_symlinks_from_list(archive_handle->symlink_placeholders);
512
511 if (archive_handle->cpio__blocks != (off_t)-1 513 if (archive_handle->cpio__blocks != (off_t)-1
512 && !(opt & OPT_QUIET) 514 && !(opt & OPT_QUIET)
513 ) { 515 ) {
diff --git a/archival/libarchive/data_extract_to_command.c b/archival/libarchive/data_extract_to_command.c
index 1114a95cb..0fcabb4a9 100644
--- a/archival/libarchive/data_extract_to_command.c
+++ b/archival/libarchive/data_extract_to_command.c
@@ -37,7 +37,7 @@ static const char *const tar_var[] = {
37static void xputenv(char *str) 37static void xputenv(char *str)
38{ 38{
39 if (putenv(str)) 39 if (putenv(str))
40 bb_error_msg_and_die(bb_msg_memory_exhausted); 40 bb_die_memory_exhausted();
41} 41}
42 42
43static void str2env(char *env[], int idx, const char *str) 43static void str2env(char *env[], int idx, const char *str)
diff --git a/archival/tar.c b/archival/tar.c
index d0684b69e..308ce7701 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -792,7 +792,7 @@ static llist_t *append_file_list_to_list(llist_t *list)
792//usage: IF_FEATURE_SEAMLESS_LZMA("a") 792//usage: IF_FEATURE_SEAMLESS_LZMA("a")
793//usage: IF_FEATURE_TAR_CREATE("h") 793//usage: IF_FEATURE_TAR_CREATE("h")
794//usage: IF_FEATURE_TAR_NOPRESERVE_TIME("m") 794//usage: IF_FEATURE_TAR_NOPRESERVE_TIME("m")
795//usage: "vO] " 795//usage: "vokO] "
796//usage: "[-f TARFILE] [-C DIR] " 796//usage: "[-f TARFILE] [-C DIR] "
797//usage: IF_FEATURE_TAR_FROM("[-T FILE] [-X FILE] "IF_FEATURE_TAR_LONG_OPTIONS("[--exclude PATTERN]... ")) 797//usage: IF_FEATURE_TAR_FROM("[-T FILE] [-X FILE] "IF_FEATURE_TAR_LONG_OPTIONS("[--exclude PATTERN]... "))
798//usage: "[FILE]..." 798//usage: "[FILE]..."
@@ -809,6 +809,13 @@ static llist_t *append_file_list_to_list(llist_t *list)
809//usage: "\n -f FILE Name of TARFILE ('-' for stdin/out)" 809//usage: "\n -f FILE Name of TARFILE ('-' for stdin/out)"
810//usage: "\n -C DIR Change to DIR before operation" 810//usage: "\n -C DIR Change to DIR before operation"
811//usage: "\n -v Verbose" 811//usage: "\n -v Verbose"
812//usage: "\n -O Extract to stdout"
813//usage: IF_FEATURE_TAR_NOPRESERVE_TIME(
814//usage: "\n -m Don't restore mtime"
815//usage: )
816//usage: "\n -o Don't restore user:group"
817///////:-p - accepted but ignored, restores mode (aliases in GNU tar: --preserve-permissions, --same-permissions)
818//usage: "\n -k Don't replace existing files"
812//usage: IF_FEATURE_SEAMLESS_Z( 819//usage: IF_FEATURE_SEAMLESS_Z(
813//usage: "\n -Z (De)compress using compress" 820//usage: "\n -Z (De)compress using compress"
814//usage: ) 821//usage: )
@@ -824,13 +831,9 @@ static llist_t *append_file_list_to_list(llist_t *list)
824//usage: IF_FEATURE_SEAMLESS_LZMA( 831//usage: IF_FEATURE_SEAMLESS_LZMA(
825//usage: "\n -a (De)compress using lzma" 832//usage: "\n -a (De)compress using lzma"
826//usage: ) 833//usage: )
827//usage: "\n -O Extract to stdout"
828//usage: IF_FEATURE_TAR_CREATE( 834//usage: IF_FEATURE_TAR_CREATE(
829//usage: "\n -h Follow symlinks" 835//usage: "\n -h Follow symlinks"
830//usage: ) 836//usage: )
831//usage: IF_FEATURE_TAR_NOPRESERVE_TIME(
832//usage: "\n -m Don't restore mtime"
833//usage: )
834//usage: IF_FEATURE_TAR_FROM( 837//usage: IF_FEATURE_TAR_FROM(
835//usage: "\n -T FILE File with names to include" 838//usage: "\n -T FILE File with names to include"
836//usage: "\n -X FILE File with glob patterns to exclude" 839//usage: "\n -X FILE File with glob patterns to exclude"
@@ -844,9 +847,6 @@ static llist_t *append_file_list_to_list(llist_t *list)
844//usage: "$ tar -cf /tmp/tarball.tar /usr/local\n" 847//usage: "$ tar -cf /tmp/tarball.tar /usr/local\n"
845 848
846// Supported but aren't in --help: 849// Supported but aren't in --help:
847// o no-same-owner
848// p same-permissions
849// k keep-old
850// no-recursion 850// no-recursion
851// numeric-owner 851// numeric-owner
852// no-same-permissions 852// no-same-permissions
diff --git a/coreutils/stat.c b/coreutils/stat.c
index 41f6d103c..2944cdfcb 100644
--- a/coreutils/stat.c
+++ b/coreutils/stat.c
@@ -211,7 +211,7 @@ static const char *human_fstype(uint32_t f_type)
211 { 0x52654973, "reiserfs" }, 211 { 0x52654973, "reiserfs" },
212 { 0x28cd3d45, "cramfs" }, 212 { 0x28cd3d45, "cramfs" },
213 { 0x7275, "romfs" }, 213 { 0x7275, "romfs" },
214 { 0x858458f6, "romfs" }, 214 { 0x858458f6, "ramfs" },
215 { 0x73717368, "squashfs" }, 215 { 0x73717368, "squashfs" },
216 { 0x62656572, "sysfs" }, 216 { 0x62656572, "sysfs" },
217 { 0, "UNKNOWN" } 217 { 0, "UNKNOWN" }
diff --git a/editors/sed.c b/editors/sed.c
index bb2809d3c..bf8a11613 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -994,7 +994,7 @@ static void flush_append(char *last_puts_char)
994static char *get_next_line(char *gets_char, char *last_puts_char) 994static char *get_next_line(char *gets_char, char *last_puts_char)
995{ 995{
996 char *temp = NULL; 996 char *temp = NULL;
997 int len; 997 size_t len;
998 char gc; 998 char gc;
999 999
1000 flush_append(last_puts_char); 1000 flush_append(last_puts_char);
diff --git a/examples/var_service/README_distro_proposal.txt b/examples/var_service/README_distro_proposal.txt
index ec887b4e1..f161406a7 100644
--- a/examples/var_service/README_distro_proposal.txt
+++ b/examples/var_service/README_distro_proposal.txt
@@ -246,7 +246,8 @@ relative to the system-wide service directory.
246This proposal asks developers of other daemontools implementations 246This proposal asks developers of other daemontools implementations
247to add "svc" command to their projects] 247to add "svc" command to their projects]
248 248
249The "svok DIR" tool exits 0 if service is running, and nonzero if not. 249The "svok DIR" tool exits 0 if service supervisor is running
250(with service itself either running or stopped), and nonzero if not.
250 251
251Other tools with different names and APIs may exist; however 252Other tools with different names and APIs may exist; however
252for portability scripts should use the above tools. 253for portability scripts should use the above tools.
diff --git a/examples/var_service/dnsmasq/README b/examples/var_service/dnsmasq/README
new file mode 100644
index 000000000..a20740d6e
--- /dev/null
+++ b/examples/var_service/dnsmasq/README
@@ -0,0 +1,10 @@
1Local DNS cache service.
2
3This service is useful if you have more than 3 DNS servers,
4or if you need a finer-grained control of which servers
5can serve which domain.
6
7To make programs use local DNS server, make sure
8/etc/resolv.conf says:
9
10nameserver 127.0.0.1
diff --git a/examples/var_service/dnsmasq/dnsmasq.conf b/examples/var_service/dnsmasq/dnsmasq.conf
new file mode 100644
index 000000000..2cfb0fe81
--- /dev/null
+++ b/examples/var_service/dnsmasq/dnsmasq.conf
@@ -0,0 +1,76 @@
1keep-in-foreground
2
3# "-" is stderr:
4log-facility=-
5
6# May also try log-queries=extra
7log-queries
8
9# No param = pidfile disabled:
10pid-file
11
12interface=lo
13listen-address=127.0.0.1
14bind-interfaces
15
16cache-size=999
17
18servers-file=/etc/dnsmasq_servers.conf
19
20# Don’t read /etc/resolv.conf and /etc/hosts:
21no-resolv
22#no-hosts
23
24# All reverse lookups for private IP ranges (ie 192.168.x.x, etc)
25# which are not found in /etc/hosts or the DHCP leases file are
26# answered with "no such domain" rather than being forwarded
27# upstream. The set of prefixes affected is the list given in
28# RFC6303.
29#bogus-priv
30
31#−T, --local-ttl=<time>
32# When replying with information from /etc/hosts or configuration
33# or the DHCP leases file dnsmasq by default sets the time-to-live
34# field to zero, meaning that the requester should not itself
35# cache the information. This is the correct thing to do in almost
36# all situations. This option allows a time-to-live (in seconds)
37# to be given for these replies. This will reduce the load on the
38# server at the expense of clients using stale data under some
39# circumstances.
40local-ttl=67
41
42#--dhcp-ttl=<time>
43# As for --local-ttl, but affects only replies with information
44# from DHCP leases. If both are given, --dhcp-ttl applies for DHCP
45# information, and --local-ttl for others. Setting this to zero
46# eliminates the effect of --local-ttl for DHCP.
47#
48#--neg-ttl=<time>
49# Negative replies from upstream servers normally contain time-to-
50# live information in SOA records which dnsmasq uses for caching.
51# If the replies from upstream servers omit this information, dns-
52# masq does not cache the reply. This option gives a default value
53# for time-to-live (in seconds) which dnsmasq uses to cache nega-
54# tive replies even in the absence of an SOA record.
55neg-ttl=67
56
57#--max-ttl=<time>
58# Set a maximum TTL value that will be handed out to clients. The
59# specified maximum TTL will be given to clients instead of the
60# true TTL value if it is lower. The true TTL value is however
61# kept in the cache to avoid flooding the upstream DNS servers.
62#
63#--max-cache-ttl=<time>
64# Set a maximum TTL value for entries in the cache.
65#
66#--min-cache-ttl=<time>
67# Extend short TTL values to the time given when caching them.
68# Note that artificially extending TTL values is in general a bad
69# idea, do not do it unless you have a good reason, and understand
70# what you are doing. Dnsmasq limits the value of this option to
71# one hour, unless recompiled.
72min-cache-ttl=67
73
74#--auth-ttl=<time>
75# Set the TTL value returned in answers from the authoritative
76# server.
diff --git a/examples/var_service/dnsmasq/log/run b/examples/var_service/dnsmasq/log/run
new file mode 100755
index 000000000..69d74b73f
--- /dev/null
+++ b/examples/var_service/dnsmasq/log/run
@@ -0,0 +1,21 @@
1#!/bin/sh
2
3user=logger
4
5logdir="/var/log/service/`(cd ..;basename $PWD)`"
6mkdir -p "$logdir" 2>/dev/null
7chown -R "$user": "$logdir"
8chmod -R go-rwxst,u+rwX "$logdir"
9rm -rf logdir
10ln -s "$logdir" logdir
11
12# make this dir accessible to logger
13chmod a+rX .
14
15exec >/dev/null
16exec 2>&1
17exec \
18env - PATH="$PATH" \
19softlimit \
20setuidgid "$user" \
21svlogd -tt "$logdir"
diff --git a/examples/var_service/dnsmasq/p_log b/examples/var_service/dnsmasq/p_log
new file mode 100755
index 000000000..a2521be05
--- /dev/null
+++ b/examples/var_service/dnsmasq/p_log
@@ -0,0 +1,4 @@
1#!/bin/sh
2
3cd log/logdir || exit 1
4cat @* current | $PAGER
diff --git a/examples/var_service/dnsmasq/run b/examples/var_service/dnsmasq/run
new file mode 100755
index 000000000..2ac94282f
--- /dev/null
+++ b/examples/var_service/dnsmasq/run
@@ -0,0 +1,12 @@
1#!/bin/sh
2
3#exec >/dev/null
4exec 2>&1
5exec </dev/null
6
7echo "* Starting dnsmasq"
8exec \
9env - PATH="$PATH" \
10softlimit \
11setuidgid root \
12dnsmasq -C dnsmasq.conf
diff --git a/examples/var_service/dnsmasq/w_log b/examples/var_service/dnsmasq/w_log
new file mode 100755
index 000000000..aa36ef13b
--- /dev/null
+++ b/examples/var_service/dnsmasq/w_log
@@ -0,0 +1,4 @@
1#!/bin/sh
2
3cd log/logdir || exit 1
4watch -n2 'w=`ttysize w`; h=`ttysize h`; tail -$((h-3)) current 2>&1 | cut -b1-$((w-2))'
diff --git a/examples/var_service/fw/etc/dnsmasq_servers.conf b/examples/var_service/fw/etc/dnsmasq_servers.conf
new file mode 100644
index 000000000..68313605f
--- /dev/null
+++ b/examples/var_service/fw/etc/dnsmasq_servers.conf
@@ -0,0 +1,38 @@
1#!/bin/bash
2
3empty=true
4
5prio=0
6i=0; while test "${if[$i]}"; do
7 test x"${dns_prio[$i]}" != x"" \
8 && test "${dns_prio[$i]}" -gt "$prio" \
9 && prio="${dns_prio[$i]}"
10let i++; done
11
12i=0; while test "${if[$i]}"; do
13 if test "${dnsmasq[$i]}"; then
14 for d in ${dnsmasq[$i]}; do
15 echo "$d"
16 empty=false
17 done
18 let i++;
19 continue
20 fi
21 # This iface has no dnsmasq-extended config.
22 # Use simple DNS names instead, if those exist.
23 for d in ${dns[$i]}; do
24 p="${dns_prio[$i]}"
25 test x"$p" == x"" && p=0
26 test x"$p" == x"$prio" || continue
27 echo "server=$d"
28 empty=false
29 done
30 let i++;
31done
32
33# Use Google DNS servers if nothing else is configured
34$empty && echo "server=8.8.8.8"
35$empty && echo "server=8.8.4.4"
36
37# SIGHUP: make dnsmasq reload config
38sv h dnsmasq
diff --git a/examples/var_service/ifplugd_if/run b/examples/var_service/ifplugd_if/run
index c4f766e88..5d1d4e355 100755
--- a/examples/var_service/ifplugd_if/run
+++ b/examples/var_service/ifplugd_if/run
@@ -16,7 +16,7 @@ exec \
16env - PATH="$PATH" \ 16env - PATH="$PATH" \
17softlimit \ 17softlimit \
18setuidgid root \ 18setuidgid root \
19ifplugd -apqns -t3 -u8 -d8 -i "$if" -r "$pwd/ifplugd_handler" 19ifplugd -aqlns -t3 -u8 -d8 -i "$if" -r "$pwd/ifplugd_handler"
20 20
21# We use -t3 to wake ifplugd up less often. 21# We use -t3 to wake ifplugd up less often.
22# If after three tests (3*3=9 > 8) link state seen to be different, 22# If after three tests (3*3=9 > 8) link state seen to be different,
@@ -24,19 +24,26 @@ ifplugd -apqns -t3 -u8 -d8 -i "$if" -r "$pwd/ifplugd_handler"
24# IOW: short link losses will be ignored, longer ones 24# IOW: short link losses will be ignored, longer ones
25# will trigger DHCP reconfiguration and such (see handler code). 25# will trigger DHCP reconfiguration and such (see handler code).
26 26
27#-a Do not up interface automatically 27# -l makes ifplugd run either "up" or "down" script on startup.
28#-p Dont run script on daemon startup 28# For example, if wired eth cable is unplugged, this stops dhcp service
29#-q Dont run script on daemon quit 29# from pointlessly trying to get a lease.
30# -q means that stopping monitoring does not stop dhcp/zcip/etc:
31# presumably, admin decided to control them manually.
32
33#-a Don't up interface automatically
34#-p Don't run "up" script on startup
35#-q Don't run "down" script on exit
36#-l Always run script on startup
30#-n Do not daemonize 37#-n Do not daemonize
31#-s Do not log to syslog 38#-s Do not log to syslog
32#-t SECS Poll time in seconds 39#-t SECS Poll time in seconds
33#-u SECS Delay before running script after link up 40#-u SECS Delay before running script after link up
34#-d SECS Delay after link down 41#-d SECS Delay after link down
35#-i IFACE Interface 42#-i IFACE Interface
36#-r PROG Script to run
37#-f/-F Treat link detection error as link down/link up (otherwise exit on error)
38#-M Monitor creation/destruction of interface (otherwise it must exist) 43#-M Monitor creation/destruction of interface (otherwise it must exist)
44#-r PROG Script to run
39#-x ARG Extra argument for script 45#-x ARG Extra argument for script
40#-I Dont exit on nonzero exit code from script 46#-I Don't exit on nonzero exit code from script
41#-l Run script on startup even if no cable is detected 47#-f/-F Treat link detection error as link down/link up (otherwise exit on error)
42#-m MODE API mode (mii, priv, ethtool, wlan, auto) 48#-m MODE API mode (mii, priv, ethtool, wlan, auto)
49#-k Kill running daemon
diff --git a/findutils/grep.c b/findutils/grep.c
index fc6de4b69..88de0d4ef 100644
--- a/findutils/grep.c
+++ b/findutils/grep.c
@@ -352,7 +352,7 @@ static int grep_file(FILE *file)
352 goto opt_f_not_found; 352 goto opt_f_not_found;
353 } else 353 } else
354 if (option_mask32 & OPT_w) { 354 if (option_mask32 & OPT_w) {
355 char c = (match != str) ? match[-1] : ' '; 355 char c = (match != line) ? match[-1] : ' ';
356 if (!isalnum(c) && c != '_') { 356 if (!isalnum(c) && c != '_') {
357 c = match[strlen(gl->pattern)]; 357 c = match[strlen(gl->pattern)];
358 if (!c || (!isalnum(c) && c != '_')) 358 if (!c || (!isalnum(c) && c != '_'))
diff --git a/include/libbb.h b/include/libbb.h
index 244d85e84..af234e7b0 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -952,7 +952,7 @@ extern void xprint_and_close_file(FILE *file) FAST_FUNC;
952 * end of line. If end isn't NULL, length of the chunk is stored in it. 952 * end of line. If end isn't NULL, length of the chunk is stored in it.
953 * Returns NULL if EOF/error. 953 * Returns NULL if EOF/error.
954 */ 954 */
955extern char *bb_get_chunk_from_file(FILE *file, int *end) FAST_FUNC; 955extern char *bb_get_chunk_from_file(FILE *file, size_t *end) FAST_FUNC;
956/* Reads up to (and including) TERMINATING_STRING: */ 956/* Reads up to (and including) TERMINATING_STRING: */
957extern char *xmalloc_fgets_str(FILE *file, const char *terminating_string) FAST_FUNC RETURNS_MALLOC; 957extern char *xmalloc_fgets_str(FILE *file, const char *terminating_string) FAST_FUNC RETURNS_MALLOC;
958/* Same, with limited max size, and returns the length (excluding NUL): */ 958/* Same, with limited max size, and returns the length (excluding NUL): */
@@ -1325,20 +1325,21 @@ extern smallint syslog_level;
1325extern smallint logmode; 1325extern smallint logmode;
1326extern uint8_t xfunc_error_retval; 1326extern uint8_t xfunc_error_retval;
1327extern void (*die_func)(void); 1327extern void (*die_func)(void);
1328extern void xfunc_die(void) NORETURN FAST_FUNC; 1328void xfunc_die(void) NORETURN FAST_FUNC;
1329extern void bb_show_usage(void) NORETURN FAST_FUNC; 1329void bb_show_usage(void) NORETURN FAST_FUNC;
1330extern void bb_error_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC; 1330void bb_error_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC;
1331extern void bb_error_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))) FAST_FUNC; 1331void bb_error_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))) FAST_FUNC;
1332extern void bb_perror_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC; 1332void bb_perror_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC;
1333extern void bb_simple_perror_msg(const char *s) FAST_FUNC; 1333void bb_simple_perror_msg(const char *s) FAST_FUNC;
1334extern void bb_perror_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))) FAST_FUNC; 1334void bb_perror_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))) FAST_FUNC;
1335extern void bb_simple_perror_msg_and_die(const char *s) NORETURN FAST_FUNC; 1335void bb_simple_perror_msg_and_die(const char *s) NORETURN FAST_FUNC;
1336extern void bb_herror_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC; 1336void bb_herror_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC;
1337extern void bb_herror_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))) FAST_FUNC; 1337void bb_herror_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))) FAST_FUNC;
1338extern void bb_perror_nomsg_and_die(void) NORETURN FAST_FUNC; 1338void bb_perror_nomsg_and_die(void) NORETURN FAST_FUNC;
1339extern void bb_perror_nomsg(void) FAST_FUNC; 1339void bb_perror_nomsg(void) FAST_FUNC;
1340extern void bb_verror_msg(const char *s, va_list p, const char *strerr) FAST_FUNC; 1340void bb_verror_msg(const char *s, va_list p, const char *strerr) FAST_FUNC;
1341extern void bb_logenv_override(void) FAST_FUNC; 1341void bb_die_memory_exhausted(void) NORETURN FAST_FUNC;
1342void bb_logenv_override(void) FAST_FUNC;
1342 1343
1343/* We need to export XXX_main from libbusybox 1344/* We need to export XXX_main from libbusybox
1344 * only if we build "individual" binaries 1345 * only if we build "individual" binaries
diff --git a/libbb/get_line_from_file.c b/libbb/get_line_from_file.c
index 4e09ddc80..09ccfba67 100644
--- a/libbb/get_line_from_file.c
+++ b/libbb/get_line_from_file.c
@@ -10,16 +10,19 @@
10 */ 10 */
11#include "libbb.h" 11#include "libbb.h"
12 12
13char* FAST_FUNC bb_get_chunk_from_file(FILE *file, int *end) 13char* FAST_FUNC bb_get_chunk_from_file(FILE *file, size_t *end)
14{ 14{
15 int ch; 15 int ch;
16 unsigned idx = 0; 16 size_t idx = 0;
17 char *linebuf = NULL; 17 char *linebuf = NULL;
18 18
19 while ((ch = getc(file)) != EOF) { 19 while ((ch = getc(file)) != EOF) {
20 /* grow the line buffer as necessary */ 20 /* grow the line buffer as necessary */
21 if (!(idx & 0xff)) 21 if (!(idx & 0xff)) {
22 if (idx == ((size_t)-1) - 0xff)
23 bb_die_memory_exhausted();
22 linebuf = xrealloc(linebuf, idx + 0x100); 24 linebuf = xrealloc(linebuf, idx + 0x100);
25 }
23 linebuf[idx++] = (char) ch; 26 linebuf[idx++] = (char) ch;
24 if (ch == '\0') 27 if (ch == '\0')
25 break; 28 break;
@@ -44,14 +47,12 @@ char* FAST_FUNC bb_get_chunk_from_file(FILE *file, int *end)
44/* Get line, including trailing \n if any */ 47/* Get line, including trailing \n if any */
45char* FAST_FUNC xmalloc_fgets(FILE *file) 48char* FAST_FUNC xmalloc_fgets(FILE *file)
46{ 49{
47 int i; 50 return bb_get_chunk_from_file(file, NULL);
48
49 return bb_get_chunk_from_file(file, &i);
50} 51}
51/* Get line. Remove trailing \n */ 52/* Get line. Remove trailing \n */
52char* FAST_FUNC xmalloc_fgetline(FILE *file) 53char* FAST_FUNC xmalloc_fgetline(FILE *file)
53{ 54{
54 int i; 55 size_t i;
55 char *c = bb_get_chunk_from_file(file, &i); 56 char *c = bb_get_chunk_from_file(file, &i);
56 57
57 if (i && c[--i] == '\n') 58 if (i && c[--i] == '\n')
diff --git a/libbb/wfopen.c b/libbb/wfopen.c
index 20fe18b23..1c7f7f3d7 100644
--- a/libbb/wfopen.c
+++ b/libbb/wfopen.c
@@ -42,7 +42,7 @@ static FILE* xfdopen_helper(unsigned fd_and_rw_bit)
42{ 42{
43 FILE* fp = fdopen(fd_and_rw_bit >> 1, fd_and_rw_bit & 1 ? "w" : "r"); 43 FILE* fp = fdopen(fd_and_rw_bit >> 1, fd_and_rw_bit & 1 ? "w" : "r");
44 if (!fp) 44 if (!fp)
45 bb_error_msg_and_die(bb_msg_memory_exhausted); 45 bb_die_memory_exhausted();
46 return fp; 46 return fp;
47} 47}
48FILE* FAST_FUNC xfdopen_for_read(int fd) 48FILE* FAST_FUNC xfdopen_for_read(int fd)
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c
index 43ae98065..e8c027f17 100644
--- a/libbb/xfuncs.c
+++ b/libbb/xfuncs.c
@@ -59,24 +59,23 @@ char* FAST_FUNC strncpy_IFNAMSIZ(char *dst, const char *src)
59 * A truncated result contains the first few digits of the result ala strncpy. 59 * A truncated result contains the first few digits of the result ala strncpy.
60 * Returns a pointer past last generated digit, does _not_ store NUL. 60 * Returns a pointer past last generated digit, does _not_ store NUL.
61 */ 61 */
62void BUG_sizeof(void);
63char* FAST_FUNC utoa_to_buf(unsigned n, char *buf, unsigned buflen) 62char* FAST_FUNC utoa_to_buf(unsigned n, char *buf, unsigned buflen)
64{ 63{
65 unsigned i, out, res; 64 unsigned i, out, res;
66 65
67 if (buflen) { 66 if (buflen) {
68 out = 0; 67 out = 0;
68
69 BUILD_BUG_ON(sizeof(n) != 4 && sizeof(n) != 8);
69 if (sizeof(n) == 4) 70 if (sizeof(n) == 4)
70 // 2^32-1 = 4294967295 71 // 2^32-1 = 4294967295
71 i = 1000000000; 72 i = 1000000000;
72#if UINT_MAX > 4294967295 /* prevents warning about "const too large" */ 73#if UINT_MAX > 0xffffffff /* prevents warning about "const too large" */
73 else 74 else
74 if (sizeof(n) == 8) 75 if (sizeof(n) == 8)
75 // 2^64-1 = 18446744073709551615 76 // 2^64-1 = 18446744073709551615
76 i = 10000000000000000000; 77 i = 10000000000000000000;
77#endif 78#endif
78 else
79 BUG_sizeof();
80 for (; i; i /= 10) { 79 for (; i; i /= 10) {
81 res = n / i; 80 res = n / i;
82 n = n % i; 81 n = n % i;
diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c
index 7032e5f8f..21263ccfe 100644
--- a/libbb/xfuncs_printf.c
+++ b/libbb/xfuncs_printf.c
@@ -25,6 +25,11 @@
25 * fail, so callers never need to check for errors. If it returned, it 25 * fail, so callers never need to check for errors. If it returned, it
26 * succeeded. */ 26 * succeeded. */
27 27
28void FAST_FUNC bb_die_memory_exhausted(void)
29{
30 bb_error_msg_and_die(bb_msg_memory_exhausted);
31}
32
28#ifndef DMALLOC 33#ifndef DMALLOC
29/* dmalloc provides variants of these that do abort() on failure. 34/* dmalloc provides variants of these that do abort() on failure.
30 * Since dmalloc's prototypes overwrite the impls here as they are 35 * Since dmalloc's prototypes overwrite the impls here as they are
@@ -44,7 +49,7 @@ void* FAST_FUNC xmalloc(size_t size)
44{ 49{
45 void *ptr = malloc(size); 50 void *ptr = malloc(size);
46 if (ptr == NULL && size != 0) 51 if (ptr == NULL && size != 0)
47 bb_error_msg_and_die(bb_msg_memory_exhausted); 52 bb_die_memory_exhausted();
48 return ptr; 53 return ptr;
49} 54}
50 55
@@ -55,7 +60,7 @@ void* FAST_FUNC xrealloc(void *ptr, size_t size)
55{ 60{
56 ptr = realloc(ptr, size); 61 ptr = realloc(ptr, size);
57 if (ptr == NULL && size != 0) 62 if (ptr == NULL && size != 0)
58 bb_error_msg_and_die(bb_msg_memory_exhausted); 63 bb_die_memory_exhausted();
59 return ptr; 64 return ptr;
60} 65}
61#endif /* DMALLOC */ 66#endif /* DMALLOC */
@@ -79,7 +84,7 @@ char* FAST_FUNC xstrdup(const char *s)
79 t = strdup(s); 84 t = strdup(s);
80 85
81 if (t == NULL) 86 if (t == NULL)
82 bb_error_msg_and_die(bb_msg_memory_exhausted); 87 bb_die_memory_exhausted();
83 88
84 return t; 89 return t;
85} 90}
@@ -327,14 +332,14 @@ char* FAST_FUNC xasprintf(const char *format, ...)
327 va_end(p); 332 va_end(p);
328 333
329 if (r < 0) 334 if (r < 0)
330 bb_error_msg_and_die(bb_msg_memory_exhausted); 335 bb_die_memory_exhausted();
331 return string_ptr; 336 return string_ptr;
332} 337}
333 338
334void FAST_FUNC xsetenv(const char *key, const char *value) 339void FAST_FUNC xsetenv(const char *key, const char *value)
335{ 340{
336 if (setenv(key, value, 1)) 341 if (setenv(key, value, 1))
337 bb_error_msg_and_die(bb_msg_memory_exhausted); 342 bb_die_memory_exhausted();
338} 343}
339 344
340/* Handles "VAR=VAL" strings, even those which are part of environ 345/* Handles "VAR=VAL" strings, even those which are part of environ
diff --git a/miscutils/fbsplash.c b/miscutils/fbsplash.c
index 5b2e5ac56..bc3c61055 100644
--- a/miscutils/fbsplash.c
+++ b/miscutils/fbsplash.c
@@ -54,7 +54,7 @@
54//usage: "\n -d Framebuffer device (default /dev/fb0)" 54//usage: "\n -d Framebuffer device (default /dev/fb0)"
55//usage: "\n -i Config file (var=value):" 55//usage: "\n -i Config file (var=value):"
56//usage: "\n BAR_LEFT,BAR_TOP,BAR_WIDTH,BAR_HEIGHT" 56//usage: "\n BAR_LEFT,BAR_TOP,BAR_WIDTH,BAR_HEIGHT"
57//usage: "\n BAR_R,BAR_G,BAR_B" 57//usage: "\n BAR_R,BAR_G,BAR_B,IMG_LEFT,IMG_TOP"
58//usage: "\n -f Control pipe (else exit after drawing image)" 58//usage: "\n -f Control pipe (else exit after drawing image)"
59//usage: "\n commands: 'NN' (% for progress bar) or 'exit'" 59//usage: "\n commands: 'NN' (% for progress bar) or 'exit'"
60 60
@@ -73,7 +73,7 @@ struct globals {
73 FILE *logfile_fd; // log file 73 FILE *logfile_fd; // log file
74#endif 74#endif
75 unsigned char *addr; // pointer to framebuffer memory 75 unsigned char *addr; // pointer to framebuffer memory
76 unsigned ns[7]; // n-parameters 76 unsigned ns[9]; // n-parameters
77 const char *image_filename; 77 const char *image_filename;
78 struct fb_var_screeninfo scr_var; 78 struct fb_var_screeninfo scr_var;
79 struct fb_fix_screeninfo scr_fix; 79 struct fb_fix_screeninfo scr_fix;
@@ -95,6 +95,8 @@ struct globals {
95#define nbar_colr ns[4] // progress bar color red component 95#define nbar_colr ns[4] // progress bar color red component
96#define nbar_colg ns[5] // progress bar color green component 96#define nbar_colg ns[5] // progress bar color green component
97#define nbar_colb ns[6] // progress bar color blue component 97#define nbar_colb ns[6] // progress bar color blue component
98#define img_posx ns[7] // image horizontal position
99#define img_posy ns[8] // image vertical position
98 100
99#if DEBUG 101#if DEBUG
100#define DEBUG_MESSAGE(strMessage, args...) \ 102#define DEBUG_MESSAGE(strMessage, args...) \
@@ -426,10 +428,10 @@ static void fb_drawimage(void)
426 line_size = width*3; 428 line_size = width*3;
427 pixline = xmalloc(line_size); 429 pixline = xmalloc(line_size);
428 430
429 if (width > G.scr_var.xres) 431 if ((width + G.img_posx) > G.scr_var.xres)
430 width = G.scr_var.xres; 432 width = G.scr_var.xres - G.img_posx;
431 if (height > G.scr_var.yres) 433 if ((height + G.img_posy) > G.scr_var.yres)
432 height = G.scr_var.yres; 434 height = G.scr_var.yres - G.img_posy;
433 for (j = 0; j < height; j++) { 435 for (j = 0; j < height; j++) {
434 unsigned char *pixel; 436 unsigned char *pixel;
435 unsigned char *src; 437 unsigned char *src;
@@ -437,7 +439,7 @@ static void fb_drawimage(void)
437 if (fread(pixline, 1, line_size, theme_file) != line_size) 439 if (fread(pixline, 1, line_size, theme_file) != line_size)
438 bb_error_msg_and_die("bad PPM file '%s'", G.image_filename); 440 bb_error_msg_and_die("bad PPM file '%s'", G.image_filename);
439 pixel = pixline; 441 pixel = pixline;
440 src = G.addr + j * G.scr_fix.line_length; 442 src = G.addr + (G.img_posy + j) * G.scr_fix.line_length + G.img_posx * G.bytes_per_pixel;
441 for (i = 0; i < width; i++) { 443 for (i = 0; i < width; i++) {
442 unsigned thispix = fb_pixel_value(pixel[0], pixel[1], pixel[2]); 444 unsigned thispix = fb_pixel_value(pixel[0], pixel[1], pixel[2]);
443 fb_write_pixel(src, thispix); 445 fb_write_pixel(src, thispix);
@@ -460,6 +462,7 @@ static void init(const char *cfg_filename)
460 "BAR_WIDTH\0" "BAR_HEIGHT\0" 462 "BAR_WIDTH\0" "BAR_HEIGHT\0"
461 "BAR_LEFT\0" "BAR_TOP\0" 463 "BAR_LEFT\0" "BAR_TOP\0"
462 "BAR_R\0" "BAR_G\0" "BAR_B\0" 464 "BAR_R\0" "BAR_G\0" "BAR_B\0"
465 "IMG_LEFT\0" "IMG_TOP\0"
463#if DEBUG 466#if DEBUG
464 "DEBUG\0" 467 "DEBUG\0"
465#endif 468#endif
@@ -472,10 +475,10 @@ static void init(const char *cfg_filename)
472 int i = index_in_strings(param_names, token[0]); 475 int i = index_in_strings(param_names, token[0]);
473 if (i < 0) 476 if (i < 0)
474 bb_error_msg_and_die("syntax error: %s", token[0]); 477 bb_error_msg_and_die("syntax error: %s", token[0]);
475 if (i >= 0 && i < 7) 478 if (i >= 0 && i < 9)
476 G.ns[i] = val; 479 G.ns[i] = val;
477#if DEBUG 480#if DEBUG
478 if (i == 7) { 481 if (i == 9) {
479 G.bdebug_messages = val; 482 G.bdebug_messages = val;
480 if (G.bdebug_messages) 483 if (G.bdebug_messages)
481 G.logfile_fd = xfopen_for_write("/tmp/fbsplash.log"); 484 G.logfile_fd = xfopen_for_write("/tmp/fbsplash.log");
diff --git a/networking/ifplugd.c b/networking/ifplugd.c
index 9bc1a075f..5059eaf73 100644
--- a/networking/ifplugd.c
+++ b/networking/ifplugd.c
@@ -367,7 +367,7 @@ static void up_iface(void)
367 /* Let user know we mess up with interface */ 367 /* Let user know we mess up with interface */
368 bb_error_msg("upping interface"); 368 bb_error_msg("upping interface");
369 if (network_ioctl(SIOCSIFFLAGS, &ifrequest, "setting interface flags") < 0) { 369 if (network_ioctl(SIOCSIFFLAGS, &ifrequest, "setting interface flags") < 0) {
370 if (errno != ENODEV) 370 if (errno != ENODEV && errno != EADDRNOTAVAIL)
371 xfunc_die(); 371 xfunc_die();
372 G.iface_exists = 0; 372 G.iface_exists = 0;
373 return; 373 return;
diff --git a/networking/ifupdown.c b/networking/ifupdown.c
index 534c9f0c7..5481134e5 100644
--- a/networking/ifupdown.c
+++ b/networking/ifupdown.c
@@ -138,6 +138,7 @@
138//usage: "\n -v Print out what would happen before doing it" 138//usage: "\n -v Print out what would happen before doing it"
139//usage: "\n -f Force deconfiguration" 139//usage: "\n -f Force deconfiguration"
140 140
141#include <net/if.h>
141#include "libbb.h" 142#include "libbb.h"
142#include "common_bufsiz.h" 143#include "common_bufsiz.h"
143/* After libbb.h, since it needs sys/types.h on some systems */ 144/* After libbb.h, since it needs sys/types.h on some systems */
@@ -503,6 +504,8 @@ static int FAST_FUNC static_up6(struct interface_defn_t *ifd, execfn *exec)
503 504
504static int FAST_FUNC static_down6(struct interface_defn_t *ifd, execfn *exec) 505static int FAST_FUNC static_down6(struct interface_defn_t *ifd, execfn *exec)
505{ 506{
507 if (!if_nametoindex(ifd->iface))
508 return 1; /* already gone */
506# if ENABLE_FEATURE_IFUPDOWN_IP 509# if ENABLE_FEATURE_IFUPDOWN_IP
507 return execute("ip link set %iface% down", ifd, exec); 510 return execute("ip link set %iface% down", ifd, exec);
508# else 511# else
@@ -598,6 +601,9 @@ static int FAST_FUNC static_up(struct interface_defn_t *ifd, execfn *exec)
598static int FAST_FUNC static_down(struct interface_defn_t *ifd, execfn *exec) 601static int FAST_FUNC static_down(struct interface_defn_t *ifd, execfn *exec)
599{ 602{
600 int result; 603 int result;
604
605 if (!if_nametoindex(ifd->iface))
606 return 2; /* already gone */
601# if ENABLE_FEATURE_IFUPDOWN_IP 607# if ENABLE_FEATURE_IFUPDOWN_IP
602 /* Optional "label LBL" is necessary if interface is an alias (eth0:0), 608 /* Optional "label LBL" is necessary if interface is an alias (eth0:0),
603 * otherwise "ip addr flush dev eth0:0" flushes all addresses on eth0. 609 * otherwise "ip addr flush dev eth0:0" flushes all addresses on eth0.
diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c
index 2aa8b683b..9c164a71d 100644
--- a/networking/libiproute/iplink.c
+++ b/networking/libiproute/iplink.c
@@ -161,7 +161,7 @@ static int get_address(char *dev, int *htype)
161 161
162 s = xsocket(PF_PACKET, SOCK_DGRAM, 0); 162 s = xsocket(PF_PACKET, SOCK_DGRAM, 0);
163 163
164 memset(&ifr, 0, sizeof(ifr)); 164 /*memset(&ifr, 0, sizeof(ifr)); - SIOCGIFINDEX does not need to clear all */
165 strncpy_IFNAMSIZ(ifr.ifr_name, dev); 165 strncpy_IFNAMSIZ(ifr.ifr_name, dev);
166 xioctl(s, SIOCGIFINDEX, &ifr); 166 xioctl(s, SIOCGIFINDEX, &ifr);
167 167
diff --git a/networking/netstat.c b/networking/netstat.c
index 33281e333..f6bcd44ba 100644
--- a/networking/netstat.c
+++ b/networking/netstat.c
@@ -397,8 +397,11 @@ static char *ip_port_str(struct sockaddr *addr, int port, const char *proto, int
397 /* Code which used "*" for INADDR_ANY is removed: it's ambiguous 397 /* Code which used "*" for INADDR_ANY is removed: it's ambiguous
398 * in IPv6, while "0.0.0.0" is not. */ 398 * in IPv6, while "0.0.0.0" is not. */
399 399
400 host = numeric ? xmalloc_sockaddr2dotted_noport(addr) 400 host = NULL;
401 : xmalloc_sockaddr2host_noport(addr); 401 if (!numeric)
402 host = xmalloc_sockaddr2host_noport(addr);
403 if (!host)
404 host = xmalloc_sockaddr2dotted_noport(addr);
402 405
403 host_port = xasprintf("%s:%s", host, get_sname(htons(port), proto, numeric)); 406 host_port = xasprintf("%s:%s", host, get_sname(htons(port), proto, numeric));
404 free(host); 407 free(host);
diff --git a/networking/route.c b/networking/route.c
index 6edc0f6d7..8387ce1bb 100644
--- a/networking/route.c
+++ b/networking/route.c
@@ -444,7 +444,7 @@ static NOINLINE void INET6_setroute(int action, char **args)
444 444
445 if (devname) { 445 if (devname) {
446 struct ifreq ifr; 446 struct ifreq ifr;
447 memset(&ifr, 0, sizeof(ifr)); 447 /*memset(&ifr, 0, sizeof(ifr)); - SIOCGIFINDEX does not need to clear all */
448 strncpy_IFNAMSIZ(ifr.ifr_name, devname); 448 strncpy_IFNAMSIZ(ifr.ifr_name, devname);
449 xioctl(skfd, SIOCGIFINDEX, &ifr); 449 xioctl(skfd, SIOCGIFINDEX, &ifr);
450 rt.rtmsg_ifindex = ifr.ifr_ifindex; 450 rt.rtmsg_ifindex = ifr.ifr_ifindex;
diff --git a/networking/ssl_client.c b/networking/ssl_client.c
index e56d82fc1..49aec6b99 100644
--- a/networking/ssl_client.c
+++ b/networking/ssl_client.c
@@ -41,7 +41,6 @@ int ssl_client_main(int argc UNUSED_PARAM, char **argv)
41 tls = new_tls_state(); 41 tls = new_tls_state();
42#if !ENABLE_PLATFORM_MINGW32 42#if !ENABLE_PLATFORM_MINGW32
43 opt = getopt32(argv, "es:+r:+n:", &tls->ofd, &tls->ifd, &sni); 43 opt = getopt32(argv, "es:+r:+n:", &tls->ofd, &tls->ifd, &sni);
44
45 if (!(opt & (1<<2))) { 44 if (!(opt & (1<<2))) {
46 /* -r N defaults to -s N */ 45 /* -r N defaults to -s N */
47 tls->ifd = tls->ofd; 46 tls->ifd = tls->ofd;
diff --git a/networking/udhcp/d6_socket.c b/networking/udhcp/d6_socket.c
index 315c8d98a..6ad53a9c2 100644
--- a/networking/udhcp/d6_socket.c
+++ b/networking/udhcp/d6_socket.c
@@ -63,7 +63,7 @@ int FAST_FUNC d6_read_interface(const char *interface, int *ifindex, struct in6_
63 struct ifreq ifr; 63 struct ifreq ifr;
64 int fd; 64 int fd;
65 65
66 memset(&ifr, 0, sizeof(ifr)); 66 /*memset(&ifr, 0, sizeof(ifr)); - SIOCGIFINDEX does not need to clear all */
67 strncpy_IFNAMSIZ(ifr.ifr_name, interface); 67 strncpy_IFNAMSIZ(ifr.ifr_name, interface);
68 fd = xsocket(AF_INET6, SOCK_RAW, IPPROTO_RAW); 68 fd = xsocket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
69 if (ioctl(fd, SIOCGIFINDEX, &ifr) == 0) { 69 if (ioctl(fd, SIOCGIFINDEX, &ifr) == 0) {
diff --git a/networking/wget.c b/networking/wget.c
index 194bf457a..aaa068ba9 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -409,7 +409,7 @@ static FILE *open_socket(len_and_sockaddr *lsa)
409 /* hopefully it understands what ESPIPE means... */ 409 /* hopefully it understands what ESPIPE means... */
410 fp = fdopen(fd, "r+"); 410 fp = fdopen(fd, "r+");
411 if (!fp) 411 if (!fp)
412 bb_perror_msg_and_die(bb_msg_memory_exhausted); 412 bb_die_memory_exhausted();
413 413
414 return fp; 414 return fp;
415} 415}
@@ -1146,7 +1146,7 @@ static void download_one_url(const char *url)
1146# endif 1146# endif
1147 sfp = fdopen(fd, "r+"); 1147 sfp = fdopen(fd, "r+");
1148 if (!sfp) 1148 if (!sfp)
1149 bb_perror_msg_and_die(bb_msg_memory_exhausted); 1149 bb_die_memory_exhausted();
1150 goto socket_opened; 1150 goto socket_opened;
1151 } 1151 }
1152 sfp = open_socket(lsa); 1152 sfp = open_socket(lsa);
diff --git a/procps/top.c b/procps/top.c
index 075c96c27..1b49a5e6b 100644
--- a/procps/top.c
+++ b/procps/top.c
@@ -1157,7 +1157,7 @@ int top_main(int argc UNUSED_PARAM, char **argv)
1157#endif 1157#endif
1158 1158
1159 while (scan_mask != EXIT_MASK) { 1159 while (scan_mask != EXIT_MASK) {
1160 unsigned new_mask; 1160 IF_FEATURE_TOP_INTERACTIVE(unsigned new_mask;)
1161 procps_status_t *p = NULL; 1161 procps_status_t *p = NULL;
1162 1162
1163 if (OPT_BATCH_MODE) { 1163 if (OPT_BATCH_MODE) {
diff --git a/runit/sv.c b/runit/sv.c
index dc5dcceb3..86d181872 100644
--- a/runit/sv.c
+++ b/runit/sv.c
@@ -163,7 +163,7 @@ Exit Codes
163//config:config SV_DEFAULT_SERVICE_DIR 163//config:config SV_DEFAULT_SERVICE_DIR
164//config: string "Default directory for services" 164//config: string "Default directory for services"
165//config: default "/var/service" 165//config: default "/var/service"
166//config: depends on SV 166//config: depends on SV || SVC || SVOK
167//config: help 167//config: help
168//config: Default directory for services. 168//config: Default directory for services.
169//config: Defaults to "/var/service" 169//config: Defaults to "/var/service"
@@ -173,13 +173,22 @@ Exit Codes
173//config: default y 173//config: default y
174//config: help 174//config: help
175//config: svc controls the state of services monitored by the runsv supervisor. 175//config: svc controls the state of services monitored by the runsv supervisor.
176//config: It is comaptible with daemontools command with the same name. 176//config: It is compatible with daemontools command with the same name.
177//config:
178//config:config SVOK
179//config: bool "svok"
180//config: default y
181//config: help
182//config: svok checks whether runsv supervisor is running.
183//config: It is compatible with daemontools command with the same name.
177 184
178//applet:IF_SV( APPLET_NOEXEC(sv, sv, BB_DIR_USR_BIN, BB_SUID_DROP, sv )) 185//applet:IF_SV( APPLET_NOEXEC(sv, sv, BB_DIR_USR_BIN, BB_SUID_DROP, sv ))
179//applet:IF_SVC(APPLET_NOEXEC(svc, svc, BB_DIR_USR_BIN, BB_SUID_DROP, svc)) 186//applet:IF_SVC( APPLET_NOEXEC(svc, svc, BB_DIR_USR_BIN, BB_SUID_DROP, svc ))
187//applet:IF_SVOK(APPLET_NOEXEC(svok, svok, BB_DIR_USR_BIN, BB_SUID_DROP, svok))
180 188
181//kbuild:lib-$(CONFIG_SV) += sv.o 189//kbuild:lib-$(CONFIG_SV) += sv.o
182//kbuild:lib-$(CONFIG_SVC) += sv.o 190//kbuild:lib-$(CONFIG_SVC) += sv.o
191//kbuild:lib-$(CONFIG_SVOK) += sv.o
183 192
184#include <sys/file.h> 193#include <sys/file.h>
185#include "libbb.h" 194#include "libbb.h"
@@ -615,7 +624,7 @@ static int sv(char **argv)
615 service = argv; 624 service = argv;
616 while ((x = *service) != NULL) { 625 while ((x = *service) != NULL) {
617 if (x[0] != '/' && x[0] != '.' 626 if (x[0] != '/' && x[0] != '.'
618 && x[0] != '\0' && x[strlen(x) - 1] != '/' 627 && !last_char_is(x, '/')
619 ) { 628 ) {
620 if (chdir(varservice) == -1) 629 if (chdir(varservice) == -1)
621 goto chdir_failed_0; 630 goto chdir_failed_0;
@@ -742,3 +751,41 @@ int svc_main(int argc UNUSED_PARAM, char **argv)
742 return 0; 751 return 0;
743} 752}
744#endif 753#endif
754
755//usage:#define svok_trivial_usage
756//usage: "SERVICE_DIR"
757//usage:#define svok_full_usage "\n\n"
758//usage: "Check whether runsv supervisor is running.\n"
759//usage: "Exit code is 0 if it does, 100 if it does not,\n"
760//usage: "111 (with error message) if SERVICE_DIR does not exist."
761#if ENABLE_SVOK
762int svok_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
763int svok_main(int argc UNUSED_PARAM, char **argv)
764{
765 const char *dir = argv[1];
766
767 if (!dir)
768 bb_show_usage();
769
770 xfunc_error_retval = 111;
771
772 /*
773 * daemontools has no concept of "default service dir", runit does.
774 * Let's act as runit.
775 */
776 if (dir[0] != '/' && dir[0] != '.'
777 && !last_char_is(dir, '/')
778 ) {
779 xchdir(CONFIG_SV_DEFAULT_SERVICE_DIR);
780 }
781
782 xchdir(dir);
783 if (open("supervise/ok", O_WRONLY) < 0) {
784 if (errno == ENOENT || errno == ENXIO)
785 return 100;
786 bb_perror_msg_and_die("can't open '%s'", "supervise/ok");
787 }
788
789 return 0;
790}
791#endif
diff --git a/shell/ash.c b/shell/ash.c
index 2ab46576c..7448b668a 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -282,6 +282,12 @@ typedef long arith_t;
282# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__ 282# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
283#endif 283#endif
284 284
285#ifndef F_DUPFD_CLOEXEC
286# define F_DUPFD_CLOEXEC F_DUPFD
287#endif
288#ifndef O_CLOEXEC
289# define O_CLOEXEC 0
290#endif
285#ifndef PIPE_BUF 291#ifndef PIPE_BUF
286# define PIPE_BUF 4096 /* amount of buffering in a pipe */ 292# define PIPE_BUF 4096 /* amount of buffering in a pipe */
287#endif 293#endif
@@ -4196,12 +4202,13 @@ setjobctl(int on)
4196 goto out; 4202 goto out;
4197 } 4203 }
4198 /* fd is a tty at this point */ 4204 /* fd is a tty at this point */
4199 fd = fcntl(fd, F_DUPFD, 10); 4205 fd = fcntl(fd, F_DUPFD_CLOEXEC, 10);
4200 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, don't */ 4206 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, don't */
4201 close(ofd); 4207 close(ofd);
4202 if (fd < 0) 4208 if (fd < 0)
4203 goto out; /* F_DUPFD failed */ 4209 goto out; /* F_DUPFD failed */
4204 close_on_exec_on(fd); 4210 if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
4211 close_on_exec_on(fd);
4205 while (1) { /* while we are in the background */ 4212 while (1) { /* while we are in the background */
4206 pgrp = tcgetpgrp(fd); 4213 pgrp = tcgetpgrp(fd);
4207 if (pgrp < 0) { 4214 if (pgrp < 0) {
@@ -5791,13 +5798,14 @@ savefd(int from)
5791 int newfd; 5798 int newfd;
5792 int err; 5799 int err;
5793 5800
5794 newfd = fcntl(from, F_DUPFD, 10); 5801 newfd = fcntl(from, F_DUPFD_CLOEXEC, 10);
5795 err = newfd < 0 ? errno : 0; 5802 err = newfd < 0 ? errno : 0;
5796 if (err != EBADF) { 5803 if (err != EBADF) {
5797 if (err) 5804 if (err)
5798 ash_msg_and_raise_perror("%d", from); 5805 ash_msg_and_raise_perror("%d", from);
5799 close(from); 5806 close(from);
5800 fcntl(newfd, F_SETFD, FD_CLOEXEC); 5807 if (F_DUPFD_CLOEXEC == F_DUPFD)
5808 close_on_exec_on(newfd);
5801 } 5809 }
5802 5810
5803 return newfd; 5811 return newfd;
@@ -5815,12 +5823,15 @@ dup2_or_raise(int from, int to)
5815 return newfd; 5823 return newfd;
5816} 5824}
5817static int 5825static int
5818fcntl_F_DUPFD(int fd, int avoid_fd) 5826dup_CLOEXEC(int fd, int avoid_fd)
5819{ 5827{
5820 int newfd; 5828 int newfd;
5821 repeat: 5829 repeat:
5822 newfd = fcntl(fd, F_DUPFD, avoid_fd + 1); 5830 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
5823 if (newfd < 0) { 5831 if (newfd >= 0) {
5832 if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
5833 close_on_exec_on(newfd);
5834 } else { /* newfd < 0 */
5824 if (errno == EBUSY) 5835 if (errno == EBUSY)
5825 goto repeat; 5836 goto repeat;
5826 if (errno == EINTR) 5837 if (errno == EINTR)
@@ -5833,7 +5844,7 @@ xdup_CLOEXEC_and_close(int fd, int avoid_fd)
5833{ 5844{
5834 int newfd; 5845 int newfd;
5835 repeat: 5846 repeat:
5836 newfd = fcntl(fd, F_DUPFD, avoid_fd + 1); 5847 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
5837 if (newfd < 0) { 5848 if (newfd < 0) {
5838 if (errno == EBUSY) 5849 if (errno == EBUSY)
5839 goto repeat; 5850 goto repeat;
@@ -5844,7 +5855,8 @@ xdup_CLOEXEC_and_close(int fd, int avoid_fd)
5844 return fd; 5855 return fd;
5845 ash_msg_and_raise_perror("%d", newfd); 5856 ash_msg_and_raise_perror("%d", newfd);
5846 } 5857 }
5847 fcntl(newfd, F_SETFD, FD_CLOEXEC); 5858 if (F_DUPFD_CLOEXEC == F_DUPFD)
5859 close_on_exec_on(newfd);
5848 close(fd); 5860 close(fd);
5849 return newfd; 5861 return newfd;
5850} 5862}
@@ -5936,7 +5948,7 @@ save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
5936 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) { 5948 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5937 /* If we collide with an already moved fd... */ 5949 /* If we collide with an already moved fd... */
5938 if (fd == sq->two_fd[i].moved_to) { 5950 if (fd == sq->two_fd[i].moved_to) {
5939 new_fd = fcntl_F_DUPFD(fd, avoid_fd); 5951 new_fd = dup_CLOEXEC(fd, avoid_fd);
5940 sq->two_fd[i].moved_to = new_fd; 5952 sq->two_fd[i].moved_to = new_fd;
5941 TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd)); 5953 TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd));
5942 if (new_fd < 0) /* what? */ 5954 if (new_fd < 0) /* what? */
@@ -5951,7 +5963,7 @@ save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
5951 } 5963 }
5952 5964
5953 /* If this fd is open, we move and remember it; if it's closed, new_fd = CLOSED (-1) */ 5965 /* If this fd is open, we move and remember it; if it's closed, new_fd = CLOSED (-1) */
5954 new_fd = fcntl_F_DUPFD(fd, avoid_fd); 5966 new_fd = dup_CLOEXEC(fd, avoid_fd);
5955 TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd)); 5967 TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd));
5956 if (new_fd < 0) { 5968 if (new_fd < 0) {
5957 if (errno != EBADF) 5969 if (errno != EBADF)
@@ -7559,7 +7571,7 @@ varvalue(char *name, int varflags, int flags, int *quotedp)
7559 case '-': 7571 case '-':
7560 expdest = makestrspace(NOPTS, expdest); 7572 expdest = makestrspace(NOPTS, expdest);
7561 for (i = NOPTS - 1; i >= 0; i--) { 7573 for (i = NOPTS - 1; i >= 0; i--) {
7562 if (optlist[i]) { 7574 if (optlist[i] && optletters(i)) {
7563 USTPUTC(optletters(i), expdest); 7575 USTPUTC(optletters(i), expdest);
7564 len++; 7576 len++;
7565 } 7577 }
@@ -7806,13 +7818,13 @@ hasmeta(const char *p)
7806 p = strpbrk(p, chars); 7818 p = strpbrk(p, chars);
7807 if (!p) 7819 if (!p)
7808 break; 7820 break;
7809 switch ((unsigned char) *p) { 7821 switch ((unsigned char)*p) {
7810 case CTLQUOTEMARK: 7822 case CTLQUOTEMARK:
7811 for (;;) { 7823 for (;;) {
7812 p++; 7824 p++;
7813 if (*p == CTLQUOTEMARK) 7825 if ((unsigned char)*p == CTLQUOTEMARK)
7814 break; 7826 break;
7815 if (*p == CTLESC) 7827 if ((unsigned char)*p == CTLESC)
7816 p++; 7828 p++;
7817 if (*p == '\0') /* huh? */ 7829 if (*p == '\0') /* huh? */
7818 return 0; 7830 return 0;
@@ -11262,7 +11274,7 @@ setinputfile(const char *fname, int flags)
11262 int fd; 11274 int fd;
11263 11275
11264 INT_OFF; 11276 INT_OFF;
11265 fd = open(fname, O_RDONLY); 11277 fd = open(fname, O_RDONLY | O_CLOEXEC);
11266 if (fd < 0) { 11278 if (fd < 0) {
11267 if (flags & INPUT_NOFILE_OK) 11279 if (flags & INPUT_NOFILE_OK)
11268 goto out; 11280 goto out;
@@ -11271,8 +11283,9 @@ setinputfile(const char *fname, int flags)
11271 } 11283 }
11272 if (fd < 10) 11284 if (fd < 10)
11273 fd = savefd(fd); 11285 fd = savefd(fd);
11274 else 11286 else if (O_CLOEXEC == 0) /* old libc */
11275 close_on_exec_on(fd); 11287 close_on_exec_on(fd);
11288
11276 setinputfd(fd, flags & INPUT_PUSH_FILE); 11289 setinputfd(fd, flags & INPUT_PUSH_FILE);
11277 out: 11290 out:
11278 INT_ON; 11291 INT_ON;
@@ -12595,6 +12608,12 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
12595 break; 12608 break;
12596#endif 12609#endif
12597 case CBQUOTE: /* '`' */ 12610 case CBQUOTE: /* '`' */
12611 if (checkkwd & CHKEOFMARK) {
12612 quotef = 1;
12613 USTPUTC('`', out);
12614 break;
12615 }
12616
12598 PARSEBACKQOLD(); 12617 PARSEBACKQOLD();
12599 break; 12618 break;
12600 case CENDFILE: 12619 case CENDFILE:
@@ -12727,7 +12746,7 @@ parseredir: {
12727 np = stzalloc(sizeof(struct nfile)); 12746 np = stzalloc(sizeof(struct nfile));
12728 if (c == '>') { 12747 if (c == '>') {
12729 np->nfile.fd = 1; 12748 np->nfile.fd = 1;
12730 c = pgetc(); 12749 c = pgetc_eatbnl();
12731 if (c == '>') 12750 if (c == '>')
12732 np->type = NAPPEND; 12751 np->type = NAPPEND;
12733 else if (c == '|') 12752 else if (c == '|')
@@ -12749,7 +12768,7 @@ parseredir: {
12749#endif 12768#endif
12750 else { /* c == '<' */ 12769 else { /* c == '<' */
12751 /*np->nfile.fd = 0; - stzalloc did it */ 12770 /*np->nfile.fd = 0; - stzalloc did it */
12752 c = pgetc(); 12771 c = pgetc_eatbnl();
12753 switch (c) { 12772 switch (c) {
12754 case '<': 12773 case '<':
12755 if (sizeof(struct nfile) != sizeof(struct nhere)) { 12774 if (sizeof(struct nfile) != sizeof(struct nhere)) {
@@ -12759,7 +12778,7 @@ parseredir: {
12759 np->type = NHERE; 12778 np->type = NHERE;
12760 heredoc = stzalloc(sizeof(struct heredoc)); 12779 heredoc = stzalloc(sizeof(struct heredoc));
12761 heredoc->here = np; 12780 heredoc->here = np;
12762 c = pgetc(); 12781 c = pgetc_eatbnl();
12763 if (c == '-') { 12782 if (c == '-') {
12764 heredoc->striptabs = 1; 12783 heredoc->striptabs = 1;
12765 } else { 12784 } else {
@@ -12989,23 +13008,13 @@ parsebackq: {
12989 int pc; 13008 int pc;
12990 13009
12991 setprompt_if(needprompt, 2); 13010 setprompt_if(needprompt, 2);
12992 pc = pgetc(); 13011 pc = pgetc_eatbnl();
12993 switch (pc) { 13012 switch (pc) {
12994 case '`': 13013 case '`':
12995 goto done; 13014 goto done;
12996 13015
12997 case '\\': 13016 case '\\':
12998 pc = pgetc(); 13017 pc = pgetc(); /* or pgetc_eatbnl()? why (example)? */
12999 if (pc == '\n') {
13000 nlprompt();
13001 /*
13002 * If eating a newline, avoid putting
13003 * the newline into the new character
13004 * stream (via the STPUTC after the
13005 * switch).
13006 */
13007 continue;
13008 }
13009 if (pc != '\\' && pc != '`' && pc != '$' 13018 if (pc != '\\' && pc != '`' && pc != '$'
13010 && (!dblquote || pc != '"') 13019 && (!dblquote || pc != '"')
13011 ) { 13020 ) {
@@ -13137,7 +13146,7 @@ xxreadtoken(void)
13137 } 13146 }
13138 setprompt_if(needprompt, 2); 13147 setprompt_if(needprompt, 2);
13139 for (;;) { /* until token or start of word found */ 13148 for (;;) { /* until token or start of word found */
13140 c = pgetc(); 13149 c = pgetc_eatbnl();
13141 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA)) 13150 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
13142 continue; 13151 continue;
13143 13152
@@ -13146,11 +13155,7 @@ xxreadtoken(void)
13146 continue; 13155 continue;
13147 pungetc(); 13156 pungetc();
13148 } else if (c == '\\') { 13157 } else if (c == '\\') {
13149 if (pgetc() != '\n') { 13158 break; /* return readtoken1(...) */
13150 pungetc();
13151 break; /* return readtoken1(...) */
13152 }
13153 nlprompt();
13154 } else { 13159 } else {
13155 const char *p; 13160 const char *p;
13156 13161
@@ -13165,7 +13170,7 @@ xxreadtoken(void)
13165 break; /* return readtoken1(...) */ 13170 break; /* return readtoken1(...) */
13166 13171
13167 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) { 13172 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
13168 int cc = pgetc(); 13173 int cc = pgetc_eatbnl();
13169 if (cc == c) { /* double occurrence? */ 13174 if (cc == c) { /* double occurrence? */
13170 p += xxreadtoken_doubles + 1; 13175 p += xxreadtoken_doubles + 1;
13171 } else { 13176 } else {
@@ -13197,7 +13202,7 @@ xxreadtoken(void)
13197 } 13202 }
13198 setprompt_if(needprompt, 2); 13203 setprompt_if(needprompt, 2);
13199 for (;;) { /* until token or start of word found */ 13204 for (;;) { /* until token or start of word found */
13200 c = pgetc(); 13205 c = pgetc_eatbnl();
13201 switch (c) { 13206 switch (c) {
13202 case ' ': case '\t': 13207 case ' ': case '\t':
13203 IF_ASH_ALIAS(case PEOA:) 13208 IF_ASH_ALIAS(case PEOA:)
@@ -13207,30 +13212,23 @@ xxreadtoken(void)
13207 continue; 13212 continue;
13208 pungetc(); 13213 pungetc();
13209 continue; 13214 continue;
13210 case '\\':
13211 if (pgetc() == '\n') {
13212 nlprompt();
13213 continue;
13214 }
13215 pungetc();
13216 goto breakloop;
13217 case '\n': 13215 case '\n':
13218 nlnoprompt(); 13216 nlnoprompt();
13219 RETURN(TNL); 13217 RETURN(TNL);
13220 case PEOF: 13218 case PEOF:
13221 RETURN(TEOF); 13219 RETURN(TEOF);
13222 case '&': 13220 case '&':
13223 if (pgetc() == '&') 13221 if (pgetc_eatbnl() == '&')
13224 RETURN(TAND); 13222 RETURN(TAND);
13225 pungetc(); 13223 pungetc();
13226 RETURN(TBACKGND); 13224 RETURN(TBACKGND);
13227 case '|': 13225 case '|':
13228 if (pgetc() == '|') 13226 if (pgetc_eatbnl() == '|')
13229 RETURN(TOR); 13227 RETURN(TOR);
13230 pungetc(); 13228 pungetc();
13231 RETURN(TPIPE); 13229 RETURN(TPIPE);
13232 case ';': 13230 case ';':
13233 if (pgetc() == ';') 13231 if (pgetc_eatbnl() == ';')
13234 RETURN(TENDCASE); 13232 RETURN(TENDCASE);
13235 pungetc(); 13233 pungetc();
13236 RETURN(TSEMI); 13234 RETURN(TSEMI);
@@ -13238,11 +13236,9 @@ xxreadtoken(void)
13238 RETURN(TLP); 13236 RETURN(TLP);
13239 case ')': 13237 case ')':
13240 RETURN(TRP); 13238 RETURN(TRP);
13241 default:
13242 goto breakloop;
13243 } 13239 }
13240 break;
13244 } 13241 }
13245 breakloop:
13246 return readtoken1(c, BASESYNTAX, (char *)NULL, 0); 13242 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
13247#undef RETURN 13243#undef RETURN
13248} 13244}
diff --git a/shell/ash_test/ash-heredoc/heredoc_backquote1.right b/shell/ash_test/ash-heredoc/heredoc_backquote1.right
new file mode 100644
index 000000000..0be2a3296
--- /dev/null
+++ b/shell/ash_test/ash-heredoc/heredoc_backquote1.right
@@ -0,0 +1,5 @@
1heredoc1
2Ok1:0
3heredoc2
4EO`false`F
5Ok2:0
diff --git a/shell/ash_test/ash-heredoc/heredoc_backquote1.tests b/shell/ash_test/ash-heredoc/heredoc_backquote1.tests
new file mode 100755
index 000000000..ec3d8fe1d
--- /dev/null
+++ b/shell/ash_test/ash-heredoc/heredoc_backquote1.tests
@@ -0,0 +1,10 @@
1cat <<EO`true`F
2heredoc1
3EO`true`F
4echo Ok1:$?
5
6cat <<EO`true`F
7heredoc2
8EO`false`F
9EO`true`F
10echo Ok2:$?
diff --git a/shell/ash_test/ash-heredoc/heredoc_backslash1.right b/shell/ash_test/ash-heredoc/heredoc_backslash1.right
new file mode 100644
index 000000000..6a6114821
--- /dev/null
+++ b/shell/ash_test/ash-heredoc/heredoc_backslash1.right
@@ -0,0 +1,43 @@
1Quoted heredoc:
2a\
3 b
4a\\
5 b
6 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
7 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
8 123456 `echo v'-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-'`
9 123456 $(echo v'-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-')
10c\
11
12Unquoted heredoc:
13a b
14a\
15 b
16 123456 -qwerty-\t-\-\"-\'-`-\--\z-\*-\?-
17 -qwerty-\t-\-\"-\'-`-\--\z-\*-\?-
18 123456 v-$a-\t-\-\"-\x-`-\--\z-\*-\?-
19 123456 v-$a-\t-\\-\"-\x-\`-\--\z-\*-\?-
20cEOF2
21
22Quoted -heredoc:
23a\
24b
25a\\
26b
27 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
28-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
29 123456 `echo v'-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-'`
30 123456 $(echo v'-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-')
31c\
32
33Unquoted -heredoc:
34a b
35a\
36b
37 123456 -qwerty-\t-\-\"-\'-`-\--\z-\*-\?-
38-qwerty-\t-\-\"-\'-`-\--\z-\*-\?-
39 123456 v-$a-\t-\-\"-\x-`-\--\z-\*-\?-
40 123456 v-$a-\t-\\-\"-\x-\`-\--\z-\*-\?-
41cEOF4
42
43Done: 0
diff --git a/shell/ash_test/ash-heredoc/heredoc_backslash1.tests b/shell/ash_test/ash-heredoc/heredoc_backslash1.tests
new file mode 100755
index 000000000..501af5490
--- /dev/null
+++ b/shell/ash_test/ash-heredoc/heredoc_backslash1.tests
@@ -0,0 +1,70 @@
1# Test for correct handling of backslashes.
2# Note that some lines in each heredoc start with a tab.
3
4a=qwerty
5
6echo Quoted heredoc:
7cat <<"EOF1"
8a\
9 b
10a\\
11 b
12 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
13 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
14 123456 `echo v'-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-'`
15 123456 $(echo v'-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-')
16c\
17EOF1
18echo
19
20echo Unquoted heredoc:
21cat <<EOF2
22a\
23 b
24a\\
25 b
26 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
27 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
28 123456 `echo v'-$a-\t-\\-\"-\x-\`-\--\z-\*-\?-'`
29 123456 $(echo v'-$a-\t-\\-\"-\x-\`-\--\z-\*-\?-')
30c\
31EOF2
32EOF2
33echo
34
35echo Quoted -heredoc:
36cat <<-"EOF3"
37a\
38 b
39a\\
40 b
41 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
42 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
43 123456 `echo v'-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-'`
44 123456 $(echo v'-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-')
45c\
46 EOF3
47# In -heredoc case the marker is detected even if it is indented.
48echo
49
50echo Unquoted -heredoc:
51cat <<-EOF4
52a\
53 b
54a\\
55 b
56 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
57 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
58 123456 `echo v'-$a-\t-\\-\"-\x-\`-\--\z-\*-\?-'`
59 123456 $(echo v'-$a-\t-\\-\"-\x-\`-\--\z-\*-\?-')
60c\
61EOF4
62 EOF4
63# The marker is not detected if preceding line ends in backslash.
64# TODO: marker should be detected even if it is split by line continuation:
65# EOF\
66# 4
67# but currently hush doesn't do it. (Tab before "4" is not allowed, though.)
68echo
69
70echo "Done: $?"
diff --git a/shell/ash_test/ash-heredoc/heredoc_bkslash_newline1.right b/shell/ash_test/ash-heredoc/heredoc_bkslash_newline1.right
new file mode 100644
index 000000000..fdb7ebd03
--- /dev/null
+++ b/shell/ash_test/ash-heredoc/heredoc_bkslash_newline1.right
@@ -0,0 +1,8 @@
1heredoc0
2Ok0:0
3heredoc1
4Ok1:0
5heredoc2
6Ok2:0
7heredoc3
8Ok4:0
diff --git a/shell/ash_test/ash-heredoc/heredoc_bkslash_newline1.tests b/shell/ash_test/ash-heredoc/heredoc_bkslash_newline1.tests
new file mode 100755
index 000000000..584edd0e4
--- /dev/null
+++ b/shell/ash_test/ash-heredoc/heredoc_bkslash_newline1.tests
@@ -0,0 +1,25 @@
1cat <\
2<\
3EOF
4heredoc0
5EOF
6echo Ok0:$?
7
8cat <<\
9 EOF
10heredoc1
11EOF
12echo Ok1:$?
13
14cat <<\
15- EOF
16heredoc2
17 EOF
18echo Ok2:$?
19
20cat <\
21<\
22- EOF
23heredoc3
24 EOF
25echo Ok4:$?
diff --git a/shell/ash_test/ash-parsing/bkslash_newline1.right b/shell/ash_test/ash-parsing/bkslash_newline1.right
new file mode 100644
index 000000000..97ea0c197
--- /dev/null
+++ b/shell/ash_test/ash-parsing/bkslash_newline1.right
@@ -0,0 +1,4 @@
1and1
2and2
3or1
4ok
diff --git a/shell/ash_test/ash-parsing/bkslash_newline1.tests b/shell/ash_test/ash-parsing/bkslash_newline1.tests
new file mode 100755
index 000000000..6e374c4fb
--- /dev/null
+++ b/shell/ash_test/ash-parsing/bkslash_newline1.tests
@@ -0,0 +1,8 @@
1echo and1 &\
2& echo and2
3
4echo or1 |\
5| echo NOT SHOWN
6
7case w in a) echo SKIP;\
8; w) echo ok;; esac;
diff --git a/shell/ash_test/ash-parsing/bkslash_newline2.right b/shell/ash_test/ash-parsing/bkslash_newline2.right
new file mode 100644
index 000000000..c863c5453
--- /dev/null
+++ b/shell/ash_test/ash-parsing/bkslash_newline2.right
@@ -0,0 +1,4 @@
1Line with one backslash:
2\
3
4Ok:0
diff --git a/shell/ash_test/ash-parsing/bkslash_newline2.tests b/shell/ash_test/ash-parsing/bkslash_newline2.tests
new file mode 100755
index 000000000..47d63042d
--- /dev/null
+++ b/shell/ash_test/ash-parsing/bkslash_newline2.tests
@@ -0,0 +1,4 @@
1echo Line with one backslash:
2echo '\
3'
4echo Ok:$?
diff --git a/shell/ash_test/ash-quoting/dollar_repl_slash_bash2.right b/shell/ash_test/ash-quoting/dollar_repl_slash_bash2.right
new file mode 100644
index 000000000..2aead7129
--- /dev/null
+++ b/shell/ash_test/ash-quoting/dollar_repl_slash_bash2.right
@@ -0,0 +1 @@
\/a\/bc\/def\/file
diff --git a/shell/ash_test/ash-quoting/dollar_repl_slash_bash2.tests b/shell/ash_test/ash-quoting/dollar_repl_slash_bash2.tests
new file mode 100755
index 000000000..64ca0c170
--- /dev/null
+++ b/shell/ash_test/ash-quoting/dollar_repl_slash_bash2.tests
@@ -0,0 +1,2 @@
1var="/a/bc/def/file"
2echo "${var//\//\\/}"
diff --git a/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_1.right b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_1.right
new file mode 100644
index 000000000..46ab7f5d1
--- /dev/null
+++ b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_1.right
@@ -0,0 +1,5 @@
1/proc/self/fd
2/proc/self/fd/0
3/proc/self/fd/1
4/proc/self/fd/2
5/proc/self/fd/3
diff --git a/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_1.tests b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_1.tests
new file mode 100755
index 000000000..544c810e3
--- /dev/null
+++ b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_1.tests
@@ -0,0 +1,6 @@
1# The "find" should not see "saved" (duplicated) fd #1
2# Explicitly use bbox find, since other implementations of "find"
3# may open other descriptors as well.
4busybox find /proc/self/fd >tmp_$$.out
5cat tmp_$$.out
6rm -f tmp_$$.out
diff --git a/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_2.right b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_2.right
new file mode 100644
index 000000000..46ab7f5d1
--- /dev/null
+++ b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_2.right
@@ -0,0 +1,5 @@
1/proc/self/fd
2/proc/self/fd/0
3/proc/self/fd/1
4/proc/self/fd/2
5/proc/self/fd/3
diff --git a/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_2.tests b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_2.tests
new file mode 100755
index 000000000..43777cade
--- /dev/null
+++ b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_2.tests
@@ -0,0 +1,6 @@
1# The "find" should not see "saved" (duplicated) fd #1
2# Explicitly use bbox find, since other implementations of "find"
3# may open other descriptors as well.
4{ busybox find /proc/self/fd; } >tmp_$$.out
5cat tmp_$$.out
6rm -f tmp_$$.out
diff --git a/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_3.right b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_3.right
new file mode 100644
index 000000000..46ab7f5d1
--- /dev/null
+++ b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_3.right
@@ -0,0 +1,5 @@
1/proc/self/fd
2/proc/self/fd/0
3/proc/self/fd/1
4/proc/self/fd/2
5/proc/self/fd/3
diff --git a/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_3.tests b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_3.tests
new file mode 100755
index 000000000..0a21173bd
--- /dev/null
+++ b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_3.tests
@@ -0,0 +1,6 @@
1# The "find" should not see "saved" (duplicated) fd #1
2# Explicitly use bbox find, since other implementations of "find"
3# may open other descriptors as well.
4{ busybox find /proc/self/fd; true; } >tmp_$$.out
5cat tmp_$$.out
6rm -f tmp_$$.out
diff --git a/shell/ash_test/ash-vars/var_LINENO1.right b/shell/ash_test/ash-vars/var_LINENO1.right
new file mode 100644
index 000000000..31e1a4478
--- /dev/null
+++ b/shell/ash_test/ash-vars/var_LINENO1.right
@@ -0,0 +1,8 @@
12:2
23:3
34:4
45:5
52:2
63:3
74:4
85:5
diff --git a/shell/ash_test/ash-vars/var_LINENO1.tests b/shell/ash_test/ash-vars/var_LINENO1.tests
new file mode 100755
index 000000000..775861e64
--- /dev/null
+++ b/shell/ash_test/ash-vars/var_LINENO1.tests
@@ -0,0 +1,6 @@
1env | grep ^LINENO
2echo 2:$LINENO
3echo 3:$LINENO >&2 \
4| { sleep 0.1; echo 4:$LINENO; }
5echo 5:$LINENO
6test "$1" || . ./var_LINENO1.tests norepeat
diff --git a/shell/hush.c b/shell/hush.c
index 6e64efb70..06fe0e405 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -1501,12 +1501,15 @@ static void free_strings(char **strings)
1501 free(strings); 1501 free(strings);
1502} 1502}
1503 1503
1504static int fcntl_F_DUPFD(int fd, int avoid_fd) 1504static int dup_CLOEXEC(int fd, int avoid_fd)
1505{ 1505{
1506 int newfd; 1506 int newfd;
1507 repeat: 1507 repeat:
1508 newfd = fcntl(fd, F_DUPFD, avoid_fd + 1); 1508 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
1509 if (newfd < 0) { 1509 if (newfd >= 0) {
1510 if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
1511 fcntl(newfd, F_SETFD, FD_CLOEXEC);
1512 } else { /* newfd < 0 */
1510 if (errno == EBUSY) 1513 if (errno == EBUSY)
1511 goto repeat; 1514 goto repeat;
1512 if (errno == EINTR) 1515 if (errno == EINTR)
@@ -2691,6 +2694,42 @@ static int i_peek2(struct in_str *i)
2691 return ch; 2694 return ch;
2692} 2695}
2693 2696
2697static int i_getch_and_eat_bkslash_nl(struct in_str *input)
2698{
2699 for (;;) {
2700 int ch, ch2;
2701
2702 ch = i_getch(input);
2703 if (ch != '\\')
2704 return ch;
2705 ch2 = i_peek(input);
2706 if (ch2 != '\n')
2707 return ch;
2708 /* backslash+newline, skip it */
2709 i_getch(input);
2710 }
2711}
2712
2713/* Note: this function _eats_ \<newline> pairs, safe to use plain
2714 * i_getch() after it instead of i_getch_and_eat_bkslash_nl().
2715 */
2716static int i_peek_and_eat_bkslash_nl(struct in_str *input)
2717{
2718 for (;;) {
2719 int ch, ch2;
2720
2721 ch = i_peek(input);
2722 if (ch != '\\')
2723 return ch;
2724 ch2 = i_peek2(input);
2725 if (ch2 != '\n')
2726 return ch;
2727 /* backslash+newline, skip it */
2728 i_getch(input);
2729 i_getch(input);
2730 }
2731}
2732
2694static void setup_file_in_str(struct in_str *i, FILE *f) 2733static void setup_file_in_str(struct in_str *i, FILE *f)
2695{ 2734{
2696 memset(i, 0, sizeof(*i)); 2735 memset(i, 0, sizeof(*i));
@@ -3119,7 +3158,7 @@ static int glob_brace(char *pattern, o_string *o, int n)
3119 return o_save_ptr_helper(o, n); 3158 return o_save_ptr_helper(o, n);
3120 } 3159 }
3121 if (gr == GLOB_NOSPACE) 3160 if (gr == GLOB_NOSPACE)
3122 bb_error_msg_and_die(bb_msg_memory_exhausted); 3161 bb_die_memory_exhausted();
3123 /* GLOB_ABORTED? Only happens with GLOB_ERR flag, 3162 /* GLOB_ABORTED? Only happens with GLOB_ERR flag,
3124 * but we didn't specify it. Paranoia again. */ 3163 * but we didn't specify it. Paranoia again. */
3125 bb_error_msg_and_die("glob error %d on '%s'", gr, pattern); 3164 bb_error_msg_and_die("glob error %d on '%s'", gr, pattern);
@@ -3221,7 +3260,7 @@ static int perform_glob(o_string *o, int n)
3221 goto literal; 3260 goto literal;
3222 } 3261 }
3223 if (gr == GLOB_NOSPACE) 3262 if (gr == GLOB_NOSPACE)
3224 bb_error_msg_and_die(bb_msg_memory_exhausted); 3263 bb_die_memory_exhausted();
3225 /* GLOB_ABORTED? Only happens with GLOB_ERR flag, 3264 /* GLOB_ABORTED? Only happens with GLOB_ERR flag,
3226 * but we didn't specify it. Paranoia again. */ 3265 * but we didn't specify it. Paranoia again. */
3227 bb_error_msg_and_die("glob error %d on '%s'", gr, pattern); 3266 bb_error_msg_and_die("glob error %d on '%s'", gr, pattern);
@@ -3812,16 +3851,28 @@ static int done_word(o_string *word, struct parse_context *ctx)
3812 if (ctx->pending_redirect) { 3851 if (ctx->pending_redirect) {
3813 /* We do not glob in e.g. >*.tmp case. bash seems to glob here 3852 /* We do not glob in e.g. >*.tmp case. bash seems to glob here
3814 * only if run as "bash", not "sh" */ 3853 * only if run as "bash", not "sh" */
3815 /* http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html 3854 /* http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
3816 * "2.7 Redirection 3855 * "2.7 Redirection
3817 * ...the word that follows the redirection operator 3856 * If the redirection operator is "<<" or "<<-", the word
3818 * shall be subjected to tilde expansion, parameter expansion, 3857 * that follows the redirection operator shall be
3819 * command substitution, arithmetic expansion, and quote 3858 * subjected to quote removal; it is unspecified whether
3820 * removal. Pathname expansion shall not be performed 3859 * any of the other expansions occur. For the other
3860 * redirection operators, the word that follows the
3861 * redirection operator shall be subjected to tilde
3862 * expansion, parameter expansion, command substitution,
3863 * arithmetic expansion, and quote removal.
3864 * Pathname expansion shall not be performed
3821 * on the word by a non-interactive shell; an interactive 3865 * on the word by a non-interactive shell; an interactive
3822 * shell may perform it, but shall do so only when 3866 * shell may perform it, but shall do so only when
3823 * the expansion would result in one word." 3867 * the expansion would result in one word."
3824 */ 3868 */
3869//bash does not do parameter/command substitution or arithmetic expansion
3870//for _heredoc_ redirection word: these constructs look for exact eof marker
3871// as written:
3872// <<EOF$t
3873// <<EOF$((1))
3874// <<EOF`true` [this case also makes heredoc "quoted", a-la <<"EOF". Probably bash-4.3.43 bug]
3875
3825 ctx->pending_redirect->rd_filename = xstrdup(word->data); 3876 ctx->pending_redirect->rd_filename = xstrdup(word->data);
3826 /* Cater for >\file case: 3877 /* Cater for >\file case:
3827 * >\a creates file a; >\\a, >"\a", >"\\a" create file \a 3878 * >\a creates file a; >\\a, >"\a", >"\\a" create file \a
@@ -4011,7 +4062,7 @@ static int parse_redirect(struct parse_context *ctx,
4011 if (dup_num == REDIRFD_SYNTAX_ERR) 4062 if (dup_num == REDIRFD_SYNTAX_ERR)
4012 return 1; 4063 return 1;
4013 } else { 4064 } else {
4014 int ch = i_peek(input); 4065 int ch = i_peek_and_eat_bkslash_nl(input);
4015 dup_num = (ch == '-'); /* HEREDOC_SKIPTABS bit is 1 */ 4066 dup_num = (ch == '-'); /* HEREDOC_SKIPTABS bit is 1 */
4016 if (dup_num) { /* <<-... */ 4067 if (dup_num) { /* <<-... */
4017 ch = i_getch(input); 4068 ch = i_getch(input);
@@ -4021,7 +4072,7 @@ static int parse_redirect(struct parse_context *ctx,
4021 } 4072 }
4022 4073
4023 if (style == REDIRECT_OVERWRITE && dup_num == REDIRFD_TO_FILE) { 4074 if (style == REDIRECT_OVERWRITE && dup_num == REDIRFD_TO_FILE) {
4024 int ch = i_peek(input); 4075 int ch = i_peek_and_eat_bkslash_nl(input);
4025 if (ch == '|') { 4076 if (ch == '|') {
4026 /* >|FILE redirect ("clobbering" >). 4077 /* >|FILE redirect ("clobbering" >).
4027 * Since we do not support "set -o noclobber" yet, 4078 * Since we do not support "set -o noclobber" yet,
@@ -4189,6 +4240,7 @@ static int fetch_heredocs(int heredoc_cnt, struct parse_context *ctx, struct in_
4189 4240
4190 redir->rd_type = REDIRECT_HEREDOC2; 4241 redir->rd_type = REDIRECT_HEREDOC2;
4191 /* redir->rd_dup is (ab)used to indicate <<- */ 4242 /* redir->rd_dup is (ab)used to indicate <<- */
4243bb_error_msg("redir->rd_filename:'%s'", redir->rd_filename);
4192 p = fetch_till_str(&ctx->as_string, input, 4244 p = fetch_till_str(&ctx->as_string, input,
4193 redir->rd_filename, redir->rd_dup); 4245 redir->rd_filename, redir->rd_dup);
4194 if (!p) { 4246 if (!p) {
@@ -4340,39 +4392,6 @@ static int parse_group(o_string *dest, struct parse_context *ctx,
4340 /* command remains "open", available for possible redirects */ 4392 /* command remains "open", available for possible redirects */
4341} 4393}
4342 4394
4343static int i_getch_and_eat_bkslash_nl(struct in_str *input)
4344{
4345 for (;;) {
4346 int ch, ch2;
4347
4348 ch = i_getch(input);
4349 if (ch != '\\')
4350 return ch;
4351 ch2 = i_peek(input);
4352 if (ch2 != '\n')
4353 return ch;
4354 /* backslash+newline, skip it */
4355 i_getch(input);
4356 }
4357}
4358
4359static int i_peek_and_eat_bkslash_nl(struct in_str *input)
4360{
4361 for (;;) {
4362 int ch, ch2;
4363
4364 ch = i_peek(input);
4365 if (ch != '\\')
4366 return ch;
4367 ch2 = i_peek2(input);
4368 if (ch2 != '\n')
4369 return ch;
4370 /* backslash+newline, skip it */
4371 i_getch(input);
4372 i_getch(input);
4373 }
4374}
4375
4376#if ENABLE_HUSH_TICK || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_DOLLAR_OPS 4395#if ENABLE_HUSH_TICK || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_DOLLAR_OPS
4377/* Subroutines for copying $(...) and `...` things */ 4396/* Subroutines for copying $(...) and `...` things */
4378static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote); 4397static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote);
@@ -4974,8 +4993,14 @@ static struct pipe *parse_stream(char **pstring,
4974 nommu_addchr(&ctx.as_string, ch); 4993 nommu_addchr(&ctx.as_string, ch);
4975 4994
4976 next = '\0'; 4995 next = '\0';
4977 if (ch != '\n') 4996 if (ch != '\n') {
4978 next = i_peek(input); 4997 next = i_peek(input);
4998 /* Can't use i_peek_and_eat_bkslash_nl(input) here:
4999 * echo '\
5000 * '
5001 * will break.
5002 */
5003 }
4979 5004
4980 is_special = "{}<>;&|()#'" /* special outside of "str" */ 5005 is_special = "{}<>;&|()#'" /* special outside of "str" */
4981 "\\$\"" IF_HUSH_TICK("`") /* always special */ 5006 "\\$\"" IF_HUSH_TICK("`") /* always special */
@@ -5178,6 +5203,8 @@ static struct pipe *parse_stream(char **pstring,
5178 goto parse_error; 5203 goto parse_error;
5179 } 5204 }
5180 redir_style = REDIRECT_OVERWRITE; 5205 redir_style = REDIRECT_OVERWRITE;
5206 if (next == '\\')
5207 next = i_peek_and_eat_bkslash_nl(input);
5181 if (next == '>') { 5208 if (next == '>') {
5182 redir_style = REDIRECT_APPEND; 5209 redir_style = REDIRECT_APPEND;
5183 ch = i_getch(input); 5210 ch = i_getch(input);
@@ -5198,6 +5225,8 @@ static struct pipe *parse_stream(char **pstring,
5198 goto parse_error; 5225 goto parse_error;
5199 } 5226 }
5200 redir_style = REDIRECT_INPUT; 5227 redir_style = REDIRECT_INPUT;
5228 if (next == '\\')
5229 next = i_peek_and_eat_bkslash_nl(input);
5201 if (next == '<') { 5230 if (next == '<') {
5202 redir_style = REDIRECT_HEREDOC; 5231 redir_style = REDIRECT_HEREDOC;
5203 heredoc_cnt++; 5232 heredoc_cnt++;
@@ -5365,7 +5394,7 @@ static struct pipe *parse_stream(char **pstring,
5365 /* Eat multiple semicolons, detect 5394 /* Eat multiple semicolons, detect
5366 * whether it means something special */ 5395 * whether it means something special */
5367 while (1) { 5396 while (1) {
5368 ch = i_peek(input); 5397 ch = i_peek_and_eat_bkslash_nl(input);
5369 if (ch != ';') 5398 if (ch != ';')
5370 break; 5399 break;
5371 ch = i_getch(input); 5400 ch = i_getch(input);
@@ -5387,6 +5416,8 @@ static struct pipe *parse_stream(char **pstring,
5387 if (done_word(&dest, &ctx)) { 5416 if (done_word(&dest, &ctx)) {
5388 goto parse_error; 5417 goto parse_error;
5389 } 5418 }
5419 if (next == '\\')
5420 next = i_peek_and_eat_bkslash_nl(input);
5390 if (next == '&') { 5421 if (next == '&') {
5391 ch = i_getch(input); 5422 ch = i_getch(input);
5392 nommu_addchr(&ctx.as_string, ch); 5423 nommu_addchr(&ctx.as_string, ch);
@@ -5403,6 +5434,8 @@ static struct pipe *parse_stream(char **pstring,
5403 if (ctx.ctx_res_w == RES_MATCH) 5434 if (ctx.ctx_res_w == RES_MATCH)
5404 break; /* we are in case's "word | word)" */ 5435 break; /* we are in case's "word | word)" */
5405#endif 5436#endif
5437 if (next == '\\')
5438 next = i_peek_and_eat_bkslash_nl(input);
5406 if (next == '|') { /* || */ 5439 if (next == '|') { /* || */
5407 ch = i_getch(input); 5440 ch = i_getch(input);
5408 nommu_addchr(&ctx.as_string, ch); 5441 nommu_addchr(&ctx.as_string, ch);
@@ -6123,7 +6156,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
6123 } else 6156 } else
6124 /* If EXP_FLAG_SINGLEWORD, we handle assignment 'a=....$@.....' 6157 /* If EXP_FLAG_SINGLEWORD, we handle assignment 'a=....$@.....'
6125 * and in this case should treat it like '$*' - see 'else...' below */ 6158 * and in this case should treat it like '$*' - see 'else...' below */
6126 if (first_ch == ('@'|0x80) /* quoted $@ */ 6159 if (first_ch == (char)('@'|0x80) /* quoted $@ */
6127 && !(output->o_expflags & EXP_FLAG_SINGLEWORD) /* not v="$@" case */ 6160 && !(output->o_expflags & EXP_FLAG_SINGLEWORD) /* not v="$@" case */
6128 ) { 6161 ) {
6129 while (1) { 6162 while (1) {
@@ -6890,7 +6923,7 @@ static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd)
6890 if (sq) for (; sq[i].orig_fd >= 0; i++) { 6923 if (sq) for (; sq[i].orig_fd >= 0; i++) {
6891 /* If we collide with an already moved fd... */ 6924 /* If we collide with an already moved fd... */
6892 if (fd == sq[i].moved_to) { 6925 if (fd == sq[i].moved_to) {
6893 sq[i].moved_to = fcntl_F_DUPFD(sq[i].moved_to, avoid_fd); 6926 sq[i].moved_to = dup_CLOEXEC(sq[i].moved_to, avoid_fd);
6894 debug_printf_redir("redirect_fd %d: already busy, moving to %d\n", fd, sq[i].moved_to); 6927 debug_printf_redir("redirect_fd %d: already busy, moving to %d\n", fd, sq[i].moved_to);
6895 if (sq[i].moved_to < 0) /* what? */ 6928 if (sq[i].moved_to < 0) /* what? */
6896 xfunc_die(); 6929 xfunc_die();
@@ -6904,7 +6937,7 @@ static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd)
6904 } 6937 }
6905 6938
6906 /* If this fd is open, we move and remember it; if it's closed, moved_to = -1 */ 6939 /* If this fd is open, we move and remember it; if it's closed, moved_to = -1 */
6907 moved_to = fcntl_F_DUPFD(fd, avoid_fd); 6940 moved_to = dup_CLOEXEC(fd, avoid_fd);
6908 debug_printf_redir("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, moved_to); 6941 debug_printf_redir("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, moved_to);
6909 if (moved_to < 0 && errno != EBADF) 6942 if (moved_to < 0 && errno != EBADF)
6910 xfunc_die(); 6943 xfunc_die();
@@ -7622,6 +7655,10 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
7622 */ 7655 */
7623 close_saved_fds_and_FILE_fds(); 7656 close_saved_fds_and_FILE_fds();
7624//FIXME: should also close saved redir fds 7657//FIXME: should also close saved redir fds
7658//This casuses test failures in
7659//redir_children_should_not_see_saved_fd_2.tests
7660//redir_children_should_not_see_saved_fd_3.tests
7661//if you replace "busybox find" with just "find" in them
7625 /* Without this, "rm -i FILE" can't be ^C'ed: */ 7662 /* Without this, "rm -i FILE" can't be ^C'ed: */
7626 switch_off_special_sigs(G.special_sig_mask); 7663 switch_off_special_sigs(G.special_sig_mask);
7627 debug_printf_exec("running applet '%s'\n", argv[0]); 7664 debug_printf_exec("running applet '%s'\n", argv[0]);
@@ -8166,6 +8203,12 @@ static NOINLINE int run_pipe(struct pipe *pi)
8166 rcode = 1; /* exitcode if redir failed */ 8203 rcode = 1; /* exitcode if redir failed */
8167 if (setup_redirects(command, &squirrel) == 0) { 8204 if (setup_redirects(command, &squirrel) == 0) {
8168 debug_printf_exec(": run_list\n"); 8205 debug_printf_exec(": run_list\n");
8206//FIXME: we need to pass squirrel down into run_list()
8207//for SH_STANDALONE case, or else this construct:
8208// { find /proc/self/fd; true; } >FILE; cmd2
8209//has no way of closing saved fd#1 for "find",
8210//and in SH_STANDALONE mode, "find" is not execed,
8211//therefore CLOEXEC on saved fd does not help.
8169 rcode = run_list(command->group) & 0xff; 8212 rcode = run_list(command->group) & 0xff;
8170 } 8213 }
8171 restore_redirects(squirrel); 8214 restore_redirects(squirrel);
@@ -9347,7 +9390,7 @@ int hush_main(int argc, char **argv)
9347 G_saved_tty_pgrp = 0; 9390 G_saved_tty_pgrp = 0;
9348 9391
9349 /* try to dup stdin to high fd#, >= 255 */ 9392 /* try to dup stdin to high fd#, >= 255 */
9350 G_interactive_fd = fcntl_F_DUPFD(STDIN_FILENO, 254); 9393 G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254);
9351 if (G_interactive_fd < 0) { 9394 if (G_interactive_fd < 0) {
9352 /* try to dup to any fd */ 9395 /* try to dup to any fd */
9353 G_interactive_fd = dup(STDIN_FILENO); 9396 G_interactive_fd = dup(STDIN_FILENO);
@@ -9420,10 +9463,10 @@ int hush_main(int argc, char **argv)
9420#elif ENABLE_HUSH_INTERACTIVE 9463#elif ENABLE_HUSH_INTERACTIVE
9421 /* No job control compiled in, only prompt/line editing */ 9464 /* No job control compiled in, only prompt/line editing */
9422 if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { 9465 if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) {
9423 G_interactive_fd = fcntl_F_DUPFD(STDIN_FILENO, 254); 9466 G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254);
9424 if (G_interactive_fd < 0) { 9467 if (G_interactive_fd < 0) {
9425 /* try to dup to any fd */ 9468 /* try to dup to any fd */
9426 G_interactive_fd = dup(STDIN_FILENO); 9469 G_interactive_fd = dup_CLOEXEC(STDIN_FILENO);
9427 if (G_interactive_fd < 0) 9470 if (G_interactive_fd < 0)
9428 /* give up */ 9471 /* give up */
9429 G_interactive_fd = 0; 9472 G_interactive_fd = 0;
diff --git a/shell/hush_test/hush-heredoc/heredoc_bkslash_newline1.right b/shell/hush_test/hush-heredoc/heredoc_bkslash_newline1.right
new file mode 100644
index 000000000..fdb7ebd03
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredoc_bkslash_newline1.right
@@ -0,0 +1,8 @@
1heredoc0
2Ok0:0
3heredoc1
4Ok1:0
5heredoc2
6Ok2:0
7heredoc3
8Ok4:0
diff --git a/shell/hush_test/hush-heredoc/heredoc_bkslash_newline1.tests b/shell/hush_test/hush-heredoc/heredoc_bkslash_newline1.tests
new file mode 100755
index 000000000..584edd0e4
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredoc_bkslash_newline1.tests
@@ -0,0 +1,25 @@
1cat <\
2<\
3EOF
4heredoc0
5EOF
6echo Ok0:$?
7
8cat <<\
9 EOF
10heredoc1
11EOF
12echo Ok1:$?
13
14cat <<\
15- EOF
16heredoc2
17 EOF
18echo Ok2:$?
19
20cat <\
21<\
22- EOF
23heredoc3
24 EOF
25echo Ok4:$?
diff --git a/shell/hush_test/hush-parsing/bkslash_newline1.right b/shell/hush_test/hush-parsing/bkslash_newline1.right
new file mode 100644
index 000000000..97ea0c197
--- /dev/null
+++ b/shell/hush_test/hush-parsing/bkslash_newline1.right
@@ -0,0 +1,4 @@
1and1
2and2
3or1
4ok
diff --git a/shell/hush_test/hush-parsing/bkslash_newline1.tests b/shell/hush_test/hush-parsing/bkslash_newline1.tests
new file mode 100755
index 000000000..6e374c4fb
--- /dev/null
+++ b/shell/hush_test/hush-parsing/bkslash_newline1.tests
@@ -0,0 +1,8 @@
1echo and1 &\
2& echo and2
3
4echo or1 |\
5| echo NOT SHOWN
6
7case w in a) echo SKIP;\
8; w) echo ok;; esac;
diff --git a/shell/hush_test/hush-parsing/bkslash_newline2.right b/shell/hush_test/hush-parsing/bkslash_newline2.right
new file mode 100644
index 000000000..c863c5453
--- /dev/null
+++ b/shell/hush_test/hush-parsing/bkslash_newline2.right
@@ -0,0 +1,4 @@
1Line with one backslash:
2\
3
4Ok:0
diff --git a/shell/hush_test/hush-parsing/bkslash_newline2.tests b/shell/hush_test/hush-parsing/bkslash_newline2.tests
new file mode 100755
index 000000000..47d63042d
--- /dev/null
+++ b/shell/hush_test/hush-parsing/bkslash_newline2.tests
@@ -0,0 +1,4 @@
1echo Line with one backslash:
2echo '\
3'
4echo Ok:$?
diff --git a/shell/hush_test/hush-quoting/dollar_repl_slash_bash2.right b/shell/hush_test/hush-quoting/dollar_repl_slash_bash2.right
new file mode 100644
index 000000000..2aead7129
--- /dev/null
+++ b/shell/hush_test/hush-quoting/dollar_repl_slash_bash2.right
@@ -0,0 +1 @@
\/a\/bc\/def\/file
diff --git a/shell/hush_test/hush-quoting/dollar_repl_slash_bash2.tests b/shell/hush_test/hush-quoting/dollar_repl_slash_bash2.tests
new file mode 100755
index 000000000..64ca0c170
--- /dev/null
+++ b/shell/hush_test/hush-quoting/dollar_repl_slash_bash2.tests
@@ -0,0 +1,2 @@
1var="/a/bc/def/file"
2echo "${var//\//\\/}"
diff --git a/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_1.right b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_1.right
new file mode 100644
index 000000000..46ab7f5d1
--- /dev/null
+++ b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_1.right
@@ -0,0 +1,5 @@
1/proc/self/fd
2/proc/self/fd/0
3/proc/self/fd/1
4/proc/self/fd/2
5/proc/self/fd/3
diff --git a/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_1.tests b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_1.tests
new file mode 100755
index 000000000..544c810e3
--- /dev/null
+++ b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_1.tests
@@ -0,0 +1,6 @@
1# The "find" should not see "saved" (duplicated) fd #1
2# Explicitly use bbox find, since other implementations of "find"
3# may open other descriptors as well.
4busybox find /proc/self/fd >tmp_$$.out
5cat tmp_$$.out
6rm -f tmp_$$.out
diff --git a/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_2.right b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_2.right
new file mode 100644
index 000000000..46ab7f5d1
--- /dev/null
+++ b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_2.right
@@ -0,0 +1,5 @@
1/proc/self/fd
2/proc/self/fd/0
3/proc/self/fd/1
4/proc/self/fd/2
5/proc/self/fd/3
diff --git a/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_2.tests b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_2.tests
new file mode 100755
index 000000000..43777cade
--- /dev/null
+++ b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_2.tests
@@ -0,0 +1,6 @@
1# The "find" should not see "saved" (duplicated) fd #1
2# Explicitly use bbox find, since other implementations of "find"
3# may open other descriptors as well.
4{ busybox find /proc/self/fd; } >tmp_$$.out
5cat tmp_$$.out
6rm -f tmp_$$.out
diff --git a/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_3.right b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_3.right
new file mode 100644
index 000000000..46ab7f5d1
--- /dev/null
+++ b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_3.right
@@ -0,0 +1,5 @@
1/proc/self/fd
2/proc/self/fd/0
3/proc/self/fd/1
4/proc/self/fd/2
5/proc/self/fd/3
diff --git a/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_3.tests b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_3.tests
new file mode 100755
index 000000000..0a21173bd
--- /dev/null
+++ b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_3.tests
@@ -0,0 +1,6 @@
1# The "find" should not see "saved" (duplicated) fd #1
2# Explicitly use bbox find, since other implementations of "find"
3# may open other descriptors as well.
4{ busybox find /proc/self/fd; true; } >tmp_$$.out
5cat tmp_$$.out
6rm -f tmp_$$.out
diff --git a/shell/hush_test/hush-vars/var_LINENO1.tests b/shell/hush_test/hush-vars/var_LINENO1.tests
index 851b52cf5..775861e64 100755
--- a/shell/hush_test/hush-vars/var_LINENO1.tests
+++ b/shell/hush_test/hush-vars/var_LINENO1.tests
@@ -1,4 +1,4 @@
1env | grep LINENO 1env | grep ^LINENO
2echo 2:$LINENO 2echo 2:$LINENO
3echo 3:$LINENO >&2 \ 3echo 3:$LINENO >&2 \
4| { sleep 0.1; echo 4:$LINENO; } 4| { sleep 0.1; echo 4:$LINENO; }
diff --git a/testsuite/grep.tests b/testsuite/grep.tests
index ed4ba455e..d0b0d2767 100755
--- a/testsuite/grep.tests
+++ b/testsuite/grep.tests
@@ -165,6 +165,12 @@ testing "grep -w word doesn't match wordword" \
165 "wordword\n" \ 165 "wordword\n" \
166 "" 166 ""
167 167
168testing "grep -F -w w doesn't match ww" \
169 "grep -F -w w input" \
170 "" \
171 "ww\n" \
172 ""
173
168testing "grep -w word match second word" \ 174testing "grep -w word match second word" \
169 "grep -w word input" \ 175 "grep -w word input" \
170 "bword,word\n""wordb,word\n""bwordb,word\n" \ 176 "bword,word\n""wordb,word\n""bwordb,word\n" \
diff --git a/util-linux/fstrim.c b/util-linux/fstrim.c
index 205d1e42b..558a94a9e 100644
--- a/util-linux/fstrim.c
+++ b/util-linux/fstrim.c
@@ -70,7 +70,9 @@ int fstrim_main(int argc UNUSED_PARAM, char **argv)
70 ; 70 ;
71#endif 71#endif
72 72
73 opts = getopt32long(argv, "^" "o:l:m:v" "\0" "=1", fstrim_longopts, 73 opts = getopt32long(argv, "^"
74 "o:l:m:v"
75 "\0" "=1", fstrim_longopts,
74 &arg_o, &arg_l, &arg_m 76 &arg_o, &arg_l, &arg_m
75 ); 77 );
76 78
@@ -85,15 +87,21 @@ int fstrim_main(int argc UNUSED_PARAM, char **argv)
85 range.minlen = xatoull_sfx(arg_m, kmg_i_suffixes); 87 range.minlen = xatoull_sfx(arg_m, kmg_i_suffixes);
86 88
87 mp = argv[optind]; 89 mp = argv[optind];
88 if (find_block_device(mp)) { 90//Wwhy bother checking that it's a blockdev?
91// if (find_block_device(mp)) {
89 fd = xopen_nonblocking(mp); 92 fd = xopen_nonblocking(mp);
93
94 /* On ENOTTY error, util-linux 2.31 says:
95 * "fstrim: FILE: the discard operation is not supported"
96 */
90 xioctl(fd, FITRIM, &range); 97 xioctl(fd, FITRIM, &range);
98
91 if (ENABLE_FEATURE_CLEAN_UP) 99 if (ENABLE_FEATURE_CLEAN_UP)
92 close(fd); 100 close(fd);
93 101
94 if (opts & OPT_v) 102 if (opts & OPT_v)
95 printf("%s: %llu bytes trimmed\n", mp, (unsigned long long)range.len); 103 printf("%s: %llu bytes trimmed\n", mp, (unsigned long long)range.len);
96 return EXIT_SUCCESS; 104 return EXIT_SUCCESS;
97 } 105// }
98 return EXIT_FAILURE; 106 return EXIT_FAILURE;
99} 107}