aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2018-02-13 09:44:44 +0000
committerRon Yorston <rmy@pobox.com>2018-02-13 09:44:44 +0000
commitdc19a361bd6c6df30338371532691bbc7f7126bb (patch)
tree1fb2cd646d54b5f8e425c4f11f3e09fc21d1966b
parent096aee2bb468d1ab044de36e176ed1f6c7e3674d (diff)
parent3459024bf404af814cacfe90a0deb719e282ae62 (diff)
downloadbusybox-w32-dc19a361bd6c6df30338371532691bbc7f7126bb.tar.gz
busybox-w32-dc19a361bd6c6df30338371532691bbc7f7126bb.tar.bz2
busybox-w32-dc19a361bd6c6df30338371532691bbc7f7126bb.zip
Merge branch 'busybox' into merge
-rw-r--r--Makefile2
-rw-r--r--Makefile.custom3
-rw-r--r--NOFORK_NOEXEC.lst6
-rwxr-xr-xNOFORK_NOEXEC.sh34
-rwxr-xr-xapplets/install.sh48
-rw-r--r--archival/bbunzip.c57
-rw-r--r--archival/bzip2.c60
-rw-r--r--archival/gzip.c425
-rw-r--r--archival/libarchive/bz/blocksort.c311
-rw-r--r--archival/libarchive/bz/bzlib.c20
-rw-r--r--archival/libarchive/bz/bzlib_private.h28
-rw-r--r--archival/libarchive/bz/compress.c329
-rw-r--r--archival/libarchive/bz/huffman.c4
-rw-r--r--archival/libarchive/decompress_gunzip.c17
-rw-r--r--archival/libarchive/decompress_unxz.c2
-rw-r--r--archival/libarchive/get_header_ar.c4
-rw-r--r--archival/libarchive/get_header_tar.c49
-rw-r--r--archival/libarchive/lzo1x_d.c3
-rw-r--r--archival/lzop.c13
-rw-r--r--archival/unzip.c4
-rw-r--r--configs/mingw32_defconfig14
-rw-r--r--configs/mingw64_defconfig14
-rw-r--r--coreutils/cat.c5
-rw-r--r--coreutils/chown.c4
-rw-r--r--coreutils/cksum.c47
-rw-r--r--coreutils/cp.c22
-rw-r--r--coreutils/dd.c44
-rw-r--r--coreutils/ls.c5
-rw-r--r--coreutils/mknod.c56
-rw-r--r--coreutils/mv.c3
-rw-r--r--coreutils/nice.c21
-rw-r--r--coreutils/od_bloaty.c10
-rw-r--r--coreutils/stat.c7
-rw-r--r--coreutils/uname.c6
-rw-r--r--debianutils/which.c16
-rw-r--r--docs/posix_conformance.txt5
-rw-r--r--editors/awk.c61
-rw-r--r--include/bb_archive.h15
-rw-r--r--include/libbb.h26
-rw-r--r--include/liblzo_interface.h6
-rw-r--r--init/init.c40
-rw-r--r--klibc-utils/nuke.c2
-rw-r--r--klibc-utils/resume.c2
-rw-r--r--klibc-utils/run-init.c2
-rw-r--r--libbb/Kbuild.src4
-rw-r--r--libbb/bb_getsockname.c19
-rw-r--r--libbb/crc32.c10
-rw-r--r--libbb/executable.c31
-rw-r--r--libbb/lineedit.c3
-rw-r--r--libbb/make_directory.c16
-rw-r--r--libbb/messages.c8
-rw-r--r--libbb/progress.c112
-rw-r--r--loginutils/addgroup.c7
-rw-r--r--mailutils/popmaildir.c4
-rwxr-xr-xmake_single_applets.sh3
-rw-r--r--miscutils/flash_eraseall.c2
-rw-r--r--miscutils/hexedit.c2
-rw-r--r--miscutils/less.c68
-rw-r--r--miscutils/nandwrite.c9
-rw-r--r--miscutils/setfattr.c2
-rw-r--r--networking/arping.c193
-rw-r--r--networking/ftpd.c14
-rw-r--r--networking/ftpgetput.c44
-rw-r--r--networking/inetd.c5
-rw-r--r--networking/libiproute/Kbuild.src6
-rw-r--r--networking/libiproute/ipaddress.c6
-rw-r--r--networking/libiproute/iplink.c4
-rw-r--r--networking/libiproute/ipneigh.c10
-rw-r--r--networking/libiproute/iproute.c4
-rw-r--r--networking/libiproute/iprule.c2
-rw-r--r--networking/libiproute/libnetlink.c7
-rw-r--r--networking/libiproute/ll_map.c2
-rw-r--r--networking/ntpd.c4
-rw-r--r--networking/parse_pasv_epsv.c66
-rw-r--r--networking/ssl_client.c14
-rw-r--r--networking/tc.c128
-rw-r--r--networking/tftp.c3
-rw-r--r--networking/tls.c98
-rw-r--r--networking/udhcp/Config.src2
-rw-r--r--networking/udhcp/d6_common.h1
-rw-r--r--networking/udhcp/d6_dhcpc.c246
-rw-r--r--networking/udhcp/d6_socket.c31
-rw-r--r--networking/udhcp/dhcpc.c8
-rw-r--r--networking/udhcp/dhcpd.c8
-rw-r--r--networking/udhcp/dhcprelay.c8
-rw-r--r--networking/wget.c278
-rw-r--r--procps/kill.c7
-rw-r--r--procps/mpstat.c2
-rw-r--r--procps/powertop.c2
-rw-r--r--runit/svlogd.c19
-rwxr-xr-xscripts/randomtest2
-rwxr-xr-xscripts/randomtest.loop1
-rw-r--r--shell/ash.c330
-rw-r--r--shell/ash_LINENO.patch498
-rw-r--r--shell/ash_test/ash-arith/arith-postinc.right5
-rwxr-xr-xshell/ash_test/ash-arith/arith-postinc.tests5
-rw-r--r--shell/ash_test/ash-arith/arith.right4
-rwxr-xr-xshell/ash_test/ash-arith/arith2.sub12
-rw-r--r--shell/ash_test/ash-misc/control_char1.right3
-rwxr-xr-xshell/ash_test/ash-misc/control_char1.tests3
-rw-r--r--shell/ash_test/ash-misc/control_char2.right2
-rwxr-xr-xshell/ash_test/ash-misc/control_char2.tests3
-rw-r--r--shell/ash_test/ash-misc/for_with_bslashes.right1
-rwxr-xr-xshell/ash_test/ash-misc/for_with_bslashes.tests8
-rw-r--r--shell/ash_test/ash-psubst/emptytick.right4
-rw-r--r--shell/ash_test/ash-quoting/mode_x.right4
-rw-r--r--shell/ash_test/ash-vars/param_expand_bash_substring.right1
-rwxr-xr-xshell/ash_test/ash-vars/param_expand_bash_substring.tests2
-rw-r--r--shell/ash_test/ash-vars/var_bash_repl_empty_pattern.right2
-rwxr-xr-xshell/ash_test/ash-vars/var_bash_repl_empty_pattern.tests3
-rw-r--r--shell/ash_test/ash-vars/var_bash_repl_empty_var.right2
-rwxr-xr-xshell/ash_test/ash-vars/var_bash_repl_empty_var.tests3
-rw-r--r--shell/hush.c385
-rw-r--r--shell/hush_test/hush-arith/arith-postinc.right5
-rwxr-xr-xshell/hush_test/hush-arith/arith-postinc.tests5
-rw-r--r--shell/hush_test/hush-arith/arith.right4
-rwxr-xr-xshell/hush_test/hush-arith/arith2.sub12
-rw-r--r--shell/hush_test/hush-misc/command2.right2
-rwxr-xr-xshell/hush_test/hush-misc/command2.tests6
-rw-r--r--shell/hush_test/hush-misc/control_char1.right3
-rwxr-xr-xshell/hush_test/hush-misc/control_char1.tests3
-rw-r--r--shell/hush_test/hush-misc/control_char2.right2
-rwxr-xr-xshell/hush_test/hush-misc/control_char2.tests3
-rw-r--r--shell/hush_test/hush-misc/for_with_bslashes.right1
-rwxr-xr-xshell/hush_test/hush-misc/for_with_bslashes.tests8
-rw-r--r--shell/hush_test/hush-vars/param_expand_bash_substring.right1
-rwxr-xr-xshell/hush_test/hush-vars/param_expand_bash_substring.tests2
-rw-r--r--shell/hush_test/hush-vars/var_LINENO1.right8
-rwxr-xr-xshell/hush_test/hush-vars/var_LINENO1.tests6
-rw-r--r--shell/hush_test/hush-vars/var_bash_repl_empty_pattern.right2
-rwxr-xr-xshell/hush_test/hush-vars/var_bash_repl_empty_pattern.tests3
-rw-r--r--shell/hush_test/hush-vars/var_bash_repl_empty_var.right2
-rwxr-xr-xshell/hush_test/hush-vars/var_bash_repl_empty_var.tests3
-rw-r--r--shell/math.c19
-rwxr-xr-xsize_single_applets.sh6
-rwxr-xr-xtestsuite/awk.tests19
-rwxr-xr-xtestsuite/busybox.tests16
-rwxr-xr-xtestsuite/bzcat.tests10
-rw-r--r--util-linux/cal.c3
-rw-r--r--util-linux/chrt.c55
-rw-r--r--util-linux/fdisk_gpt.c2
-rw-r--r--util-linux/renice.c15
-rw-r--r--util-linux/umount.c4
-rw-r--r--util-linux/volume_id/lfs.c62
-rw-r--r--util-linux/volume_id/volume_id.c3
-rw-r--r--util-linux/volume_id/volume_id_internal.h2
146 files changed, 2827 insertions, 2127 deletions
diff --git a/Makefile b/Makefile
index 5b31a41a6..7e9ead1e3 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
1VERSION = 1 1VERSION = 1
2PATCHLEVEL = 28 2PATCHLEVEL = 29
3SUBLEVEL = 0 3SUBLEVEL = 0
4EXTRAVERSION = .git 4EXTRAVERSION = .git
5NAME = Unnamed 5NAME = Unnamed
diff --git a/Makefile.custom b/Makefile.custom
index 891c9ced7..28d0ef7bc 100644
--- a/Makefile.custom
+++ b/Makefile.custom
@@ -46,6 +46,9 @@ ifeq ($(strip $(CONFIG_FEATURE_SUID)),y)
46 @echo 46 @echo
47endif 47endif
48 48
49install-noclobber: INSTALL_OPTS+=--noclobber
50install-noclobber: install
51
49uninstall: busybox.links 52uninstall: busybox.links
50 rm -f $(CONFIG_PREFIX)/bin/busybox 53 rm -f $(CONFIG_PREFIX)/bin/busybox
51 for i in `cat busybox.links` ; do rm -f $(CONFIG_PREFIX)$$i; done 54 for i in `cat busybox.links` ; do rm -f $(CONFIG_PREFIX)$$i; done
diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst
index 72c33ddd7..055f9fb24 100644
--- a/NOFORK_NOEXEC.lst
+++ b/NOFORK_NOEXEC.lst
@@ -72,7 +72,7 @@ brctl - noexec
72bunzip2 - runner 72bunzip2 - runner
73bzcat - runner 73bzcat - runner
74bzip2 - runner 74bzip2 - runner
75cal - runner: cal -n9999 75cal - noexec. can be runner: cal -n9999
76cat - runner: cat HUGEFILE 76cat - runner: cat HUGEFILE
77chat - longterm (when used as intended - talking to modem over stdin/out) 77chat - longterm (when used as intended - talking to modem over stdin/out)
78chattr - noexec. runner 78chattr - noexec. runner
@@ -89,7 +89,7 @@ clear - NOFORK
89cmp - runner 89cmp - runner
90comm - runner 90comm - runner
91conspy - interactive, longterm 91conspy - interactive, longterm
92cp - noexec. runner 92cp - noexec. sometimes runner
93cpio - runner 93cpio - runner
94crond - daemon 94crond - daemon
95crontab - longterm (runs $EDITOR), leaks: open+xasprintf 95crontab - longterm (runs $EDITOR), leaks: open+xasprintf
@@ -255,7 +255,7 @@ mount - suid
255mountpoint - noexec. leaks: option -n "print dev name": find_block_device -> readdir+xstrdup 255mountpoint - noexec. leaks: option -n "print dev name": find_block_device -> readdir+xstrdup
256mpstat - longterm: "mpstat 1" runs indefinitely 256mpstat - longterm: "mpstat 1" runs indefinitely
257mt - hardware 257mt - hardware
258mv - noexec candidate, runner 258mv - noexec. sometimes runner
259nameif - noexec. openlog(), leaks: config_open2+ioctl_or_perror_and_die 259nameif - noexec. openlog(), leaks: config_open2+ioctl_or_perror_and_die
260nbd-client - noexec 260nbd-client - noexec
261nc - runner 261nc - runner
diff --git a/NOFORK_NOEXEC.sh b/NOFORK_NOEXEC.sh
new file mode 100755
index 000000000..f4eeeef87
--- /dev/null
+++ b/NOFORK_NOEXEC.sh
@@ -0,0 +1,34 @@
1#!/bin/sh
2
3exec >NOFORK_NOEXEC.lst1
4
5false && grep -Fv 'NOFORK' NOFORK_NOEXEC.lst \
6| grep -v 'noexec.' | grep -v 'noexec$' \
7| grep -v ' suid' \
8| grep -v ' daemon' \
9| grep -v ' longterm' \
10| grep rare
11
12echo === nofork candidate
13grep -F 'nofork candidate' NOFORK_NOEXEC.lst \
14
15echo === noexec candidate
16grep -F 'noexec candidate' NOFORK_NOEXEC.lst \
17
18echo === ^C
19grep -F '^C' NOFORK_NOEXEC.lst \
20| grep -F ' - ' \
21
22echo === talks
23grep -F 'talks' NOFORK_NOEXEC.lst \
24| grep -F ' - ' \
25
26echo ===
27grep -Fv 'NOFORK' NOFORK_NOEXEC.lst \
28| grep '^[^ ][^ ]* - ' \
29| grep -v 'noexec.' | grep -v ' - noexec$' \
30| grep -v ' suid' \
31| grep -v ' daemon' \
32| grep -v 'longterm' \
33| grep -v 'interactive' \
34| grep -v 'hardware' \
diff --git a/applets/install.sh b/applets/install.sh
index f6c097e57..ae99381d7 100755
--- a/applets/install.sh
+++ b/applets/install.sh
@@ -8,6 +8,7 @@ if [ -z "$prefix" ]; then
8 echo "usage: applets/install.sh DESTINATION [--symlinks/--hardlinks/--binaries/--scriptwrapper]" 8 echo "usage: applets/install.sh DESTINATION [--symlinks/--hardlinks/--binaries/--scriptwrapper]"
9 exit 1 9 exit 1
10fi 10fi
11shift # Keep only remaining options
11 12
12# Source the configuration 13# Source the configuration
13. ./.config 14. ./.config
@@ -21,18 +22,21 @@ scriptwrapper="n"
21binaries="n" 22binaries="n"
22cleanup="0" 23cleanup="0"
23noclobber="0" 24noclobber="0"
24case "$2" in 25while [ ${#} -gt 0 ]; do
25 --hardlinks) linkopts="-f";; 26 case "$1" in
26 --symlinks) linkopts="-fs";; 27 --hardlinks) linkopts="-f";;
27 --binaries) binaries="y";; 28 --symlinks) linkopts="-fs";;
28 --scriptwrapper) scriptwrapper="y";swrapall="y";; 29 --binaries) binaries="y";;
29 --sw-sh-hard) scriptwrapper="y";linkopts="-f";; 30 --scriptwrapper) scriptwrapper="y"; swrapall="y";;
30 --sw-sh-sym) scriptwrapper="y";linkopts="-fs";; 31 --sw-sh-hard) scriptwrapper="y"; linkopts="-f";;
31 --cleanup) cleanup="1";; 32 --sw-sh-sym) scriptwrapper="y"; linkopts="-fs";;
32 --noclobber) noclobber="1";; 33 --cleanup) cleanup="1";;
33 "") h="";; 34 --noclobber) noclobber="1";;
34 *) echo "Unknown install option: $2"; exit 1;; 35 "") h="";;
35esac 36 *) echo "Unknown install option: $1"; exit 1;;
37 esac
38 shift
39done
36 40
37if [ -n "$DO_INSTALL_LIBS" ] && [ "$DO_INSTALL_LIBS" != "n" ]; then 41if [ -n "$DO_INSTALL_LIBS" ] && [ "$DO_INSTALL_LIBS" != "n" ]; then
38 # get the target dir for the libs 42 # get the target dir for the libs
@@ -77,6 +81,10 @@ install -m 755 busybox "$prefix/bin/busybox" || exit 1
77for i in $h; do 81for i in $h; do
78 appdir=`dirname "$i"` 82 appdir=`dirname "$i"`
79 app=`basename "$i"` 83 app=`basename "$i"`
84 if [ "$noclobber" = "1" ] && [ -e "$prefix/$i" ]; then
85 echo " $prefix/$i already exists"
86 continue
87 fi
80 mkdir -p "$prefix/$appdir" || exit 1 88 mkdir -p "$prefix/$appdir" || exit 1
81 if [ "$scriptwrapper" = "y" ]; then 89 if [ "$scriptwrapper" = "y" ]; then
82 if [ "$swrapall" != "y" ] && [ "$i" = "/bin/sh" ]; then 90 if [ "$swrapall" != "y" ] && [ "$i" = "/bin/sh" ]; then
@@ -90,12 +98,8 @@ for i in $h; do
90 elif [ "$binaries" = "y" ]; then 98 elif [ "$binaries" = "y" ]; then
91 # Copy the binary over rather 99 # Copy the binary over rather
92 if [ -e $sharedlib_dir/$app ]; then 100 if [ -e $sharedlib_dir/$app ]; then
93 if [ "$noclobber" = "0" ] || [ ! -e "$prefix/$i" ]; then 101 echo " Copying $sharedlib_dir/$app to $prefix/$i"
94 echo " Copying $sharedlib_dir/$app to $prefix/$i" 102 cp -pPR $sharedlib_dir/$app $prefix/$i || exit 1
95 cp -pPR $sharedlib_dir/$app $prefix/$i || exit 1
96 else
97 echo " $prefix/$i already exists"
98 fi
99 else 103 else
100 echo "Error: Could not find $sharedlib_dir/$app" 104 echo "Error: Could not find $sharedlib_dir/$app"
101 exit 1 105 exit 1
@@ -123,12 +127,8 @@ for i in $h; do
123 ;; 127 ;;
124 esac 128 esac
125 fi 129 fi
126 if [ "$noclobber" = "0" ] || [ ! -e "$prefix/$i" ]; then 130 echo " $prefix/$i -> $bb_path"
127 echo " $prefix/$i -> $bb_path" 131 ln $linkopts "$bb_path" "$prefix/$i" || exit 1
128 ln $linkopts "$bb_path" "$prefix/$i" || exit 1
129 else
130 echo " $prefix/$i already exists"
131 fi
132 fi 132 fi
133done 133done
134 134
diff --git a/archival/bbunzip.c b/archival/bbunzip.c
index 301170fd4..2d810d131 100644
--- a/archival/bbunzip.c
+++ b/archival/bbunzip.c
@@ -21,19 +21,6 @@
21#include "libbb.h" 21#include "libbb.h"
22#include "bb_archive.h" 22#include "bb_archive.h"
23 23
24/* Note: must be kept in sync with archival/lzop.c */
25enum {
26 OPT_STDOUT = 1 << 0,
27 OPT_FORCE = 1 << 1,
28 /* only some decompressors: */
29 OPT_KEEP = 1 << 2,
30 OPT_VERBOSE = 1 << 3,
31 OPT_QUIET = 1 << 4,
32 OPT_DECOMPRESS = 1 << 5,
33 OPT_TEST = 1 << 6,
34 SEAMLESS_MAGIC = (1 << 31) * ENABLE_ZCAT * SEAMLESS_COMPRESSION,
35};
36
37static 24static
38int open_to_or_warn(int to_fd, const char *filename, int flags, int mode) 25int open_to_or_warn(int to_fd, const char *filename, int flags, int mode)
39{ 26{
@@ -72,7 +59,7 @@ int FAST_FUNC bbunpack(char **argv,
72 59
73 /* Open src */ 60 /* Open src */
74 if (filename) { 61 if (filename) {
75 if (!(option_mask32 & SEAMLESS_MAGIC)) { 62 if (!(option_mask32 & BBUNPK_SEAMLESS_MAGIC)) {
76 if (stat(filename, &stat_buf) != 0) { 63 if (stat(filename, &stat_buf) != 0) {
77 err_name: 64 err_name:
78 bb_simple_perror_msg(filename); 65 bb_simple_perror_msg(filename);
@@ -91,15 +78,15 @@ int FAST_FUNC bbunpack(char **argv,
91 xmove_fd(fd, STDIN_FILENO); 78 xmove_fd(fd, STDIN_FILENO);
92 } 79 }
93 } else 80 } else
94 if (option_mask32 & SEAMLESS_MAGIC) { 81 if (option_mask32 & BBUNPK_SEAMLESS_MAGIC) {
95 /* "clever zcat" on stdin */ 82 /* "clever zcat" on stdin */
96 if (setup_unzip_on_fd(STDIN_FILENO, /*fail_if_not_compressed*/ 1)) 83 if (setup_unzip_on_fd(STDIN_FILENO, /*fail_if_not_compressed*/ 1))
97 goto err; 84 goto err;
98 } 85 }
99 86
100 /* Special cases: test, stdout */ 87 /* Special cases: test, stdout */
101 if (option_mask32 & (OPT_STDOUT|OPT_TEST)) { 88 if (option_mask32 & (BBUNPK_OPT_STDOUT|BBUNPK_OPT_TEST)) {
102 if (option_mask32 & OPT_TEST) 89 if (option_mask32 & BBUNPK_OPT_TEST)
103 if (open_to_or_warn(STDOUT_FILENO, bb_dev_null, O_WRONLY, 0)) 90 if (open_to_or_warn(STDOUT_FILENO, bb_dev_null, O_WRONLY, 0))
104 xfunc_die(); 91 xfunc_die();
105 filename = NULL; 92 filename = NULL;
@@ -114,7 +101,7 @@ int FAST_FUNC bbunpack(char **argv,
114 } 101 }
115 102
116 /* -f: overwrite existing output files */ 103 /* -f: overwrite existing output files */
117 if (option_mask32 & OPT_FORCE) { 104 if (option_mask32 & BBUNPK_OPT_FORCE) {
118 unlink(new_name); 105 unlink(new_name);
119 } 106 }
120 107
@@ -126,12 +113,12 @@ int FAST_FUNC bbunpack(char **argv,
126 } 113 }
127 114
128 /* Check that the input is sane */ 115 /* Check that the input is sane */
129 if (!(option_mask32 & OPT_FORCE) && isatty(STDIN_FILENO)) { 116 if (!(option_mask32 & BBUNPK_OPT_FORCE) && isatty(STDIN_FILENO)) {
130 bb_error_msg_and_die("compressed data not read from terminal, " 117 bb_error_msg_and_die("compressed data not read from terminal, "
131 "use -f to force it"); 118 "use -f to force it");
132 } 119 }
133 120
134 if (!(option_mask32 & SEAMLESS_MAGIC)) { 121 if (!(option_mask32 & BBUNPK_SEAMLESS_MAGIC)) {
135 init_transformer_state(&xstate); 122 init_transformer_state(&xstate);
136 /*xstate.signature_skipped = 0; - already is */ 123 /*xstate.signature_skipped = 0; - already is */
137 /*xstate.src_fd = STDIN_FILENO; - already is */ 124 /*xstate.src_fd = STDIN_FILENO; - already is */
@@ -145,7 +132,7 @@ int FAST_FUNC bbunpack(char **argv,
145 xfunc_die(); 132 xfunc_die();
146 } 133 }
147 134
148 if (!(option_mask32 & OPT_STDOUT)) 135 if (!(option_mask32 & BBUNPK_OPT_STDOUT))
149 xclose(STDOUT_FILENO); /* with error check! */ 136 xclose(STDOUT_FILENO); /* with error check! */
150 137
151 if (filename) { 138 if (filename) {
@@ -176,7 +163,7 @@ int FAST_FUNC bbunpack(char **argv,
176 } 163 }
177 /* Extreme bloat for gunzip compat */ 164 /* Extreme bloat for gunzip compat */
178 /* Some users do want this info... */ 165 /* Some users do want this info... */
179 if (ENABLE_DESKTOP && (option_mask32 & OPT_VERBOSE)) { 166 if (ENABLE_DESKTOP && (option_mask32 & BBUNPK_OPT_VERBOSE)) {
180 unsigned percent = status 167 unsigned percent = status
181 ? ((uoff_t)stat_buf.st_size * 100u / (unsigned long long)status) 168 ? ((uoff_t)stat_buf.st_size * 100u / (unsigned long long)status)
182 : 0; 169 : 0;
@@ -188,7 +175,7 @@ int FAST_FUNC bbunpack(char **argv,
188 } 175 }
189 /* Delete _source_ file */ 176 /* Delete _source_ file */
190 del = filename; 177 del = filename;
191 if (option_mask32 & OPT_KEEP) /* ... unless -k */ 178 if (option_mask32 & BBUNPK_OPT_KEEP) /* ... unless -k */
192 del = NULL; 179 del = NULL;
193 } 180 }
194 if (ENABLE_PLATFORM_MINGW32) 181 if (ENABLE_PLATFORM_MINGW32)
@@ -201,7 +188,7 @@ int FAST_FUNC bbunpack(char **argv,
201 } 188 }
202 } while (*argv && *++argv); 189 } while (*argv && *++argv);
203 190
204 if (option_mask32 & OPT_STDOUT) 191 if (option_mask32 & BBUNPK_OPT_STDOUT)
205 xclose(STDOUT_FILENO); /* with error check! */ 192 xclose(STDOUT_FILENO); /* with error check! */
206 193
207 return exitcode; 194 return exitcode;
@@ -391,9 +378,9 @@ int gunzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
391int gunzip_main(int argc UNUSED_PARAM, char **argv) 378int gunzip_main(int argc UNUSED_PARAM, char **argv)
392{ 379{
393#if ENABLE_FEATURE_GUNZIP_LONG_OPTIONS 380#if ENABLE_FEATURE_GUNZIP_LONG_OPTIONS
394 getopt32long(argv, "cfkvqdtn", gunzip_longopts); 381 getopt32long(argv, BBUNPK_OPTSTR "dtn", gunzip_longopts);
395#else 382#else
396 getopt32(argv, "cfkvqdtn"); 383 getopt32(argv, BBUNPK_OPTSTR "dtn");
397#endif 384#endif
398 argv += optind; 385 argv += optind;
399 386
@@ -402,7 +389,7 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv)
402 * But if seamless magic is enabled, then we are much more clever. 389 * But if seamless magic is enabled, then we are much more clever.
403 */ 390 */
404 if (ENABLE_ZCAT && (!ENABLE_GUNZIP || applet_name[1] == 'c')) 391 if (ENABLE_ZCAT && (!ENABLE_GUNZIP || applet_name[1] == 'c'))
405 option_mask32 |= OPT_STDOUT | SEAMLESS_MAGIC; 392 option_mask32 |= BBUNPK_OPT_STDOUT | BBUNPK_SEAMLESS_MAGIC;
406 393
407 return bbunpack(argv, unpack_gz_stream, make_new_name_gunzip, /*unused:*/ NULL); 394 return bbunpack(argv, unpack_gz_stream, make_new_name_gunzip, /*unused:*/ NULL);
408} 395}
@@ -455,10 +442,10 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv)
455int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 442int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
456int bunzip2_main(int argc UNUSED_PARAM, char **argv) 443int bunzip2_main(int argc UNUSED_PARAM, char **argv)
457{ 444{
458 getopt32(argv, "cfkvqdt"); 445 getopt32(argv, BBUNPK_OPTSTR "dt");
459 argv += optind; 446 argv += optind;
460 if (ENABLE_BZCAT && (!ENABLE_BUNZIP2 || applet_name[2] == 'c')) /* bzcat */ 447 if (ENABLE_BZCAT && (!ENABLE_BUNZIP2 || applet_name[2] == 'c')) /* bzcat */
461 option_mask32 |= OPT_STDOUT; 448 option_mask32 |= BBUNPK_OPT_STDOUT;
462 449
463 return bbunpack(argv, unpack_bz2_stream, make_new_name_generic, "bz2"); 450 return bbunpack(argv, unpack_bz2_stream, make_new_name_generic, "bz2");
464} 451}
@@ -528,15 +515,15 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv)
528int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 515int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
529int unlzma_main(int argc UNUSED_PARAM, char **argv) 516int unlzma_main(int argc UNUSED_PARAM, char **argv)
530{ 517{
531 IF_LZMA(int opts =) getopt32(argv, "cfkvqdt"); 518 IF_LZMA(int opts =) getopt32(argv, BBUNPK_OPTSTR "dt");
532# if ENABLE_LZMA 519# if ENABLE_LZMA
533 /* lzma without -d or -t? */ 520 /* lzma without -d or -t? */
534 if (applet_name[2] == 'm' && !(opts & (OPT_DECOMPRESS|OPT_TEST))) 521 if (applet_name[2] == 'm' && !(opts & (BBUNPK_OPT_DECOMPRESS|BBUNPK_OPT_TEST)))
535 bb_show_usage(); 522 bb_show_usage();
536# endif 523# endif
537 /* lzcat? */ 524 /* lzcat? */
538 if (ENABLE_LZCAT && applet_name[2] == 'c') 525 if (ENABLE_LZCAT && applet_name[2] == 'c')
539 option_mask32 |= OPT_STDOUT; 526 option_mask32 |= BBUNPK_OPT_STDOUT;
540 527
541 argv += optind; 528 argv += optind;
542 return bbunpack(argv, unpack_lzma_stream, make_new_name_generic, "lzma"); 529 return bbunpack(argv, unpack_lzma_stream, make_new_name_generic, "lzma");
@@ -596,15 +583,15 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv)
596int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 583int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
597int unxz_main(int argc UNUSED_PARAM, char **argv) 584int unxz_main(int argc UNUSED_PARAM, char **argv)
598{ 585{
599 IF_XZ(int opts =) getopt32(argv, "cfkvqdt"); 586 IF_XZ(int opts =) getopt32(argv, BBUNPK_OPTSTR "dt");
600# if ENABLE_XZ 587# if ENABLE_XZ
601 /* xz without -d or -t? */ 588 /* xz without -d or -t? */
602 if (applet_name[2] == '\0' && !(opts & (OPT_DECOMPRESS|OPT_TEST))) 589 if (applet_name[2] == '\0' && !(opts & (BBUNPK_OPT_DECOMPRESS|BBUNPK_OPT_TEST)))
603 bb_show_usage(); 590 bb_show_usage();
604# endif 591# endif
605 /* xzcat? */ 592 /* xzcat? */
606 if (ENABLE_XZCAT && applet_name[2] == 'c') 593 if (ENABLE_XZCAT && applet_name[2] == 'c')
607 option_mask32 |= OPT_STDOUT; 594 option_mask32 |= BBUNPK_OPT_STDOUT;
608 595
609 argv += optind; 596 argv += optind;
610 return bbunpack(argv, unpack_xz_stream, make_new_name_generic, "xz"); 597 return bbunpack(argv, unpack_xz_stream, make_new_name_generic, "xz");
diff --git a/archival/bzip2.c b/archival/bzip2.c
index d6fd9296d..357891ca3 100644
--- a/archival/bzip2.c
+++ b/archival/bzip2.c
@@ -19,6 +19,23 @@
19//config: Unless you have a specific application which requires bzip2, you 19//config: Unless you have a specific application which requires bzip2, you
20//config: should probably say N here. 20//config: should probably say N here.
21//config: 21//config:
22//config:config BZIP2_SMALL
23//config: int "Trade bytes for speed (0:fast, 9:small)"
24//config: default 8 # all "fast or small" options default to small
25//config: range 0 9
26//config: depends on BZIP2
27//config: help
28//config: Trade code size versus speed.
29//config: Approximate values with gcc-6.3.0 "bzip -9" compressing
30//config: linux-4.15.tar were:
31//config: value time (sec) code size (386)
32//config: 9 (smallest) 70.11 7687
33//config: 8 67.93 8091
34//config: 7 67.88 8405
35//config: 6 67.78 8624
36//config: 5 67.05 9427
37//config: 4-0 (fastest) 64.14 12083
38//config:
22//config:config FEATURE_BZIP2_DECOMPRESS 39//config:config FEATURE_BZIP2_DECOMPRESS
23//config: bool "Enable decompression" 40//config: bool "Enable decompression"
24//config: default y 41//config: default y
@@ -48,7 +65,11 @@
48#include "libbb.h" 65#include "libbb.h"
49#include "bb_archive.h" 66#include "bb_archive.h"
50 67
51#define CONFIG_BZIP2_FAST 1 68#if CONFIG_BZIP2_SMALL >= 4
69#define BZIP2_SPEED (9 - CONFIG_BZIP2_SMALL)
70#else
71#define BZIP2_SPEED 5
72#endif
52 73
53/* Speed test: 74/* Speed test:
54 * Compiled with gcc 4.2.1, run on Athlon 64 1800 MHz (512K L2 cache). 75 * Compiled with gcc 4.2.1, run on Athlon 64 1800 MHz (512K L2 cache).
@@ -56,7 +77,7 @@
56 * (time to compress gcc-4.2.1.tar is 126.4% compared to bbox). 77 * (time to compress gcc-4.2.1.tar is 126.4% compared to bbox).
57 * At SPEED 5 difference is 32.7%. 78 * At SPEED 5 difference is 32.7%.
58 * 79 *
59 * Test run of all CONFIG_BZIP2_FAST values on a 11Mb text file: 80 * Test run of all BZIP2_SPEED values on a 11Mb text file:
60 * Size Time (3 runs) 81 * Size Time (3 runs)
61 * 0: 10828 4.145 4.146 4.148 82 * 0: 10828 4.145 4.146 4.148
62 * 1: 11097 3.845 3.860 3.861 83 * 1: 11097 3.845 3.860 3.861
@@ -83,15 +104,13 @@
83/* No point in being shy and having very small buffer here. 104/* No point in being shy and having very small buffer here.
84 * bzip2 internal buffers are much bigger anyway, hundreds of kbytes. 105 * bzip2 internal buffers are much bigger anyway, hundreds of kbytes.
85 * If iobuf is several pages long, malloc() may use mmap, 106 * If iobuf is several pages long, malloc() may use mmap,
86 * making iobuf is page aligned and thus (maybe) have one memcpy less 107 * making iobuf page aligned and thus (maybe) have one memcpy less
87 * if kernel is clever enough. 108 * if kernel is clever enough.
88 */ 109 */
89enum { 110enum {
90 IOBUF_SIZE = 8 * 1024 111 IOBUF_SIZE = 8 * 1024
91}; 112};
92 113
93static uint8_t level;
94
95/* NB: compressStream() has to return -1 on errors, not die. 114/* NB: compressStream() has to return -1 on errors, not die.
96 * bbunpack() will correctly clean up in this case 115 * bbunpack() will correctly clean up in this case
97 * (delete incomplete .bz2 file) 116 * (delete incomplete .bz2 file)
@@ -143,6 +162,7 @@ static
143IF_DESKTOP(long long) int FAST_FUNC compressStream(transformer_state_t *xstate UNUSED_PARAM) 162IF_DESKTOP(long long) int FAST_FUNC compressStream(transformer_state_t *xstate UNUSED_PARAM)
144{ 163{
145 IF_DESKTOP(long long) int total; 164 IF_DESKTOP(long long) int total;
165 unsigned opt, level;
146 ssize_t count; 166 ssize_t count;
147 bz_stream bzs; /* it's small */ 167 bz_stream bzs; /* it's small */
148#define strm (&bzs) 168#define strm (&bzs)
@@ -151,6 +171,17 @@ IF_DESKTOP(long long) int FAST_FUNC compressStream(transformer_state_t *xstate U
151#define wbuf (iobuf + IOBUF_SIZE) 171#define wbuf (iobuf + IOBUF_SIZE)
152 172
153 iobuf = xmalloc(2 * IOBUF_SIZE); 173 iobuf = xmalloc(2 * IOBUF_SIZE);
174
175 opt = option_mask32 >> (BBUNPK_OPTSTRLEN IF_FEATURE_BZIP2_DECOMPRESS(+ 2) + 2);
176 /* skipped BBUNPK_OPTSTR, "dt" and "zs" bits */
177 opt |= 0x100; /* if nothing else, assume -9 */
178 level = 0;
179 for (;;) {
180 level++;
181 if (opt & 1) break;
182 opt >>= 1;
183 }
184
154 BZ2_bzCompressInit(strm, level); 185 BZ2_bzCompressInit(strm, level);
155 186
156 while (1) { 187 while (1) {
@@ -196,26 +227,19 @@ int bzip2_main(int argc UNUSED_PARAM, char **argv)
196 */ 227 */
197 228
198 opt = getopt32(argv, "^" 229 opt = getopt32(argv, "^"
199 /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */ 230 /* Must match BBUNPK_foo constants! */
200 "cfkv" IF_FEATURE_BZIP2_DECOMPRESS("dt") "123456789qzs" 231 BBUNPK_OPTSTR IF_FEATURE_BZIP2_DECOMPRESS("dt") "zs123456789"
201 "\0" "s2" /* -s means -2 (compatibility) */ 232 "\0" "s2" /* -s means -2 (compatibility) */
202 ); 233 );
203#if ENABLE_FEATURE_BZIP2_DECOMPRESS /* bunzip2_main may not be visible... */ 234#if ENABLE_FEATURE_BZIP2_DECOMPRESS /* bunzip2_main may not be visible... */
204 if (opt & 0x30) // -d and/or -t 235 if (opt & (BBUNPK_OPT_DECOMPRESS|BBUNPK_OPT_TEST)) /* -d and/or -t */
205 return bunzip2_main(argc, argv); 236 return bunzip2_main(argc, argv);
206 opt >>= 6;
207#else 237#else
208 opt >>= 4; 238 /* clear "decompress" and "test" bits (or bbunpack() can get confused) */
239 /* in !BZIP2_DECOMPRESS config, these bits are -zs and are unused */
240 option_mask32 = opt & ~(BBUNPK_OPT_DECOMPRESS|BBUNPK_OPT_TEST);
209#endif 241#endif
210 opt = (uint8_t)opt; /* isolate bits for -1..-8 */
211 opt |= 0x100; /* if nothing else, assume -9 */
212 level = 1;
213 while (!(opt & 1)) {
214 level++;
215 opt >>= 1;
216 }
217 242
218 argv += optind; 243 argv += optind;
219 option_mask32 &= 0xf; /* ignore all except -cfkv */
220 return bbunpack(argv, compressStream, append_ext, "bz2"); 244 return bbunpack(argv, compressStream, append_ext, "bz2");
221} 245}
diff --git a/archival/gzip.c b/archival/gzip.c
index ac6633044..c5a1fe9b4 100644
--- a/archival/gzip.c
+++ b/archival/gzip.c
@@ -15,21 +15,6 @@
15 * 15 *
16 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 16 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
17 */ 17 */
18/* big objects in bss:
19 * 00000020 b bl_count
20 * 00000074 b base_length
21 * 00000078 b base_dist
22 * 00000078 b static_dtree
23 * 0000009c b bl_tree
24 * 000000f4 b dyn_dtree
25 * 00000100 b length_code
26 * 00000200 b dist_code
27 * 0000023d b depth
28 * 00000400 b flag_buf
29 * 0000047a b heap
30 * 00000480 b static_ltree
31 * 000008f4 b dyn_ltree
32 */
33/* TODO: full support for -v for DESKTOP 18/* TODO: full support for -v for DESKTOP
34 * "/usr/bin/gzip -v a bogus aa" should say: 19 * "/usr/bin/gzip -v a bogus aa" should say:
35a: 85.1% -- replaced with a.gz 20a: 85.1% -- replaced with a.gz
@@ -108,12 +93,12 @@ aa: 85.1% -- replaced with aa.gz
108#include "libbb.h" 93#include "libbb.h"
109#include "bb_archive.h" 94#include "bb_archive.h"
110 95
111
112/* =========================================================================== 96/* ===========================================================================
113 */ 97 */
114//#define DEBUG 1 98//#define DEBUG 1
115/* Diagnostic functions */ 99/* Diagnostic functions */
116#ifdef DEBUG 100#ifdef DEBUG
101static int verbose;
117# define Assert(cond,msg) { if (!(cond)) bb_error_msg(msg); } 102# define Assert(cond,msg) { if (!(cond)) bb_error_msg(msg); }
118# define Trace(x) fprintf x 103# define Trace(x) fprintf x
119# define Tracev(x) {if (verbose) fprintf x; } 104# define Tracev(x) {if (verbose) fprintf x; }
@@ -129,7 +114,6 @@ aa: 85.1% -- replaced with aa.gz
129# define Tracecv(c,x) 114# define Tracecv(c,x)
130#endif 115#endif
131 116
132
133/* =========================================================================== 117/* ===========================================================================
134 */ 118 */
135#if CONFIG_GZIP_FAST == 0 119#if CONFIG_GZIP_FAST == 0
@@ -225,7 +209,6 @@ aa: 85.1% -- replaced with aa.gz
225# define MAX_SUFFIX 30 209# define MAX_SUFFIX 30
226#endif 210#endif
227 211
228
229/* =========================================================================== 212/* ===========================================================================
230 * Compile with MEDIUM_MEM to reduce the memory requirements or 213 * Compile with MEDIUM_MEM to reduce the memory requirements or
231 * with SMALL_MEM to use as little memory as possible. Use BIG_MEM if the 214 * with SMALL_MEM to use as little memory as possible. Use BIG_MEM if the
@@ -234,15 +217,14 @@ aa: 85.1% -- replaced with aa.gz
234 * affects the compression ratio. The compressed output 217 * affects the compression ratio. The compressed output
235 * is still correct, and might even be smaller in some cases. 218 * is still correct, and might even be smaller in some cases.
236 */ 219 */
237
238#ifdef SMALL_MEM 220#ifdef SMALL_MEM
239# define HASH_BITS 13 /* Number of bits used to hash strings */ 221# define HASH_BITS 13 /* Number of bits used to hash strings */
240#endif 222#endif
241#ifdef MEDIUM_MEM 223#ifdef MEDIUM_MEM
242# define HASH_BITS 14 224# define HASH_BITS 14
243#endif 225#endif
244#ifndef HASH_BITS 226#ifndef HASH_BITS
245# define HASH_BITS 15 227# define HASH_BITS 15
246 /* For portability to 16 bit machines, do not use values above 15. */ 228 /* For portability to 16 bit machines, do not use values above 15. */
247#endif 229#endif
248 230
@@ -255,7 +237,6 @@ aa: 85.1% -- replaced with aa.gz
255#endif 237#endif
256/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ 238/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
257 239
258
259/* =========================================================================== 240/* ===========================================================================
260 * These types are not really 'char', 'short' and 'long' 241 * These types are not really 'char', 'short' and 'long'
261 */ 242 */
@@ -312,46 +293,10 @@ enum {
312#endif /* ENABLE_FEATURE_GZIP_LEVELS */ 293#endif /* ENABLE_FEATURE_GZIP_LEVELS */
313}; 294};
314 295
315
316struct globals { 296struct globals {
297/* =========================================================================== */
298/* global buffers, allocated once */
317 299
318#if ENABLE_FEATURE_GZIP_LEVELS
319 unsigned max_chain_length;
320 unsigned max_lazy_match;
321 unsigned good_match;
322 unsigned nice_match;
323#define max_chain_length (G1.max_chain_length)
324#define max_lazy_match (G1.max_lazy_match)
325#define good_match (G1.good_match)
326#define nice_match (G1.nice_match)
327#endif
328
329 lng block_start;
330
331/* window position at the beginning of the current output block. Gets
332 * negative when the window is moved backwards.
333 */
334 unsigned ins_h; /* hash index of string to be inserted */
335
336#define H_SHIFT ((HASH_BITS+MIN_MATCH-1) / MIN_MATCH)
337/* Number of bits by which ins_h and del_h must be shifted at each
338 * input step. It must be such that after MIN_MATCH steps, the oldest
339 * byte no longer takes part in the hash key, that is:
340 * H_SHIFT * MIN_MATCH >= HASH_BITS
341 */
342
343 unsigned prev_length;
344
345/* Length of the best match at previous step. Matches not greater than this
346 * are discarded. This is used in the lazy match evaluation.
347 */
348
349 unsigned strstart; /* start of string to insert */
350 unsigned match_start; /* start of matching string */
351 unsigned lookahead; /* number of valid bytes ahead in window */
352
353/* ===========================================================================
354 */
355#define DECLARE(type, array, size) \ 300#define DECLARE(type, array, size) \
356 type * array 301 type * array
357#define ALLOC(type, array, size) \ 302#define ALLOC(type, array, size) \
@@ -359,8 +304,6 @@ struct globals {
359#define FREE(array) \ 304#define FREE(array) \
360 do { free(array); array = NULL; } while (0) 305 do { free(array); array = NULL; } while (0)
361 306
362 /* global buffers */
363
364 /* buffer for literals or lengths */ 307 /* buffer for literals or lengths */
365 /* DECLARE(uch, l_buf, LIT_BUFSIZE); */ 308 /* DECLARE(uch, l_buf, LIT_BUFSIZE); */
366 DECLARE(uch, l_buf, INBUFSIZ); 309 DECLARE(uch, l_buf, INBUFSIZ);
@@ -390,6 +333,46 @@ struct globals {
390 /* DECLARE(Pos, head, 1<<HASH_BITS); */ 333 /* DECLARE(Pos, head, 1<<HASH_BITS); */
391#define head (G1.prev + WSIZE) /* hash head (see deflate.c) */ 334#define head (G1.prev + WSIZE) /* hash head (see deflate.c) */
392 335
336/* =========================================================================== */
337/* all members below are zeroed out in pack_gzip() for each next file */
338
339 uint32_t crc; /* shift register contents */
340 /*uint32_t *crc_32_tab;*/
341
342#if ENABLE_FEATURE_GZIP_LEVELS
343 unsigned max_chain_length;
344 unsigned max_lazy_match;
345 unsigned good_match;
346 unsigned nice_match;
347#define max_chain_length (G1.max_chain_length)
348#define max_lazy_match (G1.max_lazy_match)
349#define good_match (G1.good_match)
350#define nice_match (G1.nice_match)
351#endif
352
353/* window position at the beginning of the current output block. Gets
354 * negative when the window is moved backwards.
355 */
356 lng block_start;
357
358 unsigned ins_h; /* hash index of string to be inserted */
359
360/* Number of bits by which ins_h and del_h must be shifted at each
361 * input step. It must be such that after MIN_MATCH steps, the oldest
362 * byte no longer takes part in the hash key, that is:
363 * H_SHIFT * MIN_MATCH >= HASH_BITS
364 */
365#define H_SHIFT ((HASH_BITS+MIN_MATCH-1) / MIN_MATCH)
366
367/* Length of the best match at previous step. Matches not greater than this
368 * are discarded. This is used in the lazy match evaluation.
369 */
370 unsigned prev_length;
371
372 unsigned strstart; /* start of string to insert */
373 unsigned match_start; /* start of matching string */
374 unsigned lookahead; /* number of valid bytes ahead in window */
375
393/* number of input bytes */ 376/* number of input bytes */
394 ulg isize; /* only 32 bits stored in .gz file */ 377 ulg isize; /* only 32 bits stored in .gz file */
395 378
@@ -401,40 +384,35 @@ struct globals {
401 unsigned insize; /* valid bytes in l_buf */ 384 unsigned insize; /* valid bytes in l_buf */
402#endif 385#endif
403 unsigned outcnt; /* bytes in output buffer */ 386 unsigned outcnt; /* bytes in output buffer */
404
405 smallint eofile; /* flag set at end of input file */ 387 smallint eofile; /* flag set at end of input file */
406 388
407/* =========================================================================== 389/* ===========================================================================
408 * Local data used by the "bit string" routines. 390 * Local data used by the "bit string" routines.
409 */ 391 */
410 392
411 unsigned short bi_buf;
412
413/* Output buffer. bits are inserted starting at the bottom (least significant 393/* Output buffer. bits are inserted starting at the bottom (least significant
414 * bits). 394 * bits).
415 */ 395 */
396 unsigned bi_buf; /* was unsigned short */
416 397
417#undef BUF_SIZE 398#undef BUF_SIZE
418#define BUF_SIZE (8 * sizeof(G1.bi_buf)) 399#define BUF_SIZE (int)(8 * sizeof(G1.bi_buf))
400
419/* Number of bits used within bi_buf. (bi_buf might be implemented on 401/* Number of bits used within bi_buf. (bi_buf might be implemented on
420 * more than 16 bits on some systems.) 402 * more than 16 bits on some systems.)
421 */ 403 */
422 404 unsigned bi_valid;
423 int bi_valid;
424
425/* Current input function. Set to mem_read for in-memory compression */
426 405
427#ifdef DEBUG 406#ifdef DEBUG
428 ulg bits_sent; /* bit length of the compressed data */ 407 ulg bits_sent; /* bit length of the compressed data */
408# define DEBUG_bits_sent(v) (void)(G1.bits_sent v)
409#else
410# define DEBUG_bits_sent(v) ((void)0)
429#endif 411#endif
430
431 /*uint32_t *crc_32_tab;*/
432 uint32_t crc; /* shift register contents */
433}; 412};
434 413
435#define G1 (*(ptr_to_globals - 1)) 414#define G1 (*(ptr_to_globals - 1))
436 415
437
438/* =========================================================================== 416/* ===========================================================================
439 * Write the output buffer outbuf[0..outcnt-1] and update bytes_out. 417 * Write the output buffer outbuf[0..outcnt-1] and update bytes_out.
440 * (used for the compressed data only) 418 * (used for the compressed data only)
@@ -448,7 +426,6 @@ static void flush_outbuf(void)
448 G1.outcnt = 0; 426 G1.outcnt = 0;
449} 427}
450 428
451
452/* =========================================================================== 429/* ===========================================================================
453 */ 430 */
454/* put_8bit is used for the compressed output */ 431/* put_8bit is used for the compressed output */
@@ -473,12 +450,13 @@ static void put_16bit(ush w)
473 if (outcnt < OUTBUFSIZ-2) { 450 if (outcnt < OUTBUFSIZ-2) {
474 /* Common case */ 451 /* Common case */
475 ush *dst16 = (void*) dst; 452 ush *dst16 = (void*) dst;
476 *dst16 = w; /* unalinged LSB 16-bit store */ 453 *dst16 = w; /* unaligned LSB 16-bit store */
477 G1.outcnt = outcnt + 2; 454 G1.outcnt = outcnt + 2;
478 return; 455 return;
479 } 456 }
480 *dst = (uch)w; 457 *dst = (uch)w;
481 w >>= 8; 458 w >>= 8;
459 G1.outcnt = ++outcnt;
482#else 460#else
483 *dst = (uch)w; 461 *dst = (uch)w;
484 w >>= 8; 462 w >>= 8;
@@ -488,20 +466,38 @@ static void put_16bit(ush w)
488 G1.outcnt = outcnt + 2; 466 G1.outcnt = outcnt + 2;
489 return; 467 return;
490 } 468 }
469 G1.outcnt = ++outcnt;
491#endif 470#endif
492 471
493 /* Slowpath: we will need to do flush_outbuf() */ 472 /* Slowpath: we will need to do flush_outbuf() */
494 G1.outcnt = ++outcnt;
495 if (outcnt == OUTBUFSIZ) 473 if (outcnt == OUTBUFSIZ)
496 flush_outbuf(); 474 flush_outbuf(); /* here */
497 put_8bit(w); 475 put_8bit(w); /* or here */
498} 476}
499 477
478#define OPTIMIZED_PUT_32BIT (CONFIG_GZIP_FAST > 0 && BB_UNALIGNED_MEMACCESS_OK && BB_LITTLE_ENDIAN)
500static void put_32bit(ulg n) 479static void put_32bit(ulg n)
501{ 480{
481 if (OPTIMIZED_PUT_32BIT) {
482 unsigned outcnt = G1.outcnt;
483 if (outcnt < OUTBUFSIZ-4) {
484 /* Common case */
485 ulg *dst32 = (void*) &G1.outbuf[outcnt];
486 *dst32 = n; /* unaligned LSB 32-bit store */
487 //bb_error_msg("%p", dst32); // store alignment debugging
488 G1.outcnt = outcnt + 4;
489 return;
490 }
491 }
502 put_16bit(n); 492 put_16bit(n);
503 put_16bit(n >> 16); 493 put_16bit(n >> 16);
504} 494}
495static ALWAYS_INLINE void flush_outbuf_if_32bit_optimized(void)
496{
497 /* If put_32bit() performs 32bit stores && it is used in send_bits() */
498 if (OPTIMIZED_PUT_32BIT && BUF_SIZE > 16)
499 flush_outbuf();
500}
505 501
506/* =========================================================================== 502/* ===========================================================================
507 * Run a set of bytes through the crc shift register. If s is a NULL 503 * Run a set of bytes through the crc shift register. If s is a NULL
@@ -513,7 +509,6 @@ static void updcrc(uch * s, unsigned n)
513 G1.crc = crc32_block_endian0(G1.crc, s, n, global_crc32_table /*G1.crc_32_tab*/); 509 G1.crc = crc32_block_endian0(G1.crc, s, n, global_crc32_table /*G1.crc_32_tab*/);
514} 510}
515 511
516
517/* =========================================================================== 512/* ===========================================================================
518 * Read a new buffer from the current input file, perform end-of-line 513 * Read a new buffer from the current input file, perform end-of-line
519 * translation, and update the crc and input file size. 514 * translation, and update the crc and input file size.
@@ -534,34 +529,45 @@ static unsigned file_read(void *buf, unsigned size)
534 return len; 529 return len;
535} 530}
536 531
537
538/* =========================================================================== 532/* ===========================================================================
539 * Send a value on a given number of bits. 533 * Send a value on a given number of bits.
540 * IN assertion: length <= 16 and value fits in length bits. 534 * IN assertion: length <= 16 and value fits in length bits.
541 */ 535 */
542static void send_bits(int value, int length) 536static void send_bits(unsigned value, unsigned length)
543{ 537{
538 unsigned new_buf;
539
544#ifdef DEBUG 540#ifdef DEBUG
545 Tracev((stderr, " l %2d v %4x ", length, value)); 541 Tracev((stderr, " l %2d v %4x ", length, value));
546 Assert(length > 0 && length <= 15, "invalid length"); 542 Assert(length > 0 && length <= 15, "invalid length");
547 G1.bits_sent += length; 543 DEBUG_bits_sent(+= length);
548#endif 544#endif
549 /* If not enough room in bi_buf, use (valid) bits from bi_buf and 545 BUILD_BUG_ON(BUF_SIZE != 32 && BUF_SIZE != 16);
550 * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) 546
551 * unused bits in value. 547 new_buf = G1.bi_buf | (value << G1.bi_valid);
552 */ 548 /* NB: the above may sometimes do "<< 32" shift (undefined)
553 if (G1.bi_valid > (int) BUF_SIZE - length) { 549 * if check below is changed to "length > BUF_SIZE" instead of >= */
554 G1.bi_buf |= (value << G1.bi_valid); 550 length += G1.bi_valid;
555 put_16bit(G1.bi_buf); 551
556 G1.bi_buf = (ush) value >> (BUF_SIZE - G1.bi_valid); 552 /* If bi_buf is full */
557 G1.bi_valid += length - BUF_SIZE; 553 if (length >= BUF_SIZE) {
558 } else { 554 /* ...use (valid) bits from bi_buf and
559 G1.bi_buf |= value << G1.bi_valid; 555 * (BUF_SIZE - bi_valid) bits from value,
560 G1.bi_valid += length; 556 * leaving (width - (BUF_SIZE-bi_valid)) unused bits in value.
557 */
558 value >>= (BUF_SIZE - G1.bi_valid);
559 if (BUF_SIZE == 32) {
560 put_32bit(new_buf);
561 } else { /* 16 */
562 put_16bit(new_buf);
563 }
564 new_buf = value;
565 length -= BUF_SIZE;
561 } 566 }
567 G1.bi_buf = new_buf;
568 G1.bi_valid = length;
562} 569}
563 570
564
565/* =========================================================================== 571/* ===========================================================================
566 * Reverse the first len bits of a code, using straightforward code (a faster 572 * Reverse the first len bits of a code, using straightforward code (a faster
567 * method would use a table) 573 * method would use a table)
@@ -579,25 +585,24 @@ static unsigned bi_reverse(unsigned code, int len)
579 } 585 }
580} 586}
581 587
582
583/* =========================================================================== 588/* ===========================================================================
584 * Write out any remaining bits in an incomplete byte. 589 * Write out any remaining bits in an incomplete byte.
585 */ 590 */
586static void bi_windup(void) 591static void bi_windup(void)
587{ 592{
588 if (G1.bi_valid > 8) { 593 unsigned bits = G1.bi_buf;
589 put_16bit(G1.bi_buf); 594 int cnt = G1.bi_valid;
590 } else if (G1.bi_valid > 0) { 595
591 put_8bit(G1.bi_buf); 596 while (cnt > 0) {
597 put_8bit(bits);
598 bits >>= 8;
599 cnt -= 8;
592 } 600 }
593 G1.bi_buf = 0; 601 G1.bi_buf = 0;
594 G1.bi_valid = 0; 602 G1.bi_valid = 0;
595#ifdef DEBUG 603 DEBUG_bits_sent(= (G1.bits_sent + 7) & ~7);
596 G1.bits_sent = (G1.bits_sent + 7) & ~7;
597#endif
598} 604}
599 605
600
601/* =========================================================================== 606/* ===========================================================================
602 * Copy a stored block to the zip file, storing first the length and its 607 * Copy a stored block to the zip file, storing first the length and its
603 * one's complement if requested. 608 * one's complement if requested.
@@ -607,21 +612,19 @@ static void copy_block(char *buf, unsigned len, int header)
607 bi_windup(); /* align on byte boundary */ 612 bi_windup(); /* align on byte boundary */
608 613
609 if (header) { 614 if (header) {
610 put_16bit(len); 615 unsigned v = ((uint16_t)len) | ((~len) << 16);
611 put_16bit(~len); 616 put_32bit(v);
612#ifdef DEBUG 617 DEBUG_bits_sent(+= 2 * 16);
613 G1.bits_sent += 2 * 16;
614#endif
615 } 618 }
616#ifdef DEBUG 619 DEBUG_bits_sent(+= (ulg) len << 3);
617 G1.bits_sent += (ulg) len << 3;
618#endif
619 while (len--) { 620 while (len--) {
620 put_8bit(*buf++); 621 put_8bit(*buf++);
621 } 622 }
623 /* The above can 32-bit misalign outbuf */
624 if (G1.outcnt & 3) /* syscalls are expensive, is it really misaligned? */
625 flush_outbuf_if_32bit_optimized();
622} 626}
623 627
624
625/* =========================================================================== 628/* ===========================================================================
626 * Fill the window when the lookahead becomes insufficient. 629 * Fill the window when the lookahead becomes insufficient.
627 * Updates strstart and lookahead, and sets eofile if end of input file. 630 * Updates strstart and lookahead, and sets eofile if end of input file.
@@ -679,7 +682,12 @@ static void fill_window(void)
679 } 682 }
680 } 683 }
681} 684}
682 685/* Both users fill window with the same loop: */
686static void fill_window_if_needed(void)
687{
688 while (G1.lookahead < MIN_LOOKAHEAD && !G1.eofile)
689 fill_window();
690}
683 691
684/* =========================================================================== 692/* ===========================================================================
685 * Set match_start to the longest match starting at the given string and 693 * Set match_start to the longest match starting at the given string and
@@ -770,7 +778,6 @@ static int longest_match(IPos cur_match)
770 return best_len; 778 return best_len;
771} 779}
772 780
773
774#ifdef DEBUG 781#ifdef DEBUG
775/* =========================================================================== 782/* ===========================================================================
776 * Check that the match at match_start is indeed a match. 783 * Check that the match at match_start is indeed a match.
@@ -1049,24 +1056,14 @@ struct globals2 {
1049 ulg opt_len; /* bit length of current block with optimal trees */ 1056 ulg opt_len; /* bit length of current block with optimal trees */
1050 ulg static_len; /* bit length of current block with static trees */ 1057 ulg static_len; /* bit length of current block with static trees */
1051 1058
1052 ulg compressed_len; /* total bit length of compressed file */ 1059// ulg compressed_len; /* total bit length of compressed file */
1053}; 1060};
1054 1061
1055#define G2ptr ((struct globals2*)(ptr_to_globals)) 1062#define G2ptr ((struct globals2*)(ptr_to_globals))
1056#define G2 (*G2ptr) 1063#define G2 (*G2ptr)
1057 1064
1058
1059/* =========================================================================== 1065/* ===========================================================================
1060 */ 1066 */
1061static void gen_codes(ct_data * tree, int max_code);
1062static void build_tree(tree_desc * desc);
1063static void scan_tree(ct_data * tree, int max_code);
1064static void send_tree(ct_data * tree, int max_code);
1065static int build_bl_tree(void);
1066static void send_all_trees(int lcodes, int dcodes, int blcodes);
1067static void compress_block(ct_data * ltree, ct_data * dtree);
1068
1069
1070#ifndef DEBUG 1067#ifndef DEBUG
1071/* Send a code of the given tree. c and tree must not have side effects */ 1068/* Send a code of the given tree. c and tree must not have side effects */
1072# define SEND_CODE(c, tree) send_bits(tree[c].Code, tree[c].Len) 1069# define SEND_CODE(c, tree) send_bits(tree[c].Code, tree[c].Len)
@@ -1086,7 +1083,6 @@ static void compress_block(ct_data * ltree, ct_data * dtree);
1086 * The arguments must not have side effects. 1083 * The arguments must not have side effects.
1087 */ 1084 */
1088 1085
1089
1090/* =========================================================================== 1086/* ===========================================================================
1091 * Initialize a new block. 1087 * Initialize a new block.
1092 */ 1088 */
@@ -1109,7 +1105,6 @@ static void init_block(void)
1109 G2.flag_bit = 1; 1105 G2.flag_bit = 1;
1110} 1106}
1111 1107
1112
1113/* =========================================================================== 1108/* ===========================================================================
1114 * Restore the heap property by moving down the tree starting at node k, 1109 * Restore the heap property by moving down the tree starting at node k,
1115 * exchanging a node with the smallest of its two sons if necessary, stopping 1110 * exchanging a node with the smallest of its two sons if necessary, stopping
@@ -1147,7 +1142,6 @@ static void pqdownheap(ct_data * tree, int k)
1147 G2.heap[k] = v; 1142 G2.heap[k] = v;
1148} 1143}
1149 1144
1150
1151/* =========================================================================== 1145/* ===========================================================================
1152 * Compute the optimal bit lengths for a tree and update the total bit length 1146 * Compute the optimal bit lengths for a tree and update the total bit length
1153 * for the current block. 1147 * for the current block.
@@ -1245,7 +1239,6 @@ static void gen_bitlen(tree_desc * desc)
1245 } 1239 }
1246} 1240}
1247 1241
1248
1249/* =========================================================================== 1242/* ===========================================================================
1250 * Generate the codes for a given tree and bit counts (which need not be 1243 * Generate the codes for a given tree and bit counts (which need not be
1251 * optimal). 1244 * optimal).
@@ -1289,7 +1282,6 @@ static void gen_codes(ct_data * tree, int max_code)
1289 } 1282 }
1290} 1283}
1291 1284
1292
1293/* =========================================================================== 1285/* ===========================================================================
1294 * Construct one Huffman tree and assigns the code bit strings and lengths. 1286 * Construct one Huffman tree and assigns the code bit strings and lengths.
1295 * Update the total bit length for the current block. 1287 * Update the total bit length for the current block.
@@ -1396,7 +1388,6 @@ static void build_tree(tree_desc * desc)
1396 gen_codes((ct_data *) tree, max_code); 1388 gen_codes((ct_data *) tree, max_code);
1397} 1389}
1398 1390
1399
1400/* =========================================================================== 1391/* ===========================================================================
1401 * Scan a literal or distance tree to determine the frequencies of the codes 1392 * Scan a literal or distance tree to determine the frequencies of the codes
1402 * in the bit length tree. Updates opt_len to take into account the repeat 1393 * in the bit length tree. Updates opt_len to take into account the repeat
@@ -1451,7 +1442,6 @@ static void scan_tree(ct_data * tree, int max_code)
1451 } 1442 }
1452} 1443}
1453 1444
1454
1455/* =========================================================================== 1445/* ===========================================================================
1456 * Send a literal or distance tree in compressed form, using the codes in 1446 * Send a literal or distance tree in compressed form, using the codes in
1457 * bl_tree. 1447 * bl_tree.
@@ -1509,7 +1499,6 @@ static void send_tree(ct_data * tree, int max_code)
1509 } 1499 }
1510} 1500}
1511 1501
1512
1513/* =========================================================================== 1502/* ===========================================================================
1514 * Construct the Huffman tree for the bit lengths and return the index in 1503 * Construct the Huffman tree for the bit lengths and return the index in
1515 * bl_order of the last bit length code to send. 1504 * bl_order of the last bit length code to send.
@@ -1538,12 +1527,11 @@ static int build_bl_tree(void)
1538 } 1527 }
1539 /* Update opt_len to include the bit length tree and counts */ 1528 /* Update opt_len to include the bit length tree and counts */
1540 G2.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4; 1529 G2.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
1541 Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", G2.opt_len, G2.static_len)); 1530 Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", (long)G2.opt_len, (long)G2.static_len));
1542 1531
1543 return max_blindex; 1532 return max_blindex;
1544} 1533}
1545 1534
1546
1547/* =========================================================================== 1535/* ===========================================================================
1548 * Send the header for a block using dynamic Huffman trees: the counts, the 1536 * Send the header for a block using dynamic Huffman trees: the counts, the
1549 * lengths of the bit length codes, the literal tree and the distance tree. 1537 * lengths of the bit length codes, the literal tree and the distance tree.
@@ -1564,16 +1552,15 @@ static void send_all_trees(int lcodes, int dcodes, int blcodes)
1564 Tracev((stderr, "\nbl code %2d ", bl_order[rank])); 1552 Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
1565 send_bits(G2.bl_tree[bl_order[rank]].Len, 3); 1553 send_bits(G2.bl_tree[bl_order[rank]].Len, 3);
1566 } 1554 }
1567 Tracev((stderr, "\nbl tree: sent %ld", G1.bits_sent)); 1555 Tracev((stderr, "\nbl tree: sent %ld", (long)G1.bits_sent));
1568 1556
1569 send_tree((ct_data *) G2.dyn_ltree, lcodes - 1); /* send the literal tree */ 1557 send_tree((ct_data *) G2.dyn_ltree, lcodes - 1); /* send the literal tree */
1570 Tracev((stderr, "\nlit tree: sent %ld", G1.bits_sent)); 1558 Tracev((stderr, "\nlit tree: sent %ld", (long)G1.bits_sent));
1571 1559
1572 send_tree((ct_data *) G2.dyn_dtree, dcodes - 1); /* send the distance tree */ 1560 send_tree((ct_data *) G2.dyn_dtree, dcodes - 1); /* send the distance tree */
1573 Tracev((stderr, "\ndist tree: sent %ld", G1.bits_sent)); 1561 Tracev((stderr, "\ndist tree: sent %ld", (long)G1.bits_sent));
1574} 1562}
1575 1563
1576
1577/* =========================================================================== 1564/* ===========================================================================
1578 * Save the match info and tally the frequency counts. Return true if 1565 * Save the match info and tally the frequency counts. Return true if
1579 * the current block must be flushed. 1566 * the current block must be flushed.
@@ -1619,7 +1606,8 @@ static int ct_tally(int dist, int lc)
1619 out_length >>= 3; 1606 out_length >>= 3;
1620 Trace((stderr, 1607 Trace((stderr,
1621 "\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ", 1608 "\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ",
1622 G2.last_lit, G2.last_dist, in_length, out_length, 1609 G2.last_lit, G2.last_dist,
1610 (long)in_length, (long)out_length,
1623 100L - out_length * 100L / in_length)); 1611 100L - out_length * 100L / in_length));
1624 if (G2.last_dist < G2.last_lit / 2 && out_length < in_length / 2) 1612 if (G2.last_dist < G2.last_lit / 2 && out_length < in_length / 2)
1625 return 1; 1613 return 1;
@@ -1679,13 +1667,12 @@ static void compress_block(ct_data * ltree, ct_data * dtree)
1679 SEND_CODE(END_BLOCK, ltree); 1667 SEND_CODE(END_BLOCK, ltree);
1680} 1668}
1681 1669
1682
1683/* =========================================================================== 1670/* ===========================================================================
1684 * Determine the best encoding for the current block: dynamic trees, static 1671 * Determine the best encoding for the current block: dynamic trees, static
1685 * trees or store, and output the encoded block to the zip file. This function 1672 * trees or store, and output the encoded block to the zip file. This function
1686 * returns the total compressed length for the file so far. 1673 * returns the total compressed length for the file so far.
1687 */ 1674 */
1688static ulg flush_block(char *buf, ulg stored_len, int eof) 1675static void flush_block(char *buf, ulg stored_len, int eof)
1689{ 1676{
1690 ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ 1677 ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
1691 int max_blindex; /* index of last bit length code of non zero freq */ 1678 int max_blindex; /* index of last bit length code of non zero freq */
@@ -1694,10 +1681,10 @@ static ulg flush_block(char *buf, ulg stored_len, int eof)
1694 1681
1695 /* Construct the literal and distance trees */ 1682 /* Construct the literal and distance trees */
1696 build_tree(&G2.l_desc); 1683 build_tree(&G2.l_desc);
1697 Tracev((stderr, "\nlit data: dyn %ld, stat %ld", G2.opt_len, G2.static_len)); 1684 Tracev((stderr, "\nlit data: dyn %ld, stat %ld", (long)G2.opt_len, (long)G2.static_len));
1698 1685
1699 build_tree(&G2.d_desc); 1686 build_tree(&G2.d_desc);
1700 Tracev((stderr, "\ndist data: dyn %ld, stat %ld", G2.opt_len, G2.static_len)); 1687 Tracev((stderr, "\ndist data: dyn %ld, stat %ld", (long)G2.opt_len, (long)G2.static_len));
1701 /* At this point, opt_len and static_len are the total bit lengths of 1688 /* At this point, opt_len and static_len are the total bit lengths of
1702 * the compressed block data, excluding the tree representations. 1689 * the compressed block data, excluding the tree representations.
1703 */ 1690 */
@@ -1713,7 +1700,9 @@ static ulg flush_block(char *buf, ulg stored_len, int eof)
1713 1700
1714 Trace((stderr, 1701 Trace((stderr,
1715 "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ", 1702 "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ",
1716 opt_lenb, G2.opt_len, static_lenb, G2.static_len, stored_len, 1703 (unsigned long)opt_lenb, (unsigned long)G2.opt_len,
1704 (unsigned long)static_lenb, (unsigned long)G2.static_len,
1705 (unsigned long)stored_len,
1717 G2.last_lit, G2.last_dist)); 1706 G2.last_lit, G2.last_dist));
1718 1707
1719 if (static_lenb <= opt_lenb) 1708 if (static_lenb <= opt_lenb)
@@ -1723,14 +1712,17 @@ static ulg flush_block(char *buf, ulg stored_len, int eof)
1723 * and if the zip file can be seeked (to rewrite the local header), 1712 * and if the zip file can be seeked (to rewrite the local header),
1724 * the whole file is transformed into a stored file: 1713 * the whole file is transformed into a stored file:
1725 */ 1714 */
1726 if (stored_len <= opt_lenb && eof && G2.compressed_len == 0L && seekable()) { 1715// seekable() is constant FALSE in busybox, and G2.compressed_len is disabled
1727 /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */ 1716// (this was the only user)
1728 if (buf == NULL) 1717// if (stored_len <= opt_lenb && eof && G2.compressed_len == 0L && seekable()) {
1729 bb_error_msg("block vanished"); 1718// /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
1730 1719// if (buf == NULL)
1731 copy_block(buf, (unsigned) stored_len, 0); /* without header */ 1720// bb_error_msg("block vanished");
1732 G2.compressed_len = stored_len << 3; 1721//
1733 } else if (stored_len + 4 <= opt_lenb && buf != NULL) { 1722// G2.compressed_len = stored_len << 3;
1723// copy_block(buf, (unsigned) stored_len, 0); /* without header */
1724// } else
1725 if (stored_len + 4 <= opt_lenb && buf != NULL) {
1734 /* 4: two words for the lengths */ 1726 /* 4: two words for the lengths */
1735 /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. 1727 /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
1736 * Otherwise we can't have processed more than WSIZE input bytes since 1728 * Otherwise we can't have processed more than WSIZE input bytes since
@@ -1739,35 +1731,35 @@ static ulg flush_block(char *buf, ulg stored_len, int eof)
1739 * transform a block into a stored block. 1731 * transform a block into a stored block.
1740 */ 1732 */
1741 send_bits((STORED_BLOCK << 1) + eof, 3); /* send block type */ 1733 send_bits((STORED_BLOCK << 1) + eof, 3); /* send block type */
1742 G2.compressed_len = (G2.compressed_len + 3 + 7) & ~7L; 1734// G2.compressed_len = ((G2.compressed_len + 3 + 7) & ~7L)
1743 G2.compressed_len += (stored_len + 4) << 3; 1735// + ((stored_len + 4) << 3);
1744
1745 copy_block(buf, (unsigned) stored_len, 1); /* with header */ 1736 copy_block(buf, (unsigned) stored_len, 1); /* with header */
1746 } else if (static_lenb == opt_lenb) { 1737 } else
1738 if (static_lenb == opt_lenb) {
1747 send_bits((STATIC_TREES << 1) + eof, 3); 1739 send_bits((STATIC_TREES << 1) + eof, 3);
1748 compress_block((ct_data *) G2.static_ltree, (ct_data *) G2.static_dtree); 1740 compress_block((ct_data *) G2.static_ltree, (ct_data *) G2.static_dtree);
1749 G2.compressed_len += 3 + G2.static_len; 1741// G2.compressed_len += 3 + G2.static_len;
1750 } else { 1742 } else {
1751 send_bits((DYN_TREES << 1) + eof, 3); 1743 send_bits((DYN_TREES << 1) + eof, 3);
1752 send_all_trees(G2.l_desc.max_code + 1, G2.d_desc.max_code + 1, 1744 send_all_trees(G2.l_desc.max_code + 1, G2.d_desc.max_code + 1,
1753 max_blindex + 1); 1745 max_blindex + 1);
1754 compress_block((ct_data *) G2.dyn_ltree, (ct_data *) G2.dyn_dtree); 1746 compress_block((ct_data *) G2.dyn_ltree, (ct_data *) G2.dyn_dtree);
1755 G2.compressed_len += 3 + G2.opt_len; 1747// G2.compressed_len += 3 + G2.opt_len;
1756 } 1748 }
1757 Assert(G2.compressed_len == G1.bits_sent, "bad compressed size"); 1749// Assert(G2.compressed_len == G1.bits_sent, "bad compressed size");
1758 init_block(); 1750 init_block();
1759 1751
1760 if (eof) { 1752 if (eof) {
1761 bi_windup(); 1753 bi_windup();
1762 G2.compressed_len += 7; /* align on byte boundary */ 1754// G2.compressed_len += 7; /* align on byte boundary */
1763 } 1755 }
1764 Tracev((stderr, "\ncomprlen %lu(%lu) ", G2.compressed_len >> 3, 1756// Tracev((stderr, "\ncomprlen %lu(%lu) ",
1765 G2.compressed_len - 7 * eof)); 1757// (unsigned long)G2.compressed_len >> 3,
1758// (unsigned long)G2.compressed_len - 7 * eof));
1766 1759
1767 return G2.compressed_len >> 3; 1760 return; /* was "return G2.compressed_len >> 3;" */
1768} 1761}
1769 1762
1770
1771/* =========================================================================== 1763/* ===========================================================================
1772 * Update a hash value with the given input byte 1764 * Update a hash value with the given input byte
1773 * IN assertion: all calls to UPDATE_HASH are made with consecutive 1765 * IN assertion: all calls to UPDATE_HASH are made with consecutive
@@ -1776,7 +1768,6 @@ static ulg flush_block(char *buf, ulg stored_len, int eof)
1776 */ 1768 */
1777#define UPDATE_HASH(h, c) (h = (((h)<<H_SHIFT) ^ (c)) & HASH_MASK) 1769#define UPDATE_HASH(h, c) (h = (((h)<<H_SHIFT) ^ (c)) & HASH_MASK)
1778 1770
1779
1780/* =========================================================================== 1771/* ===========================================================================
1781 * Same as above, but achieves better compression. We use a lazy 1772 * Same as above, but achieves better compression. We use a lazy
1782 * evaluation for matches: a match is finally adopted only if there is 1773 * evaluation for matches: a match is finally adopted only if there is
@@ -1811,7 +1802,7 @@ do { \
1811 head[G1.ins_h] = (s); \ 1802 head[G1.ins_h] = (s); \
1812} while (0) 1803} while (0)
1813 1804
1814static ulg deflate(void) 1805static NOINLINE void deflate(void)
1815{ 1806{
1816 IPos hash_head; /* head of hash chain */ 1807 IPos hash_head; /* head of hash chain */
1817 IPos prev_match; /* previous match */ 1808 IPos prev_match; /* previous match */
@@ -1900,40 +1891,35 @@ static ulg deflate(void)
1900 G1.strstart++; 1891 G1.strstart++;
1901 G1.lookahead--; 1892 G1.lookahead--;
1902 } 1893 }
1903 Assert(G1.strstart <= G1.isize && lookahead <= G1.isize, "a bit too far"); 1894 Assert(G1.strstart <= G1.isize && G1.lookahead <= G1.isize, "a bit too far");
1904 1895
1905 /* Make sure that we always have enough lookahead, except 1896 /* Make sure that we always have enough lookahead, except
1906 * at the end of the input file. We need MAX_MATCH bytes 1897 * at the end of the input file. We need MAX_MATCH bytes
1907 * for the next match, plus MIN_MATCH bytes to insert the 1898 * for the next match, plus MIN_MATCH bytes to insert the
1908 * string following the next match. 1899 * string following the next match.
1909 */ 1900 */
1910 while (G1.lookahead < MIN_LOOKAHEAD && !G1.eofile) 1901 fill_window_if_needed();
1911 fill_window();
1912 } 1902 }
1913 if (match_available) 1903 if (match_available)
1914 ct_tally(0, G1.window[G1.strstart - 1]); 1904 ct_tally(0, G1.window[G1.strstart - 1]);
1915 1905
1916 return FLUSH_BLOCK(1); /* eof */ 1906 FLUSH_BLOCK(1); /* eof */
1917} 1907}
1918 1908
1919
1920/* =========================================================================== 1909/* ===========================================================================
1921 * Initialize the bit string routines. 1910 * Initialize the bit string routines.
1922 */ 1911 */
1923static void bi_init(void) 1912static void bi_init(void)
1924{ 1913{
1925 G1.bi_buf = 0; 1914 //G1.bi_buf = 0; // globals are zeroed in pack_gzip()
1926 G1.bi_valid = 0; 1915 //G1.bi_valid = 0; // globals are zeroed in pack_gzip()
1927#ifdef DEBUG 1916 //DEBUG_bits_sent(= 0L); // globals are zeroed in pack_gzip()
1928 G1.bits_sent = 0L;
1929#endif
1930} 1917}
1931 1918
1932
1933/* =========================================================================== 1919/* ===========================================================================
1934 * Initialize the "longest match" routines for a new file 1920 * Initialize the "longest match" routines for a new file
1935 */ 1921 */
1936static void lm_init(ush * flagsp) 1922static void lm_init(unsigned *flags16p)
1937{ 1923{
1938 unsigned j; 1924 unsigned j;
1939 1925
@@ -1942,11 +1928,11 @@ static void lm_init(ush * flagsp)
1942 /* prev will be initialized on the fly */ 1928 /* prev will be initialized on the fly */
1943 1929
1944 /* speed options for the general purpose bit flag */ 1930 /* speed options for the general purpose bit flag */
1945 *flagsp |= 2; /* FAST 4, SLOW 2 */ 1931 *flags16p |= 2; /* FAST 4, SLOW 2 */
1946 /* ??? reduce max_chain_length for binary files */ 1932 /* ??? reduce max_chain_length for binary files */
1947 1933
1948 G1.strstart = 0; 1934 //G1.strstart = 0; // globals are zeroed in pack_gzip()
1949 G1.block_start = 0L; 1935 //G1.block_start = 0L; // globals are zeroed in pack_gzip()
1950 1936
1951 G1.lookahead = file_read(G1.window, 1937 G1.lookahead = file_read(G1.window,
1952 sizeof(int) <= 2 ? (unsigned) WSIZE : 2 * WSIZE); 1938 sizeof(int) <= 2 ? (unsigned) WSIZE : 2 * WSIZE);
@@ -1956,14 +1942,14 @@ static void lm_init(ush * flagsp)
1956 G1.lookahead = 0; 1942 G1.lookahead = 0;
1957 return; 1943 return;
1958 } 1944 }
1959 G1.eofile = 0; 1945 //G1.eofile = 0; // globals are zeroed in pack_gzip()
1946
1960 /* Make sure that we always have enough lookahead. This is important 1947 /* Make sure that we always have enough lookahead. This is important
1961 * if input comes from a device such as a tty. 1948 * if input comes from a device such as a tty.
1962 */ 1949 */
1963 while (G1.lookahead < MIN_LOOKAHEAD && !G1.eofile) 1950 fill_window_if_needed();
1964 fill_window();
1965 1951
1966 G1.ins_h = 0; 1952 //G1.ins_h = 0; // globals are zeroed in pack_gzip()
1967 for (j = 0; j < MIN_MATCH - 1; j++) 1953 for (j = 0; j < MIN_MATCH - 1; j++)
1968 UPDATE_HASH(G1.ins_h, G1.window[j]); 1954 UPDATE_HASH(G1.ins_h, G1.window[j]);
1969 /* If lookahead < MIN_MATCH, ins_h is garbage, but this is 1955 /* If lookahead < MIN_MATCH, ins_h is garbage, but this is
@@ -1971,7 +1957,6 @@ static void lm_init(ush * flagsp)
1971 */ 1957 */
1972} 1958}
1973 1959
1974
1975/* =========================================================================== 1960/* ===========================================================================
1976 * Allocate the match buffer, initialize the various tables and save the 1961 * Allocate the match buffer, initialize the various tables and save the
1977 * location of the internal file attribute (ascii/binary) and method 1962 * location of the internal file attribute (ascii/binary) and method
@@ -1985,7 +1970,7 @@ static void ct_init(void)
1985 int code; /* code value */ 1970 int code; /* code value */
1986 int dist; /* distance index */ 1971 int dist; /* distance index */
1987 1972
1988 G2.compressed_len = 0L; 1973// //G2.compressed_len = 0L; // globals are zeroed in pack_gzip()
1989 1974
1990#ifdef NOT_NEEDED 1975#ifdef NOT_NEEDED
1991 if (G2.static_dtree[0].Len != 0) 1976 if (G2.static_dtree[0].Len != 0)
@@ -2026,27 +2011,33 @@ static void ct_init(void)
2026 Assert(dist == 256, "ct_init: 256+dist != 512"); 2011 Assert(dist == 256, "ct_init: 256+dist != 512");
2027 2012
2028 /* Construct the codes of the static literal tree */ 2013 /* Construct the codes of the static literal tree */
2029 /* already zeroed - it's in bss 2014 //for (n = 0; n <= MAX_BITS; n++) // globals are zeroed in pack_gzip()
2030 for (n = 0; n <= MAX_BITS; n++) 2015 // G2.bl_count[n] = 0;
2031 G2.bl_count[n] = 0; */
2032 2016
2033 n = 0; 2017 n = 0;
2034 while (n <= 143) { 2018 while (n <= 143) {
2035 G2.static_ltree[n++].Len = 8; 2019 G2.static_ltree[n++].Len = 8;
2036 G2.bl_count[8]++; 2020 //G2.bl_count[8]++;
2037 } 2021 }
2022 //G2.bl_count[8] = 143 + 1;
2038 while (n <= 255) { 2023 while (n <= 255) {
2039 G2.static_ltree[n++].Len = 9; 2024 G2.static_ltree[n++].Len = 9;
2040 G2.bl_count[9]++; 2025 //G2.bl_count[9]++;
2041 } 2026 }
2027 //G2.bl_count[9] = 255 - 143;
2042 while (n <= 279) { 2028 while (n <= 279) {
2043 G2.static_ltree[n++].Len = 7; 2029 G2.static_ltree[n++].Len = 7;
2044 G2.bl_count[7]++; 2030 //G2.bl_count[7]++;
2045 } 2031 }
2032 //G2.bl_count[7] = 279 - 255;
2046 while (n <= 287) { 2033 while (n <= 287) {
2047 G2.static_ltree[n++].Len = 8; 2034 G2.static_ltree[n++].Len = 8;
2048 G2.bl_count[8]++; 2035 //G2.bl_count[8]++;
2049 } 2036 }
2037 //G2.bl_count[8] += 287 - 279;
2038 G2.bl_count[7] = 279 - 255;
2039 G2.bl_count[8] = (143 + 1) + (287 - 279);
2040 G2.bl_count[9] = 255 - 143;
2050 /* Codes 286 and 287 do not exist, but we must include them in the 2041 /* Codes 286 and 287 do not exist, but we must include them in the
2051 * tree construction to get a canonical Huffman tree (longest code 2042 * tree construction to get a canonical Huffman tree (longest code
2052 * all ones) 2043 * all ones)
@@ -2063,17 +2054,15 @@ static void ct_init(void)
2063 init_block(); 2054 init_block();
2064} 2055}
2065 2056
2066
2067/* =========================================================================== 2057/* ===========================================================================
2068 * Deflate in to out. 2058 * Deflate in to out.
2069 * IN assertions: the input and output buffers are cleared. 2059 * IN assertions: the input and output buffers are cleared.
2070 */ 2060 */
2071
2072static void zip(void) 2061static void zip(void)
2073{ 2062{
2074 ush deflate_flags = 0; /* pkzip -es, -en or -ex equivalent */ 2063 unsigned deflate_flags;
2075 2064
2076 G1.outcnt = 0; 2065 //G1.outcnt = 0; // globals are zeroed in pack_gzip()
2077 2066
2078 /* Write the header to the gzip file. See algorithm.doc for the format */ 2067 /* Write the header to the gzip file. See algorithm.doc for the format */
2079 /* magic header for gzip files: 1F 8B */ 2068 /* magic header for gzip files: 1F 8B */
@@ -2087,10 +2076,13 @@ static void zip(void)
2087 2076
2088 bi_init(); 2077 bi_init();
2089 ct_init(); 2078 ct_init();
2079 deflate_flags = 0; /* pkzip -es, -en or -ex equivalent */
2090 lm_init(&deflate_flags); 2080 lm_init(&deflate_flags);
2091 2081
2092 put_8bit(deflate_flags); /* extra flags */ 2082 put_16bit(deflate_flags | 0x300); /* extra flags. OS id = 3 (Unix) */
2093 put_8bit(3); /* OS identifier = 3 (Unix) */ 2083
2084 /* The above 32-bit misaligns outbuf (10 bytes are stored), flush it */
2085 flush_outbuf_if_32bit_optimized();
2094 2086
2095 deflate(); 2087 deflate();
2096 2088
@@ -2101,20 +2093,21 @@ static void zip(void)
2101 flush_outbuf(); 2093 flush_outbuf();
2102} 2094}
2103 2095
2104
2105/* ======================================================================== */ 2096/* ======================================================================== */
2106static 2097static
2107IF_DESKTOP(long long) int FAST_FUNC pack_gzip(transformer_state_t *xstate UNUSED_PARAM) 2098IF_DESKTOP(long long) int FAST_FUNC pack_gzip(transformer_state_t *xstate UNUSED_PARAM)
2108{ 2099{
2100 /* Reinit G1.xxx except pointers to allocated buffers, and entire G2 */
2101 memset(&G1.crc, 0, (sizeof(G1) - offsetof(struct globals, crc)) + sizeof(G2));
2102
2109 /* Clear input and output buffers */ 2103 /* Clear input and output buffers */
2110 G1.outcnt = 0; 2104 //G1.outcnt = 0;
2111#ifdef DEBUG 2105#ifdef DEBUG
2112 G1.insize = 0; 2106 //G1.insize = 0;
2113#endif 2107#endif
2114 G1.isize = 0; 2108 //G1.isize = 0;
2115 2109
2116 /* Reinit G2.xxx */ 2110 /* Reinit G2.xxx */
2117 memset(&G2, 0, sizeof(G2));
2118 G2.l_desc.dyn_tree = G2.dyn_ltree; 2111 G2.l_desc.dyn_tree = G2.dyn_ltree;
2119 G2.l_desc.static_tree = G2.static_ltree; 2112 G2.l_desc.static_tree = G2.static_ltree;
2120 G2.l_desc.extra_bits = extra_lbits; 2113 G2.l_desc.extra_bits = extra_lbits;
@@ -2218,16 +2211,16 @@ int gzip_main(int argc UNUSED_PARAM, char **argv)
2218 2211
2219 /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */ 2212 /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */
2220#if ENABLE_FEATURE_GZIP_LONG_OPTIONS 2213#if ENABLE_FEATURE_GZIP_LONG_OPTIONS
2221 opt = getopt32long(argv, "cfkv" IF_FEATURE_GZIP_DECOMPRESS("dt") "qn123456789", gzip_longopts); 2214 opt = getopt32long(argv, BBUNPK_OPTSTR IF_FEATURE_GZIP_DECOMPRESS("dt") "n123456789", gzip_longopts);
2222#else 2215#else
2223 opt = getopt32(argv, "cfkv" IF_FEATURE_GZIP_DECOMPRESS("dt") "qn123456789"); 2216 opt = getopt32(argv, BBUNPK_OPTSTR IF_FEATURE_GZIP_DECOMPRESS("dt") "n123456789");
2224#endif 2217#endif
2225#if ENABLE_FEATURE_GZIP_DECOMPRESS /* gunzip_main may not be visible... */ 2218#if ENABLE_FEATURE_GZIP_DECOMPRESS /* gunzip_main may not be visible... */
2226 if (opt & 0x30) // -d and/or -t 2219 if (opt & (BBUNPK_OPT_DECOMPRESS|BBUNPK_OPT_TEST)) /* -d and/or -t */
2227 return gunzip_main(argc, argv); 2220 return gunzip_main(argc, argv);
2228#endif 2221#endif
2229#if ENABLE_FEATURE_GZIP_LEVELS 2222#if ENABLE_FEATURE_GZIP_LEVELS
2230 opt >>= ENABLE_FEATURE_GZIP_DECOMPRESS ? 8 : 6; /* drop cfkv[dt]qn bits */ 2223 opt >>= (BBUNPK_OPTSTRLEN IF_FEATURE_GZIP_DECOMPRESS(+ 2) + 1); /* drop cfkvq[dt]n bits */
2231 if (opt == 0) 2224 if (opt == 0)
2232 opt = 1 << 6; /* default: 6 */ 2225 opt = 1 << 6; /* default: 6 */
2233 opt = ffs(opt >> 4); /* Maps -1..-4 to [0], -5 to [1] ... -9 to [5] */ 2226 opt = ffs(opt >> 4); /* Maps -1..-4 to [0], -5 to [1] ... -9 to [5] */
@@ -2236,7 +2229,7 @@ int gzip_main(int argc UNUSED_PARAM, char **argv)
2236 max_lazy_match = gzip_level_config[opt].lazy2 * 2; 2229 max_lazy_match = gzip_level_config[opt].lazy2 * 2;
2237 nice_match = gzip_level_config[opt].nice2 * 2; 2230 nice_match = gzip_level_config[opt].nice2 * 2;
2238#endif 2231#endif
2239 option_mask32 &= 0xf; /* retain only -cfkv */ 2232 option_mask32 &= BBUNPK_OPTSTRMASK; /* retain only -cfkvq */
2240 2233
2241 /* Allocate all global buffers (for DYN_ALLOC option) */ 2234 /* Allocate all global buffers (for DYN_ALLOC option) */
2242 ALLOC(uch, G1.l_buf, INBUFSIZ); 2235 ALLOC(uch, G1.l_buf, INBUFSIZ);
@@ -2246,7 +2239,7 @@ int gzip_main(int argc UNUSED_PARAM, char **argv)
2246 ALLOC(ush, G1.prev, 1L << BITS); 2239 ALLOC(ush, G1.prev, 1L << BITS);
2247 2240
2248 /* Initialize the CRC32 table */ 2241 /* Initialize the CRC32 table */
2249 global_crc32_table = crc32_filltable(NULL, 0); 2242 global_crc32_new_table_le();
2250 2243
2251 argv += optind; 2244 argv += optind;
2252 return bbunpack(argv, pack_gzip, append_ext, "gz"); 2245 return bbunpack(argv, pack_gzip, append_ext, "gz");
diff --git a/archival/libarchive/bz/blocksort.c b/archival/libarchive/bz/blocksort.c
index e600cb7a7..92d6d8251 100644
--- a/archival/libarchive/bz/blocksort.c
+++ b/archival/libarchive/bz/blocksort.c
@@ -113,9 +113,8 @@ void fallbackQSort3(uint32_t* fmap,
113 int32_t loSt, 113 int32_t loSt,
114 int32_t hiSt) 114 int32_t hiSt)
115{ 115{
116 int32_t unLo, unHi, ltLo, gtHi, n, m; 116 int32_t sp;
117 int32_t sp, lo, hi; 117 uint32_t r;
118 uint32_t med, r, r3;
119 int32_t stackLo[FALLBACK_QSORT_STACK_SIZE]; 118 int32_t stackLo[FALLBACK_QSORT_STACK_SIZE];
120 int32_t stackHi[FALLBACK_QSORT_STACK_SIZE]; 119 int32_t stackHi[FALLBACK_QSORT_STACK_SIZE];
121 120
@@ -125,6 +124,11 @@ void fallbackQSort3(uint32_t* fmap,
125 fpush(loSt, hiSt); 124 fpush(loSt, hiSt);
126 125
127 while (sp > 0) { 126 while (sp > 0) {
127 int32_t unLo, unHi, ltLo, gtHi, n, m;
128 int32_t lo, hi;
129 uint32_t med;
130 uint32_t r3;
131
128 AssertH(sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004); 132 AssertH(sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004);
129 133
130 fpop(lo, hi); 134 fpop(lo, hi);
@@ -161,7 +165,7 @@ void fallbackQSort3(uint32_t* fmap,
161 ltLo++; 165 ltLo++;
162 unLo++; 166 unLo++;
163 continue; 167 continue;
164 }; 168 }
165 if (n > 0) break; 169 if (n > 0) break;
166 unLo++; 170 unLo++;
167 } 171 }
@@ -172,7 +176,7 @@ void fallbackQSort3(uint32_t* fmap,
172 mswap(fmap[unHi], fmap[gtHi]); 176 mswap(fmap[unHi], fmap[gtHi]);
173 gtHi--; unHi--; 177 gtHi--; unHi--;
174 continue; 178 continue;
175 }; 179 }
176 if (n < 0) break; 180 if (n < 0) break;
177 unHi--; 181 unHi--;
178 } 182 }
@@ -227,17 +231,19 @@ void fallbackQSort3(uint32_t* fmap,
227#define UNALIGNED_BH(zz) ((zz) & 0x01f) 231#define UNALIGNED_BH(zz) ((zz) & 0x01f)
228 232
229static 233static
230void fallbackSort(uint32_t* fmap, 234void fallbackSort(EState* state)
231 uint32_t* eclass,
232 uint32_t* bhtab,
233 int32_t nblock)
234{ 235{
235 int32_t ftab[257]; 236 int32_t ftab[257];
236 int32_t ftabCopy[256]; 237 int32_t ftabCopy[256];
237 int32_t H, i, j, k, l, r, cc, cc1; 238 int32_t H, i, j, k, l, r, cc, cc1;
238 int32_t nNotDone; 239 int32_t nNotDone;
239 int32_t nBhtab; 240 int32_t nBhtab;
240 uint8_t* eclass8 = (uint8_t*)eclass; 241 /* params */
242 uint32_t *const fmap = state->arr1;
243 uint32_t *const eclass = state->arr2;
244#define eclass8 ((uint8_t*)eclass)
245 uint32_t *const bhtab = state->ftab;
246 const int32_t nblock = state->nblock;
241 247
242 /* 248 /*
243 * Initial 1-char radix sort to generate 249 * Initial 1-char radix sort to generate
@@ -326,7 +332,7 @@ void fallbackSort(uint32_t* fmap,
326 if (cc != cc1) { 332 if (cc != cc1) {
327 SET_BH(i); 333 SET_BH(i);
328 cc = cc1; 334 cc = cc1;
329 }; 335 }
330 } 336 }
331 } 337 }
332 } 338 }
@@ -349,6 +355,7 @@ void fallbackSort(uint32_t* fmap,
349 eclass8[fmap[i]] = (uint8_t)j; 355 eclass8[fmap[i]] = (uint8_t)j;
350 } 356 }
351 AssertH(j < 256, 1005); 357 AssertH(j < 256, 1005);
358#undef eclass8
352} 359}
353 360
354#undef SET_BH 361#undef SET_BH
@@ -367,25 +374,25 @@ void fallbackSort(uint32_t* fmap,
367/*---------------------------------------------*/ 374/*---------------------------------------------*/
368static 375static
369NOINLINE 376NOINLINE
370int mainGtU( 377int mainGtU(EState* state,
371 uint32_t i1, 378 uint32_t i1,
372 uint32_t i2, 379 uint32_t i2)
373 uint8_t* block,
374 uint16_t* quadrant,
375 uint32_t nblock,
376 int32_t* budget)
377{ 380{
378 int32_t k; 381 int32_t k;
379 uint8_t c1, c2; 382 uint8_t c1, c2;
380 uint16_t s1, s2; 383 uint16_t s1, s2;
381 384
385 uint8_t *const block = state->block;
386 uint16_t *const quadrant = state->quadrant;
387 const int32_t nblock = state->nblock;
388
382/* Loop unrolling here is actually very useful 389/* Loop unrolling here is actually very useful
383 * (generated code is much simpler), 390 * (generated code is much simpler),
384 * code size increase is only 270 bytes (i386) 391 * code size increase is only 270 bytes (i386)
385 * but speeds up compression 10% overall 392 * but speeds up compression 10% overall
386 */ 393 */
387 394
388#if CONFIG_BZIP2_FAST >= 1 395#if BZIP2_SPEED >= 1
389 396
390#define TIMES_8(code) \ 397#define TIMES_8(code) \
391 code; code; code; code; \ 398 code; code; code; code; \
@@ -435,7 +442,7 @@ int mainGtU(
435 if (i1 >= nblock) i1 -= nblock; 442 if (i1 >= nblock) i1 -= nblock;
436 if (i2 >= nblock) i2 -= nblock; 443 if (i2 >= nblock) i2 -= nblock;
437 444
438 (*budget)--; 445 state->budget--;
439 k -= 8; 446 k -= 8;
440 } while (k >= 0); 447 } while (k >= 0);
441 448
@@ -452,42 +459,45 @@ int mainGtU(
452 * usually small, typically <= 20. 459 * usually small, typically <= 20.
453 */ 460 */
454static 461static
455const int32_t incs[14] = { 462const uint32_t incs[14] = {
456 1, 4, 13, 40, 121, 364, 1093, 3280, 463 1, 4, 13, 40, 121, 364, 1093, 3280,
457 9841, 29524, 88573, 265720, 464 9841, 29524, 88573, 265720,
458 797161, 2391484 465 797161, 2391484
459}; 466};
460 467
461static 468static
462void mainSimpleSort(uint32_t* ptr, 469void mainSimpleSort(EState* state,
463 uint8_t* block,
464 uint16_t* quadrant,
465 int32_t nblock,
466 int32_t lo, 470 int32_t lo,
467 int32_t hi, 471 int32_t hi,
468 int32_t d, 472 int32_t d)
469 int32_t* budget)
470{ 473{
471 int32_t i, j, h, bigN, hp; 474 uint32_t *const ptr = state->ptr;
472 uint32_t v;
473
474 bigN = hi - lo + 1;
475 if (bigN < 2) return;
476 475
477 hp = 0; 476 /* At which increment to start? */
478 while (incs[hp] < bigN) hp++; 477 int hp = 0;
479 hp--; 478 {
479 int bigN = hi - lo;
480 if (bigN <= 0)
481 return;
482 while (incs[hp] <= bigN)
483 hp++;
484 hp--;
485 }
480 486
481 for (; hp >= 0; hp--) { 487 for (; hp >= 0; hp--) {
482 h = incs[hp]; 488 int32_t i;
489 unsigned h;
483 490
491 h = incs[hp];
484 i = lo + h; 492 i = lo + h;
485 while (1) { 493 while (1) {
486 /*-- copy 1 --*/ 494 unsigned j;
495 unsigned v;
496
487 if (i > hi) break; 497 if (i > hi) break;
488 v = ptr[i]; 498 v = ptr[i];
489 j = i; 499 j = i;
490 while (mainGtU(ptr[j-h]+d, v+d, block, quadrant, nblock, budget)) { 500 while (mainGtU(state, ptr[j-h]+d, v+d)) {
491 ptr[j] = ptr[j-h]; 501 ptr[j] = ptr[j-h];
492 j = j - h; 502 j = j - h;
493 if (j <= (lo + h - 1)) break; 503 if (j <= (lo + h - 1)) break;
@@ -496,24 +506,23 @@ void mainSimpleSort(uint32_t* ptr,
496 i++; 506 i++;
497 507
498/* 1.5% overall speedup, +290 bytes */ 508/* 1.5% overall speedup, +290 bytes */
499#if CONFIG_BZIP2_FAST >= 3 509#if BZIP2_SPEED >= 3
500 /*-- copy 2 --*/ 510 /*-- copy 2 --*/
501 if (i > hi) break; 511 if (i > hi) break;
502 v = ptr[i]; 512 v = ptr[i];
503 j = i; 513 j = i;
504 while (mainGtU(ptr[j-h]+d, v+d, block, quadrant, nblock, budget)) { 514 while (mainGtU(state, ptr[j-h]+d, v+d)) {
505 ptr[j] = ptr[j-h]; 515 ptr[j] = ptr[j-h];
506 j = j - h; 516 j = j - h;
507 if (j <= (lo + h - 1)) break; 517 if (j <= (lo + h - 1)) break;
508 } 518 }
509 ptr[j] = v; 519 ptr[j] = v;
510 i++; 520 i++;
511
512 /*-- copy 3 --*/ 521 /*-- copy 3 --*/
513 if (i > hi) break; 522 if (i > hi) break;
514 v = ptr[i]; 523 v = ptr[i];
515 j = i; 524 j = i;
516 while (mainGtU(ptr[j-h]+d, v+d, block, quadrant, nblock, budget)) { 525 while (mainGtU(state, ptr[j-h]+d, v+d)) {
517 ptr[j] = ptr[j-h]; 526 ptr[j] = ptr[j-h];
518 j = j - h; 527 j = j - h;
519 if (j <= (lo + h - 1)) break; 528 if (j <= (lo + h - 1)) break;
@@ -521,7 +530,7 @@ void mainSimpleSort(uint32_t* ptr,
521 ptr[j] = v; 530 ptr[j] = v;
522 i++; 531 i++;
523#endif 532#endif
524 if (*budget < 0) return; 533 if (state->budget < 0) return;
525 } 534 }
526 } 535 }
527} 536}
@@ -545,7 +554,7 @@ uint8_t mmed3(uint8_t a, uint8_t b, uint8_t c)
545 t = a; 554 t = a;
546 a = b; 555 a = b;
547 b = t; 556 b = t;
548 }; 557 }
549 /* here b >= a */ 558 /* here b >= a */
550 if (b > c) { 559 if (b > c) {
551 b = c; 560 b = c;
@@ -586,15 +595,12 @@ uint8_t mmed3(uint8_t a, uint8_t b, uint8_t c)
586#define MAIN_QSORT_STACK_SIZE 100 595#define MAIN_QSORT_STACK_SIZE 100
587 596
588static NOINLINE 597static NOINLINE
589void mainQSort3(uint32_t* ptr, 598void mainQSort3(EState* state,
590 uint8_t* block,
591 uint16_t* quadrant,
592 int32_t nblock,
593 int32_t loSt, 599 int32_t loSt,
594 int32_t hiSt, 600 int32_t hiSt
595 int32_t dSt, 601 /*int32_t dSt*/)
596 int32_t* budget)
597{ 602{
603 enum { dSt = BZ_N_RADIX };
598 int32_t unLo, unHi, ltLo, gtHi, n, m, med; 604 int32_t unLo, unHi, ltLo, gtHi, n, m, med;
599 int32_t sp, lo, hi, d; 605 int32_t sp, lo, hi, d;
600 606
@@ -606,6 +612,9 @@ void mainQSort3(uint32_t* ptr,
606 int32_t nextHi[3]; 612 int32_t nextHi[3];
607 int32_t nextD [3]; 613 int32_t nextD [3];
608 614
615 uint32_t *const ptr = state->ptr;
616 uint8_t *const block = state->block;
617
609 sp = 0; 618 sp = 0;
610 mpush(loSt, hiSt, dSt); 619 mpush(loSt, hiSt, dSt);
611 620
@@ -616,8 +625,8 @@ void mainQSort3(uint32_t* ptr,
616 if (hi - lo < MAIN_QSORT_SMALL_THRESH 625 if (hi - lo < MAIN_QSORT_SMALL_THRESH
617 || d > MAIN_QSORT_DEPTH_THRESH 626 || d > MAIN_QSORT_DEPTH_THRESH
618 ) { 627 ) {
619 mainSimpleSort(ptr, block, quadrant, nblock, lo, hi, d, budget); 628 mainSimpleSort(state, lo, hi, d);
620 if (*budget < 0) 629 if (state->budget < 0)
621 return; 630 return;
622 continue; 631 continue;
623 } 632 }
@@ -638,8 +647,8 @@ void mainQSort3(uint32_t* ptr,
638 ltLo++; 647 ltLo++;
639 unLo++; 648 unLo++;
640 continue; 649 continue;
641 }; 650 }
642 if (n > 0) break; 651 if (n > 0) break;
643 unLo++; 652 unLo++;
644 } 653 }
645 while (1) { 654 while (1) {
@@ -651,8 +660,8 @@ void mainQSort3(uint32_t* ptr,
651 gtHi--; 660 gtHi--;
652 unHi--; 661 unHi--;
653 continue; 662 continue;
654 }; 663 }
655 if (n < 0) break; 664 if (n < 0) break;
656 unHi--; 665 unHi--;
657 } 666 }
658 if (unLo > unHi) 667 if (unLo > unHi)
@@ -721,28 +730,24 @@ void mainQSort3(uint32_t* ptr,
721#define CLEARMASK (~(SETMASK)) 730#define CLEARMASK (~(SETMASK))
722 731
723static NOINLINE 732static NOINLINE
724void mainSort(EState* state, 733void mainSort(EState* state)
725 uint32_t* ptr,
726 uint8_t* block,
727 uint16_t* quadrant,
728 uint32_t* ftab,
729 int32_t nblock,
730 int32_t* budget)
731{ 734{
732 int32_t i, j, k, ss, sb; 735 int32_t i, j;
733 uint8_t c1;
734 int32_t numQSorted;
735 uint16_t s;
736 Bool bigDone[256]; 736 Bool bigDone[256];
737 uint8_t runningOrder[256];
737 /* bbox: moved to EState to save stack 738 /* bbox: moved to EState to save stack
738 int32_t runningOrder[256];
739 int32_t copyStart[256]; 739 int32_t copyStart[256];
740 int32_t copyEnd [256]; 740 int32_t copyEnd [256];
741 */ 741 */
742#define runningOrder (state->mainSort__runningOrder)
743#define copyStart (state->mainSort__copyStart) 742#define copyStart (state->mainSort__copyStart)
744#define copyEnd (state->mainSort__copyEnd) 743#define copyEnd (state->mainSort__copyEnd)
745 744
745 uint32_t *const ptr = state->ptr;
746 uint8_t *const block = state->block;
747 uint32_t *const ftab = state->ftab;
748 const int32_t nblock = state->nblock;
749 uint16_t *const quadrant = state->quadrant;
750
746 /*-- set up the 2-byte frequency table --*/ 751 /*-- set up the 2-byte frequency table --*/
747 /* was: for (i = 65536; i >= 0; i--) ftab[i] = 0; */ 752 /* was: for (i = 65536; i >= 0; i--) ftab[i] = 0; */
748 memset(ftab, 0, 65537 * sizeof(ftab[0])); 753 memset(ftab, 0, 65537 * sizeof(ftab[0]));
@@ -750,25 +755,25 @@ void mainSort(EState* state,
750 j = block[0] << 8; 755 j = block[0] << 8;
751 i = nblock - 1; 756 i = nblock - 1;
752/* 3%, +300 bytes */ 757/* 3%, +300 bytes */
753#if CONFIG_BZIP2_FAST >= 2 758#if BZIP2_SPEED >= 2
754 for (; i >= 3; i -= 4) { 759 for (; i >= 3; i -= 4) {
755 quadrant[i] = 0; 760 quadrant[i] = 0;
756 j = (j >> 8) | (((uint16_t)block[i]) << 8); 761 j = (j >> 8) | (((unsigned)block[i]) << 8);
757 ftab[j]++; 762 ftab[j]++;
758 quadrant[i-1] = 0; 763 quadrant[i-1] = 0;
759 j = (j >> 8) | (((uint16_t)block[i-1]) << 8); 764 j = (j >> 8) | (((unsigned)block[i-1]) << 8);
760 ftab[j]++; 765 ftab[j]++;
761 quadrant[i-2] = 0; 766 quadrant[i-2] = 0;
762 j = (j >> 8) | (((uint16_t)block[i-2]) << 8); 767 j = (j >> 8) | (((unsigned)block[i-2]) << 8);
763 ftab[j]++; 768 ftab[j]++;
764 quadrant[i-3] = 0; 769 quadrant[i-3] = 0;
765 j = (j >> 8) | (((uint16_t)block[i-3]) << 8); 770 j = (j >> 8) | (((unsigned)block[i-3]) << 8);
766 ftab[j]++; 771 ftab[j]++;
767 } 772 }
768#endif 773#endif
769 for (; i >= 0; i--) { 774 for (; i >= 0; i--) {
770 quadrant[i] = 0; 775 quadrant[i] = 0;
771 j = (j >> 8) | (((uint16_t)block[i]) << 8); 776 j = (j >> 8) | (((unsigned)block[i]) << 8);
772 ftab[j]++; 777 ftab[j]++;
773 } 778 }
774 779
@@ -785,33 +790,36 @@ void mainSort(EState* state,
785 ftab[i] = j; 790 ftab[i] = j;
786 } 791 }
787 792
788 s = block[0] << 8; 793 {
789 i = nblock - 1; 794 unsigned s;
790#if CONFIG_BZIP2_FAST >= 2 795 s = block[0] << 8;
791 for (; i >= 3; i -= 4) { 796 i = nblock - 1;
792 s = (s >> 8) | (block[i] << 8); 797#if BZIP2_SPEED >= 2
793 j = ftab[s] - 1; 798 for (; i >= 3; i -= 4) {
794 ftab[s] = j; 799 s = (s >> 8) | (block[i] << 8);
795 ptr[j] = i; 800 j = ftab[s] - 1;
796 s = (s >> 8) | (block[i-1] << 8); 801 ftab[s] = j;
797 j = ftab[s] - 1; 802 ptr[j] = i;
798 ftab[s] = j; 803 s = (s >> 8) | (block[i-1] << 8);
799 ptr[j] = i-1; 804 j = ftab[s] - 1;
800 s = (s >> 8) | (block[i-2] << 8); 805 ftab[s] = j;
801 j = ftab[s] - 1; 806 ptr[j] = i-1;
802 ftab[s] = j; 807 s = (s >> 8) | (block[i-2] << 8);
803 ptr[j] = i-2; 808 j = ftab[s] - 1;
804 s = (s >> 8) | (block[i-3] << 8); 809 ftab[s] = j;
805 j = ftab[s] - 1; 810 ptr[j] = i-2;
806 ftab[s] = j; 811 s = (s >> 8) | (block[i-3] << 8);
807 ptr[j] = i-3; 812 j = ftab[s] - 1;
808 } 813 ftab[s] = j;
814 ptr[j] = i-3;
815 }
809#endif 816#endif
810 for (; i >= 0; i--) { 817 for (; i >= 0; i--) {
811 s = (s >> 8) | (block[i] << 8); 818 s = (s >> 8) | (block[i] << 8);
812 j = ftab[s] - 1; 819 j = ftab[s] - 1;
813 ftab[s] = j; 820 ftab[s] = j;
814 ptr[j] = i; 821 ptr[j] = i;
822 }
815 } 823 }
816 824
817 /* 825 /*
@@ -825,24 +833,23 @@ void mainSort(EState* state,
825 } 833 }
826 834
827 { 835 {
828 int32_t vv;
829 /* bbox: was: int32_t h = 1; */ 836 /* bbox: was: int32_t h = 1; */
830 /* do h = 3 * h + 1; while (h <= 256); */ 837 /* do h = 3 * h + 1; while (h <= 256); */
831 uint32_t h = 364; 838 unsigned h = 364;
832 839
833 do { 840 do {
834 /*h = h / 3;*/ 841 /*h = h / 3;*/
835 h = (h * 171) >> 9; /* bbox: fast h/3 */ 842 h = (h * 171) >> 9; /* bbox: fast h/3 */
836 for (i = h; i <= 255; i++) { 843 for (i = h; i <= 255; i++) {
837 vv = runningOrder[i]; 844 unsigned vv, jh;
845 vv = runningOrder[i]; /* uint8[] */
838 j = i; 846 j = i;
839 while (BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv)) { 847 while (jh = j - h, BIGFREQ(runningOrder[jh]) > BIGFREQ(vv)) {
840 runningOrder[j] = runningOrder[j-h]; 848 runningOrder[j] = runningOrder[jh];
841 j = j - h; 849 j = jh;
842 if (j <= (h - 1)) 850 if (j < h)
843 goto zero; 851 break;
844 } 852 }
845 zero:
846 runningOrder[j] = vv; 853 runningOrder[j] = vv;
847 } 854 }
848 } while (h != 1); 855 } while (h != 1);
@@ -852,9 +859,8 @@ void mainSort(EState* state,
852 * The main sorting loop. 859 * The main sorting loop.
853 */ 860 */
854 861
855 numQSorted = 0; 862 for (i = 0; /*i <= 255*/; i++) {
856 863 unsigned ss;
857 for (i = 0; i <= 255; i++) {
858 864
859 /* 865 /*
860 * Process big buckets, starting with the least full. 866 * Process big buckets, starting with the least full.
@@ -874,17 +880,14 @@ void mainSort(EState* state,
874 */ 880 */
875 for (j = 0; j <= 255; j++) { 881 for (j = 0; j <= 255; j++) {
876 if (j != ss) { 882 if (j != ss) {
883 unsigned sb;
877 sb = (ss << 8) + j; 884 sb = (ss << 8) + j;
878 if (!(ftab[sb] & SETMASK)) { 885 if (!(ftab[sb] & SETMASK)) {
879 int32_t lo = ftab[sb] & CLEARMASK; 886 int32_t lo = ftab[sb] /*& CLEARMASK (redundant)*/;
880 int32_t hi = (ftab[sb+1] & CLEARMASK) - 1; 887 int32_t hi = (ftab[sb+1] & CLEARMASK) - 1;
881 if (hi > lo) { 888 if (hi > lo) {
882 mainQSort3( 889 mainQSort3(state, lo, hi /*,BZ_N_RADIX*/);
883 ptr, block, quadrant, nblock, 890 if (state->budget < 0) return;
884 lo, hi, BZ_N_RADIX, budget
885 );
886 if (*budget < 0) return;
887 numQSorted += (hi - lo + 1);
888 } 891 }
889 } 892 }
890 ftab[sb] |= SETMASK; 893 ftab[sb] |= SETMASK;
@@ -906,6 +909,8 @@ void mainSort(EState* state,
906 copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1; 909 copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1;
907 } 910 }
908 for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) { 911 for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) {
912 unsigned c1;
913 int32_t k;
909 k = ptr[j] - 1; 914 k = ptr[j] - 1;
910 if (k < 0) 915 if (k < 0)
911 k += nblock; 916 k += nblock;
@@ -914,6 +919,8 @@ void mainSort(EState* state,
914 ptr[copyStart[c1]++] = k; 919 ptr[copyStart[c1]++] = k;
915 } 920 }
916 for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) { 921 for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) {
922 unsigned c1;
923 int32_t k;
917 k = ptr[j]-1; 924 k = ptr[j]-1;
918 if (k < 0) 925 if (k < 0)
919 k += nblock; 926 k += nblock;
@@ -933,6 +940,9 @@ void mainSort(EState* state,
933 for (j = 0; j <= 255; j++) 940 for (j = 0; j <= 255; j++)
934 ftab[(j << 8) + ss] |= SETMASK; 941 ftab[(j << 8) + ss] |= SETMASK;
935 942
943 if (i == 255)
944 break;
945
936 /* 946 /*
937 * Step 3: 947 * Step 3:
938 * The [ss] big bucket is now done. Record this fact, 948 * The [ss] big bucket is now done. Record this fact,
@@ -974,15 +984,15 @@ void mainSort(EState* state,
974 */ 984 */
975 bigDone[ss] = True; 985 bigDone[ss] = True;
976 986
977 if (i < 255) { 987 {
978 int32_t bbStart = ftab[ss << 8] & CLEARMASK; 988 unsigned bbStart = ftab[ss << 8] & CLEARMASK;
979 int32_t bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart; 989 unsigned bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart;
980 int32_t shifts = 0; 990 unsigned shifts = 0;
981 991
982 while ((bbSize >> shifts) > 65534) shifts++; 992 while ((bbSize >> shifts) > 65534) shifts++;
983 993
984 for (j = bbSize-1; j >= 0; j--) { 994 for (j = bbSize-1; j >= 0; j--) {
985 int32_t a2update = ptr[bbStart + j]; 995 unsigned a2update = ptr[bbStart + j]; /* uint32[] */
986 uint16_t qVal = (uint16_t)(j >> shifts); 996 uint16_t qVal = (uint16_t)(j >> shifts);
987 quadrant[a2update] = qVal; 997 quadrant[a2update] = qVal;
988 if (a2update < BZ_N_OVERSHOOT) 998 if (a2update < BZ_N_OVERSHOOT)
@@ -1015,31 +1025,24 @@ void mainSort(EState* state,
1015 * arr1[0 .. nblock-1] holds sorted order 1025 * arr1[0 .. nblock-1] holds sorted order
1016 */ 1026 */
1017static NOINLINE 1027static NOINLINE
1018void BZ2_blockSort(EState* s) 1028int32_t BZ2_blockSort(EState* state)
1019{ 1029{
1020 /* In original bzip2 1.0.4, it's a parameter, but 30 1030 /* In original bzip2 1.0.4, it's a parameter, but 30
1021 * (which was the default) should work ok. */ 1031 * (which was the default) should work ok. */
1022 enum { wfact = 30 }; 1032 enum { wfact = 30 };
1033 unsigned i;
1034 int32_t origPtr = origPtr;
1023 1035
1024 uint32_t* ptr = s->ptr; 1036 if (state->nblock >= 10000) {
1025 uint8_t* block = s->block;
1026 uint32_t* ftab = s->ftab;
1027 int32_t nblock = s->nblock;
1028 uint16_t* quadrant;
1029 int32_t budget;
1030 int32_t i;
1031
1032 if (nblock < 10000) {
1033 fallbackSort(s->arr1, s->arr2, ftab, nblock);
1034 } else {
1035 /* Calculate the location for quadrant, remembering to get 1037 /* Calculate the location for quadrant, remembering to get
1036 * the alignment right. Assumes that &(block[0]) is at least 1038 * the alignment right. Assumes that &(block[0]) is at least
1037 * 2-byte aligned -- this should be ok since block is really 1039 * 2-byte aligned -- this should be ok since block is really
1038 * the first section of arr2. 1040 * the first section of arr2.
1039 */ 1041 */
1040 i = nblock + BZ_N_OVERSHOOT; 1042 i = state->nblock + BZ_N_OVERSHOOT;
1041 if (i & 1) i++; 1043 if (i & 1)
1042 quadrant = (uint16_t*)(&(block[i])); 1044 i++;
1045 state->quadrant = (uint16_t*) &(state->block[i]);
1043 1046
1044 /* (wfact-1) / 3 puts the default-factor-30 1047 /* (wfact-1) / 3 puts the default-factor-30
1045 * transition point at very roughly the same place as 1048 * transition point at very roughly the same place as
@@ -1048,22 +1051,26 @@ void BZ2_blockSort(EState* s)
1048 * resulting compressed stream is now the same regardless 1051 * resulting compressed stream is now the same regardless
1049 * of whether or not we use the main sort or fallback sort. 1052 * of whether or not we use the main sort or fallback sort.
1050 */ 1053 */
1051 budget = nblock * ((wfact-1) / 3); 1054 state->budget = state->nblock * ((wfact-1) / 3);
1052 1055 mainSort(state);
1053 mainSort(s, ptr, block, quadrant, ftab, nblock, &budget); 1056 if (state->budget >= 0)
1054 if (budget < 0) { 1057 goto good;
1055 fallbackSort(s->arr1, s->arr2, ftab, nblock);
1056 }
1057 } 1058 }
1059 fallbackSort(state);
1060 good:
1058 1061
1059 s->origPtr = -1; 1062#if BZ_LIGHT_DEBUG
1060 for (i = 0; i < s->nblock; i++) 1063 origPtr = -1;
1061 if (ptr[i] == 0) { 1064#endif
1062 s->origPtr = i; 1065 for (i = 0; i < state->nblock; i++) {
1066 if (state->ptr[i] == 0) {
1067 origPtr = i;
1063 break; 1068 break;
1064 }; 1069 }
1070 }
1065 1071
1066 AssertH(s->origPtr != -1, 1003); 1072 AssertH(origPtr != -1, 1003);
1073 return origPtr;
1067} 1074}
1068 1075
1069 1076
diff --git a/archival/libarchive/bz/bzlib.c b/archival/libarchive/bz/bzlib.c
index 5f7db747a..9af2f026d 100644
--- a/archival/libarchive/bz/bzlib.c
+++ b/archival/libarchive/bz/bzlib.c
@@ -55,8 +55,9 @@ void prepare_new_block(EState* s)
55{ 55{
56 int i; 56 int i;
57 s->nblock = 0; 57 s->nblock = 0;
58 s->numZ = 0; 58 //indexes into s->zbits[], initialzation moved to init of s->zbits
59 s->state_out_pos = 0; 59 //s->posZ = s->zbits; // was: s->numZ = 0;
60 //s->state_out_pos = s->zbits;
60 BZ_INITIALISE_CRC(s->blockCRC); 61 BZ_INITIALISE_CRC(s->blockCRC);
61 /* inlined memset would be nice to have here */ 62 /* inlined memset would be nice to have here */
62 for (i = 0; i < 256; i++) 63 for (i = 0; i < 256; i++)
@@ -86,7 +87,7 @@ int isempty_RL(EState* s)
86static 87static
87void BZ2_bzCompressInit(bz_stream *strm, int blockSize100k) 88void BZ2_bzCompressInit(bz_stream *strm, int blockSize100k)
88{ 89{
89 int32_t n; 90 unsigned n;
90 EState* s; 91 EState* s;
91 92
92 s = xzalloc(sizeof(EState)); 93 s = xzalloc(sizeof(EState));
@@ -237,11 +238,10 @@ void /*Bool*/ copy_output_until_stop(EState* s)
237 if (s->strm->avail_out == 0) break; 238 if (s->strm->avail_out == 0) break;
238 239
239 /*-- block done? --*/ 240 /*-- block done? --*/
240 if (s->state_out_pos >= s->numZ) break; 241 if (s->state_out_pos >= s->posZ) break;
241 242
242 /*progress_out = True;*/ 243 /*progress_out = True;*/
243 *(s->strm->next_out) = s->zbits[s->state_out_pos]; 244 *(s->strm->next_out) = *s->state_out_pos++;
244 s->state_out_pos++;
245 s->strm->avail_out--; 245 s->strm->avail_out--;
246 s->strm->next_out++; 246 s->strm->next_out++;
247 s->strm->total_out++; 247 s->strm->total_out++;
@@ -261,7 +261,7 @@ void /*Bool*/ handle_compress(bz_stream *strm)
261 while (1) { 261 while (1) {
262 if (s->state == BZ_S_OUTPUT) { 262 if (s->state == BZ_S_OUTPUT) {
263 /*progress_out |=*/ copy_output_until_stop(s); 263 /*progress_out |=*/ copy_output_until_stop(s);
264 if (s->state_out_pos < s->numZ) break; 264 if (s->state_out_pos < s->posZ) break;
265 if (s->mode == BZ_M_FINISHING 265 if (s->mode == BZ_M_FINISHING
266 //# && s->avail_in_expect == 0 266 //# && s->avail_in_expect == 0
267 && s->strm->avail_in == 0 267 && s->strm->avail_in == 0
@@ -336,7 +336,7 @@ int BZ2_bzCompress(bz_stream *strm, int action)
336 /*if (s->avail_in_expect != s->strm->avail_in) 336 /*if (s->avail_in_expect != s->strm->avail_in)
337 return BZ_SEQUENCE_ERROR;*/ 337 return BZ_SEQUENCE_ERROR;*/
338 /*progress =*/ handle_compress(strm); 338 /*progress =*/ handle_compress(strm);
339 if (s->avail_in_expect > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ) 339 if (s->avail_in_expect > 0 || !isempty_RL(s) || s->state_out_pos < s->posZ)
340 return BZ_FLUSH_OK; 340 return BZ_FLUSH_OK;
341 s->mode = BZ_M_RUNNING; 341 s->mode = BZ_M_RUNNING;
342 return BZ_RUN_OK; 342 return BZ_RUN_OK;
@@ -349,9 +349,9 @@ int BZ2_bzCompress(bz_stream *strm, int action)
349 return BZ_SEQUENCE_ERROR;*/ 349 return BZ_SEQUENCE_ERROR;*/
350 /*progress =*/ handle_compress(strm); 350 /*progress =*/ handle_compress(strm);
351 /*if (!progress) return BZ_SEQUENCE_ERROR;*/ 351 /*if (!progress) return BZ_SEQUENCE_ERROR;*/
352 //#if (s->avail_in_expect > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ) 352 //#if (s->avail_in_expect > 0 || !isempty_RL(s) || s->state_out_pos < s->posZ)
353 //# return BZ_FINISH_OK; 353 //# return BZ_FINISH_OK;
354 if (s->strm->avail_in > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ) 354 if (s->strm->avail_in > 0 || !isempty_RL(s) || s->state_out_pos < s->posZ)
355 return BZ_FINISH_OK; 355 return BZ_FINISH_OK;
356 /*s->mode = BZ_M_IDLE;*/ 356 /*s->mode = BZ_M_IDLE;*/
357 return BZ_STREAM_END; 357 return BZ_STREAM_END;
diff --git a/archival/libarchive/bz/bzlib_private.h b/archival/libarchive/bz/bzlib_private.h
index 43e674bec..ea0f29b7c 100644
--- a/archival/libarchive/bz/bzlib_private.h
+++ b/archival/libarchive/bz/bzlib_private.h
@@ -120,8 +120,11 @@ typedef struct EState {
120 120
121 /* mode this stream is in, and whether inputting */ 121 /* mode this stream is in, and whether inputting */
122 /* or outputting data */ 122 /* or outputting data */
123 int32_t mode; 123 uint8_t mode;
124 int32_t state; 124 uint8_t state;
125
126 /* misc administratium */
127 uint8_t blockSize100k;
125 128
126 /* remembers avail_in when flush/finish requested */ 129 /* remembers avail_in when flush/finish requested */
127/* bbox: not needed, strm->avail_in always has the same value */ 130/* bbox: not needed, strm->avail_in always has the same value */
@@ -129,20 +132,19 @@ typedef struct EState {
129 /* uint32_t avail_in_expect; */ 132 /* uint32_t avail_in_expect; */
130 133
131 /* for doing the block sorting */ 134 /* for doing the block sorting */
132 int32_t origPtr;
133 uint32_t *arr1; 135 uint32_t *arr1;
134 uint32_t *arr2; 136 uint32_t *arr2;
135 uint32_t *ftab; 137 uint32_t *ftab;
136 138
139 uint16_t *quadrant;
140 int32_t budget;
141
137 /* aliases for arr1 and arr2 */ 142 /* aliases for arr1 and arr2 */
138 uint32_t *ptr; 143 uint32_t *ptr;
139 uint8_t *block; 144 uint8_t *block;
140 uint16_t *mtfv; 145 uint16_t *mtfv;
141 uint8_t *zbits; 146 uint8_t *zbits;
142 147
143 /* guess what */
144 uint32_t *crc32table;
145
146 /* run-length-encoding of the input */ 148 /* run-length-encoding of the input */
147 uint32_t state_in_ch; 149 uint32_t state_in_ch;
148 int32_t state_in_len; 150 int32_t state_in_len;
@@ -150,20 +152,23 @@ typedef struct EState {
150 /* input and output limits and current posns */ 152 /* input and output limits and current posns */
151 int32_t nblock; 153 int32_t nblock;
152 int32_t nblockMAX; 154 int32_t nblockMAX;
153 int32_t numZ; 155 //int32_t numZ; // index into s->zbits[], replaced by pointer:
154 int32_t state_out_pos; 156 uint8_t *posZ;
157 uint8_t *state_out_pos;
155 158
156 /* the buffer for bit stream creation */ 159 /* the buffer for bit stream creation */
157 uint32_t bsBuff; 160 uint32_t bsBuff;
158 int32_t bsLive; 161 int32_t bsLive;
159 162
163 /* guess what */
164 uint32_t *crc32table;
165
160 /* block and combined CRCs */ 166 /* block and combined CRCs */
161 uint32_t blockCRC; 167 uint32_t blockCRC;
162 uint32_t combinedCRC; 168 uint32_t combinedCRC;
163 169
164 /* misc administratium */ 170 /* misc administratium */
165 int32_t blockNo; 171 int32_t blockNo;
166 int32_t blockSize100k;
167 172
168 /* stuff for coding the MTF values */ 173 /* stuff for coding the MTF values */
169 int32_t nMTF; 174 int32_t nMTF;
@@ -183,7 +188,7 @@ typedef struct EState {
183 /* stack-saving measures: these can be local, but they are too big */ 188 /* stack-saving measures: these can be local, but they are too big */
184 int32_t sendMTFValues__code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; 189 int32_t sendMTFValues__code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
185 int32_t sendMTFValues__rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; 190 int32_t sendMTFValues__rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
186#if CONFIG_BZIP2_FAST >= 5 191#if BZIP2_SPEED >= 5
187 /* second dimension: only 3 needed; 4 makes index calculations faster */ 192 /* second dimension: only 3 needed; 4 makes index calculations faster */
188 uint32_t sendMTFValues__len_pack[BZ_MAX_ALPHA_SIZE][4]; 193 uint32_t sendMTFValues__len_pack[BZ_MAX_ALPHA_SIZE][4];
189#endif 194#endif
@@ -191,7 +196,6 @@ typedef struct EState {
191 int32_t BZ2_hbMakeCodeLengths__weight[BZ_MAX_ALPHA_SIZE * 2]; 196 int32_t BZ2_hbMakeCodeLengths__weight[BZ_MAX_ALPHA_SIZE * 2];
192 int32_t BZ2_hbMakeCodeLengths__parent[BZ_MAX_ALPHA_SIZE * 2]; 197 int32_t BZ2_hbMakeCodeLengths__parent[BZ_MAX_ALPHA_SIZE * 2];
193 198
194 int32_t mainSort__runningOrder[256];
195 int32_t mainSort__copyStart[256]; 199 int32_t mainSort__copyStart[256];
196 int32_t mainSort__copyEnd[256]; 200 int32_t mainSort__copyEnd[256];
197} EState; 201} EState;
@@ -199,7 +203,7 @@ typedef struct EState {
199 203
200/*-- compression. --*/ 204/*-- compression. --*/
201 205
202static void 206static int32_t
203BZ2_blockSort(EState*); 207BZ2_blockSort(EState*);
204 208
205static void 209static void
diff --git a/archival/libarchive/bz/compress.c b/archival/libarchive/bz/compress.c
index 2d994685c..539ab927e 100644
--- a/archival/libarchive/bz/compress.c
+++ b/archival/libarchive/bz/compress.c
@@ -32,6 +32,12 @@ in the file LICENSE.
32 32
33/* #include "bzlib_private.h" */ 33/* #include "bzlib_private.h" */
34 34
35#if BZIP2_SPEED >= 5
36# define ALWAYS_INLINE_5 ALWAYS_INLINE
37#else
38# define ALWAYS_INLINE_5 /*nothing*/
39#endif
40
35/*---------------------------------------------------*/ 41/*---------------------------------------------------*/
36/*--- Bit stream I/O ---*/ 42/*--- Bit stream I/O ---*/
37/*---------------------------------------------------*/ 43/*---------------------------------------------------*/
@@ -50,8 +56,7 @@ static NOINLINE
50void bsFinishWrite(EState* s) 56void bsFinishWrite(EState* s)
51{ 57{
52 while (s->bsLive > 0) { 58 while (s->bsLive > 0) {
53 s->zbits[s->numZ] = (uint8_t)(s->bsBuff >> 24); 59 *s->posZ++ = (uint8_t)(s->bsBuff >> 24);
54 s->numZ++;
55 s->bsBuff <<= 8; 60 s->bsBuff <<= 8;
56 s->bsLive -= 8; 61 s->bsLive -= 8;
57 } 62 }
@@ -61,39 +66,74 @@ void bsFinishWrite(EState* s)
61/*---------------------------------------------------*/ 66/*---------------------------------------------------*/
62static 67static
63/* Helps only on level 5, on other levels hurts. ? */ 68/* Helps only on level 5, on other levels hurts. ? */
64#if CONFIG_BZIP2_FAST >= 5 69ALWAYS_INLINE_5
65ALWAYS_INLINE
66#endif
67void bsW(EState* s, int32_t n, uint32_t v) 70void bsW(EState* s, int32_t n, uint32_t v)
68{ 71{
69 while (s->bsLive >= 8) { 72 while (s->bsLive >= 8) {
70 s->zbits[s->numZ] = (uint8_t)(s->bsBuff >> 24); 73 *s->posZ++ = (uint8_t)(s->bsBuff >> 24);
71 s->numZ++;
72 s->bsBuff <<= 8; 74 s->bsBuff <<= 8;
73 s->bsLive -= 8; 75 s->bsLive -= 8;
74 } 76 }
75 s->bsBuff |= (v << (32 - s->bsLive - n)); 77 s->bsBuff |= (v << (32 - s->bsLive - n));
76 s->bsLive += n; 78 s->bsLive += n;
77} 79}
80/* Same with n == 16: */
81static
82ALWAYS_INLINE_5
83void bsW16(EState* s, uint32_t v)
84{
85 while (s->bsLive >= 8) {
86 *s->posZ++ = (uint8_t)(s->bsBuff >> 24);
87 s->bsBuff <<= 8;
88 s->bsLive -= 8;
89 }
90 s->bsBuff |= (v << (16 - s->bsLive));
91 s->bsLive += 16;
92}
93/* Same with n == 1: */
94static
95ALWAYS_INLINE /* one callsite */
96void bsW1_1(EState* s)
97{
98 /* need space for only 1 bit, no need for loop freeing > 8 bits */
99 if (s->bsLive >= 8) {
100 *s->posZ++ = (uint8_t)(s->bsBuff >> 24);
101 s->bsBuff <<= 8;
102 s->bsLive -= 8;
103 }
104 s->bsBuff |= (1 << (31 - s->bsLive));
105 s->bsLive += 1;
106}
107static
108ALWAYS_INLINE_5
109void bsW1_0(EState* s)
110{
111 /* need space for only 1 bit, no need for loop freeing > 8 bits */
112 if (s->bsLive >= 8) {
113 *s->posZ++ = (uint8_t)(s->bsBuff >> 24);
114 s->bsBuff <<= 8;
115 s->bsLive -= 8;
116 }
117 //s->bsBuff |= (0 << (31 - s->bsLive));
118 s->bsLive += 1;
119}
78 120
79 121
80/*---------------------------------------------------*/ 122/*---------------------------------------------------*/
81static 123static ALWAYS_INLINE
82void bsPutU32(EState* s, unsigned u) 124void bsPutU16(EState* s, unsigned u)
83{ 125{
84 bsW(s, 8, (u >> 24) & 0xff); 126 bsW16(s, u);
85 bsW(s, 8, (u >> 16) & 0xff);
86 bsW(s, 8, (u >> 8) & 0xff);
87 bsW(s, 8, u & 0xff);
88} 127}
89 128
90 129
91/*---------------------------------------------------*/ 130/*---------------------------------------------------*/
92static 131static
93void bsPutU16(EState* s, unsigned u) 132void bsPutU32(EState* s, unsigned u)
94{ 133{
95 bsW(s, 8, (u >> 8) & 0xff); 134 //bsW(s, 32, u); // can't use: may try "uint32 << -n"
96 bsW(s, 8, u & 0xff); 135 bsW16(s, (u >> 16) & 0xffff);
136 bsW16(s, u & 0xffff);
97} 137}
98 138
99 139
@@ -106,25 +146,57 @@ static
106void makeMaps_e(EState* s) 146void makeMaps_e(EState* s)
107{ 147{
108 int i; 148 int i;
109 s->nInUse = 0; 149 unsigned cnt = 0;
110 for (i = 0; i < 256; i++) { 150 for (i = 0; i < 256; i++) {
111 if (s->inUse[i]) { 151 if (s->inUse[i]) {
112 s->unseqToSeq[i] = s->nInUse; 152 s->unseqToSeq[i] = cnt;
113 s->nInUse++; 153 cnt++;
114 } 154 }
115 } 155 }
156 s->nInUse = cnt;
116} 157}
117 158
118 159
119/*---------------------------------------------------*/ 160/*---------------------------------------------------*/
161/*
162 * This bit of code is performance-critical.
163 * On 32bit x86, gcc-6.3.0 was observed to spill ryy_j to stack,
164 * resulting in abysmal performance (x3 slowdown).
165 * Forcing it into a separate function alleviates register pressure,
166 * and spillage no longer happens.
167 * Other versions of gcc do not exhibit this problem, but out-of-line code
168 * seems to be helping them too (code is both smaller and faster).
169 * Therefore NOINLINE is enabled for the entire 32bit x86 arch for now,
170 * without a check for gcc version.
171 */
172static
173#if defined __i386__
174NOINLINE
175#endif
176int inner_loop(uint8_t *yy, uint8_t ll_i)
177{
178 register uint8_t rtmp;
179 register uint8_t* ryy_j;
180 rtmp = yy[1];
181 yy[1] = yy[0];
182 ryy_j = &(yy[1]);
183 while (ll_i != rtmp) {
184 register uint8_t rtmp2;
185 ryy_j++;
186 rtmp2 = rtmp;
187 rtmp = *ryy_j;
188 *ryy_j = rtmp2;
189 }
190 yy[0] = rtmp;
191 return ryy_j - &(yy[0]);
192}
120static NOINLINE 193static NOINLINE
121void generateMTFValues(EState* s) 194void generateMTFValues(EState* s)
122{ 195{
123 uint8_t yy[256]; 196 uint8_t yy[256];
124 int32_t i, j; 197 int i;
125 int32_t zPend; 198 int zPend;
126 int32_t wr; 199 int32_t wr;
127 int32_t EOB;
128 200
129 /* 201 /*
130 * After sorting (eg, here), 202 * After sorting (eg, here),
@@ -148,95 +220,74 @@ void generateMTFValues(EState* s)
148 * compressBlock(). 220 * compressBlock().
149 */ 221 */
150 uint32_t* ptr = s->ptr; 222 uint32_t* ptr = s->ptr;
151 uint8_t* block = s->block;
152 uint16_t* mtfv = s->mtfv;
153 223
154 makeMaps_e(s); 224 makeMaps_e(s);
155 EOB = s->nInUse+1;
156
157 for (i = 0; i <= EOB; i++)
158 s->mtfFreq[i] = 0;
159 225
160 wr = 0; 226 wr = 0;
161 zPend = 0; 227 zPend = 0;
228 for (i = 0; i <= s->nInUse+1; i++)
229 s->mtfFreq[i] = 0;
230
162 for (i = 0; i < s->nInUse; i++) 231 for (i = 0; i < s->nInUse; i++)
163 yy[i] = (uint8_t) i; 232 yy[i] = (uint8_t) i;
164 233
165 for (i = 0; i < s->nblock; i++) { 234 for (i = 0; i < s->nblock; i++) {
166 uint8_t ll_i; 235 uint8_t ll_i = ll_i; /* gcc 4.3.1 thinks it may be used w/o init */
236 int32_t j;
237
167 AssertD(wr <= i, "generateMTFValues(1)"); 238 AssertD(wr <= i, "generateMTFValues(1)");
168 j = ptr[i] - 1; 239 j = ptr[i] - 1;
169 if (j < 0) 240 if (j < 0)
170 j += s->nblock; 241 j += s->nblock;
171 ll_i = s->unseqToSeq[block[j]]; 242 ll_i = s->unseqToSeq[s->block[j]];
172 AssertD(ll_i < s->nInUse, "generateMTFValues(2a)"); 243 AssertD(ll_i < s->nInUse, "generateMTFValues(2a)");
173 244
174 if (yy[0] == ll_i) { 245 if (yy[0] == ll_i) {
175 zPend++; 246 zPend++;
176 } else { 247 continue;
177 if (zPend > 0) {
178 zPend--;
179 while (1) {
180 if (zPend & 1) {
181 mtfv[wr] = BZ_RUNB; wr++;
182 s->mtfFreq[BZ_RUNB]++;
183 } else {
184 mtfv[wr] = BZ_RUNA; wr++;
185 s->mtfFreq[BZ_RUNA]++;
186 }
187 if (zPend < 2) break;
188 zPend = (uint32_t)(zPend - 2) / 2;
189 /* bbox: unsigned div is easier */
190 };
191 zPend = 0;
192 }
193 {
194 register uint8_t rtmp;
195 register uint8_t* ryy_j;
196 register uint8_t rll_i;
197 rtmp = yy[1];
198 yy[1] = yy[0];
199 ryy_j = &(yy[1]);
200 rll_i = ll_i;
201 while (rll_i != rtmp) {
202 register uint8_t rtmp2;
203 ryy_j++;
204 rtmp2 = rtmp;
205 rtmp = *ryy_j;
206 *ryy_j = rtmp2;
207 };
208 yy[0] = rtmp;
209 j = ryy_j - &(yy[0]);
210 mtfv[wr] = j+1;
211 wr++;
212 s->mtfFreq[j+1]++;
213 }
214 } 248 }
215 }
216 249
217 if (zPend > 0) { 250 if (zPend > 0) {
218 zPend--; 251 process_zPend:
219 while (1) { 252 zPend--;
220 if (zPend & 1) { 253 while (1) {
221 mtfv[wr] = BZ_RUNB; 254#if 0
222 wr++; 255 if (zPend & 1) {
223 s->mtfFreq[BZ_RUNB]++; 256 s->mtfv[wr] = BZ_RUNB; wr++;
224 } else { 257 s->mtfFreq[BZ_RUNB]++;
225 mtfv[wr] = BZ_RUNA; 258 } else {
259 s->mtfv[wr] = BZ_RUNA; wr++;
260 s->mtfFreq[BZ_RUNA]++;
261 }
262#else /* same as above, since BZ_RUNA is 0 and BZ_RUNB is 1 */
263 unsigned run = zPend & 1;
264 s->mtfv[wr] = run;
226 wr++; 265 wr++;
227 s->mtfFreq[BZ_RUNA]++; 266 s->mtfFreq[run]++;
267#endif
268 zPend -= 2;
269 if (zPend < 0)
270 break;
271 zPend = (unsigned)zPend / 2;
272 /* bbox: unsigned div is easier */
228 } 273 }
229 if (zPend < 2) 274 if (i < 0) /* came via "goto process_zPend"? exit */
230 break; 275 goto end;
231 zPend = (uint32_t)(zPend - 2) / 2; 276 zPend = 0;
232 /* bbox: unsigned div is easier */ 277 }
233 }; 278 j = inner_loop(yy, ll_i);
234 zPend = 0; 279 s->mtfv[wr] = j+1;
280 wr++;
281 s->mtfFreq[j+1]++;
235 } 282 }
236 283
237 mtfv[wr] = EOB; 284 i = -1;
285 if (zPend > 0)
286 goto process_zPend; /* "process it and come back here" */
287 end:
288 s->mtfv[wr] = s->nInUse+1;
238 wr++; 289 wr++;
239 s->mtfFreq[EOB]++; 290 s->mtfFreq[s->nInUse+1]++;
240 291
241 s->nMTF = wr; 292 s->nMTF = wr;
242} 293}
@@ -249,8 +300,11 @@ void generateMTFValues(EState* s)
249static NOINLINE 300static NOINLINE
250void sendMTFValues(EState* s) 301void sendMTFValues(EState* s)
251{ 302{
252 int32_t v, t, i, j, gs, ge, bt, bc, iter; 303 int32_t t, i;
253 int32_t nSelectors, alphaSize, minLen, maxLen, selCtr; 304 unsigned iter;
305 unsigned gs;
306 int32_t alphaSize;
307 unsigned nSelectors, selCtr;
254 int32_t nGroups; 308 int32_t nGroups;
255 309
256 /* 310 /*
@@ -266,39 +320,49 @@ void sendMTFValues(EState* s)
266#define rfreq sendMTFValues__rfreq 320#define rfreq sendMTFValues__rfreq
267#define len_pack sendMTFValues__len_pack 321#define len_pack sendMTFValues__len_pack
268 322
269 uint16_t cost[BZ_N_GROUPS]; 323 unsigned /*uint16_t*/ cost[BZ_N_GROUPS];
270 int32_t fave[BZ_N_GROUPS];
271 324
272 uint16_t* mtfv = s->mtfv; 325 uint16_t* mtfv = s->mtfv;
273 326
274 alphaSize = s->nInUse + 2; 327 alphaSize = s->nInUse + 2;
275 for (t = 0; t < BZ_N_GROUPS; t++) 328 for (t = 0; t < BZ_N_GROUPS; t++) {
329 unsigned v;
276 for (v = 0; v < alphaSize; v++) 330 for (v = 0; v < alphaSize; v++)
277 s->len[t][v] = BZ_GREATER_ICOST; 331 s->len[t][v] = BZ_GREATER_ICOST;
332 }
278 333
279 /*--- Decide how many coding tables to use ---*/ 334 /*--- Decide how many coding tables to use ---*/
280 AssertH(s->nMTF > 0, 3001); 335 AssertH(s->nMTF > 0, 3001);
281 if (s->nMTF < 200) nGroups = 2; else 336 // 1..199 = 2
282 if (s->nMTF < 600) nGroups = 3; else 337 // 200..599 = 3
283 if (s->nMTF < 1200) nGroups = 4; else 338 // 600..1199 = 4
284 if (s->nMTF < 2400) nGroups = 5; else 339 // 1200..2399 = 5
285 nGroups = 6; 340 // 2400..99999 = 6
341 nGroups = 2;
342 nGroups += (s->nMTF >= 200);
343 nGroups += (s->nMTF >= 600);
344 nGroups += (s->nMTF >= 1200);
345 nGroups += (s->nMTF >= 2400);
286 346
287 /*--- Generate an initial set of coding tables ---*/ 347 /*--- Generate an initial set of coding tables ---*/
288 { 348 {
289 int32_t nPart, remF, tFreq, aFreq; 349 unsigned nPart, remF;
290 350
291 nPart = nGroups; 351 nPart = nGroups;
292 remF = s->nMTF; 352 remF = s->nMTF;
293 gs = 0; 353 gs = 0;
294 while (nPart > 0) { 354 while (nPart > 0) {
355 unsigned v;
356 unsigned ge;
357 unsigned tFreq, aFreq;
358
295 tFreq = remF / nPart; 359 tFreq = remF / nPart;
296 ge = gs - 1; 360 ge = gs;
297 aFreq = 0; 361 aFreq = 0;
298 while (aFreq < tFreq && ge < alphaSize-1) { 362 while (aFreq < tFreq && ge < alphaSize) {
299 ge++; 363 aFreq += s->mtfFreq[ge++];
300 aFreq += s->mtfFreq[ge];
301 } 364 }
365 ge--;
302 366
303 if (ge > gs 367 if (ge > gs
304 && nPart != nGroups && nPart != 1 368 && nPart != nGroups && nPart != 1
@@ -324,19 +388,19 @@ void sendMTFValues(EState* s)
324 * Iterate up to BZ_N_ITERS times to improve the tables. 388 * Iterate up to BZ_N_ITERS times to improve the tables.
325 */ 389 */
326 for (iter = 0; iter < BZ_N_ITERS; iter++) { 390 for (iter = 0; iter < BZ_N_ITERS; iter++) {
327 for (t = 0; t < nGroups; t++) 391 for (t = 0; t < nGroups; t++) {
328 fave[t] = 0; 392 unsigned v;
329
330 for (t = 0; t < nGroups; t++)
331 for (v = 0; v < alphaSize; v++) 393 for (v = 0; v < alphaSize; v++)
332 s->rfreq[t][v] = 0; 394 s->rfreq[t][v] = 0;
395 }
333 396
334#if CONFIG_BZIP2_FAST >= 5 397#if BZIP2_SPEED >= 5
335 /* 398 /*
336 * Set up an auxiliary length table which is used to fast-track 399 * Set up an auxiliary length table which is used to fast-track
337 * the common case (nGroups == 6). 400 * the common case (nGroups == 6).
338 */ 401 */
339 if (nGroups == 6) { 402 if (nGroups == 6) {
403 unsigned v;
340 for (v = 0; v < alphaSize; v++) { 404 for (v = 0; v < alphaSize; v++) {
341 s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v]; 405 s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v];
342 s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v]; 406 s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v];
@@ -347,6 +411,9 @@ void sendMTFValues(EState* s)
347 nSelectors = 0; 411 nSelectors = 0;
348 gs = 0; 412 gs = 0;
349 while (1) { 413 while (1) {
414 unsigned ge;
415 unsigned bt, bc;
416
350 /*--- Set group start & end marks. --*/ 417 /*--- Set group start & end marks. --*/
351 if (gs >= s->nMTF) 418 if (gs >= s->nMTF)
352 break; 419 break;
@@ -360,7 +427,7 @@ void sendMTFValues(EState* s)
360 */ 427 */
361 for (t = 0; t < nGroups; t++) 428 for (t = 0; t < nGroups; t++)
362 cost[t] = 0; 429 cost[t] = 0;
363#if CONFIG_BZIP2_FAST >= 5 430#if BZIP2_SPEED >= 5
364 if (nGroups == 6 && 50 == ge-gs+1) { 431 if (nGroups == 6 && 50 == ge-gs+1) {
365 /*--- fast track the common case ---*/ 432 /*--- fast track the common case ---*/
366 register uint32_t cost01, cost23, cost45; 433 register uint32_t cost01, cost23, cost45;
@@ -390,7 +457,7 @@ void sendMTFValues(EState* s)
390 { 457 {
391 /*--- slow version which correctly handles all situations ---*/ 458 /*--- slow version which correctly handles all situations ---*/
392 for (i = gs; i <= ge; i++) { 459 for (i = gs; i <= ge; i++) {
393 uint16_t icv = mtfv[i]; 460 unsigned /*uint16_t*/ icv = mtfv[i];
394 for (t = 0; t < nGroups; t++) 461 for (t = 0; t < nGroups; t++)
395 cost[t] += s->len[t][icv]; 462 cost[t] += s->len[t][icv];
396 } 463 }
@@ -409,7 +476,6 @@ void sendMTFValues(EState* s)
409 bt = t; 476 bt = t;
410 } 477 }
411 } 478 }
412 fave[bt]++;
413 s->selector[nSelectors] = bt; 479 s->selector[nSelectors] = bt;
414 nSelectors++; 480 nSelectors++;
415 481
@@ -417,7 +483,7 @@ void sendMTFValues(EState* s)
417 * Increment the symbol frequencies for the selected table. 483 * Increment the symbol frequencies for the selected table.
418 */ 484 */
419/* 1% faster compress. +800 bytes */ 485/* 1% faster compress. +800 bytes */
420#if CONFIG_BZIP2_FAST >= 4 486#if BZIP2_SPEED >= 4
421 if (nGroups == 6 && 50 == ge-gs+1) { 487 if (nGroups == 6 && 50 == ge-gs+1) {
422 /*--- fast track the common case ---*/ 488 /*--- fast track the common case ---*/
423#define BZ_ITUR(nn) s->rfreq[bt][mtfv[gs + (nn)]]++ 489#define BZ_ITUR(nn) s->rfreq[bt][mtfv[gs + (nn)]]++
@@ -464,6 +530,7 @@ void sendMTFValues(EState* s)
464 for (i = 0; i < nGroups; i++) 530 for (i = 0; i < nGroups; i++)
465 pos[i] = i; 531 pos[i] = i;
466 for (i = 0; i < nSelectors; i++) { 532 for (i = 0; i < nSelectors; i++) {
533 unsigned j;
467 ll_i = s->selector[i]; 534 ll_i = s->selector[i];
468 j = 0; 535 j = 0;
469 tmp = pos[j]; 536 tmp = pos[j];
@@ -472,16 +539,16 @@ void sendMTFValues(EState* s)
472 tmp2 = tmp; 539 tmp2 = tmp;
473 tmp = pos[j]; 540 tmp = pos[j];
474 pos[j] = tmp2; 541 pos[j] = tmp2;
475 }; 542 }
476 pos[0] = tmp; 543 pos[0] = tmp;
477 s->selectorMtf[i] = j; 544 s->selectorMtf[i] = j;
478 } 545 }
479 }; 546 }
480 547
481 /*--- Assign actual codes for the tables. --*/ 548 /*--- Assign actual codes for the tables. --*/
482 for (t = 0; t < nGroups; t++) { 549 for (t = 0; t < nGroups; t++) {
483 minLen = 32; 550 unsigned minLen = 32; //todo: s->len[t][0];
484 maxLen = 0; 551 unsigned maxLen = 0; //todo: s->len[t][0];
485 for (i = 0; i < alphaSize; i++) { 552 for (i = 0; i < alphaSize; i++) {
486 if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; 553 if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
487 if (s->len[t][i] < minLen) minLen = s->len[t][i]; 554 if (s->len[t][i] < minLen) minLen = s->len[t][i];
@@ -509,15 +576,16 @@ void sendMTFValues(EState* s)
509 } 576 }
510 } 577 }
511 578
512 bsW(s, 16, inUse16); 579 bsW16(s, inUse16);
513 580
514 inUse16 <<= (sizeof(int)*8 - 16); /* move 15th bit into sign bit */ 581 inUse16 <<= (sizeof(int)*8 - 16); /* move 15th bit into sign bit */
515 for (i = 0; i < 16; i++) { 582 for (i = 0; i < 16; i++) {
516 if (inUse16 < 0) { 583 if (inUse16 < 0) {
517 unsigned v16 = 0; 584 unsigned v16 = 0;
585 unsigned j;
518 for (j = 0; j < 16; j++) 586 for (j = 0; j < 16; j++)
519 v16 = v16*2 + s->inUse[i * 16 + j]; 587 v16 = v16*2 + s->inUse[i * 16 + j];
520 bsW(s, 16, v16); 588 bsW16(s, v16);
521 } 589 }
522 inUse16 <<= 1; 590 inUse16 <<= 1;
523 } 591 }
@@ -527,19 +595,20 @@ void sendMTFValues(EState* s)
527 bsW(s, 3, nGroups); 595 bsW(s, 3, nGroups);
528 bsW(s, 15, nSelectors); 596 bsW(s, 15, nSelectors);
529 for (i = 0; i < nSelectors; i++) { 597 for (i = 0; i < nSelectors; i++) {
598 unsigned j;
530 for (j = 0; j < s->selectorMtf[i]; j++) 599 for (j = 0; j < s->selectorMtf[i]; j++)
531 bsW(s, 1, 1); 600 bsW1_1(s);
532 bsW(s, 1, 0); 601 bsW1_0(s);
533 } 602 }
534 603
535 /*--- Now the coding tables. ---*/ 604 /*--- Now the coding tables. ---*/
536 for (t = 0; t < nGroups; t++) { 605 for (t = 0; t < nGroups; t++) {
537 int32_t curr = s->len[t][0]; 606 unsigned curr = s->len[t][0];
538 bsW(s, 5, curr); 607 bsW(s, 5, curr);
539 for (i = 0; i < alphaSize; i++) { 608 for (i = 0; i < alphaSize; i++) {
540 while (curr < s->len[t][i]) { bsW(s, 2, 2); curr++; /* 10 */ }; 609 while (curr < s->len[t][i]) { bsW(s, 2, 2); curr++; /* 10 */ }
541 while (curr > s->len[t][i]) { bsW(s, 2, 3); curr--; /* 11 */ }; 610 while (curr > s->len[t][i]) { bsW(s, 2, 3); curr--; /* 11 */ }
542 bsW(s, 1, 0); 611 bsW1_0(s);
543 } 612 }
544 } 613 }
545 614
@@ -547,6 +616,8 @@ void sendMTFValues(EState* s)
547 selCtr = 0; 616 selCtr = 0;
548 gs = 0; 617 gs = 0;
549 while (1) { 618 while (1) {
619 unsigned ge;
620
550 if (gs >= s->nMTF) 621 if (gs >= s->nMTF)
551 break; 622 break;
552 ge = gs + BZ_G_SIZE - 1; 623 ge = gs + BZ_G_SIZE - 1;
@@ -605,17 +676,21 @@ void sendMTFValues(EState* s)
605static 676static
606void BZ2_compressBlock(EState* s, int is_last_block) 677void BZ2_compressBlock(EState* s, int is_last_block)
607{ 678{
679 int32_t origPtr = origPtr;
680
608 if (s->nblock > 0) { 681 if (s->nblock > 0) {
609 BZ_FINALISE_CRC(s->blockCRC); 682 BZ_FINALISE_CRC(s->blockCRC);
610 s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31); 683 s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31);
611 s->combinedCRC ^= s->blockCRC; 684 s->combinedCRC ^= s->blockCRC;
612 if (s->blockNo > 1) 685 if (s->blockNo > 1)
613 s->numZ = 0; 686 s->posZ = s->zbits; // was: s->numZ = 0;
614 687
615 BZ2_blockSort(s); 688 origPtr = BZ2_blockSort(s);
616 } 689 }
617 690
618 s->zbits = &((uint8_t*)s->arr2)[s->nblock]; 691 s->zbits = &((uint8_t*)s->arr2)[s->nblock];
692 s->posZ = s->zbits;
693 s->state_out_pos = s->zbits;
619 694
620 /*-- If this is the first block, create the stream header. --*/ 695 /*-- If this is the first block, create the stream header. --*/
621 if (s->blockNo == 1) { 696 if (s->blockNo == 1) {
@@ -649,9 +724,9 @@ void BZ2_compressBlock(EState* s, int is_last_block)
649 * so as to maintain backwards compatibility with 724 * so as to maintain backwards compatibility with
650 * older versions of bzip2. 725 * older versions of bzip2.
651 */ 726 */
652 bsW(s, 1, 0); 727 bsW1_0(s);
653 728
654 bsW(s, 24, s->origPtr); 729 bsW(s, 24, origPtr);
655 generateMTFValues(s); 730 generateMTFValues(s);
656 sendMTFValues(s); 731 sendMTFValues(s);
657 } 732 }
diff --git a/archival/libarchive/bz/huffman.c b/archival/libarchive/bz/huffman.c
index bbec11adb..dc851cd3f 100644
--- a/archival/libarchive/bz/huffman.c
+++ b/archival/libarchive/bz/huffman.c
@@ -48,7 +48,7 @@ in the file LICENSE.
48 48
49 49
50/* 90 bytes, 0.3% of overall compress speed */ 50/* 90 bytes, 0.3% of overall compress speed */
51#if CONFIG_BZIP2_FAST >= 1 51#if BZIP2_SPEED >= 1
52 52
53/* macro works better than inline (gcc 4.2.1) */ 53/* macro works better than inline (gcc 4.2.1) */
54#define DOWNHEAP1(heap, weight, Heap) \ 54#define DOWNHEAP1(heap, weight, Heap) \
@@ -217,7 +217,7 @@ void BZ2_hbAssignCodes(int32_t *code,
217 if (length[i] == n) { 217 if (length[i] == n) {
218 code[i] = vec; 218 code[i] = vec;
219 vec++; 219 vec++;
220 }; 220 }
221 } 221 }
222 vec <<= 1; 222 vec <<= 1;
223 } 223 }
diff --git a/archival/libarchive/decompress_gunzip.c b/archival/libarchive/decompress_gunzip.c
index 14a901792..7483a2cea 100644
--- a/archival/libarchive/decompress_gunzip.c
+++ b/archival/libarchive/decompress_gunzip.c
@@ -280,8 +280,8 @@ static unsigned fill_bitbuffer(STATE_PARAM unsigned bitbuffer, unsigned *current
280/* Given a list of code lengths and a maximum table size, make a set of 280/* Given a list of code lengths and a maximum table size, make a set of
281 * tables to decode that set of codes. Return zero on success, one if 281 * tables to decode that set of codes. Return zero on success, one if
282 * the given code set is incomplete (the tables are still built in this 282 * the given code set is incomplete (the tables are still built in this
283 * case), two if the input is invalid (all zero length codes or an 283 * case), two if the input is invalid (an oversubscribed set of lengths)
284 * oversubscribed set of lengths) - in this case stores NULL in *t. 284 * - in this case stores NULL in *t.
285 * 285 *
286 * b: code lengths in bits (all assumed <= BMAX) 286 * b: code lengths in bits (all assumed <= BMAX)
287 * n: number of codes (assumed <= N_MAX) 287 * n: number of codes (assumed <= N_MAX)
@@ -330,8 +330,15 @@ static int huft_build(const unsigned *b, const unsigned n,
330 p++; /* can't combine with above line (Solaris bug) */ 330 p++; /* can't combine with above line (Solaris bug) */
331 } while (--i); 331 } while (--i);
332 if (c[0] == n) { /* null input - all zero length codes */ 332 if (c[0] == n) { /* null input - all zero length codes */
333 *m = 0; 333 q = xzalloc(3 * sizeof(*q));
334 return 2; 334 //q[0].v.t = NULL;
335 q[1].e = 99; /* invalid code marker */
336 q[1].b = 1;
337 q[2].e = 99; /* invalid code marker */
338 q[2].b = 1;
339 *t = q + 1;
340 *m = 1;
341 return 0;
335 } 342 }
336 343
337 /* Find minimum and maximum length, bound *m by those */ 344 /* Find minimum and maximum length, bound *m by those */
@@ -1000,7 +1007,7 @@ inflate_unzip_internal(STATE_PARAM transformer_state_t *xstate)
1000 gunzip_bb = 0; 1007 gunzip_bb = 0;
1001 1008
1002 /* Create the crc table */ 1009 /* Create the crc table */
1003 gunzip_crc_table = crc32_filltable(NULL, 0); 1010 gunzip_crc_table = crc32_new_table_le();
1004 gunzip_crc = ~0; 1011 gunzip_crc = ~0;
1005 1012
1006 error_msg = "corrupted data"; 1013 error_msg = "corrupted data";
diff --git a/archival/libarchive/decompress_unxz.c b/archival/libarchive/decompress_unxz.c
index 0be85500c..8ae7a275b 100644
--- a/archival/libarchive/decompress_unxz.c
+++ b/archival/libarchive/decompress_unxz.c
@@ -52,7 +52,7 @@ unpack_xz_stream(transformer_state_t *xstate)
52 IF_DESKTOP(long long) int total = 0; 52 IF_DESKTOP(long long) int total = 0;
53 53
54 if (!global_crc32_table) 54 if (!global_crc32_table)
55 global_crc32_table = crc32_filltable(NULL, /*endian:*/ 0); 55 global_crc32_new_table_le();
56 56
57 memset(&iobuf, 0, sizeof(iobuf)); 57 memset(&iobuf, 0, sizeof(iobuf));
58 membuf = xmalloc(2 * BUFSIZ); 58 membuf = xmalloc(2 * BUFSIZ);
diff --git a/archival/libarchive/get_header_ar.c b/archival/libarchive/get_header_ar.c
index 1809ec396..93e071c9f 100644
--- a/archival/libarchive/get_header_ar.c
+++ b/archival/libarchive/get_header_ar.c
@@ -83,7 +83,7 @@ char FAST_FUNC get_header_ar(archive_handle_t *archive_handle)
83 */ 83 */
84 ar_long_name_size = size; 84 ar_long_name_size = size;
85 free(ar_long_names); 85 free(ar_long_names);
86 ar_long_names = xmalloc(size); 86 ar_long_names = xzalloc(size + 1);
87 xread(archive_handle->src_fd, ar_long_names, size); 87 xread(archive_handle->src_fd, ar_long_names, size);
88 archive_handle->offset += size; 88 archive_handle->offset += size;
89 /* Return next header */ 89 /* Return next header */
@@ -107,7 +107,7 @@ char FAST_FUNC get_header_ar(archive_handle_t *archive_handle)
107 unsigned long_offset; 107 unsigned long_offset;
108 108
109 /* The number after the '/' indicates the offset in the ar data section 109 /* The number after the '/' indicates the offset in the ar data section
110 * (saved in ar_long_names) that conatains the real filename */ 110 * (saved in ar_long_names) that contains the real filename */
111 long_offset = read_num(&ar.formatted.name[1], 10, 111 long_offset = read_num(&ar.formatted.name[1], 10,
112 sizeof(ar.formatted.name) - 1); 112 sizeof(ar.formatted.name) - 1);
113 if (long_offset >= ar_long_name_size) { 113 if (long_offset >= ar_long_name_size) {
diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c
index aeb54190f..5c495e14e 100644
--- a/archival/libarchive/get_header_tar.c
+++ b/archival/libarchive/get_header_tar.c
@@ -152,6 +152,7 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
152 file_header_t *file_header = archive_handle->file_header; 152 file_header_t *file_header = archive_handle->file_header;
153 struct tar_header_t tar; 153 struct tar_header_t tar;
154 char *cp; 154 char *cp;
155 int tar_typeflag; /* can be "char", "int" seems give smaller code */
155 int i, sum_u, sum; 156 int i, sum_u, sum;
156#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY 157#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
157 int sum_s; 158 int sum_s;
@@ -253,10 +254,10 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
253 * POSIX says that checksum is done on unsigned bytes, but 254 * POSIX says that checksum is done on unsigned bytes, but
254 * Sun and HP-UX gets it wrong... more details in 255 * Sun and HP-UX gets it wrong... more details in
255 * GNU tar source. */ 256 * GNU tar source. */
257 sum_u = ' ' * sizeof(tar.chksum);
256#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY 258#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
257 sum_s = ' ' * sizeof(tar.chksum); 259 sum_s = sum_u;
258#endif 260#endif
259 sum_u = ' ' * sizeof(tar.chksum);
260 for (i = 0; i < 148; i++) { 261 for (i = 0; i < 148; i++) {
261 sum_u += ((unsigned char*)&tar)[i]; 262 sum_u += ((unsigned char*)&tar)[i];
262#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY 263#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
@@ -269,27 +270,22 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
269 sum_s += ((signed char*)&tar)[i]; 270 sum_s += ((signed char*)&tar)[i];
270#endif 271#endif
271 } 272 }
272 /* This field does not need special treatment (getOctal) */ 273 /* Most tarfiles have tar.chksum NUL or space terminated, but
273 { 274 * github.com decided to be "special" and have unterminated field:
274 char *endp; /* gcc likes temp var for &endp */ 275 * 0090: 30343300 30303031 33323731 30000000 |043.000132710...|
275 sum = strtoul(tar.chksum, &endp, 8); 276 * ^^^^^^^^|
276 if ((*endp != '\0' && *endp != ' ') 277 * Need to use GET_OCTAL. This overwrites tar.typeflag ---+
277 || (sum_u != sum IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)) 278 * (the '0' char immediately after chksum in example above) with NUL.
278 ) { 279 */
279 bb_error_msg_and_die("invalid tar header checksum"); 280 tar_typeflag = (uint8_t)tar.typeflag; /* save it */
280 } 281 sum = GET_OCTAL(tar.chksum);
281 } 282 if (sum_u != sum
282 /* don't use xstrtoul, tar.chksum may have leading spaces */ 283 IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)
283 sum = strtoul(tar.chksum, NULL, 8); 284 ) {
284 if (sum_u != sum IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)) {
285 bb_error_msg_and_die("invalid tar header checksum"); 285 bb_error_msg_and_die("invalid tar header checksum");
286 } 286 }
287 287
288 /* 0 is reserved for high perf file, treat as normal file */ 288 /* GET_OCTAL trashes subsequent field, therefore we call it
289 if (!tar.typeflag) tar.typeflag = '0';
290 parse_names = (tar.typeflag >= '0' && tar.typeflag <= '7');
291
292 /* getOctal trashes subsequent field, therefore we call it
293 * on fields in reverse order */ 289 * on fields in reverse order */
294 if (tar.devmajor[0]) { 290 if (tar.devmajor[0]) {
295 char t = tar.prefix[0]; 291 char t = tar.prefix[0];
@@ -299,6 +295,11 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
299 file_header->device = makedev(major, minor); 295 file_header->device = makedev(major, minor);
300 tar.prefix[0] = t; 296 tar.prefix[0] = t;
301 } 297 }
298
299 /* 0 is reserved for high perf file, treat as normal file */
300 if (tar_typeflag == '\0') tar_typeflag = '0';
301 parse_names = (tar_typeflag >= '0' && tar_typeflag <= '7');
302
302 file_header->link_target = NULL; 303 file_header->link_target = NULL;
303 if (!p_linkname && parse_names && tar.linkname[0]) { 304 if (!p_linkname && parse_names && tar.linkname[0]) {
304 file_header->link_target = xstrndup(tar.linkname, sizeof(tar.linkname)); 305 file_header->link_target = xstrndup(tar.linkname, sizeof(tar.linkname));
@@ -332,7 +333,7 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
332 333
333 /* Set bits 12-15 of the files mode */ 334 /* Set bits 12-15 of the files mode */
334 /* (typeflag was not trashed because chksum does not use getOctal) */ 335 /* (typeflag was not trashed because chksum does not use getOctal) */
335 switch (tar.typeflag) { 336 switch (tar_typeflag) {
336 case '1': /* hardlink */ 337 case '1': /* hardlink */
337 /* we mark hardlinks as regular files with zero size and a link name */ 338 /* we mark hardlinks as regular files with zero size and a link name */
338 file_header->mode |= S_IFREG; 339 file_header->mode |= S_IFREG;
@@ -381,7 +382,7 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
381 case 'x': { /* pax extended header */ 382 case 'x': { /* pax extended header */
382 if ((uoff_t)file_header->size > 0xfffff) /* paranoia */ 383 if ((uoff_t)file_header->size > 0xfffff) /* paranoia */
383 goto skip_ext_hdr; 384 goto skip_ext_hdr;
384 process_pax_hdr(archive_handle, file_header->size, (tar.typeflag == 'g')); 385 process_pax_hdr(archive_handle, file_header->size, (tar_typeflag == 'g'));
385 goto again_after_align; 386 goto again_after_align;
386#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS 387#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
387/* See http://www.gnu.org/software/tar/manual/html_node/Extensions.html */ 388/* See http://www.gnu.org/software/tar/manual/html_node/Extensions.html */
@@ -419,7 +420,7 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
419 skip_ext_hdr: 420 skip_ext_hdr:
420 { 421 {
421 off_t sz; 422 off_t sz;
422 bb_error_msg("warning: skipping header '%c'", tar.typeflag); 423 bb_error_msg("warning: skipping header '%c'", tar_typeflag);
423 sz = (file_header->size + 511) & ~(off_t)511; 424 sz = (file_header->size + 511) & ~(off_t)511;
424 archive_handle->offset += sz; 425 archive_handle->offset += sz;
425 sz >>= 9; /* sz /= 512 but w/o contortions for signed div */ 426 sz >>= 9; /* sz /= 512 but w/o contortions for signed div */
@@ -429,7 +430,7 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
429 goto again_after_align; 430 goto again_after_align;
430 } 431 }
431 default: 432 default:
432 bb_error_msg_and_die("unknown typeflag: 0x%x", tar.typeflag); 433 bb_error_msg_and_die("unknown typeflag: 0x%x", tar_typeflag);
433 } 434 }
434 435
435#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS 436#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
diff --git a/archival/libarchive/lzo1x_d.c b/archival/libarchive/lzo1x_d.c
index 40b167e68..43cf4a04e 100644
--- a/archival/libarchive/lzo1x_d.c
+++ b/archival/libarchive/lzo1x_d.c
@@ -31,8 +31,7 @@
31************************************************************************/ 31************************************************************************/
32/* safe decompression with overrun testing */ 32/* safe decompression with overrun testing */
33int lzo1x_decompress_safe(const uint8_t* in, unsigned in_len, 33int lzo1x_decompress_safe(const uint8_t* in, unsigned in_len,
34 uint8_t* out, unsigned* out_len, 34 uint8_t* out, unsigned* out_len /*, void* wrkmem */)
35 void* wrkmem UNUSED_PARAM)
36{ 35{
37 register uint8_t* op; 36 register uint8_t* op;
38 register const uint8_t* ip; 37 register const uint8_t* ip;
diff --git a/archival/lzop.c b/archival/lzop.c
index 92411c23f..fef8cdba3 100644
--- a/archival/lzop.c
+++ b/archival/lzop.c
@@ -80,7 +80,7 @@
80//usage: "\n -F Don't verify checksum" 80//usage: "\n -F Don't verify checksum"
81//usage: 81//usage:
82//usage:#define unlzop_trivial_usage 82//usage:#define unlzop_trivial_usage
83//usage: "[-cfkvF] [FILE]..." 83//usage: "[-cfUvF] [FILE]..."
84//usage:#define unlzop_full_usage "\n\n" 84//usage:#define unlzop_full_usage "\n\n"
85//usage: " -c Write to stdout" 85//usage: " -c Write to stdout"
86//usage: "\n -f Force" 86//usage: "\n -f Force"
@@ -141,8 +141,7 @@ static void copy3(uint8_t* ip, const uint8_t* m_pos, unsigned off)
141#define TEST_OP (op <= op_end) 141#define TEST_OP (op <= op_end)
142 142
143static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len, 143static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len,
144 uint8_t *out, unsigned *out_len, 144 uint8_t *out, unsigned *out_len /*, void* wrkmem */)
145 void* wrkmem UNUSED_PARAM)
146{ 145{
147 uint8_t* op; 146 uint8_t* op;
148 uint8_t* ip; 147 uint8_t* ip;
@@ -724,7 +723,7 @@ static NOINLINE int lzo_compress(const header_t *h)
724 /* optimize */ 723 /* optimize */
725 if (h->method == M_LZO1X_999) { 724 if (h->method == M_LZO1X_999) {
726 unsigned new_len = src_len; 725 unsigned new_len = src_len;
727 r = lzo1x_optimize(b2, dst_len, b1, &new_len, NULL); 726 r = lzo1x_optimize(b2, dst_len, b1, &new_len /*, NULL*/);
728 if (r != 0 /*LZO_E_OK*/ || new_len != src_len) 727 if (r != 0 /*LZO_E_OK*/ || new_len != src_len)
729 bb_error_msg_and_die("internal error - optimization failed"); 728 bb_error_msg_and_die("internal error - optimization failed");
730 } 729 }
@@ -859,9 +858,9 @@ static NOINLINE int lzo_decompress(const header_t *h)
859 858
860 /* decompress */ 859 /* decompress */
861// if (option_mask32 & OPT_F) 860// if (option_mask32 & OPT_F)
862// r = lzo1x_decompress(b1, src_len, b2, &d, NULL); 861// r = lzo1x_decompress(b1, src_len, b2, &d /*, NULL*/);
863// else 862// else
864 r = lzo1x_decompress_safe(b1, src_len, b2, &d, NULL); 863 r = lzo1x_decompress_safe(b1, src_len, b2, &d /*, NULL*/);
865 864
866 if (r != 0 /*LZO_E_OK*/ || dst_len != d) { 865 if (r != 0 /*LZO_E_OK*/ || dst_len != d) {
867 bb_error_msg_and_die("corrupted data"); 866 bb_error_msg_and_die("corrupted data");
@@ -1149,6 +1148,6 @@ int lzop_main(int argc UNUSED_PARAM, char **argv)
1149 if (ENABLE_UNLZOP && applet_name[4] == 'o') 1148 if (ENABLE_UNLZOP && applet_name[4] == 'o')
1150 option_mask32 |= OPT_DECOMPRESS; 1149 option_mask32 |= OPT_DECOMPRESS;
1151 1150
1152 global_crc32_table = crc32_filltable(NULL, 0); 1151 global_crc32_new_table_le();
1153 return bbunpack(argv, pack_lzop, make_new_name_lzop, /*unused:*/ NULL); 1152 return bbunpack(argv, pack_lzop, make_new_name_lzop, /*unused:*/ NULL);
1154} 1153}
diff --git a/archival/unzip.c b/archival/unzip.c
index c5fb6a3ed..fb58b62c0 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -339,7 +339,9 @@ static void unzip_create_leading_dirs(const char *fn)
339{ 339{
340 /* Create all leading directories */ 340 /* Create all leading directories */
341 char *name = xstrdup(fn); 341 char *name = xstrdup(fn);
342 if (bb_make_directory(dirname(name), 0777, FILEUTILS_RECUR)) { 342
343 /* mode of -1: set mode according to umask */
344 if (bb_make_directory(dirname(name), -1, FILEUTILS_RECUR)) {
343 xfunc_die(); /* bb_make_directory is noisy */ 345 xfunc_die(); /* bb_make_directory is noisy */
344 } 346 }
345 free(name); 347 free(name);
diff --git a/configs/mingw32_defconfig b/configs/mingw32_defconfig
index e401f3f83..4adc4471e 100644
--- a/configs/mingw32_defconfig
+++ b/configs/mingw32_defconfig
@@ -1,7 +1,7 @@
1# 1#
2# Automatically generated make config: don't edit 2# Automatically generated make config: don't edit
3# Busybox version: 1.28.0.git 3# Busybox version: 1.29.0.git
4# Wed Sep 27 10:21:20 2017 4# Wed Feb 7 15:11:44 2018
5# 5#
6CONFIG_HAVE_DOT_CONFIG=y 6CONFIG_HAVE_DOT_CONFIG=y
7# CONFIG_PLATFORM_POSIX is not set 7# CONFIG_PLATFORM_POSIX is not set
@@ -153,6 +153,7 @@ CONFIG_UNXZ=y
153CONFIG_XZCAT=y 153CONFIG_XZCAT=y
154CONFIG_XZ=y 154CONFIG_XZ=y
155CONFIG_BZIP2=y 155CONFIG_BZIP2=y
156CONFIG_BZIP2_SMALL=8
156CONFIG_FEATURE_BZIP2_DECOMPRESS=y 157CONFIG_FEATURE_BZIP2_DECOMPRESS=y
157CONFIG_CPIO=y 158CONFIG_CPIO=y
158CONFIG_FEATURE_CPIO_O=y 159CONFIG_FEATURE_CPIO_O=y
@@ -696,6 +697,7 @@ CONFIG_REV=y
696# CONFIG_FEATURE_VOLUMEID_HFS is not set 697# CONFIG_FEATURE_VOLUMEID_HFS is not set
697# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set 698# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set
698# CONFIG_FEATURE_VOLUMEID_JFS is not set 699# CONFIG_FEATURE_VOLUMEID_JFS is not set
700# CONFIG_FEATURE_VOLUMEID_LFS is not set
699# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set 701# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set
700# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set 702# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set
701# CONFIG_FEATURE_VOLUMEID_LUKS is not set 703# CONFIG_FEATURE_VOLUMEID_LUKS is not set
@@ -772,6 +774,8 @@ CONFIG_FEATURE_LESS_REGEXP=y
772# CONFIG_FEATURE_LESS_ASK_TERMINAL is not set 774# CONFIG_FEATURE_LESS_ASK_TERMINAL is not set
773CONFIG_FEATURE_LESS_DASHCMD=y 775CONFIG_FEATURE_LESS_DASHCMD=y
774CONFIG_FEATURE_LESS_LINENUMS=y 776CONFIG_FEATURE_LESS_LINENUMS=y
777CONFIG_FEATURE_LESS_RAW=y
778CONFIG_FEATURE_LESS_ENV=y
775# CONFIG_LSSCSI is not set 779# CONFIG_LSSCSI is not set
776# CONFIG_MAKEDEVS is not set 780# CONFIG_MAKEDEVS is not set
777# CONFIG_FEATURE_MAKEDEVS_LEAF is not set 781# CONFIG_FEATURE_MAKEDEVS_LEAF is not set
@@ -901,6 +905,8 @@ CONFIG_NC_SERVER=y
901# CONFIG_ROUTE is not set 905# CONFIG_ROUTE is not set
902# CONFIG_SLATTACH is not set 906# CONFIG_SLATTACH is not set
903# CONFIG_SSL_CLIENT is not set 907# CONFIG_SSL_CLIENT is not set
908# CONFIG_TC is not set
909# CONFIG_FEATURE_TC_INGRESS is not set
904# CONFIG_TCPSVD is not set 910# CONFIG_TCPSVD is not set
905# CONFIG_UDPSVD is not set 911# CONFIG_UDPSVD is not set
906# CONFIG_TELNET is not set 912# CONFIG_TELNET is not set
@@ -1058,6 +1064,8 @@ CONFIG_ASH=y
1058CONFIG_ASH_OPTIMIZE_FOR_SIZE=y 1064CONFIG_ASH_OPTIMIZE_FOR_SIZE=y
1059CONFIG_ASH_INTERNAL_GLOB=y 1065CONFIG_ASH_INTERNAL_GLOB=y
1060CONFIG_ASH_BASH_COMPAT=y 1066CONFIG_ASH_BASH_COMPAT=y
1067# CONFIG_ASH_BASH_SOURCE_CURDIR is not set
1068CONFIG_ASH_BASH_NOT_FOUND_HOOK=y
1061# CONFIG_ASH_JOB_CONTROL is not set 1069# CONFIG_ASH_JOB_CONTROL is not set
1062CONFIG_ASH_ALIAS=y 1070CONFIG_ASH_ALIAS=y
1063CONFIG_ASH_RANDOM_SUPPORT=y 1071CONFIG_ASH_RANDOM_SUPPORT=y
@@ -1075,6 +1083,7 @@ CONFIG_ASH_NOCONSOLE=y
1075# CONFIG_HUSH is not set 1083# CONFIG_HUSH is not set
1076# CONFIG_HUSH_BASH_COMPAT is not set 1084# CONFIG_HUSH_BASH_COMPAT is not set
1077# CONFIG_HUSH_BRACE_EXPANSION is not set 1085# CONFIG_HUSH_BRACE_EXPANSION is not set
1086# CONFIG_HUSH_BASH_SOURCE_CURDIR is not set
1078# CONFIG_HUSH_INTERACTIVE is not set 1087# CONFIG_HUSH_INTERACTIVE is not set
1079# CONFIG_HUSH_SAVEHISTORY is not set 1088# CONFIG_HUSH_SAVEHISTORY is not set
1080# CONFIG_HUSH_JOB is not set 1089# CONFIG_HUSH_JOB is not set
@@ -1095,6 +1104,7 @@ CONFIG_ASH_NOCONSOLE=y
1095# CONFIG_HUSH_READONLY is not set 1104# CONFIG_HUSH_READONLY is not set
1096# CONFIG_HUSH_KILL is not set 1105# CONFIG_HUSH_KILL is not set
1097# CONFIG_HUSH_WAIT is not set 1106# CONFIG_HUSH_WAIT is not set
1107# CONFIG_HUSH_COMMAND is not set
1098# CONFIG_HUSH_TRAP is not set 1108# CONFIG_HUSH_TRAP is not set
1099# CONFIG_HUSH_TYPE is not set 1109# CONFIG_HUSH_TYPE is not set
1100# CONFIG_HUSH_TIMES is not set 1110# CONFIG_HUSH_TIMES is not set
diff --git a/configs/mingw64_defconfig b/configs/mingw64_defconfig
index daa74a4ce..fdc755d93 100644
--- a/configs/mingw64_defconfig
+++ b/configs/mingw64_defconfig
@@ -1,7 +1,7 @@
1# 1#
2# Automatically generated make config: don't edit 2# Automatically generated make config: don't edit
3# Busybox version: 1.28.0.git 3# Busybox version: 1.29.0.git
4# Wed Sep 27 10:21:20 2017 4# Wed Feb 7 15:18:49 2018
5# 5#
6CONFIG_HAVE_DOT_CONFIG=y 6CONFIG_HAVE_DOT_CONFIG=y
7# CONFIG_PLATFORM_POSIX is not set 7# CONFIG_PLATFORM_POSIX is not set
@@ -153,6 +153,7 @@ CONFIG_UNXZ=y
153CONFIG_XZCAT=y 153CONFIG_XZCAT=y
154CONFIG_XZ=y 154CONFIG_XZ=y
155CONFIG_BZIP2=y 155CONFIG_BZIP2=y
156CONFIG_BZIP2_SMALL=8
156CONFIG_FEATURE_BZIP2_DECOMPRESS=y 157CONFIG_FEATURE_BZIP2_DECOMPRESS=y
157CONFIG_CPIO=y 158CONFIG_CPIO=y
158CONFIG_FEATURE_CPIO_O=y 159CONFIG_FEATURE_CPIO_O=y
@@ -696,6 +697,7 @@ CONFIG_REV=y
696# CONFIG_FEATURE_VOLUMEID_HFS is not set 697# CONFIG_FEATURE_VOLUMEID_HFS is not set
697# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set 698# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set
698# CONFIG_FEATURE_VOLUMEID_JFS is not set 699# CONFIG_FEATURE_VOLUMEID_JFS is not set
700# CONFIG_FEATURE_VOLUMEID_LFS is not set
699# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set 701# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set
700# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set 702# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set
701# CONFIG_FEATURE_VOLUMEID_LUKS is not set 703# CONFIG_FEATURE_VOLUMEID_LUKS is not set
@@ -772,6 +774,8 @@ CONFIG_FEATURE_LESS_REGEXP=y
772# CONFIG_FEATURE_LESS_ASK_TERMINAL is not set 774# CONFIG_FEATURE_LESS_ASK_TERMINAL is not set
773CONFIG_FEATURE_LESS_DASHCMD=y 775CONFIG_FEATURE_LESS_DASHCMD=y
774CONFIG_FEATURE_LESS_LINENUMS=y 776CONFIG_FEATURE_LESS_LINENUMS=y
777CONFIG_FEATURE_LESS_RAW=y
778CONFIG_FEATURE_LESS_ENV=y
775# CONFIG_LSSCSI is not set 779# CONFIG_LSSCSI is not set
776# CONFIG_MAKEDEVS is not set 780# CONFIG_MAKEDEVS is not set
777# CONFIG_FEATURE_MAKEDEVS_LEAF is not set 781# CONFIG_FEATURE_MAKEDEVS_LEAF is not set
@@ -901,6 +905,8 @@ CONFIG_NC_SERVER=y
901# CONFIG_ROUTE is not set 905# CONFIG_ROUTE is not set
902# CONFIG_SLATTACH is not set 906# CONFIG_SLATTACH is not set
903# CONFIG_SSL_CLIENT is not set 907# CONFIG_SSL_CLIENT is not set
908# CONFIG_TC is not set
909# CONFIG_FEATURE_TC_INGRESS is not set
904# CONFIG_TCPSVD is not set 910# CONFIG_TCPSVD is not set
905# CONFIG_UDPSVD is not set 911# CONFIG_UDPSVD is not set
906# CONFIG_TELNET is not set 912# CONFIG_TELNET is not set
@@ -1058,6 +1064,8 @@ CONFIG_ASH=y
1058CONFIG_ASH_OPTIMIZE_FOR_SIZE=y 1064CONFIG_ASH_OPTIMIZE_FOR_SIZE=y
1059CONFIG_ASH_INTERNAL_GLOB=y 1065CONFIG_ASH_INTERNAL_GLOB=y
1060CONFIG_ASH_BASH_COMPAT=y 1066CONFIG_ASH_BASH_COMPAT=y
1067# CONFIG_ASH_BASH_SOURCE_CURDIR is not set
1068CONFIG_ASH_BASH_NOT_FOUND_HOOK=y
1061# CONFIG_ASH_JOB_CONTROL is not set 1069# CONFIG_ASH_JOB_CONTROL is not set
1062CONFIG_ASH_ALIAS=y 1070CONFIG_ASH_ALIAS=y
1063CONFIG_ASH_RANDOM_SUPPORT=y 1071CONFIG_ASH_RANDOM_SUPPORT=y
@@ -1075,6 +1083,7 @@ CONFIG_ASH_CMDCMD=y
1075# CONFIG_HUSH is not set 1083# CONFIG_HUSH is not set
1076# CONFIG_HUSH_BASH_COMPAT is not set 1084# CONFIG_HUSH_BASH_COMPAT is not set
1077# CONFIG_HUSH_BRACE_EXPANSION is not set 1085# CONFIG_HUSH_BRACE_EXPANSION is not set
1086# CONFIG_HUSH_BASH_SOURCE_CURDIR is not set
1078# CONFIG_HUSH_INTERACTIVE is not set 1087# CONFIG_HUSH_INTERACTIVE is not set
1079# CONFIG_HUSH_SAVEHISTORY is not set 1088# CONFIG_HUSH_SAVEHISTORY is not set
1080# CONFIG_HUSH_JOB is not set 1089# CONFIG_HUSH_JOB is not set
@@ -1095,6 +1104,7 @@ CONFIG_ASH_CMDCMD=y
1095# CONFIG_HUSH_READONLY is not set 1104# CONFIG_HUSH_READONLY is not set
1096# CONFIG_HUSH_KILL is not set 1105# CONFIG_HUSH_KILL is not set
1097# CONFIG_HUSH_WAIT is not set 1106# CONFIG_HUSH_WAIT is not set
1107# CONFIG_HUSH_COMMAND is not set
1098# CONFIG_HUSH_TRAP is not set 1108# CONFIG_HUSH_TRAP is not set
1099# CONFIG_HUSH_TYPE is not set 1109# CONFIG_HUSH_TYPE is not set
1100# CONFIG_HUSH_TIMES is not set 1110# CONFIG_HUSH_TIMES is not set
diff --git a/coreutils/cat.c b/coreutils/cat.c
index 7e35fa5ee..5f02233ca 100644
--- a/coreutils/cat.c
+++ b/coreutils/cat.c
@@ -168,9 +168,12 @@ static int catv(unsigned opts, char **argv)
168int cat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 168int cat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
169int cat_main(int argc UNUSED_PARAM, char **argv) 169int cat_main(int argc UNUSED_PARAM, char **argv)
170{ 170{
171#if ENABLE_FEATURE_CATV || ENABLE_FEATURE_CATN
171 unsigned opts; 172 unsigned opts;
172 173
173 opts = getopt32(argv, IF_FEATURE_CATV("^") 174 opts =
175#endif
176 getopt32(argv, IF_FEATURE_CATV("^")
174 /* -u is ignored ("unbuffered") */ 177 /* -u is ignored ("unbuffered") */
175 IF_FEATURE_CATV("etvA")IF_FEATURE_CATN("nb")"u" 178 IF_FEATURE_CATV("etvA")IF_FEATURE_CATN("nb")"u"
176 IF_FEATURE_CATV("\0" "Aetv" /* -A == -vet */) 179 IF_FEATURE_CATV("\0" "Aetv" /* -A == -vet */)
diff --git a/coreutils/chown.c b/coreutils/chown.c
index 985d18d6f..6429fd030 100644
--- a/coreutils/chown.c
+++ b/coreutils/chown.c
@@ -128,9 +128,9 @@ int chown_main(int argc UNUSED_PARAM, char **argv)
128 struct param_t param; 128 struct param_t param;
129 129
130#if ENABLE_FEATURE_CHOWN_LONG_OPTIONS 130#if ENABLE_FEATURE_CHOWN_LONG_OPTIONS
131 opt = getopt32long(argv, "^" OPT_STR "\0" "=2", chown_longopts); 131 opt = getopt32long(argv, "^" OPT_STR "\0" "-2", chown_longopts);
132#else 132#else
133 opt = getopt32(argv, "^" OPT_STR "\0" "=2"); 133 opt = getopt32(argv, "^" OPT_STR "\0" "-2");
134#endif 134#endif
135 argv += optind; 135 argv += optind;
136 136
diff --git a/coreutils/cksum.c b/coreutils/cksum.c
index 059a33310..e46e249f2 100644
--- a/coreutils/cksum.c
+++ b/coreutils/cksum.c
@@ -31,9 +31,6 @@ int cksum_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
31int cksum_main(int argc UNUSED_PARAM, char **argv) 31int cksum_main(int argc UNUSED_PARAM, char **argv)
32{ 32{
33 uint32_t *crc32_table = crc32_filltable(NULL, 1); 33 uint32_t *crc32_table = crc32_filltable(NULL, 1);
34 uint32_t crc;
35 off_t length, filesize;
36 int bytes_read;
37 int exit_code = EXIT_SUCCESS; 34 int exit_code = EXIT_SUCCESS;
38 35
39#if ENABLE_DESKTOP 36#if ENABLE_DESKTOP
@@ -45,38 +42,42 @@ int cksum_main(int argc UNUSED_PARAM, char **argv)
45 42
46 setup_common_bufsiz(); 43 setup_common_bufsiz();
47 do { 44 do {
45 uint32_t crc;
46 off_t filesize;
48 int fd = open_or_warn_stdin(*argv ? *argv : bb_msg_standard_input); 47 int fd = open_or_warn_stdin(*argv ? *argv : bb_msg_standard_input);
49 48
50 if (fd < 0) { 49 if (fd < 0) {
51 exit_code = EXIT_FAILURE; 50 exit_code = EXIT_FAILURE;
52 continue; 51 continue;
53 } 52 }
54 crc = 0;
55 length = 0;
56 53
54 crc = 0;
55 filesize = 0;
57#define read_buf bb_common_bufsiz1 56#define read_buf bb_common_bufsiz1
58 while ((bytes_read = safe_read(fd, read_buf, COMMON_BUFSIZE)) > 0) { 57 for (;;) {
59 length += bytes_read; 58 uoff_t t;
59 int bytes_read = safe_read(fd, read_buf, COMMON_BUFSIZE);
60 if (bytes_read > 0) {
61 filesize += bytes_read;
62 } else {
63 /* Checksum filesize bytes, LSB first, and exit */
64 close(fd);
65 fd = -1; /* break flag */
66 t = filesize;
67 bytes_read = 0;
68 while (t != 0) {
69 read_buf[bytes_read++] = (uint8_t)t;
70 t >>= 8;
71 }
72 }
60 crc = crc32_block_endian1(crc, read_buf, bytes_read, crc32_table); 73 crc = crc32_block_endian1(crc, read_buf, bytes_read, crc32_table);
74 if (fd < 0)
75 break;
61 } 76 }
62 close(fd);
63
64 filesize = length;
65 77
66 while (length) {
67 crc = (crc << 8) ^ crc32_table[(uint8_t)(crc >> 24) ^ (uint8_t)length];
68 /* must ensure that shift is unsigned! */
69 if (sizeof(length) <= sizeof(unsigned))
70 length = (unsigned)length >> 8;
71 else if (sizeof(length) <= sizeof(unsigned long))
72 length = (unsigned long)length >> 8;
73 else
74 length = (unsigned long long)length >> 8;
75 }
76 crc = ~crc; 78 crc = ~crc;
77 79 printf((*argv ? "%u %"OFF_FMT"u %s\n" : "%u %"OFF_FMT"u\n"),
78 printf((*argv ? "%"PRIu32" %"OFF_FMT"i %s\n" : "%"PRIu32" %"OFF_FMT"i\n"), 80 (unsigned)crc, filesize, *argv);
79 crc, filesize, *argv);
80 } while (*argv && *++argv); 81 } while (*argv && *++argv);
81 82
82 fflush_stdout_and_exit(exit_code); 83 fflush_stdout_and_exit(exit_code);
diff --git a/coreutils/cp.c b/coreutils/cp.c
index 5b34c27e7..455bffbba 100644
--- a/coreutils/cp.c
+++ b/coreutils/cp.c
@@ -26,6 +26,7 @@
26//config: Also add support for --parents option. 26//config: Also add support for --parents option.
27 27
28//applet:IF_CP(APPLET_NOEXEC(cp, cp, BB_DIR_BIN, BB_SUID_DROP, cp)) 28//applet:IF_CP(APPLET_NOEXEC(cp, cp, BB_DIR_BIN, BB_SUID_DROP, cp))
29/* NOEXEC despite cases when it can be a "runner" (cp -r LARGE_DIR NEW_DIR) */
29 30
30//kbuild:lib-$(CONFIG_CP) += cp.o 31//kbuild:lib-$(CONFIG_CP) += cp.o
31 32
@@ -47,6 +48,7 @@
47//usage: "\n -f Overwrite" 48//usage: "\n -f Overwrite"
48//usage: "\n -i Prompt before overwrite" 49//usage: "\n -i Prompt before overwrite"
49//usage: "\n -l,-s Create (sym)links" 50//usage: "\n -l,-s Create (sym)links"
51//usage: "\n -T Treat DEST as a normal file"
50//usage: "\n -u Copy only newer files" 52//usage: "\n -u Copy only newer files"
51 53
52#include "libbb.h" 54#include "libbb.h"
@@ -92,13 +94,18 @@ int cp_main(int argc, char **argv)
92 "no-dereference\0" No_argument "P" 94 "no-dereference\0" No_argument "P"
93 "recursive\0" No_argument "R" 95 "recursive\0" No_argument "R"
94 "symbolic-link\0" No_argument "s" 96 "symbolic-link\0" No_argument "s"
97 "no-target-directory\0" No_argument "T"
95 "verbose\0" No_argument "v" 98 "verbose\0" No_argument "v"
96 "update\0" No_argument "u" 99 "update\0" No_argument "u"
97 "remove-destination\0" No_argument "\xff" 100 "remove-destination\0" No_argument "\xff"
98 "parents\0" No_argument "\xfe" 101 "parents\0" No_argument "\xfe"
99 ); 102 );
100#else 103#else
101 flags = getopt32(argv, FILEUTILS_CP_OPTSTR); 104 flags = getopt32(argv, "^"
105 FILEUTILS_CP_OPTSTR
106 "\0"
107 "-2:l--s:s--l:Pd:rRd:Rd:apdR"
108 );
102#endif 109#endif
103 /* Options of cp from GNU coreutils 6.10: 110 /* Options of cp from GNU coreutils 6.10:
104 * -a, --archive 111 * -a, --archive
@@ -121,6 +128,8 @@ int cp_main(int argc, char **argv)
121 * remove each existing destination file before attempting to open 128 * remove each existing destination file before attempting to open
122 * --parents 129 * --parents
123 * use full source file name under DIRECTORY 130 * use full source file name under DIRECTORY
131 * -T, --no-target-directory
132 * treat DEST as a normal file
124 * NOT SUPPORTED IN BBOX: 133 * NOT SUPPORTED IN BBOX:
125 * --backup[=CONTROL] 134 * --backup[=CONTROL]
126 * make a backup of each existing destination file 135 * make a backup of each existing destination file
@@ -139,8 +148,6 @@ int cp_main(int argc, char **argv)
139 * override the usual backup suffix 148 * override the usual backup suffix
140 * -t, --target-directory=DIRECTORY 149 * -t, --target-directory=DIRECTORY
141 * copy all SOURCE arguments into DIRECTORY 150 * copy all SOURCE arguments into DIRECTORY
142 * -T, --no-target-directory
143 * treat DEST as a normal file
144 * -x, --one-file-system 151 * -x, --one-file-system
145 * stay on this file system 152 * stay on this file system
146 * -Z, --context=CONTEXT 153 * -Z, --context=CONTEXT
@@ -175,6 +182,12 @@ int cp_main(int argc, char **argv)
175 if (d_flags < 0) 182 if (d_flags < 0)
176 return EXIT_FAILURE; 183 return EXIT_FAILURE;
177 184
185 if (flags & FILEUTILS_NO_TARGET_DIR) { /* -T */
186 if (!(s_flags & 2) && (d_flags & 2))
187 /* cp -T NOTDIR DIR */
188 bb_error_msg_and_die("'%s' is a directory", last);
189 }
190
178#if ENABLE_FEATURE_CP_LONG_OPTIONS 191#if ENABLE_FEATURE_CP_LONG_OPTIONS
179 //bb_error_msg("flags:%x FILEUTILS_RMDEST:%x OPT_parents:%x", 192 //bb_error_msg("flags:%x FILEUTILS_RMDEST:%x OPT_parents:%x",
180 // flags, FILEUTILS_RMDEST, OPT_parents); 193 // flags, FILEUTILS_RMDEST, OPT_parents);
@@ -192,11 +205,14 @@ int cp_main(int argc, char **argv)
192 if (!((s_flags | d_flags) & 2) 205 if (!((s_flags | d_flags) & 2)
193 /* ...or: recursing, the 1st is a directory, and the 2nd doesn't exist... */ 206 /* ...or: recursing, the 1st is a directory, and the 2nd doesn't exist... */
194 || ((flags & FILEUTILS_RECUR) && (s_flags & 2) && !d_flags) 207 || ((flags & FILEUTILS_RECUR) && (s_flags & 2) && !d_flags)
208 || (flags & FILEUTILS_NO_TARGET_DIR)
195 ) { 209 ) {
196 /* Do a simple copy */ 210 /* Do a simple copy */
197 dest = last; 211 dest = last;
198 goto DO_COPY; /* NB: argc==2 -> *++argv==last */ 212 goto DO_COPY; /* NB: argc==2 -> *++argv==last */
199 } 213 }
214 } else if (flags & FILEUTILS_NO_TARGET_DIR) {
215 bb_error_msg_and_die("too many arguments");
200 } 216 }
201 217
202 while (1) { 218 while (1) {
diff --git a/coreutils/dd.c b/coreutils/dd.c
index 14d270a1e..178576752 100644
--- a/coreutils/dd.c
+++ b/coreutils/dd.c
@@ -37,7 +37,7 @@
37//config: elapsed time and speed. 37//config: elapsed time and speed.
38//config: 38//config:
39//config:config FEATURE_DD_IBS_OBS 39//config:config FEATURE_DD_IBS_OBS
40//config: bool "Enable ibs, obs and conv options" 40//config: bool "Enable ibs, obs, iflag and conv options"
41//config: default y 41//config: default y
42//config: depends on DD 42//config: depends on DD
43//config: help 43//config: help
@@ -57,7 +57,7 @@
57 57
58//usage:#define dd_trivial_usage 58//usage:#define dd_trivial_usage
59//usage: "[if=FILE] [of=FILE] " IF_FEATURE_DD_IBS_OBS("[ibs=N] [obs=N] ") "[bs=N] [count=N] [skip=N]\n" 59//usage: "[if=FILE] [of=FILE] " IF_FEATURE_DD_IBS_OBS("[ibs=N] [obs=N] ") "[bs=N] [count=N] [skip=N]\n"
60//usage: " [seek=N]" IF_FEATURE_DD_IBS_OBS(" [conv=notrunc|noerror|sync|fsync] [iflag=skip_bytes]") 60//usage: " [seek=N]" IF_FEATURE_DD_IBS_OBS(" [conv=notrunc|noerror|sync|fsync] [iflag=skip_bytes|fullblock]")
61//usage:#define dd_full_usage "\n\n" 61//usage:#define dd_full_usage "\n\n"
62//usage: "Copy a file with converting and formatting\n" 62//usage: "Copy a file with converting and formatting\n"
63//usage: "\n if=FILE Read from FILE instead of stdin" 63//usage: "\n if=FILE Read from FILE instead of stdin"
@@ -79,6 +79,7 @@
79//usage: "\n conv=fsync Physically write data out before finishing" 79//usage: "\n conv=fsync Physically write data out before finishing"
80//usage: "\n conv=swab Swap every pair of bytes" 80//usage: "\n conv=swab Swap every pair of bytes"
81//usage: "\n iflag=skip_bytes skip=N is in bytes" 81//usage: "\n iflag=skip_bytes skip=N is in bytes"
82//usage: "\n iflag=fullblock Read full blocks"
82//usage: ) 83//usage: )
83//usage: IF_FEATURE_DD_STATUS( 84//usage: IF_FEATURE_DD_STATUS(
84//usage: "\n status=noxfer Suppress rate output" 85//usage: "\n status=noxfer Suppress rate output"
@@ -130,11 +131,12 @@ enum {
130 /* start of input flags */ 131 /* start of input flags */
131 FLAG_IFLAG_SHIFT = 5, 132 FLAG_IFLAG_SHIFT = 5,
132 FLAG_SKIP_BYTES = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS, 133 FLAG_SKIP_BYTES = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS,
134 FLAG_FULLBLOCK = (1 << 6) * ENABLE_FEATURE_DD_IBS_OBS,
133 /* end of input flags */ 135 /* end of input flags */
134 FLAG_TWOBUFS = (1 << 6) * ENABLE_FEATURE_DD_IBS_OBS, 136 FLAG_TWOBUFS = (1 << 7) * ENABLE_FEATURE_DD_IBS_OBS,
135 FLAG_COUNT = 1 << 7, 137 FLAG_COUNT = 1 << 8,
136 FLAG_STATUS_NONE = 1 << 8, 138 FLAG_STATUS_NONE = 1 << 9,
137 FLAG_STATUS_NOXFER = 1 << 9, 139 FLAG_STATUS_NOXFER = 1 << 10,
138}; 140};
139 141
140static void dd_output_status(int UNUSED_PARAM cur_signal) 142static void dd_output_status(int UNUSED_PARAM cur_signal)
@@ -195,14 +197,18 @@ static bool write_and_stats(const void *buf, size_t len, size_t obs,
195 ssize_t n = full_write_or_warn(buf, len, filename); 197 ssize_t n = full_write_or_warn(buf, len, filename);
196 if (n < 0) 198 if (n < 0)
197 return 1; 199 return 1;
198 if ((size_t)n == obs)
199 G.out_full++;
200 else if (n) /* > 0 */
201 G.out_part++;
202#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE 200#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
203 G.total_bytes += n; 201 G.total_bytes += n;
204#endif 202#endif
205 return 0; 203 if ((size_t)n == obs) {
204 G.out_full++;
205 return 0;
206 }
207 if ((size_t)n == len) {
208 G.out_part++;
209 return 0;
210 }
211 return 1;
206} 212}
207 213
208#if ENABLE_LFS 214#if ENABLE_LFS
@@ -251,7 +257,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
251 static const char conv_words[] ALIGN1 = 257 static const char conv_words[] ALIGN1 =
252 "notrunc\0""sync\0""noerror\0""fsync\0""swab\0"; 258 "notrunc\0""sync\0""noerror\0""fsync\0""swab\0";
253 static const char iflag_words[] ALIGN1 = 259 static const char iflag_words[] ALIGN1 =
254 "skip_bytes\0"; 260 "skip_bytes\0""fullblock\0";
255#endif 261#endif
256#if ENABLE_FEATURE_DD_STATUS 262#if ENABLE_FEATURE_DD_STATUS
257 static const char status_words[] ALIGN1 = 263 static const char status_words[] ALIGN1 =
@@ -290,6 +296,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
290 /* Partially implemented: */ 296 /* Partially implemented: */
291 //swab swap every pair of input bytes: will abort on non-even reads 297 //swab swap every pair of input bytes: will abort on non-even reads
292 OP_iflag_skip_bytes, 298 OP_iflag_skip_bytes,
299 OP_iflag_fullblock,
293#endif 300#endif
294 }; 301 };
295 smallint exitcode = EXIT_FAILURE; 302 smallint exitcode = EXIT_FAILURE;
@@ -456,7 +463,13 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
456 size_t blocksz = (G.flags & FLAG_SKIP_BYTES) ? 1 : ibs; 463 size_t blocksz = (G.flags & FLAG_SKIP_BYTES) ? 1 : ibs;
457 if (lseek(ifd, skip * blocksz, SEEK_CUR) < 0) { 464 if (lseek(ifd, skip * blocksz, SEEK_CUR) < 0) {
458 do { 465 do {
459 ssize_t n = safe_read(ifd, ibuf, blocksz); 466 ssize_t n;
467#if ENABLE_FEATURE_DD_IBS_OBS
468 if (G.flags & FLAG_FULLBLOCK)
469 n = full_read(ifd, ibuf, blocksz);
470 else
471#endif
472 n = safe_read(ifd, ibuf, blocksz);
460 if (n < 0) 473 if (n < 0)
461 goto die_infile; 474 goto die_infile;
462 if (n == 0) 475 if (n == 0)
@@ -477,6 +490,11 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
477 n = ibs; 490 n = ibs;
478 } 491 }
479 else 492 else
493#if ENABLE_FEATURE_DD_IBS_OBS
494 if (G.flags & FLAG_FULLBLOCK)
495 n = full_read(ifd, ibuf, ibs);
496 else
497#endif
480 n = safe_read(ifd, ibuf, ibs); 498 n = safe_read(ifd, ibuf, ibs);
481 if (n == 0) 499 if (n == 0)
482 break; 500 break;
diff --git a/coreutils/ls.c b/coreutils/ls.c
index 22286d713..4cc9517b1 100644
--- a/coreutils/ls.c
+++ b/coreutils/ls.c
@@ -482,12 +482,11 @@ static NOINLINE unsigned display_single(const struct dnode *dn)
482 int opt; 482 int opt;
483#if ENABLE_FEATURE_LS_FILETYPES || ENABLE_FEATURE_LS_COLOR 483#if ENABLE_FEATURE_LS_FILETYPES || ENABLE_FEATURE_LS_COLOR
484 struct stat statbuf; 484 struct stat statbuf;
485 char append;
486#endif 485#endif
487
488#if ENABLE_FEATURE_LS_FILETYPES 486#if ENABLE_FEATURE_LS_FILETYPES
489 append = append_char(dn->dn_mode); 487 char append = append_char(dn->dn_mode);
490#endif 488#endif
489
491 opt = option_mask32; 490 opt = option_mask32;
492 491
493 /* Do readlink early, so that if it fails, error message 492 /* Do readlink early, so that if it fails, error message
diff --git a/coreutils/mknod.c b/coreutils/mknod.c
index 565b33d20..d57167f7d 100644
--- a/coreutils/mknod.c
+++ b/coreutils/mknod.c
@@ -20,7 +20,7 @@
20/* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */ 20/* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */
21 21
22//usage:#define mknod_trivial_usage 22//usage:#define mknod_trivial_usage
23//usage: "[-m MODE] " IF_SELINUX("[-Z] ") "NAME TYPE MAJOR MINOR" 23//usage: "[-m MODE] " IF_SELINUX("[-Z] ") "NAME TYPE [MAJOR MINOR]"
24//usage:#define mknod_full_usage "\n\n" 24//usage:#define mknod_full_usage "\n\n"
25//usage: "Create a special file (block, character, or pipe)\n" 25//usage: "Create a special file (block, character, or pipe)\n"
26//usage: "\n -m MODE Creation mode (default a=rw)" 26//usage: "\n -m MODE Creation mode (default a=rw)"
@@ -30,7 +30,7 @@
30//usage: "\nTYPE:" 30//usage: "\nTYPE:"
31//usage: "\n b Block device" 31//usage: "\n b Block device"
32//usage: "\n c or u Character device" 32//usage: "\n c or u Character device"
33//usage: "\n p Named pipe (MAJOR and MINOR are ignored)" 33//usage: "\n p Named pipe (MAJOR MINOR must be omitted)"
34//usage: 34//usage:
35//usage:#define mknod_example_usage 35//usage:#define mknod_example_usage
36//usage: "$ mknod /dev/fd0 b 2 0\n" 36//usage: "$ mknod /dev/fd0 b 2 0\n"
@@ -47,40 +47,40 @@ static const char modes_chars[] ALIGN1 = { 'p', 'c', 'u', 'b', 0, 1, 1, 2 };
47static const mode_t modes_cubp[] = { S_IFIFO, S_IFCHR, S_IFBLK }; 47static const mode_t modes_cubp[] = { S_IFIFO, S_IFCHR, S_IFBLK };
48 48
49int mknod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 49int mknod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
50int mknod_main(int argc, char **argv) 50int mknod_main(int argc UNUSED_PARAM, char **argv)
51{ 51{
52 mode_t mode; 52 mode_t mode;
53 dev_t dev; 53 dev_t dev;
54 const char *name; 54 const char *type, *arg;
55 55
56 mode = getopt_mk_fifo_nod(argv); 56 mode = getopt_mk_fifo_nod(argv);
57 argv += optind; 57 argv += optind;
58 argc -= optind; 58 //argc -= optind;
59 59
60 if (argc >= 2) { 60 if (!argv[0] || !argv[1])
61 name = strchr(modes_chars, argv[1][0]); 61 bb_show_usage();
62 if (name != NULL) { 62 type = strchr(modes_chars, argv[1][0]);
63 mode |= modes_cubp[(int)(name[4])]; 63 if (!type)
64 bb_show_usage();
64 65
65 dev = 0; 66 mode |= modes_cubp[(int)(type[4])];
66 if (*name != 'p') {
67 argc -= 2;
68 if (argc == 2) {
69 /* Autodetect what the system supports; these macros should
70 * optimize out to two constants. */
71 dev = makedev(xatoul_range(argv[2], 0, major(UINT_MAX)),
72 xatoul_range(argv[3], 0, minor(UINT_MAX)));
73 }
74 }
75 67
76 if (argc == 2) { 68 dev = 0;
77 name = *argv; 69 arg = argv[2];
78 if (mknod(name, mode, dev) == 0) { 70 if (*type != 'p') {
79 return EXIT_SUCCESS; 71 if (!argv[2] || !argv[3])
80 } 72 bb_show_usage();
81 bb_simple_perror_msg_and_die(name); 73 /* Autodetect what the system supports; these macros should
82 } 74 * optimize out to two constants. */
83 } 75 dev = makedev(xatoul_range(argv[2], 0, major(UINT_MAX)),
76 xatoul_range(argv[3], 0, minor(UINT_MAX)));
77 arg = argv[4];
84 } 78 }
85 bb_show_usage(); 79 if (arg)
80 bb_show_usage();
81
82 if (mknod(argv[0], mode, dev) != 0) {
83 bb_simple_perror_msg_and_die(argv[0]);
84 }
85 return EXIT_SUCCESS;
86} 86}
diff --git a/coreutils/mv.c b/coreutils/mv.c
index 10cbc506f..aeafd1e40 100644
--- a/coreutils/mv.c
+++ b/coreutils/mv.c
@@ -17,7 +17,8 @@
17//config: help 17//config: help
18//config: mv is used to move or rename files or directories. 18//config: mv is used to move or rename files or directories.
19 19
20//applet:IF_MV(APPLET(mv, BB_DIR_BIN, BB_SUID_DROP)) 20//applet:IF_MV(APPLET_NOEXEC(mv, mv, BB_DIR_BIN, BB_SUID_DROP, mv))
21/* NOEXEC despite cases when it can be a "runner" (mv LARGE_DIR OTHER_FS) */
21 22
22//kbuild:lib-$(CONFIG_MV) += mv.o 23//kbuild:lib-$(CONFIG_MV) += mv.o
23 24
diff --git a/coreutils/nice.c b/coreutils/nice.c
index d6818cf00..aa8b06cce 100644
--- a/coreutils/nice.c
+++ b/coreutils/nice.c
@@ -26,7 +26,7 @@
26#include "libbb.h" 26#include "libbb.h"
27 27
28int nice_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 28int nice_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
29int nice_main(int argc, char **argv) 29int nice_main(int argc UNUSED_PARAM, char **argv)
30{ 30{
31 int old_priority, adjustment; 31 int old_priority, adjustment;
32 32
@@ -40,18 +40,21 @@ int nice_main(int argc, char **argv)
40 adjustment = 10; /* Set default adjustment. */ 40 adjustment = 10; /* Set default adjustment. */
41 41
42 if (argv[0][0] == '-') { 42 if (argv[0][0] == '-') {
43 if (argv[0][1] == 'n') { /* -n */ 43 char *nnn = argv[0] + 1;
44 if (argv[0][2]) { /* -nNNNN (w/o space) */ 44 if (nnn[0] == 'n') { /* -n */
45 argv[0] += 2; argv--; argc++; 45 nnn += 1;
46 if (!nnn[0]) { /* "-n NNN" */
47 nnn = *++argv;
46 } 48 }
47 } else { /* -NNN (NNN may be negative) == -n NNN */ 49 /* else: "-nNNN" (w/o space) */
48 argv[0] += 1; argv--; argc++;
49 } 50 }
50 if (argc < 4) { /* Missing priority and/or utility! */ 51 /* else: "-NNN" (NNN may be negative) - same as "-n NNN" */
52
53 if (!nnn || !argv[1]) { /* Missing priority or PROG! */
51 bb_show_usage(); 54 bb_show_usage();
52 } 55 }
53 adjustment = xatoi_range(argv[1], INT_MIN/2, INT_MAX/2); 56 adjustment = xatoi_range(nnn, INT_MIN/2, INT_MAX/2);
54 argv += 2; 57 argv++;
55 } 58 }
56 59
57 { /* Set our priority. */ 60 { /* Set our priority. */
diff --git a/coreutils/od_bloaty.c b/coreutils/od_bloaty.c
index df7354b7b..645a05f57 100644
--- a/coreutils/od_bloaty.c
+++ b/coreutils/od_bloaty.c
@@ -1378,9 +1378,13 @@ int od_main(int argc UNUSED_PARAM, char **argv)
1378 } 1378 }
1379 1379
1380#ifdef DEBUG 1380#ifdef DEBUG
1381 for (i = 0; i < G.n_specs; i++) { 1381 {
1382 printf("%d: fmt=\"%s\" width=%d\n", 1382 int i;
1383 i, spec[i].fmt_string, width_bytes[spec[i].size]); 1383 for (i = 0; i < G.n_specs; i++) {
1384 printf("%d: fmt='%s' width=%d\n",
1385 i, G.spec[i].fmt_string,
1386 width_bytes[G.spec[i].size]);
1387 }
1384 } 1388 }
1385#endif 1389#endif
1386 1390
diff --git a/coreutils/stat.c b/coreutils/stat.c
index 177ced2f9..41f6d103c 100644
--- a/coreutils/stat.c
+++ b/coreutils/stat.c
@@ -758,10 +758,13 @@ int stat_main(int argc UNUSED_PARAM, char **argv)
758 IF_FEATURE_STAT_FORMAT(char *format = NULL;) 758 IF_FEATURE_STAT_FORMAT(char *format = NULL;)
759 int i; 759 int i;
760 int ok; 760 int ok;
761 unsigned opts;
762 statfunc_ptr statfunc = do_stat; 761 statfunc_ptr statfunc = do_stat;
762#if ENABLE_FEATURE_STAT_FILESYSTEM || ENABLE_SELINUX
763 unsigned opts;
763 764
764 opts = getopt32(argv, "^" 765 opts =
766#endif
767 getopt32(argv, "^"
765 "tL" 768 "tL"
766 IF_FEATURE_STAT_FILESYSTEM("f") 769 IF_FEATURE_STAT_FILESYSTEM("f")
767 IF_SELINUX("Z") 770 IF_SELINUX("Z")
diff --git a/coreutils/uname.c b/coreutils/uname.c
index 57039b1bf..765809658 100644
--- a/coreutils/uname.c
+++ b/coreutils/uname.c
@@ -127,11 +127,9 @@ int uname_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
127{ 127{
128 uname_info_t uname_info; 128 uname_info_t uname_info;
129 IF_UNAME(const char *unknown_str = "unknown";) 129 IF_UNAME(const char *unknown_str = "unknown";)
130 unsigned toprint;
131
132 toprint = (1 << 4); /* "arch" = "uname -m" */
133
134#if ENABLE_UNAME 130#if ENABLE_UNAME
131 unsigned toprint = (1 << 4); /* "arch" = "uname -m" */
132
135 if (!ENABLE_BB_ARCH || applet_name[0] == 'u') { 133 if (!ENABLE_BB_ARCH || applet_name[0] == 'u') {
136# if ENABLE_LONG_OPTS 134# if ENABLE_LONG_OPTS
137 static const char uname_longopts[] ALIGN1 = 135 static const char uname_longopts[] ALIGN1 =
diff --git a/debianutils/which.c b/debianutils/which.c
index fbfd19cdc..9613c6fc5 100644
--- a/debianutils/which.c
+++ b/debianutils/which.c
@@ -30,12 +30,15 @@
30int which_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 30int which_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
31int which_main(int argc UNUSED_PARAM, char **argv) 31int which_main(int argc UNUSED_PARAM, char **argv)
32{ 32{
33 const char *env_path; 33 char *env_path;
34 int status = 0; 34 int status = 0;
35 /* This sizeof(): bb_default_root_path is shorter than BB_PATH_ROOT_PATH */
36 char buf[sizeof(BB_PATH_ROOT_PATH)];
35 37
36 env_path = getenv("PATH"); 38 env_path = getenv("PATH");
37 if (!env_path) 39 if (!env_path)
38 env_path = bb_default_root_path; 40 /* env_path must be writable, and must not alloc, so... */
41 env_path = strcpy(buf, bb_default_root_path);
39 42
40 getopt32(argv, "^" "a" "\0" "-1"/*at least one arg*/); 43 getopt32(argv, "^" "a" "\0" "-1"/*at least one arg*/);
41 argv += optind; 44 argv += optind;
@@ -69,19 +72,16 @@ int which_main(int argc UNUSED_PARAM, char **argv)
69#endif 72#endif
70 } else { 73 } else {
71 char *path; 74 char *path;
72 char *tmp;
73 75
74 path = tmp = xstrdup(env_path); 76 path = env_path;
75//NOFORK FIXME: nested xmallocs (one is inside find_executable()) 77 /* NOFORK NB: xmalloc inside find_executable(), must have no allocs above! */
76//can leak memory on failure 78 while ((p = find_executable(*argv, &path)) != NULL) {
77 while ((p = find_executable(*argv, &tmp)) != NULL) {
78 missing = 0; 79 missing = 0;
79 puts(p); 80 puts(p);
80 free(p); 81 free(p);
81 if (!option_mask32) /* -a not set */ 82 if (!option_mask32) /* -a not set */
82 break; 83 break;
83 } 84 }
84 free(path);
85 } 85 }
86 status |= missing; 86 status |= missing;
87 } while (*++argv); 87 } while (*++argv);
diff --git a/docs/posix_conformance.txt b/docs/posix_conformance.txt
index 8b9112020..cdf89b744 100644
--- a/docs/posix_conformance.txt
+++ b/docs/posix_conformance.txt
@@ -178,9 +178,10 @@ dd POSIX options:
178 conv=noerror | yes | | 178 conv=noerror | yes | |
179 conv=notrunc | yes | | 179 conv=notrunc | yes | |
180 conv=sync | yes | | 180 conv=sync | yes | |
181dd compatibility options:
182 conv=fsync | yes | |
181 iflag=skip_bytes| yes | | 183 iflag=skip_bytes| yes | |
182dd Busybox specific options: 184 iflag=fullblock | yes | |
183 conv=fsync
184 185
185df POSIX options 186df POSIX options
186 option | exists | compliant | remarks 187 option | exists | compliant | remarks
diff --git a/editors/awk.c b/editors/awk.c
index 1a273ff2e..9d74d931d 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -2518,6 +2518,32 @@ static var *evaluate(node *op, var *res)
2518 op1 = op->l.n; 2518 op1 = op->l.n;
2519 debug_printf_eval("opinfo:%08x opn:%08x\n", opinfo, opn); 2519 debug_printf_eval("opinfo:%08x opn:%08x\n", opinfo, opn);
2520 2520
2521 /* "delete" is special:
2522 * "delete array[var--]" must evaluate index expr only once,
2523 * must not evaluate it in "execute inevitable things" part.
2524 */
2525 if (XC(opinfo & OPCLSMASK) == XC(OC_DELETE)) {
2526 uint32_t info = op1->info & OPCLSMASK;
2527 var *v;
2528
2529 debug_printf_eval("DELETE\n");
2530 if (info == OC_VAR) {
2531 v = op1->l.v;
2532 } else if (info == OC_FNARG) {
2533 v = &fnargs[op1->l.aidx];
2534 } else {
2535 syntax_error(EMSG_NOT_ARRAY);
2536 }
2537 if (op1->r.n) { /* array ref? */
2538 const char *s;
2539 s = getvar_s(evaluate(op1->r.n, v1));
2540 hash_remove(iamarray(v), s);
2541 } else {
2542 clear_array(iamarray(v));
2543 }
2544 goto next;
2545 }
2546
2521 /* execute inevitable things */ 2547 /* execute inevitable things */
2522 if (opinfo & OF_RES1) 2548 if (opinfo & OF_RES1)
2523 L.v = evaluate(op1, v1); 2549 L.v = evaluate(op1, v1);
@@ -2625,28 +2651,7 @@ static var *evaluate(node *op, var *res)
2625 break; 2651 break;
2626 } 2652 }
2627 2653
2628 case XC( OC_DELETE ): { 2654 /* case XC( OC_DELETE ): - moved to happen before arg evaluation */
2629 uint32_t info = op1->info & OPCLSMASK;
2630 var *v;
2631
2632 if (info == OC_VAR) {
2633 v = op1->l.v;
2634 } else if (info == OC_FNARG) {
2635 v = &fnargs[op1->l.aidx];
2636 } else {
2637 syntax_error(EMSG_NOT_ARRAY);
2638 }
2639
2640 if (op1->r.n) {
2641 const char *s;
2642 clrvar(L.v);
2643 s = getvar_s(evaluate(op1->r.n, v1));
2644 hash_remove(iamarray(v), s);
2645 } else {
2646 clear_array(iamarray(v));
2647 }
2648 break;
2649 }
2650 2655
2651 case XC( OC_NEWSOURCE ): 2656 case XC( OC_NEWSOURCE ):
2652 g_progname = op->l.new_progname; 2657 g_progname = op->l.new_progname;
@@ -2670,12 +2675,14 @@ static var *evaluate(node *op, var *res)
2670 /* -- recursive node type -- */ 2675 /* -- recursive node type -- */
2671 2676
2672 case XC( OC_VAR ): 2677 case XC( OC_VAR ):
2678 debug_printf_eval("VAR\n");
2673 L.v = op->l.v; 2679 L.v = op->l.v;
2674 if (L.v == intvar[NF]) 2680 if (L.v == intvar[NF])
2675 split_f0(); 2681 split_f0();
2676 goto v_cont; 2682 goto v_cont;
2677 2683
2678 case XC( OC_FNARG ): 2684 case XC( OC_FNARG ):
2685 debug_printf_eval("FNARG[%d]\n", op->l.aidx);
2679 L.v = &fnargs[op->l.aidx]; 2686 L.v = &fnargs[op->l.aidx];
2680 v_cont: 2687 v_cont:
2681 res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v; 2688 res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
@@ -3039,7 +3046,8 @@ static var *evaluate(node *op, var *res)
3039 3046
3040 default: 3047 default:
3041 syntax_error(EMSG_POSSIBLE_ERROR); 3048 syntax_error(EMSG_POSSIBLE_ERROR);
3042 } 3049 } /* switch */
3050 next:
3043 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS) 3051 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
3044 op = op->a.n; 3052 op = op->a.n;
3045 if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS) 3053 if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS)
@@ -3145,7 +3153,7 @@ static rstream *next_input_file(void)
3145} 3153}
3146 3154
3147int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 3155int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
3148int awk_main(int argc, char **argv) 3156int awk_main(int argc UNUSED_PARAM, char **argv)
3149{ 3157{
3150 unsigned opt; 3158 unsigned opt;
3151 char *opt_F; 3159 char *opt_F;
@@ -3214,7 +3222,7 @@ int awk_main(int argc, char **argv)
3214 } 3222 }
3215 opt = getopt32(argv, OPTSTR_AWK, &opt_F, &list_v, &list_f, IF_FEATURE_AWK_GNU_EXTENSIONS(&list_e,) NULL); 3223 opt = getopt32(argv, OPTSTR_AWK, &opt_F, &list_v, &list_f, IF_FEATURE_AWK_GNU_EXTENSIONS(&list_e,) NULL);
3216 argv += optind; 3224 argv += optind;
3217 argc -= optind; 3225 //argc -= optind;
3218 if (opt & OPT_W) 3226 if (opt & OPT_W)
3219 bb_error_msg("warning: option -W is ignored"); 3227 bb_error_msg("warning: option -W is ignored");
3220 if (opt & OPT_F) { 3228 if (opt & OPT_F) {
@@ -3251,15 +3259,14 @@ int awk_main(int argc, char **argv)
3251 if (!*argv) 3259 if (!*argv)
3252 bb_show_usage(); 3260 bb_show_usage();
3253 parse_program(*argv++); 3261 parse_program(*argv++);
3254 argc--;
3255 } 3262 }
3256 3263
3257 /* fill in ARGV array */ 3264 /* fill in ARGV array */
3258 setvar_i(intvar[ARGC], argc + 1);
3259 setari_u(intvar[ARGV], 0, "awk"); 3265 setari_u(intvar[ARGV], 0, "awk");
3260 i = 0; 3266 i = 0;
3261 while (*argv) 3267 while (*argv)
3262 setari_u(intvar[ARGV], ++i, *argv++); 3268 setari_u(intvar[ARGV], ++i, *argv++);
3269 setvar_i(intvar[ARGC], i + 1);
3263 3270
3264 evaluate(beginseq.first, &tv); 3271 evaluate(beginseq.first, &tv);
3265 if (!mainseq.first && !endseq.first) 3272 if (!mainseq.first && !endseq.first)
diff --git a/include/bb_archive.h b/include/bb_archive.h
index acb3c3cbd..c67a299d1 100644
--- a/include/bb_archive.h
+++ b/include/bb_archive.h
@@ -260,6 +260,21 @@ int bbunpack(char **argv,
260 char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext), 260 char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext),
261 const char *expected_ext 261 const char *expected_ext
262) FAST_FUNC; 262) FAST_FUNC;
263#define BBUNPK_OPTSTR "cfkvq"
264#define BBUNPK_OPTSTRLEN 5
265#define BBUNPK_OPTSTRMASK ((1 << BBUNPK_OPTSTRLEN) - 1)
266enum {
267 BBUNPK_OPT_STDOUT = 1 << 0,
268 BBUNPK_OPT_FORCE = 1 << 1,
269 /* only some decompressors: */
270 BBUNPK_OPT_KEEP = 1 << 2,
271 BBUNPK_OPT_VERBOSE = 1 << 3,
272 BBUNPK_OPT_QUIET = 1 << 4,
273 /* not included in BBUNPK_OPTSTR: */
274 BBUNPK_OPT_DECOMPRESS = 1 << 5,
275 BBUNPK_OPT_TEST = 1 << 6,
276 BBUNPK_SEAMLESS_MAGIC = (1 << 31) * ENABLE_ZCAT * SEAMLESS_COMPRESSION,
277};
263 278
264void check_errors_in_children(int signo); 279void check_errors_in_children(int signo);
265#if BB_MMU 280#if BB_MMU
diff --git a/include/libbb.h b/include/libbb.h
index 5be5684da..761370111 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -422,10 +422,11 @@ enum { /* cp.c, mv.c, install.c depend on these values. CAREFUL when changing th
422 /* -P = -d (mapped in cp.c) */ 422 /* -P = -d (mapped in cp.c) */
423 FILEUTILS_VERBOSE = (1 << 12) * ENABLE_FEATURE_VERBOSE, /* -v */ 423 FILEUTILS_VERBOSE = (1 << 12) * ENABLE_FEATURE_VERBOSE, /* -v */
424 FILEUTILS_UPDATE = 1 << 13, /* -u */ 424 FILEUTILS_UPDATE = 1 << 13, /* -u */
425 FILEUTILS_NO_TARGET_DIR = 1 << 14, /* -T */
425#if ENABLE_SELINUX 426#if ENABLE_SELINUX
426 FILEUTILS_PRESERVE_SECURITY_CONTEXT = 1 << 14, /* -c */ 427 FILEUTILS_PRESERVE_SECURITY_CONTEXT = 1 << 15, /* -c */
427#endif 428#endif
428 FILEUTILS_RMDEST = 1 << (15 - !ENABLE_SELINUX), /* --remove-destination */ 429 FILEUTILS_RMDEST = 1 << (16 - !ENABLE_SELINUX), /* --remove-destination */
429 /* 430 /*
430 * Hole. cp may have some bits set here, 431 * Hole. cp may have some bits set here,
431 * they should not affect remove_file()/copy_file() 432 * they should not affect remove_file()/copy_file()
@@ -435,7 +436,7 @@ enum { /* cp.c, mv.c, install.c depend on these values. CAREFUL when changing th
435#endif 436#endif
436 FILEUTILS_IGNORE_CHMOD_ERR = 1 << 31, 437 FILEUTILS_IGNORE_CHMOD_ERR = 1 << 31,
437}; 438};
438#define FILEUTILS_CP_OPTSTR "pdRfilsLHarPvu" IF_SELINUX("c") 439#define FILEUTILS_CP_OPTSTR "pdRfilsLHarPvuT" IF_SELINUX("c")
439extern int remove_file(const char *path, int flags) FAST_FUNC; 440extern int remove_file(const char *path, int flags) FAST_FUNC;
440/* NB: without FILEUTILS_RECUR in flags, it will basically "cat" 441/* NB: without FILEUTILS_RECUR in flags, it will basically "cat"
441 * the source, not copy (unless "source" is a directory). 442 * the source, not copy (unless "source" is a directory).
@@ -658,6 +659,7 @@ void setsockopt_reuseaddr(int fd) FAST_FUNC; /* On Linux this never fails. */
658int setsockopt_keepalive(int fd) FAST_FUNC; 659int setsockopt_keepalive(int fd) FAST_FUNC;
659int setsockopt_broadcast(int fd) FAST_FUNC; 660int setsockopt_broadcast(int fd) FAST_FUNC;
660int setsockopt_bindtodevice(int fd, const char *iface) FAST_FUNC; 661int setsockopt_bindtodevice(int fd, const char *iface) FAST_FUNC;
662int bb_getsockname(int sockfd, void *addr, socklen_t addrlen) FAST_FUNC;
661/* NB: returns port in host byte order */ 663/* NB: returns port in host byte order */
662unsigned bb_lookup_port(const char *port, const char *protocol, unsigned default_port) FAST_FUNC; 664unsigned bb_lookup_port(const char *port, const char *protocol, unsigned default_port) FAST_FUNC;
663typedef struct len_and_sockaddr { 665typedef struct len_and_sockaddr {
@@ -794,7 +796,8 @@ static inline tls_state_t *new_tls_state(void)
794 return tls; 796 return tls;
795} 797}
796void tls_handshake(tls_state_t *tls, const char *sni) FAST_FUNC; 798void tls_handshake(tls_state_t *tls, const char *sni) FAST_FUNC;
797void tls_run_copy_loop(tls_state_t *tls) FAST_FUNC; 799#define TLSLOOP_EXIT_ON_LOCAL_EOF (1 << 0)
800void tls_run_copy_loop(tls_state_t *tls, unsigned flags) FAST_FUNC;
798 801
799 802
800void socket_want_pktinfo(int fd) FAST_FUNC; 803void socket_want_pktinfo(int fd) FAST_FUNC;
@@ -808,6 +811,7 @@ ssize_t recv_from_to(int fd, void *buf, size_t len, int flags,
808 socklen_t sa_size) FAST_FUNC; 811 socklen_t sa_size) FAST_FUNC;
809 812
810uint16_t inet_cksum(uint16_t *addr, int len) FAST_FUNC; 813uint16_t inet_cksum(uint16_t *addr, int len) FAST_FUNC;
814int parse_pasv_epsv(char *buf) FAST_FUNC;
811 815
812/* 0 if argv[0] is NULL: */ 816/* 0 if argv[0] is NULL: */
813unsigned string_array_len(char **argv) FAST_FUNC; 817unsigned string_array_len(char **argv) FAST_FUNC;
@@ -1966,6 +1970,8 @@ typedef struct md5_ctx_t md5sha_ctx_t;
1966 1970
1967extern uint32_t *global_crc32_table; 1971extern uint32_t *global_crc32_table;
1968uint32_t *crc32_filltable(uint32_t *tbl256, int endian) FAST_FUNC; 1972uint32_t *crc32_filltable(uint32_t *tbl256, int endian) FAST_FUNC;
1973uint32_t *crc32_new_table_le(void) FAST_FUNC;
1974uint32_t *global_crc32_new_table_le(void) FAST_FUNC;
1969uint32_t crc32_block_endian1(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) FAST_FUNC; 1975uint32_t crc32_block_endian1(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) FAST_FUNC;
1970uint32_t crc32_block_endian0(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) FAST_FUNC; 1976uint32_t crc32_block_endian0(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) FAST_FUNC;
1971 1977
@@ -2048,10 +2054,16 @@ extern const char bb_path_wtmp_file[] ALIGN1;
2048#else 2054#else
2049extern const char bb_busybox_exec_path[] ALIGN1; 2055extern const char bb_busybox_exec_path[] ALIGN1;
2050#endif 2056#endif
2051/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin, 2057/* allow default system PATH to be extended via CFLAGS */
2052 * but I want to save a few bytes here */ 2058#ifndef BB_ADDITIONAL_PATH
2053extern const char bb_PATH_root_path[] ALIGN1; /* "PATH=/sbin:/usr/sbin:/bin:/usr/bin" */ 2059#define BB_ADDITIONAL_PATH ""
2060#endif
2061#define BB_PATH_ROOT_PATH "PATH=/sbin:/usr/sbin:/bin:/usr/bin" BB_ADDITIONAL_PATH
2062extern const char bb_PATH_root_path[] ALIGN1; /* BB_PATH_ROOT_PATH */
2054#define bb_default_root_path (bb_PATH_root_path + sizeof("PATH")) 2063#define bb_default_root_path (bb_PATH_root_path + sizeof("PATH"))
2064/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin,
2065 * but I want to save a few bytes here:
2066 */
2055#define bb_default_path (bb_PATH_root_path + sizeof("PATH=/sbin:/usr/sbin")) 2067#define bb_default_path (bb_PATH_root_path + sizeof("PATH=/sbin:/usr/sbin"))
2056 2068
2057extern const int const_int_0; 2069extern const int const_int_0;
diff --git a/include/liblzo_interface.h b/include/liblzo_interface.h
index b7f1b639b..1e194b944 100644
--- a/include/liblzo_interface.h
+++ b/include/liblzo_interface.h
@@ -49,12 +49,10 @@ int lzo1x_999_compress_level(const uint8_t* in, unsigned in_len,
49 49
50/* decompression */ 50/* decompression */
51//int lzo1x_decompress(const uint8_t* src, unsigned src_len, 51//int lzo1x_decompress(const uint8_t* src, unsigned src_len,
52// uint8_t* dst, unsigned* dst_len, 52// uint8_t* dst, unsigned* dst_len /*, void* wrkmem */);
53// void* wrkmem /* NOT USED */);
54/* safe decompression with overrun testing */ 53/* safe decompression with overrun testing */
55int lzo1x_decompress_safe(const uint8_t* src, unsigned src_len, 54int lzo1x_decompress_safe(const uint8_t* src, unsigned src_len,
56 uint8_t* dst, unsigned* dst_len, 55 uint8_t* dst, unsigned* dst_len /*, void* wrkmem */);
57 void* wrkmem /* NOT USED */);
58 56
59#define LZO_E_OK 0 57#define LZO_E_OK 0
60#define LZO_E_ERROR (-1) 58#define LZO_E_ERROR (-1)
diff --git a/init/init.c b/init/init.c
index 6f3374eac..cac165fc7 100644
--- a/init/init.c
+++ b/init/init.c
@@ -128,6 +128,7 @@
128#define DEBUG_SEGV_HANDLER 0 128#define DEBUG_SEGV_HANDLER 0
129 129
130#include "libbb.h" 130#include "libbb.h"
131#include "common_bufsiz.h"
131#include <syslog.h> 132#include <syslog.h>
132#include <sys/resource.h> 133#include <sys/resource.h>
133#ifdef __linux__ 134#ifdef __linux__
@@ -203,7 +204,6 @@
203 */ 204 */
204#define RESTART 0x80 205#define RESTART 0x80
205 206
206
207/* A linked list of init_actions, to be read from inittab */ 207/* A linked list of init_actions, to be read from inittab */
208struct init_action { 208struct init_action {
209 struct init_action *next; 209 struct init_action *next;
@@ -213,11 +213,17 @@ struct init_action {
213 char command[1]; 213 char command[1];
214}; 214};
215 215
216static struct init_action *init_action_list = NULL; 216struct globals {
217 217 struct init_action *init_action_list;
218#if !ENABLE_FEATURE_INIT_SYSLOG 218#if !ENABLE_FEATURE_INIT_SYSLOG
219static const char *log_console = VC_5; 219 const char *log_console;
220#endif 220#endif
221} FIX_ALIASING;
222#define G (*(struct globals*)bb_common_bufsiz1)
223#define INIT_G() do { \
224 setup_common_bufsiz(); \
225 IF_NOT_FEATURE_INIT_SYSLOG(G.log_console = VC_5;) \
226} while (0)
221 227
222enum { 228enum {
223 L_LOG = 0x1, 229 L_LOG = 0x1,
@@ -265,10 +271,10 @@ static void message(int where, const char *fmt, ...)
265 271
266 if (log_fd < 0) { 272 if (log_fd < 0) {
267 log_fd = STDERR_FILENO; 273 log_fd = STDERR_FILENO;
268 if (log_console) { 274 if (G.log_console) {
269 log_fd = device_open(log_console, O_WRONLY | O_NONBLOCK | O_NOCTTY); 275 log_fd = device_open(G.log_console, O_WRONLY | O_NONBLOCK | O_NOCTTY);
270 if (log_fd < 0) { 276 if (log_fd < 0) {
271 bb_error_msg("can't log to %s", log_console); 277 bb_error_msg("can't log to %s", G.log_console);
272 where = L_CONSOLE; 278 where = L_CONSOLE;
273 } else { 279 } else {
274 close_on_exec_on(log_fd); 280 close_on_exec_on(log_fd);
@@ -328,7 +334,7 @@ static void console_init(void)
328 if (!s || strcmp(s, "linux") == 0) 334 if (!s || strcmp(s, "linux") == 0)
329 putenv((char*)"TERM=vt102"); 335 putenv((char*)"TERM=vt102");
330# if !ENABLE_FEATURE_INIT_SYSLOG 336# if !ENABLE_FEATURE_INIT_SYSLOG
331 log_console = NULL; 337 G.log_console = NULL;
332# endif 338# endif
333 } else 339 } else
334#endif 340#endif
@@ -562,7 +568,7 @@ static struct init_action *mark_terminated(pid_t pid)
562 568
563 if (pid > 0) { 569 if (pid > 0) {
564 update_utmp_DEAD_PROCESS(pid); 570 update_utmp_DEAD_PROCESS(pid);
565 for (a = init_action_list; a; a = a->next) { 571 for (a = G.init_action_list; a; a = a->next) {
566 if (a->pid == pid) { 572 if (a->pid == pid) {
567 a->pid = 0; 573 a->pid = 0;
568 return a; 574 return a;
@@ -596,7 +602,7 @@ static void run_actions(int action_type)
596{ 602{
597 struct init_action *a; 603 struct init_action *a;
598 604
599 for (a = init_action_list; a; a = a->next) { 605 for (a = G.init_action_list; a; a = a->next) {
600 if (!(a->action_type & action_type)) 606 if (!(a->action_type & action_type))
601 continue; 607 continue;
602 608
@@ -630,7 +636,7 @@ static void new_init_action(uint8_t action_type, const char *command, const char
630 * To achieve that, if we find a matching entry, we move it 636 * To achieve that, if we find a matching entry, we move it
631 * to the end. 637 * to the end.
632 */ 638 */
633 nextp = &init_action_list; 639 nextp = &G.init_action_list;
634 while ((a = *nextp) != NULL) { 640 while ((a = *nextp) != NULL) {
635 /* Don't enter action if it's already in the list. 641 /* Don't enter action if it's already in the list.
636 * This prevents losing running RESPAWNs. 642 * This prevents losing running RESPAWNs.
@@ -845,7 +851,7 @@ static void exec_restart_action(void)
845{ 851{
846 struct init_action *a; 852 struct init_action *a;
847 853
848 for (a = init_action_list; a; a = a->next) { 854 for (a = G.init_action_list; a; a = a->next) {
849 if (!(a->action_type & RESTART)) 855 if (!(a->action_type & RESTART))
850 continue; 856 continue;
851 857
@@ -923,7 +929,7 @@ static void reload_inittab(void)
923 message(L_LOG, "reloading /etc/inittab"); 929 message(L_LOG, "reloading /etc/inittab");
924 930
925 /* Disable old entries */ 931 /* Disable old entries */
926 for (a = init_action_list; a; a = a->next) 932 for (a = G.init_action_list; a; a = a->next)
927 a->action_type = 0; 933 a->action_type = 0;
928 934
929 /* Append new entries, or modify existing entries 935 /* Append new entries, or modify existing entries
@@ -936,14 +942,14 @@ static void reload_inittab(void)
936#if ENABLE_FEATURE_KILL_REMOVED 942#if ENABLE_FEATURE_KILL_REMOVED
937 /* Kill stale entries */ 943 /* Kill stale entries */
938 /* Be nice and send SIGTERM first */ 944 /* Be nice and send SIGTERM first */
939 for (a = init_action_list; a; a = a->next) 945 for (a = G.init_action_list; a; a = a->next)
940 if (a->action_type == 0 && a->pid != 0) 946 if (a->action_type == 0 && a->pid != 0)
941 kill(a->pid, SIGTERM); 947 kill(a->pid, SIGTERM);
942 if (CONFIG_FEATURE_KILL_DELAY) { 948 if (CONFIG_FEATURE_KILL_DELAY) {
943 /* NB: parent will wait in NOMMU case */ 949 /* NB: parent will wait in NOMMU case */
944 if ((BB_MMU ? fork() : vfork()) == 0) { /* child */ 950 if ((BB_MMU ? fork() : vfork()) == 0) { /* child */
945 sleep(CONFIG_FEATURE_KILL_DELAY); 951 sleep(CONFIG_FEATURE_KILL_DELAY);
946 for (a = init_action_list; a; a = a->next) 952 for (a = G.init_action_list; a; a = a->next)
947 if (a->action_type == 0 && a->pid != 0) 953 if (a->action_type == 0 && a->pid != 0)
948 kill(a->pid, SIGKILL); 954 kill(a->pid, SIGKILL);
949 _exit(EXIT_SUCCESS); 955 _exit(EXIT_SUCCESS);
@@ -955,7 +961,7 @@ static void reload_inittab(void)
955 * We never rerun SYSINIT entries anyway, 961 * We never rerun SYSINIT entries anyway,
956 * removing them too saves a few bytes 962 * removing them too saves a few bytes
957 */ 963 */
958 nextp = &init_action_list; 964 nextp = &G.init_action_list;
959 while ((a = *nextp) != NULL) { 965 while ((a = *nextp) != NULL) {
960 /* 966 /*
961 * Why pid == 0 check? 967 * Why pid == 0 check?
@@ -1046,6 +1052,8 @@ static void sleep_much(void)
1046int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1052int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1047int init_main(int argc UNUSED_PARAM, char **argv) 1053int init_main(int argc UNUSED_PARAM, char **argv)
1048{ 1054{
1055 INIT_G();
1056
1049 if (argv[1] && strcmp(argv[1], "-q") == 0) { 1057 if (argv[1] && strcmp(argv[1], "-q") == 0) {
1050 return kill(1, SIGHUP); 1058 return kill(1, SIGHUP);
1051 } 1059 }
diff --git a/klibc-utils/nuke.c b/klibc-utils/nuke.c
index 6b65f705f..60a5f7145 100644
--- a/klibc-utils/nuke.c
+++ b/klibc-utils/nuke.c
@@ -4,7 +4,7 @@
4 * Licensed under GPLv2, see file LICENSE in this source tree. 4 * Licensed under GPLv2, see file LICENSE in this source tree.
5 */ 5 */
6//config:config NUKE 6//config:config NUKE
7//config: bool "nuke" 7//config: bool "nuke (2.4 kb)"
8//config: default y 8//config: default y
9//config: help 9//config: help
10//config: Alias to "rm -rf". 10//config: Alias to "rm -rf".
diff --git a/klibc-utils/resume.c b/klibc-utils/resume.c
index f85384853..3424f076b 100644
--- a/klibc-utils/resume.c
+++ b/klibc-utils/resume.c
@@ -4,7 +4,7 @@
4 * Licensed under GPLv2, see file LICENSE in this source tree. 4 * Licensed under GPLv2, see file LICENSE in this source tree.
5 */ 5 */
6//config:config RESUME 6//config:config RESUME
7//config: bool "resume" 7//config: bool "resume (3.3 kb)"
8//config: default y 8//config: default y
9//config: help 9//config: help
10//config: Resume from saved "suspend-to-disk" image 10//config: Resume from saved "suspend-to-disk" image
diff --git a/klibc-utils/run-init.c b/klibc-utils/run-init.c
index a70d1bfbf..61c16fd0b 100644
--- a/klibc-utils/run-init.c
+++ b/klibc-utils/run-init.c
@@ -6,7 +6,7 @@
6 * Licensed under GPLv2, see file LICENSE in this source tree. 6 * Licensed under GPLv2, see file LICENSE in this source tree.
7 */ 7 */
8//config:config RUN_INIT 8//config:config RUN_INIT
9//config: bool "run-init" 9//config: bool "run-init (7.5 kb)"
10//config: default y 10//config: default y
11//config: select PLATFORM_LINUX 11//config: select PLATFORM_LINUX
12//config: help 12//config: help
diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src
index 6749cceda..c0cc2baf5 100644
--- a/libbb/Kbuild.src
+++ b/libbb/Kbuild.src
@@ -128,6 +128,7 @@ lib-$(CONFIG_UNICODE_SUPPORT) += unicode.o
128lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o 128lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o
129 129
130lib-$(CONFIG_NC_110_COMPAT) += udp_io.o 130lib-$(CONFIG_NC_110_COMPAT) += udp_io.o
131lib-$(CONFIG_NETCAT) += udp_io.o
131lib-$(CONFIG_DNSD) += udp_io.o 132lib-$(CONFIG_DNSD) += udp_io.o
132lib-$(CONFIG_NTPD) += udp_io.o 133lib-$(CONFIG_NTPD) += udp_io.o
133lib-$(CONFIG_TFTP) += udp_io.o 134lib-$(CONFIG_TFTP) += udp_io.o
@@ -146,7 +147,8 @@ lib-$(CONFIG_DELGROUP) += update_passwd.o
146lib-$(CONFIG_DELUSER) += update_passwd.o 147lib-$(CONFIG_DELUSER) += update_passwd.o
147 148
148lib-$(CONFIG_FTPD) += pw_encrypt.o correct_password.o 149lib-$(CONFIG_FTPD) += pw_encrypt.o correct_password.o
149lib-$(CONFIG_PASSWD) += pw_encrypt.o update_passwd.o obscure.o 150lib-$(CONFIG_PASSWD) += pw_encrypt.o update_passwd.o
151lib-$(CONFIG_FEATURE_PASSWD_WEAK_CHECK) += obscure.o
150lib-$(CONFIG_CHPASSWD) += pw_encrypt.o update_passwd.o 152lib-$(CONFIG_CHPASSWD) += pw_encrypt.o update_passwd.o
151lib-$(CONFIG_CRYPTPW) += pw_encrypt.o 153lib-$(CONFIG_CRYPTPW) += pw_encrypt.o
152lib-$(CONFIG_MKPASSWD) += pw_encrypt.o 154lib-$(CONFIG_MKPASSWD) += pw_encrypt.o
diff --git a/libbb/bb_getsockname.c b/libbb/bb_getsockname.c
new file mode 100644
index 000000000..1af9b39b9
--- /dev/null
+++ b/libbb/bb_getsockname.c
@@ -0,0 +1,19 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Licensed under GPLv2, see file LICENSE in this source tree.
6 */
7//kbuild:lib-y += bb_getsockname.o
8
9#include "libbb.h"
10
11int FAST_FUNC bb_getsockname(int sockfd, void *addr, socklen_t addrlen)
12{
13 /* The usefullness of this function is that for getsockname(),
14 * addrlen must go on stack (to _have_ an address to be passed),
15 * but many callers do not need its modified value.
16 * By using this shim, they can avoid unnecessary stack spillage.
17 */
18 return getsockname(sockfd, (struct sockaddr *)addr, &addrlen);
19}
diff --git a/libbb/crc32.c b/libbb/crc32.c
index b00b580d0..728bcb736 100644
--- a/libbb/crc32.c
+++ b/libbb/crc32.c
@@ -41,6 +41,16 @@ uint32_t* FAST_FUNC crc32_filltable(uint32_t *crc_table, int endian)
41 41
42 return crc_table - 256; 42 return crc_table - 256;
43} 43}
44/* Common uses: */
45uint32_t* FAST_FUNC crc32_new_table_le(void)
46{
47 return crc32_filltable(NULL, 0);
48}
49uint32_t* FAST_FUNC global_crc32_new_table_le(void)
50{
51 global_crc32_table = crc32_new_table_le();
52 return global_crc32_table;
53}
44 54
45uint32_t FAST_FUNC crc32_block_endian1(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) 55uint32_t FAST_FUNC crc32_block_endian1(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table)
46{ 56{
diff --git a/libbb/executable.c b/libbb/executable.c
index b28f020e0..8e2f99732 100644
--- a/libbb/executable.c
+++ b/libbb/executable.c
@@ -25,7 +25,8 @@ int FAST_FUNC file_is_executable(const char *name)
25 * you may call find_executable again with this PATHp to continue 25 * you may call find_executable again with this PATHp to continue
26 * (if it's not NULL). 26 * (if it's not NULL).
27 * return NULL otherwise; (PATHp is undefined) 27 * return NULL otherwise; (PATHp is undefined)
28 * in all cases (*PATHp) contents will be trashed (s/:/NUL/). 28 * in all cases (*PATHp) contents are temporarily modified
29 * but are restored on return (s/:/NUL/ and back).
29 */ 30 */
30#if !ENABLE_PLATFORM_MINGW32 31#if !ENABLE_PLATFORM_MINGW32
31#define next_path_sep(s) strchr(s, ':') 32#define next_path_sep(s) strchr(s, ':')
@@ -48,14 +49,30 @@ char* FAST_FUNC find_executable(const char *filename, char **PATHp)
48 49
49 p = *PATHp; 50 p = *PATHp;
50 while (p) { 51 while (p) {
52 int ex;
53#if ENABLE_PLATFORM_MINGW32
54 char sep;
55
51 n = (char*)next_path_sep(p); 56 n = (char*)next_path_sep(p);
52 if (n) 57 if (n) {
53 *n++ = '\0'; 58 sep = *n;
59 *n = '\0';
60 }
61#else
62 n = strchr(p, ':');
63 if (n) *n = '\0';
64#endif
54 p = concat_path_file( 65 p = concat_path_file(
55 p[0] ? p : ".", /* handle "::" case */ 66 p[0] ? p : ".", /* handle "::" case */
56 filename 67 filename
57 ); 68 );
58 if (file_is_executable(p)) { 69 ex = file_is_executable(p);
70#if ENABLE_PLATFORM_MINGW32
71 if (n) *n++ = sep;
72#else
73 if (n) *n++ = ':';
74#endif
75 if (ex) {
59 *PATHp = n; 76 *PATHp = n;
60 return p; 77 return p;
61 } 78 }
@@ -78,10 +95,8 @@ char* FAST_FUNC find_executable(const char *filename, char **PATHp)
78 */ 95 */
79int FAST_FUNC executable_exists(const char *filename) 96int FAST_FUNC executable_exists(const char *filename)
80{ 97{
81 char *path = xstrdup(getenv("PATH")); 98 char *path = getenv("PATH");
82 char *tmp = path; 99 char *ret = find_executable(filename, &path);
83 char *ret = find_executable(filename, &tmp);
84 free(path);
85 free(ret); 100 free(ret);
86 return ret != NULL; 101 return ret != NULL;
87} 102}
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 3df67abb1..f22f5768f 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -90,7 +90,8 @@ static bool BB_ispunct(CHAR_T c) { return ((unsigned)c < 256 && ispunct(c)); }
90# define CHAR_T char 90# define CHAR_T char
91# define BB_isspace(c) isspace(c) 91# define BB_isspace(c) isspace(c)
92# if ENABLE_FEATURE_EDITING_VI 92# if ENABLE_FEATURE_EDITING_VI
93static bool BB_isalnum_or_underscore(CHAR_T c) { 93static bool BB_isalnum_or_underscore(CHAR_T c)
94{
94 return ((unsigned)c < 256 && isalnum(c)) || c == '_'; 95 return ((unsigned)c < 256 && isalnum(c)) || c == '_';
95} 96}
96# endif 97# endif
diff --git a/libbb/make_directory.c b/libbb/make_directory.c
index 6422c863f..1f3aecf40 100644
--- a/libbb/make_directory.c
+++ b/libbb/make_directory.c
@@ -125,6 +125,7 @@ int FAST_FUNC bb_make_directory(char *path, long mode, int flags)
125 } 125 }
126 } 126 }
127 127
128 //bb_error_msg("mkdir '%s'", path);
128 if (mkdir(path, 0777) < 0) { 129 if (mkdir(path, 0777) < 0) {
129 /* If we failed for any other reason than the directory 130 /* If we failed for any other reason than the directory
130 * already exists, output a diagnostic and return -1 */ 131 * already exists, output a diagnostic and return -1 */
@@ -151,13 +152,16 @@ int FAST_FUNC bb_make_directory(char *path, long mode, int flags)
151 /* Done. If necessary, update perms on the newly 152 /* Done. If necessary, update perms on the newly
152 * created directory. Failure to update here _is_ 153 * created directory. Failure to update here _is_
153 * an error. */ 154 * an error. */
154 if ((mode != -1) && (chmod(path, mode) < 0)) { 155 if (mode != -1) {
155 fail_msg = "set permissions of"; 156 //bb_error_msg("chmod 0%03lo mkdir '%s'", mode, path);
156 if (flags & FILEUTILS_IGNORE_CHMOD_ERR) { 157 if (chmod(path, mode) < 0) {
157 flags = 0; 158 fail_msg = "set permissions of";
158 goto print_err; 159 if (flags & FILEUTILS_IGNORE_CHMOD_ERR) {
160 flags = 0;
161 goto print_err;
162 }
163 break;
159 } 164 }
160 break;
161 } 165 }
162 goto ret0; 166 goto ret0;
163 } 167 }
diff --git a/libbb/messages.c b/libbb/messages.c
index 31721a3b3..f5bbd3e32 100644
--- a/libbb/messages.c
+++ b/libbb/messages.c
@@ -6,11 +6,6 @@
6 */ 6 */
7#include "libbb.h" 7#include "libbb.h"
8 8
9/* allow default system PATH to be extended via CFLAGS */
10#ifndef BB_ADDITIONAL_PATH
11#define BB_ADDITIONAL_PATH ""
12#endif
13
14/* allow version to be extended, via CFLAGS */ 9/* allow version to be extended, via CFLAGS */
15#ifndef BB_EXTRA_VERSION 10#ifndef BB_EXTRA_VERSION
16#define BB_EXTRA_VERSION " ("AUTOCONF_TIMESTAMP")" 11#define BB_EXTRA_VERSION " ("AUTOCONF_TIMESTAMP")"
@@ -38,8 +33,7 @@ const char bb_busybox_exec_path[] ALIGN1 = CONFIG_BUSYBOX_EXEC_PATH;
38const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL; 33const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL;
39/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin, 34/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin,
40 * but I want to save a few bytes here. Check libbb.h before changing! */ 35 * but I want to save a few bytes here. Check libbb.h before changing! */
41const char bb_PATH_root_path[] ALIGN1 = 36const char bb_PATH_root_path[] ALIGN1 = BB_PATH_ROOT_PATH;
42 "PATH=/sbin:/usr/sbin:/bin:/usr/bin" BB_ADDITIONAL_PATH;
43 37
44 38
45//const int const_int_1 = 1; 39//const int const_int_1 = 1;
diff --git a/libbb/progress.c b/libbb/progress.c
index 64e6529ac..f1d980d68 100644
--- a/libbb/progress.c
+++ b/libbb/progress.c
@@ -71,10 +71,9 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p,
71 uoff_t transferred, 71 uoff_t transferred,
72 uoff_t totalsize) 72 uoff_t totalsize)
73{ 73{
74 uoff_t beg_and_transferred; 74 char numbuf5[6]; /* 5 + 1 for NUL */
75 unsigned since_last_update, elapsed; 75 unsigned since_last_update, elapsed;
76 int notty; 76 int notty;
77 int kiloscale;
78 77
79 //transferred = 1234; /* use for stall detection testing */ 78 //transferred = 1234; /* use for stall detection testing */
80 //totalsize = 0; /* use for unknown size download testing */ 79 //totalsize = 0; /* use for unknown size download testing */
@@ -95,74 +94,69 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p,
95 return; 94 return;
96 } 95 }
97 96
98 kiloscale = 0; 97 /* Before we lose real, unscaled sizes, produce human-readable size string */
98 smart_ulltoa5(beg_size + transferred, numbuf5, " kMGTPEZY")[0] = '\0';
99
99 /* 100 /*
100 * Scale sizes down if they are close to overflowing. 101 * Scale sizes down if they are close to overflowing.
101 * This allows calculations like (100 * transferred / totalsize) 102 * This allows calculations like (100 * transferred / totalsize)
102 * without risking overflow: we guarantee 10 highest bits to be 0. 103 * without risking overflow: we guarantee 10 highest bits to be 0.
103 * Introduced error is less than 1 / 2^12 ~= 0.025% 104 * Introduced error is less than 1 / 2^12 ~= 0.025%
104 */ 105 */
105 if (ULONG_MAX > 0xffffffff || sizeof(off_t) == 4 || sizeof(off_t) != 8) { 106 while (totalsize >= (1 << 20)) {
106 /* 107 totalsize >>= 8;
107 * 64-bit CPU || small off_t: in either case, 108 beg_size >>= 8;
108 * >> is cheap, single-word operation. 109 transferred >>= 8;
109 * ... || strange off_t: also use this code
110 * (it is safe, just suboptimal wrt code size),
111 * because 32/64 optimized one works only for 64-bit off_t.
112 */
113 if (totalsize >= (1 << 22)) {
114 totalsize >>= 10;
115 beg_size >>= 10;
116 transferred >>= 10;
117 kiloscale = 1;
118 }
119 } else {
120 /* 32-bit CPU and 64-bit off_t.
121 * Use a 40-bit shift, it is easier to do on 32-bit CPU.
122 */
123/* ONE suppresses "warning: shift count >= width of type" */
124#define ONE (sizeof(off_t) > 4)
125 if (totalsize >= (uoff_t)(1ULL << 54*ONE)) {
126 totalsize = (uint32_t)(totalsize >> 32*ONE) >> 8;
127 beg_size = (uint32_t)(beg_size >> 32*ONE) >> 8;
128 transferred = (uint32_t)(transferred >> 32*ONE) >> 8;
129 kiloscale = 4;
130 }
131 } 110 }
111 /* If they were huge, now they are scaled down to [1048575,4096] range.
112 * (N * totalsize) won't overflow 32 bits for N up to 4096.
113 */
114#if ULONG_MAX == 0xffffffff
115/* 32-bit CPU, uoff_t arithmetic is complex on it, cast variables to narrower types */
116# define totalsize ((unsigned)totalsize)
117# define beg_size ((unsigned)beg_size)
118# define transferred ((unsigned)transferred)
119#endif
132 120
133 notty = !isatty(STDERR_FILENO); 121 notty = !isatty(STDERR_FILENO);
134 122
135 if (ENABLE_UNICODE_SUPPORT) 123 if (ENABLE_UNICODE_SUPPORT)
136 fprintf(stderr, "\r%s" + notty, p->curfile); 124 fprintf(stderr, "\r%s " + notty, p->curfile);
137 else 125 else
138 fprintf(stderr, "\r%-20.20s" + notty, p->curfile); 126 fprintf(stderr, "\r%-20.20s " + notty, p->curfile);
139
140 beg_and_transferred = beg_size + transferred;
141 127
142 if (totalsize != 0) { 128 if (totalsize != 0) {
143 int barlength; 129 int barlength;
144 unsigned ratio = 100 * beg_and_transferred / totalsize; 130 unsigned beg_and_transferred; /* does not need uoff_t, see scaling code */
145 fprintf(stderr, "%4u%%", ratio); 131 unsigned ratio;
146 132
147 barlength = get_terminal_width(2) - 49; 133 beg_and_transferred = beg_size + transferred;
148 if (barlength > 0) { 134 ratio = 100 * beg_and_transferred / totalsize;
149 /* god bless gcc for variable arrays :) */ 135 /* can't overflow ^^^^^^^^^^^^^^^ */
150 char buf[barlength + 1]; 136 fprintf(stderr, "%3u%% ", ratio);
151 unsigned stars = (unsigned)barlength * beg_and_transferred / totalsize; 137
152 memset(buf, ' ', barlength); 138 barlength = get_terminal_width(2) - 48;
153 buf[barlength] = '\0'; 139 /*
154 memset(buf, '*', stars); 140 * Must reject barlength <= 0 (terminal too narrow). While at it,
155 fprintf(stderr, " |%s|", buf); 141 * also reject: 1-char bar (useless), 2-char bar (ridiculous).
142 */
143 if (barlength > 2) {
144 if (barlength > 999)
145 barlength = 999;
146 {
147 /* god bless gcc for variable arrays :) */
148 char buf[barlength + 1];
149 unsigned stars = (unsigned)barlength * beg_and_transferred / totalsize;
150 /* can't overflow ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
151 memset(buf, ' ', barlength);
152 buf[barlength] = '\0';
153 memset(buf, '*', stars);
154 fprintf(stderr, "|%s| ", buf);
155 }
156 } 156 }
157 } 157 }
158 158
159 while (beg_and_transferred >= 100000) { 159 fputs(numbuf5, stderr); /* "NNNNk" */
160 beg_and_transferred >>= 10;
161 kiloscale++;
162 }
163 /* see http://en.wikipedia.org/wiki/Tera */
164 fprintf(stderr, "%6u%c", (unsigned)beg_and_transferred, " kMGTPEZY"[kiloscale]);
165#define beg_and_transferred dont_use_beg_and_transferred_below()
166 160
167 since_last_update = elapsed - p->last_change_sec; 161 since_last_update = elapsed - p->last_change_sec;
168 if ((unsigned)transferred != p->last_size) { 162 if ((unsigned)transferred != p->last_size) {
@@ -184,16 +178,18 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p,
184 fprintf(stderr, " --:--:-- ETA"); 178 fprintf(stderr, " --:--:-- ETA");
185 } else { 179 } else {
186 unsigned eta, secs, hours; 180 unsigned eta, secs, hours;
181 unsigned bytes;
187 182
188 totalsize -= beg_size; /* now it's "total to upload" */ 183 bytes = totalsize - beg_size;
189 184
190 /* Estimated remaining time = 185 /* Estimated remaining time =
191 * estimated_sec_to_dl_totalsize_bytes - elapsed_sec = 186 * estimated_sec_to_dl_bytes - elapsed_sec =
192 * totalsize / average_bytes_sec_so_far - elapsed = 187 * bytes / average_bytes_sec_so_far - elapsed =
193 * totalsize / (transferred/elapsed) - elapsed = 188 * bytes / (transferred/elapsed) - elapsed =
194 * totalsize * elapsed / transferred - elapsed 189 * bytes * elapsed / transferred - elapsed
195 */ 190 */
196 eta = totalsize * elapsed / transferred - elapsed; 191 eta = (unsigned long)bytes * elapsed / transferred - elapsed;
192 /* if 32bit, can overflow ^^^^^^^^^^, but this would only show bad ETA */
197 if (eta >= 1000*60*60) 193 if (eta >= 1000*60*60)
198 eta = 1000*60*60 - 1; 194 eta = 1000*60*60 - 1;
199 secs = eta % 3600; 195 secs = eta % 3600;
diff --git a/loginutils/addgroup.c b/loginutils/addgroup.c
index ec11b30ca..6839eafbd 100644
--- a/loginutils/addgroup.c
+++ b/loginutils/addgroup.c
@@ -142,7 +142,9 @@ static const char addgroup_longopts[] ALIGN1 =
142int addgroup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 142int addgroup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
143int addgroup_main(int argc UNUSED_PARAM, char **argv) 143int addgroup_main(int argc UNUSED_PARAM, char **argv)
144{ 144{
145#if ENABLE_FEATURE_ADDUSER_TO_GROUP
145 unsigned opts; 146 unsigned opts;
147#endif
146 const char *gid = "0"; 148 const char *gid = "0";
147 149
148 /* need to be root */ 150 /* need to be root */
@@ -154,7 +156,10 @@ int addgroup_main(int argc UNUSED_PARAM, char **argv)
154 * addgroup --gid num group 156 * addgroup --gid num group
155 * addgroup user group 157 * addgroup user group
156 * Check for min, max and missing args */ 158 * Check for min, max and missing args */
157 opts = getopt32long(argv, "^" "g:S" "\0" "-1:?2", addgroup_longopts, 159#if ENABLE_FEATURE_ADDUSER_TO_GROUP
160 opts =
161#endif
162 getopt32long(argv, "^" "g:S" "\0" "-1:?2", addgroup_longopts,
158 &gid 163 &gid
159 ); 164 );
160 /* move past the commandline options */ 165 /* move past the commandline options */
diff --git a/mailutils/popmaildir.c b/mailutils/popmaildir.c
index 5756eaa76..a4aad3662 100644
--- a/mailutils/popmaildir.c
+++ b/mailutils/popmaildir.c
@@ -45,8 +45,8 @@
45//usage: "\n -k Keep retrieved messages on the server" 45//usage: "\n -k Keep retrieved messages on the server"
46//usage: "\n -t SEC Network timeout" 46//usage: "\n -t SEC Network timeout"
47//usage: IF_FEATURE_POPMAILDIR_DELIVERY( 47//usage: IF_FEATURE_POPMAILDIR_DELIVERY(
48//usage: "\n -F \"PROG ARGS\" Filter program (may be repeated)" 48//usage: "\n -F 'PROG ARGS' Filter program (may be repeated)"
49//usage: "\n -M \"PROG ARGS\" Delivery program" 49//usage: "\n -M 'PROG ARGS' Delivery program"
50//usage: ) 50//usage: )
51//usage: "\n" 51//usage: "\n"
52//usage: "\nFetch from plain POP3 server:" 52//usage: "\nFetch from plain POP3 server:"
diff --git a/make_single_applets.sh b/make_single_applets.sh
index 329a27d32..aa1ace265 100755
--- a/make_single_applets.sh
+++ b/make_single_applets.sh
@@ -12,8 +12,9 @@ makeopts="-j9"
12test -f include/applets.h || { echo "No include/applets.h file"; exit 1; } 12test -f include/applets.h || { echo "No include/applets.h file"; exit 1; }
13apps="` 13apps="`
14grep ^IF_ include/applets.h \ 14grep ^IF_ include/applets.h \
15| grep -v ^IF_FEATURE_ \ 15| grep -v '^IF_FEATURE_' \
16| sed 's/IF_\([A-Z0-9._-]*\)(.*/\1/' \ 16| sed 's/IF_\([A-Z0-9._-]*\)(.*/\1/' \
17| grep -v '^BUSYBOX$' \
17| sort | uniq 18| sort | uniq
18`" 19`"
19 20
diff --git a/miscutils/flash_eraseall.c b/miscutils/flash_eraseall.c
index fab21291c..8e93060ca 100644
--- a/miscutils/flash_eraseall.c
+++ b/miscutils/flash_eraseall.c
@@ -101,7 +101,7 @@ int flash_eraseall_main(int argc UNUSED_PARAM, char **argv)
101 if (flags & OPTION_J) { 101 if (flags & OPTION_J) {
102 uint32_t *crc32_table; 102 uint32_t *crc32_table;
103 103
104 crc32_table = crc32_filltable(NULL, 0); 104 crc32_table = crc32_new_table_le();
105 105
106 cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); 106 cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
107 cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); 107 cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
diff --git a/miscutils/hexedit.c b/miscutils/hexedit.c
index bafb834b5..95c930d12 100644
--- a/miscutils/hexedit.c
+++ b/miscutils/hexedit.c
@@ -4,7 +4,7 @@
4 * Licensed under GPLv2, see file LICENSE in this source tree. 4 * Licensed under GPLv2, see file LICENSE in this source tree.
5 */ 5 */
6//config:config HEXEDIT 6//config:config HEXEDIT
7//config: bool "hexedit" 7//config: bool "hexedit (20 kb)"
8//config: default y 8//config: default y
9//config: help 9//config: help
10//config: Edit file in hexadecimal. 10//config: Edit file in hexadecimal.
diff --git a/miscutils/less.c b/miscutils/less.c
index 4ab0e17da..41e4989ad 100644
--- a/miscutils/less.c
+++ b/miscutils/less.c
@@ -99,6 +99,22 @@
99//config: bool "Enable -N (dynamic switching of line numbers)" 99//config: bool "Enable -N (dynamic switching of line numbers)"
100//config: default y 100//config: default y
101//config: depends on FEATURE_LESS_DASHCMD 101//config: depends on FEATURE_LESS_DASHCMD
102//config:
103//config:config FEATURE_LESS_RAW
104//config: bool "Enable -R ('raw control characters')"
105//config: default y
106//config: depends on FEATURE_LESS_DASHCMD
107//config: help
108//config: This is essential for less applet to work with tools that use colors
109//config: and paging, such as git, systemd tools or nmcli.
110//config:
111//config:config FEATURE_LESS_ENV
112//config: bool "Take options from $LESS environment variable"
113//config: default y
114//config: depends on FEATURE_LESS_DASHCMD
115//config: help
116//config: This is essential for less applet to work with tools that use colors
117//config: and paging, such as git, systemd tools or nmcli.
102 118
103//applet:IF_LESS(APPLET(less, BB_DIR_USR_BIN, BB_SUID_DROP)) 119//applet:IF_LESS(APPLET(less, BB_DIR_USR_BIN, BB_SUID_DROP))
104 120
@@ -106,7 +122,7 @@
106 122
107//usage:#define less_trivial_usage 123//usage:#define less_trivial_usage
108//usage: "[-E" IF_FEATURE_LESS_REGEXP("I")IF_FEATURE_LESS_FLAGS("Mm") 124//usage: "[-E" IF_FEATURE_LESS_REGEXP("I")IF_FEATURE_LESS_FLAGS("Mm")
109//usage: "N" IF_FEATURE_LESS_TRUNCATE("S") "h~] [FILE]..." 125//usage: "N" IF_FEATURE_LESS_TRUNCATE("S") IF_FEATURE_LESS_RAW("R") "h~] [FILE]..."
110//usage:#define less_full_usage "\n\n" 126//usage:#define less_full_usage "\n\n"
111//usage: "View FILE (or stdin) one screenful at a time\n" 127//usage: "View FILE (or stdin) one screenful at a time\n"
112//usage: "\n -E Quit once the end of a file is reached" 128//usage: "\n -E Quit once the end of a file is reached"
@@ -121,6 +137,9 @@
121//usage: IF_FEATURE_LESS_TRUNCATE( 137//usage: IF_FEATURE_LESS_TRUNCATE(
122//usage: "\n -S Truncate long lines" 138//usage: "\n -S Truncate long lines"
123//usage: ) 139//usage: )
140//usage: IF_FEATURE_LESS_RAW(
141//usage: "\n -R Remove color escape codes in input"
142//usage: )
124//usage: "\n -~ Suppress ~s displayed past EOF" 143//usage: "\n -~ Suppress ~s displayed past EOF"
125 144
126#include <sched.h> /* sched_yield() */ 145#include <sched.h> /* sched_yield() */
@@ -161,6 +180,7 @@ enum {
161 FLAG_TILDE = 1 << 4, 180 FLAG_TILDE = 1 << 4,
162 FLAG_I = 1 << 5, 181 FLAG_I = 1 << 5,
163 FLAG_S = (1 << 6) * ENABLE_FEATURE_LESS_TRUNCATE, 182 FLAG_S = (1 << 6) * ENABLE_FEATURE_LESS_TRUNCATE,
183 FLAG_R = (1 << 7) * ENABLE_FEATURE_LESS_RAW,
164/* hijack command line options variable for internal state vars */ 184/* hijack command line options variable for internal state vars */
165 LESS_STATE_MATCH_BACKWARDS = 1 << 15, 185 LESS_STATE_MATCH_BACKWARDS = 1 << 15,
166}; 186};
@@ -211,6 +231,9 @@ struct globals {
211 regex_t pattern; 231 regex_t pattern;
212 smallint pattern_valid; 232 smallint pattern_valid;
213#endif 233#endif
234#if ENABLE_FEATURE_LESS_RAW
235 smallint in_escape;
236#endif
214#if ENABLE_FEATURE_LESS_ASK_TERMINAL 237#if ENABLE_FEATURE_LESS_ASK_TERMINAL
215 smallint winsize_err; 238 smallint winsize_err;
216#endif 239#endif
@@ -259,7 +282,6 @@ struct globals {
259 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ 282 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
260 less_gets_pos = -1; \ 283 less_gets_pos = -1; \
261 empty_line_marker = "~"; \ 284 empty_line_marker = "~"; \
262 num_files = 1; \
263 current_file = 1; \ 285 current_file = 1; \
264 eof_error = 1; \ 286 eof_error = 1; \
265 terminated = 1; \ 287 terminated = 1; \
@@ -518,6 +540,26 @@ static void read_lines(void)
518 *--p = '\0'; 540 *--p = '\0';
519 continue; 541 continue;
520 } 542 }
543#if ENABLE_FEATURE_LESS_RAW
544 if (option_mask32 & FLAG_R) {
545 if (c == '\033')
546 goto discard;
547 if (G.in_escape) {
548 if (isdigit(c)
549 || c == '['
550 || c == ';'
551 || c == 'm'
552 ) {
553 discard:
554 G.in_escape = (c != 'm');
555 readpos++;
556 continue;
557 }
558 /* Hmm, unexpected end of "ESC [ N ; N m" sequence */
559 G.in_escape = 0;
560 }
561 }
562#endif
521 { 563 {
522 size_t new_last_line_pos = last_line_pos + 1; 564 size_t new_last_line_pos = last_line_pos + 1;
523 if (c == '\t') { 565 if (c == '\t') {
@@ -1849,11 +1891,29 @@ int less_main(int argc, char **argv)
1849 * (used by some setups for manpage display) 1891 * (used by some setups for manpage display)
1850 */ 1892 */
1851 getopt32(argv, "EMmN~I" IF_FEATURE_LESS_TRUNCATE("S") /*ignored:*/"s"); 1893 getopt32(argv, "EMmN~I" IF_FEATURE_LESS_TRUNCATE("S") /*ignored:*/"s");
1852 argc -= optind;
1853 argv += optind; 1894 argv += optind;
1854 num_files = argc; 1895 num_files = argc - optind;
1855 files = argv; 1896 files = argv;
1856 1897
1898 /* Tools typically pass LESS="FRSXMK".
1899 * The options we don't understand are ignored. */
1900 if (ENABLE_FEATURE_LESS_ENV) {
1901 char *c = getenv("LESS");
1902 if (c) while (*c) switch (*c++) {
1903 case 'M':
1904 option_mask32 |= FLAG_M;
1905 break;
1906 case 'R':
1907 option_mask32 |= FLAG_R;
1908 break;
1909 case 'S':
1910 option_mask32 |= FLAG_S;
1911 break;
1912 default:
1913 break;
1914 }
1915 }
1916
1857 /* Another popular pager, most, detects when stdout 1917 /* Another popular pager, most, detects when stdout
1858 * is not a tty and turns into cat. This makes sense. */ 1918 * is not a tty and turns into cat. This makes sense. */
1859 if (!isatty(STDOUT_FILENO)) 1919 if (!isatty(STDOUT_FILENO))
diff --git a/miscutils/nandwrite.c b/miscutils/nandwrite.c
index 72f028ed3..29c800612 100644
--- a/miscutils/nandwrite.c
+++ b/miscutils/nandwrite.c
@@ -53,6 +53,15 @@
53#include "libbb.h" 53#include "libbb.h"
54#include <mtd/mtd-user.h> 54#include <mtd/mtd-user.h>
55 55
56/* Old headers call it MTD_MODE_RAW.
57 * FIXME: In kernel headers, MTD_FILE_MODE_RAW is not a define,
58 * it's an enum. How I can test for existence of an enum?
59 */
60#if !defined(MTD_FILE_MODE_RAW)
61# define MTD_FILE_MODE_RAW 3
62#endif
63
64
56#define IS_NANDDUMP (ENABLE_NANDDUMP && (!ENABLE_NANDWRITE || (applet_name[4] == 'd'))) 65#define IS_NANDDUMP (ENABLE_NANDDUMP && (!ENABLE_NANDWRITE || (applet_name[4] == 'd')))
57#define IS_NANDWRITE (ENABLE_NANDWRITE && (!ENABLE_NANDDUMP || (applet_name[4] != 'd'))) 66#define IS_NANDWRITE (ENABLE_NANDWRITE && (!ENABLE_NANDDUMP || (applet_name[4] != 'd')))
58 67
diff --git a/miscutils/setfattr.c b/miscutils/setfattr.c
index f0ef227cb..12eebc56e 100644
--- a/miscutils/setfattr.c
+++ b/miscutils/setfattr.c
@@ -6,7 +6,7 @@
6 * Licensed under GPLv2, see file LICENSE in this source tree. 6 * Licensed under GPLv2, see file LICENSE in this source tree.
7 */ 7 */
8//config:config SETFATTR 8//config:config SETFATTR
9//config: bool "setfattr" 9//config: bool "setfattr (3.6 kb)"
10//config: default y 10//config: default y
11//config: help 11//config: help
12//config: Set/delete extended attributes on files 12//config: Set/delete extended attributes on files
diff --git a/networking/arping.c b/networking/arping.c
index f9967d81e..788fded3c 100644
--- a/networking/arping.c
+++ b/networking/arping.c
@@ -11,7 +11,6 @@
11//config: select PLATFORM_LINUX 11//config: select PLATFORM_LINUX
12//config: help 12//config: help
13//config: Ping hosts by ARP packets. 13//config: Ping hosts by ARP packets.
14//config:
15 14
16//applet:IF_ARPING(APPLET(arping, BB_DIR_USR_SBIN, BB_SUID_DROP)) 15//applet:IF_ARPING(APPLET(arping, BB_DIR_USR_SBIN, BB_SUID_DROP))
17 16
@@ -29,6 +28,7 @@
29//usage: "\n -A ARP answer mode, update your neighbors" 28//usage: "\n -A ARP answer mode, update your neighbors"
30//usage: "\n -c N Stop after sending N ARP requests" 29//usage: "\n -c N Stop after sending N ARP requests"
31//usage: "\n -w TIMEOUT Seconds to wait for ARP reply" 30//usage: "\n -w TIMEOUT Seconds to wait for ARP reply"
31//NB: in iputils-s20160308, iface is mandatory, no default
32//usage: "\n -I IFACE Interface to use (default eth0)" 32//usage: "\n -I IFACE Interface to use (default eth0)"
33//usage: "\n -s SRC_IP Sender IP address" 33//usage: "\n -s SRC_IP Sender IP address"
34//usage: "\n DST_IP Target IP address" 34//usage: "\n DST_IP Target IP address"
@@ -45,21 +45,29 @@
45#define MONOTONIC_US() ((unsigned)monotonic_us()) 45#define MONOTONIC_US() ((unsigned)monotonic_us())
46 46
47enum { 47enum {
48 DAD = 1, 48 UNSOLICITED = 1 << 0,
49 UNSOLICITED = 2, 49 DAD = 1 << 1,
50 ADVERT = 4, 50 ADVERT = 1 << 2,
51 QUIET = 8, 51 QUIET = 1 << 3,
52 QUIT_ON_REPLY = 16, 52 QUIT_ON_REPLY = 1 << 4,
53 BCAST_ONLY = 32, 53 BCAST_ONLY = 1 << 5,
54 UNICASTING = 64 54 UNICASTING = 1 << 6,
55 TIMEOUT = 1 << 7,
55}; 56};
57#define GETOPT32(str_timeout, device, source) \
58 getopt32(argv, "^" \
59 "UDAqfbc:+w:I:s:" \
60 /* DAD also sets quit_on_reply, */ \
61 /* advert also sets unsolicited: */ \
62 "\0" "=1:Df:AU", \
63 &count, &str_timeout, &device, &source \
64 );
56 65
57struct globals { 66struct globals {
58 struct in_addr src; 67 struct in_addr src;
59 struct in_addr dst; 68 struct in_addr dst;
60 struct sockaddr_ll me; 69 struct sockaddr_ll me;
61 struct sockaddr_ll he; 70 struct sockaddr_ll he;
62 int sock_fd;
63 71
64 int count; // = -1; 72 int count; // = -1;
65 unsigned last; 73 unsigned last;
@@ -71,13 +79,17 @@ struct globals {
71 unsigned received; 79 unsigned received;
72 unsigned brd_recv; 80 unsigned brd_recv;
73 unsigned req_recv; 81 unsigned req_recv;
82
83 /* should be in main(), but are here to reduce stack use: */
84 struct ifreq ifr;
85 struct sockaddr_in probe_saddr;
86 sigset_t sset;
87 unsigned char packet[4096];
74} FIX_ALIASING; 88} FIX_ALIASING;
75#define G (*(struct globals*)bb_common_bufsiz1)
76#define src (G.src ) 89#define src (G.src )
77#define dst (G.dst ) 90#define dst (G.dst )
78#define me (G.me ) 91#define me (G.me )
79#define he (G.he ) 92#define he (G.he )
80#define sock_fd (G.sock_fd )
81#define count (G.count ) 93#define count (G.count )
82#define last (G.last ) 94#define last (G.last )
83#define timeout_us (G.timeout_us) 95#define timeout_us (G.timeout_us)
@@ -87,26 +99,25 @@ struct globals {
87#define received (G.received ) 99#define received (G.received )
88#define brd_recv (G.brd_recv ) 100#define brd_recv (G.brd_recv )
89#define req_recv (G.req_recv ) 101#define req_recv (G.req_recv )
102//#define G (*(struct globals*)bb_common_bufsiz1)
103#define G (*ptr_to_globals)
90#define INIT_G() do { \ 104#define INIT_G() do { \
91 setup_common_bufsiz(); \ 105 /*setup_common_bufsiz();*/ \
106 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
92 count = -1; \ 107 count = -1; \
93} while (0) 108} while (0)
94 109
95// If GNUisms are not available... 110#define sock_fd 3
96//static void *mempcpy(void *_dst, const void *_src, int n)
97//{
98// memcpy(_dst, _src, n);
99// return (char*)_dst + n;
100//}
101 111
102static int send_pack(struct in_addr *src_addr, 112static int send_pack(struct in_addr *src_addr,
103 struct in_addr *dst_addr, struct sockaddr_ll *ME, 113 struct in_addr *dst_addr,
114 struct sockaddr_ll *ME,
104 struct sockaddr_ll *HE) 115 struct sockaddr_ll *HE)
105{ 116{
106 int err; 117 int err;
107 unsigned char buf[256]; 118 unsigned char buf[256];
108 struct arphdr *ah = (struct arphdr *) buf; 119 struct arphdr *ah = (struct arphdr *) buf;
109 unsigned char *p = (unsigned char *) (ah + 1); 120 unsigned char *p;
110 121
111 ah->ar_hrd = htons(ARPHRD_ETHER); 122 ah->ar_hrd = htons(ARPHRD_ETHER);
112 ah->ar_pro = htons(ETH_P_IP); 123 ah->ar_pro = htons(ETH_P_IP);
@@ -114,6 +125,7 @@ static int send_pack(struct in_addr *src_addr,
114 ah->ar_pln = 4; 125 ah->ar_pln = 4;
115 ah->ar_op = option_mask32 & ADVERT ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST); 126 ah->ar_op = option_mask32 & ADVERT ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST);
116 127
128 p = (unsigned char *) (ah + 1);
117 p = mempcpy(p, &ME->sll_addr, ah->ar_hln); 129 p = mempcpy(p, &ME->sll_addr, ah->ar_hln);
118 p = mempcpy(p, src_addr, 4); 130 p = mempcpy(p, src_addr, 4);
119 131
@@ -139,10 +151,10 @@ static void finish(void)
139{ 151{
140 if (!(option_mask32 & QUIET)) { 152 if (!(option_mask32 & QUIET)) {
141 printf("Sent %u probe(s) (%u broadcast(s))\n" 153 printf("Sent %u probe(s) (%u broadcast(s))\n"
142 "Received %u repl%s" 154 "Received %u response(s)"
143 " (%u request(s), %u broadcast(s))\n", 155 " (%u request(s), %u broadcast(s))\n",
144 sent, brd_sent, 156 sent, brd_sent,
145 received, (received == 1) ? "ies" : "y", 157 received,
146 req_recv, brd_recv); 158 req_recv, brd_recv);
147 } 159 }
148 if (option_mask32 & DAD) 160 if (option_mask32 & DAD)
@@ -180,15 +192,10 @@ static void recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
180 struct arphdr *ah = (struct arphdr *) buf; 192 struct arphdr *ah = (struct arphdr *) buf;
181 unsigned char *p = (unsigned char *) (ah + 1); 193 unsigned char *p = (unsigned char *) (ah + 1);
182 struct in_addr src_ip, dst_ip; 194 struct in_addr src_ip, dst_ip;
195
183 /* moves below assume in_addr is 4 bytes big, ensure that */ 196 /* moves below assume in_addr is 4 bytes big, ensure that */
184 struct BUG_in_addr_must_be_4 { 197 BUILD_BUG_ON(sizeof(struct in_addr) != 4);
185 char BUG_in_addr_must_be_4[ 198 BUILD_BUG_ON(sizeof(src_ip.s_addr) != 4);
186 sizeof(struct in_addr) == 4 ? 1 : -1
187 ];
188 char BUG_s_addr_must_be_4[
189 sizeof(src_ip.s_addr) == 4 ? 1 : -1
190 ];
191 };
192 199
193 /* Filter out wild packets */ 200 /* Filter out wild packets */
194 if (FROM->sll_pkttype != PACKET_HOST 201 if (FROM->sll_pkttype != PACKET_HOST
@@ -209,8 +216,10 @@ static void recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
209 if (ah->ar_pro != htons(ETH_P_IP) 216 if (ah->ar_pro != htons(ETH_P_IP)
210 || (ah->ar_pln != 4) 217 || (ah->ar_pln != 4)
211 || (ah->ar_hln != me.sll_halen) 218 || (ah->ar_hln != me.sll_halen)
212 || (len < (int)(sizeof(*ah) + 2 * (4 + ah->ar_hln)))) 219 || (len < (int)(sizeof(*ah) + 2 * (4 + ah->ar_hln)))
220 ) {
213 return; 221 return;
222 }
214 223
215 move_from_unaligned32(src_ip.s_addr, p + ah->ar_hln); 224 move_from_unaligned32(src_ip.s_addr, p + ah->ar_hln);
216 move_from_unaligned32(dst_ip.s_addr, p + ah->ar_hln + 4 + ah->ar_hln); 225 move_from_unaligned32(dst_ip.s_addr, p + ah->ar_hln + 4 + ah->ar_hln);
@@ -242,6 +251,7 @@ static void recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
242 if (!(option_mask32 & QUIET)) { 251 if (!(option_mask32 & QUIET)) {
243 int s_printed = 0; 252 int s_printed = 0;
244 253
254//TODO: arping from iputils-s20160308 print upprcase hex in MAC, follow them?
245 printf("%scast re%s from %s [%02x:%02x:%02x:%02x:%02x:%02x]", 255 printf("%scast re%s from %s [%02x:%02x:%02x:%02x:%02x:%02x]",
246 FROM->sll_pkttype == PACKET_HOST ? "Uni" : "Broad", 256 FROM->sll_pkttype == PACKET_HOST ? "Uni" : "Broad",
247 ah->ar_op == htons(ARPOP_REPLY) ? "ply" : "quest", 257 ah->ar_op == htons(ARPOP_REPLY) ? "ply" : "quest",
@@ -249,14 +259,14 @@ static void recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
249 p[0], p[1], p[2], p[3], p[4], p[5] 259 p[0], p[1], p[2], p[3], p[4], p[5]
250 ); 260 );
251 if (dst_ip.s_addr != src.s_addr) { 261 if (dst_ip.s_addr != src.s_addr) {
252 printf("for %s ", inet_ntoa(dst_ip)); 262 printf("for %s", inet_ntoa(dst_ip));
253 s_printed = 1; 263 s_printed = 1;
254 } 264 }
255 if (memcmp(p + ah->ar_hln + 4, me.sll_addr, ah->ar_hln)) { 265 if (memcmp(p + ah->ar_hln + 4, me.sll_addr, ah->ar_hln)) {
256 unsigned char *pp = p + ah->ar_hln + 4; 266 unsigned char *pp = p + ah->ar_hln + 4;
257 if (!s_printed) 267 if (!s_printed)
258 printf("for "); 268 printf(" for");
259 printf("[%02x:%02x:%02x:%02x:%02x:%02x]", 269 printf(" [%02x:%02x:%02x:%02x:%02x:%02x]",
260 pp[0], pp[1], pp[2], pp[3], pp[4], pp[5] 270 pp[0], pp[1], pp[2], pp[3], pp[4], pp[5]
261 ); 271 );
262 } 272 }
@@ -288,12 +298,11 @@ int arping_main(int argc UNUSED_PARAM, char **argv)
288 const char *device = "eth0"; 298 const char *device = "eth0";
289 char *source = NULL; 299 char *source = NULL;
290 char *target; 300 char *target;
291 unsigned char *packet;
292 char *err_str; 301 char *err_str;
293 302
294 INIT_G(); 303 INIT_G();
295 304
296 sock_fd = xsocket(AF_PACKET, SOCK_DGRAM, 0); 305 xmove_fd(xsocket(AF_PACKET, SOCK_DGRAM, 0), sock_fd);
297 306
298 // If you ever change BB_SUID_DROP to BB_SUID_REQUIRE, 307 // If you ever change BB_SUID_DROP to BB_SUID_REQUIRE,
299 // drop suid root privileges here: 308 // drop suid root privileges here:
@@ -303,41 +312,30 @@ int arping_main(int argc UNUSED_PARAM, char **argv)
303 unsigned opt; 312 unsigned opt;
304 char *str_timeout; 313 char *str_timeout;
305 314
306 /* Dad also sets quit_on_reply. 315 opt = GETOPT32(str_timeout, device, source);
307 * Advert also sets unsolicited. 316 if (opt & TIMEOUT)
308 */
309 opt = getopt32(argv, "^" "DUAqfbc:+w:I:s:" "\0" "=1:Df:AU",
310 &count, &str_timeout, &device, &source
311 );
312 if (opt & 0x80) /* -w: timeout */
313 timeout_us = xatou_range(str_timeout, 0, INT_MAX/2000000) * 1000000 + 500000; 317 timeout_us = xatou_range(str_timeout, 0, INT_MAX/2000000) * 1000000 + 500000;
314 //if (opt & 0x200) /* -s: source */
315 option_mask32 &= 0x3f; /* set respective flags */
316 } 318 }
317 319
318 target = argv[optind]; 320 target = argv[optind];
319 err_str = xasprintf("interface %s %%s", device); 321 err_str = xasprintf("interface %s %%s", device);
320 xfunc_error_retval = 2; 322 xfunc_error_retval = 2;
321 323
322 { 324 /*memset(&G.ifr, 0, sizeof(G.ifr)); - zeroed by INIT_G */
323 struct ifreq ifr; 325 strncpy_IFNAMSIZ(G.ifr.ifr_name, device);
324 326 ioctl_or_perror_and_die(sock_fd, SIOCGIFINDEX, &G.ifr, err_str, "not found");
325 memset(&ifr, 0, sizeof(ifr)); 327 me.sll_ifindex = G.ifr.ifr_ifindex;
326 strncpy_IFNAMSIZ(ifr.ifr_name, device);
327 /* We use ifr.ifr_name in error msg so that problem
328 * with truncated name will be visible */
329 ioctl_or_perror_and_die(sock_fd, SIOCGIFINDEX, &ifr, err_str, "not found");
330 me.sll_ifindex = ifr.ifr_ifindex;
331 328
332 xioctl(sock_fd, SIOCGIFFLAGS, (char *) &ifr); 329 xioctl(sock_fd, SIOCGIFFLAGS, (char *) &G.ifr);
333 330
334 if (!(ifr.ifr_flags & IFF_UP)) { 331 if (!(G.ifr.ifr_flags & IFF_UP)) {
335 bb_error_msg_and_die(err_str, "is down"); 332 bb_error_msg_and_die(err_str, "is down");
336 } 333 }
337 if (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) { 334 if (G.ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) {
338 bb_error_msg(err_str, "is not ARPable"); 335 bb_error_msg(err_str, "is not ARPable");
339 return (option_mask32 & DAD ? 0 : 2); 336 BUILD_BUG_ON(DAD != 2);
340 } 337 /* exit 0 if DAD, else exit 2 */
338 return (~option_mask32 & DAD);
341 } 339 }
342 340
343 /* if (!inet_aton(target, &dst)) - not needed */ { 341 /* if (!inet_aton(target, &dst)) - not needed */ {
@@ -356,33 +354,29 @@ int arping_main(int argc UNUSED_PARAM, char **argv)
356 src = dst; 354 src = dst;
357 355
358 if (!(option_mask32 & DAD) || src.s_addr) { 356 if (!(option_mask32 & DAD) || src.s_addr) {
359 struct sockaddr_in saddr; 357 /*struct sockaddr_in probe_saddr;*/
360 int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0); 358 int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0);
361 359
362 setsockopt_bindtodevice(probe_fd, device); 360 setsockopt_bindtodevice(probe_fd, device);
363 memset(&saddr, 0, sizeof(saddr)); 361
364 saddr.sin_family = AF_INET; 362 /*memset(&G.probe_saddr, 0, sizeof(G.probe_saddr)); - zeroed by INIT_G */
363 G.probe_saddr.sin_family = AF_INET;
365 if (src.s_addr) { 364 if (src.s_addr) {
366 /* Check that this is indeed our IP */ 365 /* Check that this is indeed our IP */
367 saddr.sin_addr = src; 366 G.probe_saddr.sin_addr = src;
368 xbind(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); 367 xbind(probe_fd, (struct sockaddr *) &G.probe_saddr, sizeof(G.probe_saddr));
369 } else { /* !(option_mask32 & DAD) case */ 368 } else { /* !(option_mask32 & DAD) case */
370 /* Find IP address on this iface */ 369 /* Find IP address on this iface */
371 socklen_t alen = sizeof(saddr); 370 G.probe_saddr.sin_port = htons(1025);
372 371 G.probe_saddr.sin_addr = dst;
373 saddr.sin_port = htons(1025);
374 saddr.sin_addr = dst;
375 372
376 if (setsockopt_SOL_SOCKET_1(probe_fd, SO_DONTROUTE) != 0) 373 if (setsockopt_SOL_SOCKET_1(probe_fd, SO_DONTROUTE) != 0)
377 bb_perror_msg("setsockopt(%s)", "SO_DONTROUTE"); 374 bb_perror_msg("setsockopt(%s)", "SO_DONTROUTE");
378 xconnect(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); 375 xconnect(probe_fd, (struct sockaddr *) &G.probe_saddr, sizeof(G.probe_saddr));
379 getsockname(probe_fd, (struct sockaddr *) &saddr, &alen); 376 bb_getsockname(probe_fd, (struct sockaddr *) &G.probe_saddr, sizeof(G.probe_saddr));
380 //never happens: 377 if (G.probe_saddr.sin_family != AF_INET)
381 //if (getsockname(probe_fd, (struct sockaddr *) &saddr, &alen) == -1)
382 // bb_perror_msg_and_die("getsockname");
383 if (saddr.sin_family != AF_INET)
384 bb_error_msg_and_die("no IP address configured"); 378 bb_error_msg_and_die("no IP address configured");
385 src = saddr.sin_addr; 379 src = G.probe_saddr.sin_addr;
386 } 380 }
387 close(probe_fd); 381 close(probe_fd);
388 } 382 }
@@ -392,48 +386,53 @@ int arping_main(int argc UNUSED_PARAM, char **argv)
392 me.sll_protocol = htons(ETH_P_ARP); 386 me.sll_protocol = htons(ETH_P_ARP);
393 xbind(sock_fd, (struct sockaddr *) &me, sizeof(me)); 387 xbind(sock_fd, (struct sockaddr *) &me, sizeof(me));
394 388
395 { 389 bb_getsockname(sock_fd, (struct sockaddr *) &me, sizeof(me));
396 socklen_t alen = sizeof(me); 390 //never happens:
397 getsockname(sock_fd, (struct sockaddr *) &me, &alen); 391 //if (getsockname(sock_fd, (struct sockaddr *) &me, &alen) == -1)
398 //never happens: 392 // bb_perror_msg_and_die("getsockname");
399 //if (getsockname(sock_fd, (struct sockaddr *) &me, &alen) == -1)
400 // bb_perror_msg_and_die("getsockname");
401 }
402 if (me.sll_halen == 0) { 393 if (me.sll_halen == 0) {
403 bb_error_msg(err_str, "is not ARPable (no ll address)"); 394 bb_error_msg(err_str, "is not ARPable (no ll address)");
404 return (option_mask32 & DAD ? 0 : 2); 395 BUILD_BUG_ON(DAD != 2);
396 /* exit 0 if DAD, else exit 2 */
397 return (~option_mask32 & DAD);
405 } 398 }
406 he = me; 399 he = me;
407 memset(he.sll_addr, -1, he.sll_halen); 400 memset(he.sll_addr, -1, he.sll_halen);
408 401
409 if (!(option_mask32 & QUIET)) { 402 if (!(option_mask32 & QUIET)) {
410 /* inet_ntoa uses static storage, can't use in same printf */ 403 /* inet_ntoa uses static storage, can't use in same printf */
411 printf("ARPING to %s", inet_ntoa(dst)); 404 printf("ARPING %s", inet_ntoa(dst));
412 printf(" from %s via %s\n", inet_ntoa(src), device); 405 printf(" from %s %s\n", inet_ntoa(src), device);
413 } 406 }
414 407
408 /*sigemptyset(&G.sset); - zeroed by INIT_G */
409 sigaddset(&G.sset, SIGALRM);
410 sigaddset(&G.sset, SIGINT);
415 signal_SA_RESTART_empty_mask(SIGINT, (void (*)(int))finish); 411 signal_SA_RESTART_empty_mask(SIGINT, (void (*)(int))finish);
416 signal_SA_RESTART_empty_mask(SIGALRM, (void (*)(int))catcher); 412 signal_SA_RESTART_empty_mask(SIGALRM, (void (*)(int))catcher);
417 413
414 /* Send the first packet, arm ALRM */
418 catcher(); 415 catcher();
419 416
420 packet = xmalloc(4096);
421 while (1) { 417 while (1) {
422 sigset_t sset, osset;
423 struct sockaddr_ll from; 418 struct sockaddr_ll from;
424 socklen_t alen = sizeof(from); 419 socklen_t alen = sizeof(from);
425 int cc; 420 int cc;
426 421
427 cc = recvfrom(sock_fd, packet, 4096, 0, (struct sockaddr *) &from, &alen); 422 /* Unblock SIGALRM so that the previously called alarm()
423 * can prevent recvfrom from blocking forever in case the
424 * inherited procmask is blocking SIGALRM.
425 */
426 sigprocmask(SIG_UNBLOCK, &G.sset, NULL);
427
428 cc = recvfrom(sock_fd, G.packet, sizeof(G.packet), 0, (struct sockaddr *) &from, &alen);
429
430 /* Don't allow SIGALRMs while we process the reply */
431 sigprocmask(SIG_BLOCK, &G.sset, NULL);
428 if (cc < 0) { 432 if (cc < 0) {
429 bb_perror_msg("recvfrom"); 433 bb_perror_msg("recvfrom");
430 continue; 434 continue;
431 } 435 }
432 sigemptyset(&sset); 436 recv_pack(G.packet, cc, &from);
433 sigaddset(&sset, SIGALRM);
434 sigaddset(&sset, SIGINT);
435 sigprocmask(SIG_BLOCK, &sset, &osset);
436 recv_pack(packet, cc, &from);
437 sigprocmask(SIG_SETMASK, &osset, NULL);
438 } 437 }
439} 438}
diff --git a/networking/ftpd.c b/networking/ftpd.c
index 8af5acac2..8abbf7f57 100644
--- a/networking/ftpd.c
+++ b/networking/ftpd.c
@@ -171,9 +171,13 @@ struct globals {
171 char msg_ok [(sizeof("NNN " MSG_OK ) + 3) & 0xfffc]; 171 char msg_ok [(sizeof("NNN " MSG_OK ) + 3) & 0xfffc];
172 char msg_err[(sizeof("NNN " MSG_ERR) + 3) & 0xfffc]; 172 char msg_err[(sizeof("NNN " MSG_ERR) + 3) & 0xfffc];
173} FIX_ALIASING; 173} FIX_ALIASING;
174#define G (*(struct globals*)bb_common_bufsiz1) 174#define G (*ptr_to_globals)
175/* ^^^ about 75 bytes smaller code than this: */
176//#define G (*(struct globals*)bb_common_bufsiz1)
175#define INIT_G() do { \ 177#define INIT_G() do { \
176 setup_common_bufsiz(); \ 178 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
179 /*setup_common_bufsiz();*/ \
180 \
177 /* Moved to main */ \ 181 /* Moved to main */ \
178 /*strcpy(G.msg_ok + 4, MSG_OK );*/ \ 182 /*strcpy(G.msg_ok + 4, MSG_OK );*/ \
179 /*strcpy(G.msg_err + 4, MSG_ERR);*/ \ 183 /*strcpy(G.msg_err + 4, MSG_ERR);*/ \
@@ -258,7 +262,7 @@ cmdio_write(uint32_t status_str, const char *str)
258static void 262static void
259cmdio_write_ok(unsigned status) 263cmdio_write_ok(unsigned status)
260{ 264{
261 *(uint32_t *) G.msg_ok = status; 265 *(bb__aliased_uint32_t *) G.msg_ok = status;
262 xwrite(STDOUT_FILENO, G.msg_ok, sizeof("NNN " MSG_OK) - 1); 266 xwrite(STDOUT_FILENO, G.msg_ok, sizeof("NNN " MSG_OK) - 1);
263 if (G.verbose > 1) 267 if (G.verbose > 1)
264 verbose_log(G.msg_ok); 268 verbose_log(G.msg_ok);
@@ -269,7 +273,7 @@ cmdio_write_ok(unsigned status)
269static void 273static void
270cmdio_write_error(unsigned status) 274cmdio_write_error(unsigned status)
271{ 275{
272 *(uint32_t *) G.msg_err = status; 276 *(bb__aliased_uint32_t *) G.msg_err = status;
273 xwrite(STDOUT_FILENO, G.msg_err, sizeof("NNN " MSG_ERR) - 1); 277 xwrite(STDOUT_FILENO, G.msg_err, sizeof("NNN " MSG_ERR) - 1);
274 if (G.verbose > 0) 278 if (G.verbose > 0)
275 verbose_log(G.msg_err); 279 verbose_log(G.msg_err);
@@ -599,7 +603,7 @@ static void
599handle_rest(void) 603handle_rest(void)
600{ 604{
601 /* When ftp_arg == NULL simply restart from beginning */ 605 /* When ftp_arg == NULL simply restart from beginning */
602 G.restart_pos = G.ftp_arg ? xatoi_positive(G.ftp_arg) : 0; 606 G.restart_pos = G.ftp_arg ? XATOOFF(G.ftp_arg) : 0;
603 WRITE_OK(FTP_RESTOK); 607 WRITE_OK(FTP_RESTOK);
604} 608}
605 609
diff --git a/networking/ftpgetput.c b/networking/ftpgetput.c
index 029587aa2..ffc4cd5f1 100644
--- a/networking/ftpgetput.c
+++ b/networking/ftpgetput.c
@@ -158,46 +158,16 @@ static void ftp_login(void)
158 158
159static int xconnect_ftpdata(void) 159static int xconnect_ftpdata(void)
160{ 160{
161 char *buf_ptr; 161 int port_num;
162 unsigned port_num;
163 162
164/* 163 if (ENABLE_FEATURE_IPV6 && ftpcmd("EPSV", NULL) == 229) {
165TODO: PASV command will not work for IPv6. RFC2428 describes 164 /* good */
166IPv6-capable "extended PASV" - EPSV. 165 } else if (ftpcmd("PASV", NULL) != 227) {
167
168"EPSV [protocol]" asks server to bind to and listen on a data port
169in specified protocol. Protocol is 1 for IPv4, 2 for IPv6.
170If not specified, defaults to "same as used for control connection".
171If server understood you, it should answer "229 <some text>(|||port|)"
172where "|" are literal pipe chars and "port" is ASCII decimal port#.
173
174There is also an IPv6-capable replacement for PORT (EPRT),
175but we don't need that.
176
177NB: PASV may still work for some servers even over IPv6.
178For example, vsftp happily answers
179"227 Entering Passive Mode (0,0,0,0,n,n)" and proceeds as usual.
180
181TODO2: need to stop ignoring IP address in PASV response.
182*/
183
184 if (ftpcmd("PASV", NULL) != 227) {
185 ftp_die("PASV"); 166 ftp_die("PASV");
186 } 167 }
187 168 port_num = parse_pasv_epsv(buf);
188 /* Response is "NNN garbageN1,N2,N3,N4,P1,P2[)garbage] 169 if (port_num < 0)
189 * Server's IP is N1.N2.N3.N4 (we ignore it) 170 ftp_die("PASV");
190 * Server's port for data connection is P1*256+P2 */
191 buf_ptr = strrchr(buf, ')');
192 if (buf_ptr) *buf_ptr = '\0';
193
194 buf_ptr = strrchr(buf, ',');
195 *buf_ptr = '\0';
196 port_num = xatoul_range(buf_ptr + 1, 0, 255);
197
198 buf_ptr = strrchr(buf, ',');
199 *buf_ptr = '\0';
200 port_num += xatoul_range(buf_ptr + 1, 0, 255) * 256;
201 171
202 set_nport(&lsa->u.sa, htons(port_num)); 172 set_nport(&lsa->u.sa, htons(port_num));
203 return xconnect_stream(lsa); 173 return xconnect_stream(lsa);
diff --git a/networking/inetd.c b/networking/inetd.c
index 4dfa0089a..6843845fb 100644
--- a/networking/inetd.c
+++ b/networking/inetd.c
@@ -497,10 +497,9 @@ static void register_rpc(servtab_t *sep)
497{ 497{
498 int n; 498 int n;
499 struct sockaddr_in ir_sin; 499 struct sockaddr_in ir_sin;
500 socklen_t size;
501 500
502 size = sizeof(ir_sin); 501 if (bb_getsockname(sep->se_fd, (struct sockaddr *) &ir_sin, sizeof(ir_sin)) < 0) {
503 if (getsockname(sep->se_fd, (struct sockaddr *) &ir_sin, &size) < 0) { 502//TODO: verify that such failure is even possible in Linux kernel
504 bb_perror_msg("getsockname"); 503 bb_perror_msg("getsockname");
505 return; 504 return;
506 } 505 }
diff --git a/networking/libiproute/Kbuild.src b/networking/libiproute/Kbuild.src
index 056a58540..d94e4c6e5 100644
--- a/networking/libiproute/Kbuild.src
+++ b/networking/libiproute/Kbuild.src
@@ -12,6 +12,12 @@ INSERT
12lib-$(CONFIG_SLATTACH) += \ 12lib-$(CONFIG_SLATTACH) += \
13 utils.o 13 utils.o
14 14
15lib-$(CONFIG_TC) += \
16 libnetlink.o \
17 ll_map.o \
18 ll_proto.o \
19 utils.o
20
15lib-$(CONFIG_IP) += \ 21lib-$(CONFIG_IP) += \
16 ip_parse_common_args.o \ 22 ip_parse_common_args.o \
17 libnetlink.o \ 23 libnetlink.o \
diff --git a/networking/libiproute/ipaddress.c b/networking/libiproute/ipaddress.c
index 921ecf0d9..d7f888176 100644
--- a/networking/libiproute/ipaddress.c
+++ b/networking/libiproute/ipaddress.c
@@ -113,7 +113,7 @@ static NOINLINE int print_linkinfo(const struct nlmsghdr *n)
113 if (G_filter.up && !(ifi->ifi_flags & IFF_UP)) 113 if (G_filter.up && !(ifi->ifi_flags & IFF_UP))
114 return 0; 114 return 0;
115 115
116 memset(tb, 0, sizeof(tb)); 116 //memset(tb, 0, sizeof(tb)); - parse_rtattr does this
117 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); 117 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
118 if (tb[IFLA_IFNAME] == NULL) { 118 if (tb[IFLA_IFNAME] == NULL) {
119 bb_error_msg("nil ifname"); 119 bb_error_msg("nil ifname");
@@ -227,7 +227,7 @@ static int FAST_FUNC print_addrinfo(const struct sockaddr_nl *who UNUSED_PARAM,
227 if (G_filter.flushb && n->nlmsg_type != RTM_NEWADDR) 227 if (G_filter.flushb && n->nlmsg_type != RTM_NEWADDR)
228 return 0; 228 return 0;
229 229
230 memset(rta_tb, 0, sizeof(rta_tb)); 230 //memset(rta_tb, 0, sizeof(rta_tb)); - parse_rtattr does this
231 parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa))); 231 parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
232 232
233 if (!rta_tb[IFA_LOCAL]) 233 if (!rta_tb[IFA_LOCAL])
@@ -535,7 +535,7 @@ int FAST_FUNC ipaddr_list_or_flush(char **argv, int flush)
535 continue; 535 continue;
536 if (G_filter.pfx.family || G_filter.label) { 536 if (G_filter.pfx.family || G_filter.label) {
537 struct rtattr *tb[IFA_MAX+1]; 537 struct rtattr *tb[IFA_MAX+1];
538 memset(tb, 0, sizeof(tb)); 538 //memset(tb, 0, sizeof(tb)); - parse_rtattr does this
539 parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(n)); 539 parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(n));
540 if (!tb[IFA_LOCAL]) 540 if (!tb[IFA_LOCAL])
541 tb[IFA_LOCAL] = tb[IFA_ADDRESS]; 541 tb[IFA_LOCAL] = tb[IFA_ADDRESS];
diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c
index aef5f6490..f38fba055 100644
--- a/networking/libiproute/iplink.c
+++ b/networking/libiproute/iplink.c
@@ -132,7 +132,6 @@ static int get_address(char *dev, int *htype)
132{ 132{
133 struct ifreq ifr; 133 struct ifreq ifr;
134 struct sockaddr_ll me; 134 struct sockaddr_ll me;
135 socklen_t alen;
136 int s; 135 int s;
137 136
138 s = xsocket(PF_PACKET, SOCK_DGRAM, 0); 137 s = xsocket(PF_PACKET, SOCK_DGRAM, 0);
@@ -146,8 +145,7 @@ static int get_address(char *dev, int *htype)
146 me.sll_ifindex = ifr.ifr_ifindex; 145 me.sll_ifindex = ifr.ifr_ifindex;
147 me.sll_protocol = htons(ETH_P_LOOP); 146 me.sll_protocol = htons(ETH_P_LOOP);
148 xbind(s, (struct sockaddr*)&me, sizeof(me)); 147 xbind(s, (struct sockaddr*)&me, sizeof(me));
149 alen = sizeof(me); 148 bb_getsockname(s, (struct sockaddr*)&me, sizeof(me));
150 getsockname(s, (struct sockaddr*)&me, &alen);
151 //never happens: 149 //never happens:
152 //if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) 150 //if (getsockname(s, (struct sockaddr*)&me, &alen) == -1)
153 // bb_perror_msg_and_die("getsockname"); 151 // bb_perror_msg_and_die("getsockname");
diff --git a/networking/libiproute/ipneigh.c b/networking/libiproute/ipneigh.c
index 1cd90d707..f572414e9 100644
--- a/networking/libiproute/ipneigh.c
+++ b/networking/libiproute/ipneigh.c
@@ -110,11 +110,13 @@ static int FAST_FUNC print_neigh(const struct sockaddr_nl *who UNUSED_PARAM,
110 return 0; 110 return 0;
111 if (G_filter.index && G_filter.index != r->ndm_ifindex) 111 if (G_filter.index && G_filter.index != r->ndm_ifindex)
112 return 0; 112 return 0;
113 if (!(G_filter.state&r->ndm_state) && 113 if (!(G_filter.state&r->ndm_state)
114 !(r->ndm_flags & NTF_PROXY) && 114 && !(r->ndm_flags & NTF_PROXY)
115 (r->ndm_state || !(G_filter.state & 0x100)) && 115 && (r->ndm_state || !(G_filter.state & 0x100))
116 (r->ndm_family != AF_DECnet)) 116 && (r->ndm_family != AF_DECnet)
117 ) {
117 return 0; 118 return 0;
119 }
118 120
119 parse_rtattr(tb, NDA_MAX, NDA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); 121 parse_rtattr(tb, NDA_MAX, NDA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
120 122
diff --git a/networking/libiproute/iproute.c b/networking/libiproute/iproute.c
index 95dafe183..2a8610ea6 100644
--- a/networking/libiproute/iproute.c
+++ b/networking/libiproute/iproute.c
@@ -83,7 +83,7 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
83 if (len < 0) 83 if (len < 0)
84 bb_error_msg_and_die("wrong nlmsg len %d", len); 84 bb_error_msg_and_die("wrong nlmsg len %d", len);
85 85
86 memset(tb, 0, sizeof(tb)); 86 //memset(tb, 0, sizeof(tb)); - parse_rtattr does this
87 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); 87 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
88 88
89#if HAVE_RTA_TABLE 89#if HAVE_RTA_TABLE
@@ -1081,7 +1081,7 @@ static int iproute_get(char **argv)
1081 bb_error_msg_and_die("wrong len %d", len); 1081 bb_error_msg_and_die("wrong len %d", len);
1082 } 1082 }
1083 1083
1084 memset(tb, 0, sizeof(tb)); 1084 //memset(tb, 0, sizeof(tb)); - parse_rtattr does this
1085 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); 1085 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
1086 1086
1087 if (tb[RTA_PREFSRC]) { 1087 if (tb[RTA_PREFSRC]) {
diff --git a/networking/libiproute/iprule.c b/networking/libiproute/iprule.c
index 53b11e16c..0ce0dfeef 100644
--- a/networking/libiproute/iprule.c
+++ b/networking/libiproute/iprule.c
@@ -63,7 +63,7 @@ static int FAST_FUNC print_rule(const struct sockaddr_nl *who UNUSED_PARAM,
63 if (len < 0) 63 if (len < 0)
64 return -1; 64 return -1;
65 65
66 memset(tb, 0, sizeof(tb)); 66 //memset(tb, 0, sizeof(tb)); - parse_rtattr does this
67 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); 67 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
68 68
69 if (r->rtm_family == AF_INET) 69 if (r->rtm_family == AF_INET)
diff --git a/networking/libiproute/libnetlink.c b/networking/libiproute/libnetlink.c
index 3f0f70326..40955fcae 100644
--- a/networking/libiproute/libnetlink.c
+++ b/networking/libiproute/libnetlink.c
@@ -15,16 +15,13 @@
15 15
16void FAST_FUNC xrtnl_open(struct rtnl_handle *rth/*, unsigned subscriptions*/) 16void FAST_FUNC xrtnl_open(struct rtnl_handle *rth/*, unsigned subscriptions*/)
17{ 17{
18 socklen_t addr_len;
19
20 memset(rth, 0, sizeof(*rth)); 18 memset(rth, 0, sizeof(*rth));
21 rth->fd = xsocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 19 rth->fd = xsocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
22 rth->local.nl_family = AF_NETLINK; 20 rth->local.nl_family = AF_NETLINK;
23 /*rth->local.nl_groups = subscriptions;*/ 21 /*rth->local.nl_groups = subscriptions;*/
24 22
25 xbind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)); 23 xbind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local));
26 addr_len = sizeof(rth->local); 24 bb_getsockname(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local));
27 getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len);
28 25
29/* too much paranoia 26/* too much paranoia
30 if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) 27 if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0)
@@ -401,6 +398,8 @@ int FAST_FUNC rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data
401 398
402void FAST_FUNC parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) 399void FAST_FUNC parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
403{ 400{
401 memset(tb, 0, (max + 1) * sizeof(tb[0]));
402
404 while (RTA_OK(rta, len)) { 403 while (RTA_OK(rta, len)) {
405 if (rta->rta_type <= max) { 404 if (rta->rta_type <= max) {
406 tb[rta->rta_type] = rta; 405 tb[rta->rta_type] = rta;
diff --git a/networking/libiproute/ll_map.c b/networking/libiproute/ll_map.c
index be88a04e8..66401da77 100644
--- a/networking/libiproute/ll_map.c
+++ b/networking/libiproute/ll_map.c
@@ -51,7 +51,7 @@ int FAST_FUNC ll_remember_index(const struct sockaddr_nl *who UNUSED_PARAM,
51 if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi))) 51 if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi)))
52 return -1; 52 return -1;
53 53
54 memset(tb, 0, sizeof(tb)); 54 //memset(tb, 0, sizeof(tb)); - parse_rtattr does this
55 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n)); 55 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n));
56 if (tb[IFLA_IFNAME] == NULL) 56 if (tb[IFLA_IFNAME] == NULL)
57 return 0; 57 return 0;
diff --git a/networking/ntpd.c b/networking/ntpd.c
index 0b60d003b..17e5c7da6 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -2362,7 +2362,9 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv)
2362 2362
2363 /* Nothing between here and poll() blocks for any significant time */ 2363 /* Nothing between here and poll() blocks for any significant time */
2364 2364
2365 nextaction = G.cur_time + 3600; 2365 nextaction = G.last_script_run + (11*60);
2366 if (nextaction < G.cur_time + 1)
2367 nextaction = G.cur_time + 1;
2366 2368
2367 i = 0; 2369 i = 0;
2368#if ENABLE_FEATURE_NTPD_SERVER 2370#if ENABLE_FEATURE_NTPD_SERVER
diff --git a/networking/parse_pasv_epsv.c b/networking/parse_pasv_epsv.c
new file mode 100644
index 000000000..14f4d4258
--- /dev/null
+++ b/networking/parse_pasv_epsv.c
@@ -0,0 +1,66 @@
1/*
2 * Utility routines.
3 *
4 * Copyright (C) 2018 Denys Vlasenko
5 *
6 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
7 */
8//kbuild:lib-$(CONFIG_FTPGET) += parse_pasv_epsv.o
9//kbuild:lib-$(CONFIG_FTPPUT) += parse_pasv_epsv.o
10//kbuild:lib-$(CONFIG_WGET) += parse_pasv_epsv.o
11
12#include "libbb.h"
13
14int FAST_FUNC parse_pasv_epsv(char *buf)
15{
16/*
17 * PASV command will not work for IPv6. RFC2428 describes
18 * IPv6-capable "extended PASV" - EPSV.
19 *
20 * "EPSV [protocol]" asks server to bind to and listen on a data port
21 * in specified protocol. Protocol is 1 for IPv4, 2 for IPv6.
22 * If not specified, defaults to "same as used for control connection".
23 * If server understood you, it should answer "229 <some text>(|||port|)"
24 * where "|" are literal pipe chars and "port" is ASCII decimal port#.
25 *
26 * There is also an IPv6-capable replacement for PORT (EPRT),
27 * but we don't need that.
28 *
29 * NB: PASV may still work for some servers even over IPv6.
30 * For example, vsftp happily answers
31 * "227 Entering Passive Mode (0,0,0,0,n,n)" and proceeds as usual.
32 */
33 char *ptr;
34 int port;
35
36 if (!ENABLE_FEATURE_IPV6 || buf[2] == '7' /* "227" */) {
37 /* Response is "227 garbageN1,N2,N3,N4,P1,P2[)garbage]"
38 * Server's IP is N1.N2.N3.N4 (we ignore it)
39 * Server's port for data connection is P1*256+P2 */
40 ptr = strrchr(buf, ')');
41 if (ptr) *ptr = '\0';
42
43 ptr = strrchr(buf, ',');
44 if (!ptr) return -1;
45 *ptr = '\0';
46 port = xatou_range(ptr + 1, 0, 255);
47
48 ptr = strrchr(buf, ',');
49 if (!ptr) return -1;
50 *ptr = '\0';
51 port += xatou_range(ptr + 1, 0, 255) * 256;
52 } else {
53 /* Response is "229 garbage(|||P1|)"
54 * Server's port for data connection is P1 */
55 ptr = strrchr(buf, '|');
56 if (!ptr) return -1;
57 *ptr = '\0';
58
59 ptr = strrchr(buf, '|');
60 if (!ptr) return -1;
61 *ptr = '\0';
62 port = xatou_range(ptr + 1, 0, 65535);
63 }
64
65 return port;
66}
diff --git a/networking/ssl_client.c b/networking/ssl_client.c
index d479846d7..eb84e7726 100644
--- a/networking/ssl_client.c
+++ b/networking/ssl_client.c
@@ -15,7 +15,7 @@
15//kbuild:lib-$(CONFIG_SSL_CLIENT) += ssl_client.o 15//kbuild:lib-$(CONFIG_SSL_CLIENT) += ssl_client.o
16 16
17//usage:#define ssl_client_trivial_usage 17//usage:#define ssl_client_trivial_usage
18//usage: "-s FD [-r FD] [-n SNI]" 18//usage: "[-e] -s FD [-r FD] [-n SNI]"
19//usage:#define ssl_client_full_usage "" 19//usage:#define ssl_client_full_usage ""
20 20
21#include "libbb.h" 21#include "libbb.h"
@@ -30,26 +30,28 @@ int ssl_client_main(int argc UNUSED_PARAM, char **argv)
30 // INIT_G(); 30 // INIT_G();
31 31
32 tls = new_tls_state(); 32 tls = new_tls_state();
33 opt = getopt32(argv, "s:#r:#n:", &tls->ofd, &tls->ifd, &sni); 33 opt = getopt32(argv, "es:#r:#n:", &tls->ofd, &tls->ifd, &sni);
34 if (!(opt & 2)) { 34 if (!(opt & (1<<2))) {
35 /* -r N defaults to -s N */ 35 /* -r N defaults to -s N */
36 tls->ifd = tls->ofd; 36 tls->ifd = tls->ofd;
37 } 37 }
38 38
39 if (!(opt & 3)) { 39 if (!(opt & (3<<1))) {
40 if (!argv[1]) 40 if (!argv[1])
41 bb_show_usage(); 41 bb_show_usage();
42 /* Undocumented debug feature: without -s and -r, takes HOST arg and connects to it */ 42 /* Undocumented debug feature: without -s and -r, takes HOST arg and connects to it */
43 // 43 //
44 // Talk to kernel.org: 44 // Talk to kernel.org:
45 // printf "GET / HTTP/1.1\r\nHost: kernel.org\r\n\r\n" | ./busybox ssl_client kernel.org 45 // printf "GET / HTTP/1.1\r\nHost: kernel.org\r\n\r\n" | busybox ssl_client kernel.org
46 if (!sni) 46 if (!sni)
47 sni = argv[1]; 47 sni = argv[1];
48 tls->ifd = tls->ofd = create_and_connect_stream_or_die(argv[1], 443); 48 tls->ifd = tls->ofd = create_and_connect_stream_or_die(argv[1], 443);
49 } 49 }
50 50
51 tls_handshake(tls, sni); 51 tls_handshake(tls, sni);
52 tls_run_copy_loop(tls); 52
53 BUILD_BUG_ON(TLSLOOP_EXIT_ON_LOCAL_EOF != 1);
54 tls_run_copy_loop(tls, /*flags*/ opt & 1);
53 55
54 return EXIT_SUCCESS; 56 return EXIT_SUCCESS;
55} 57}
diff --git a/networking/tc.c b/networking/tc.c
index 23abf636c..4fa3e47bf 100644
--- a/networking/tc.c
+++ b/networking/tc.c
@@ -6,22 +6,20 @@
6 * 6 *
7 * Bernhard Reutner-Fischer adjusted for busybox 7 * Bernhard Reutner-Fischer adjusted for busybox
8 */ 8 */
9//config:config TC
10//config: bool "tc (3.1 kb)"
11//config: default y
12//config: help
13//config: Show / manipulate traffic control settings
14//config:
15//config:config FEATURE_TC_INGRESS
16//config: bool "Enable ingress"
17//config: default y
18//config: depends on TC
9 19
10/* Was disabled in 2008 by Bernhard, not known why. 20//applet:IF_TC(APPLET(tc, BB_DIR_SBIN, BB_SUID_DROP))
11--//config:#config TC 21
12--//config:# bool "tc" 22//kbuild:lib-$(CONFIG_TC) += tc.o
13--//config:# default y
14--//config:# help
15--//config:# Show / manipulate traffic control settings
16--//config:#
17--//config:#config FEATURE_TC_INGRESS
18--//config:# default y
19--//config:# depends on TC
20--
21--//applet:IF_TC(APPLET(tc, BB_DIR_SBIN, BB_SUID_DROP))
22--
23--//kbuild:lib-$(CONFIG_TC) += tc.o
24*/
25 23
26//usage:#define tc_trivial_usage 24//usage:#define tc_trivial_usage
27/* //usage: "[OPTIONS] OBJECT CMD [dev STRING]" */ 25/* //usage: "[OPTIONS] OBJECT CMD [dev STRING]" */
@@ -52,22 +50,37 @@
52#include "libiproute/rt_names.h" 50#include "libiproute/rt_names.h"
53#include <linux/pkt_sched.h> /* for the TC_H_* macros */ 51#include <linux/pkt_sched.h> /* for the TC_H_* macros */
54 52
53/* This is the deprecated multiqueue interface */
54#ifndef TCA_PRIO_MAX
55enum
56{
57 TCA_PRIO_UNSPEC,
58 TCA_PRIO_MQ,
59 __TCA_PRIO_MAX
60};
61#define TCA_PRIO_MAX (__TCA_PRIO_MAX - 1)
62#endif
63
55#define parse_rtattr_nested(tb, max, rta) \ 64#define parse_rtattr_nested(tb, max, rta) \
56 (parse_rtattr((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta))) 65 (parse_rtattr((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta)))
57 66
58/* nullifies tb on error */ 67/* nullifies tb on error */
59#define __parse_rtattr_nested_compat(tb, max, rta, len) \ 68#define __parse_rtattr_nested_compat(tb, max, rta, len) \
60 ({if ((RTA_PAYLOAD(rta) >= len) && \ 69({ \
61 (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr))) { \ 70 if ((RTA_PAYLOAD(rta) >= len) \
62 rta = RTA_DATA(rta) + RTA_ALIGN(len); \ 71 && (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) \
63 parse_rtattr_nested(tb, max, rta); \ 72 ) { \
64 } else \ 73 rta = RTA_DATA(rta) + RTA_ALIGN(len); \
65 memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); \ 74 parse_rtattr_nested(tb, max, rta); \
66 }) 75 } else \
76 memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); \
77})
67 78
68#define parse_rtattr_nested_compat(tb, max, rta, data, len) \ 79#define parse_rtattr_nested_compat(tb, max, rta, data, len) \
69 ({data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL; \ 80({ \
70 __parse_rtattr_nested_compat(tb, max, rta, len); }) 81 data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL; \
82 __parse_rtattr_nested_compat(tb, max, rta, len); \
83})
71 84
72#define show_details (0) /* not implemented. Does anyone need it? */ 85#define show_details (0) /* not implemented. Does anyone need it? */
73#define use_iec (0) /* not currently documented in the upstream manpage */ 86#define use_iec (0) /* not currently documented in the upstream manpage */
@@ -184,11 +197,13 @@ static void print_rate(char *buf, int len, uint32_t rate)
184 } 197 }
185} 198}
186 199
200#if 0
187/* This is "pfifo_fast". */ 201/* This is "pfifo_fast". */
188static int prio_parse_opt(int argc, char **argv, struct nlmsghdr *n) 202static int prio_parse_opt(int argc, char **argv, struct nlmsghdr *n)
189{ 203{
190 return 0; 204 return 0;
191} 205}
206#endif
192static int prio_print_opt(struct rtattr *opt) 207static int prio_print_opt(struct rtattr *opt)
193{ 208{
194 int i; 209 int i;
@@ -211,11 +226,13 @@ static int prio_print_opt(struct rtattr *opt)
211 return 0; 226 return 0;
212} 227}
213 228
229#if 0
214/* Class Based Queue */ 230/* Class Based Queue */
215static int cbq_parse_opt(int argc, char **argv, struct nlmsghdr *n) 231static int cbq_parse_opt(int argc, char **argv, struct nlmsghdr *n)
216{ 232{
217 return 0; 233 return 0;
218} 234}
235#endif
219static int cbq_print_opt(struct rtattr *opt) 236static int cbq_print_opt(struct rtattr *opt)
220{ 237{
221 struct rtattr *tb[TCA_CBQ_MAX+1]; 238 struct rtattr *tb[TCA_CBQ_MAX+1];
@@ -308,8 +325,10 @@ static int cbq_print_opt(struct rtattr *opt)
308 return 0; 325 return 0;
309} 326}
310 327
311static int print_qdisc(const struct sockaddr_nl *who UNUSED_PARAM, 328static FAST_FUNC int print_qdisc(
312 struct nlmsghdr *hdr, void *arg UNUSED_PARAM) 329 const struct sockaddr_nl *who UNUSED_PARAM,
330 struct nlmsghdr *hdr,
331 void *arg UNUSED_PARAM)
313{ 332{
314 struct tcmsg *msg = NLMSG_DATA(hdr); 333 struct tcmsg *msg = NLMSG_DATA(hdr);
315 int len = hdr->nlmsg_len; 334 int len = hdr->nlmsg_len;
@@ -364,8 +383,10 @@ static int print_qdisc(const struct sockaddr_nl *who UNUSED_PARAM,
364 return 0; 383 return 0;
365} 384}
366 385
367static int print_class(const struct sockaddr_nl *who UNUSED_PARAM, 386static FAST_FUNC int print_class(
368 struct nlmsghdr *hdr, void *arg UNUSED_PARAM) 387 const struct sockaddr_nl *who UNUSED_PARAM,
388 struct nlmsghdr *hdr,
389 void *arg UNUSED_PARAM)
369{ 390{
370 struct tcmsg *msg = NLMSG_DATA(hdr); 391 struct tcmsg *msg = NLMSG_DATA(hdr);
371 int len = hdr->nlmsg_len; 392 int len = hdr->nlmsg_len;
@@ -432,8 +453,10 @@ static int print_class(const struct sockaddr_nl *who UNUSED_PARAM,
432 return 0; 453 return 0;
433} 454}
434 455
435static int print_filter(const struct sockaddr_nl *who UNUSED_PARAM, 456static FAST_FUNC int print_filter(
436 struct nlmsghdr *hdr, void *arg UNUSED_PARAM) 457 const struct sockaddr_nl *who UNUSED_PARAM,
458 struct nlmsghdr *hdr UNUSED_PARAM,
459 void *arg UNUSED_PARAM)
437{ 460{
438 return 0; 461 return 0;
439} 462}
@@ -451,6 +474,12 @@ int tc_main(int argc UNUSED_PARAM, char **argv)
451 "replace\0" 474 "replace\0"
452 "show\0""list\0" 475 "show\0""list\0"
453 ; 476 ;
477 enum {
478 CMD_add = 0, CMD_del, CMD_change,
479 CMD_link,
480 CMD_replace,
481 CMD_show
482 };
454 static const char args[] ALIGN1 = 483 static const char args[] ALIGN1 =
455 "dev\0" /* qdisc, class, filter */ 484 "dev\0" /* qdisc, class, filter */
456 "root\0" /* class, filter */ 485 "root\0" /* class, filter */
@@ -460,9 +489,15 @@ int tc_main(int argc UNUSED_PARAM, char **argv)
460 "classid\0" /* change: for class use "handle" */ 489 "classid\0" /* change: for class use "handle" */
461 "preference\0""priority\0""protocol\0" /* filter */ 490 "preference\0""priority\0""protocol\0" /* filter */
462 ; 491 ;
463 enum { CMD_add = 0, CMD_del, CMD_change, CMD_link, CMD_replace, CMD_show }; 492 enum {
464 enum { ARG_dev = 0, ARG_root, ARG_parent, ARG_qdisc, 493 ARG_dev = 0,
465 ARG_handle, ARG_classid, ARG_pref, ARG_prio, ARG_proto}; 494 ARG_root,
495 ARG_parent,
496 ARG_qdisc,
497 ARG_handle,
498 ARG_classid,
499 ARG_pref, ARG_prio, ARG_proto
500 };
466 struct rtnl_handle rth; 501 struct rtnl_handle rth;
467 struct tcmsg msg; 502 struct tcmsg msg;
468 int ret, obj, cmd, arg; 503 int ret, obj, cmd, arg;
@@ -487,9 +522,12 @@ int tc_main(int argc UNUSED_PARAM, char **argv)
487 invarg_1_to_2(*argv, argv[-1]); 522 invarg_1_to_2(*argv, argv[-1]);
488 argv++; 523 argv++;
489 } 524 }
525
490 memset(&msg, 0, sizeof(msg)); 526 memset(&msg, 0, sizeof(msg));
491 msg.tcm_family = AF_UNSPEC; 527 if (AF_UNSPEC != 0)
528 msg.tcm_family = AF_UNSPEC;
492 ll_init_map(&rth); 529 ll_init_map(&rth);
530
493 while (*argv) { 531 while (*argv) {
494 arg = index_in_substrings(args, *argv); 532 arg = index_in_substrings(args, *argv);
495 if (arg == ARG_dev) { 533 if (arg == ARG_dev) {
@@ -526,7 +564,8 @@ int tc_main(int argc UNUSED_PARAM, char **argv)
526 msg.tcm_parent = TC_H_ROOT; 564 msg.tcm_parent = TC_H_ROOT;
527 if (obj == OBJ_filter) 565 if (obj == OBJ_filter)
528 filter_parent = TC_H_ROOT; 566 filter_parent = TC_H_ROOT;
529 } else if (arg == ARG_parent) { 567 } else
568 if (arg == ARG_parent) {
530 uint32_t handle; 569 uint32_t handle;
531 if (msg.tcm_parent) 570 if (msg.tcm_parent)
532 duparg(*argv, "parent"); 571 duparg(*argv, "parent");
@@ -535,23 +574,31 @@ int tc_main(int argc UNUSED_PARAM, char **argv)
535 msg.tcm_parent = handle; 574 msg.tcm_parent = handle;
536 if (obj == OBJ_filter) 575 if (obj == OBJ_filter)
537 filter_parent = handle; 576 filter_parent = handle;
538 } else if (arg == ARG_handle) { /* filter::list */ 577 } else
578 if (arg == ARG_handle) { /* filter::list */
539 if (msg.tcm_handle) 579 if (msg.tcm_handle)
540 duparg(*argv, "handle"); 580 duparg(*argv, "handle");
541 /* reject LONG_MIN || LONG_MAX */ 581 /* reject LONG_MIN || LONG_MAX */
542 /* TODO: for fw 582 /* TODO: for fw
543 slash = strchr(handle, '/'); 583 slash = strchr(handle, '/');
544 if (slash != NULL) 584 if (slash != NULL)
545 *slash = '\0'; 585 *slash = '\0';
546 */ 586 */
547 msg.tcm_handle = get_u32(*argv, "handle"); 587 msg.tcm_handle = get_u32(*argv, "handle");
548 /* if (slash) {if (get_u32(uint32_t &mask, slash+1, NULL)) inv mask; addattr32(n, MAX_MSG, TCA_FW_MASK, mask); */ 588 /* if (slash) {if (get_u32(uint32_t &mask, slash+1, NULL)) inv mask; addattr32(n, MAX_MSG, TCA_FW_MASK, mask); */
549 } else if (arg == ARG_classid && obj == OBJ_class && cmd == CMD_change){ 589 } else
550 } else if (arg == ARG_pref || arg == ARG_prio) { /* filter::list */ 590 if (arg == ARG_classid
591 && obj == OBJ_class
592 && cmd == CMD_change
593 ) {
594 /* TODO */
595 } else
596 if (arg == ARG_pref || arg == ARG_prio) { /* filter::list */
551 if (filter_prio) 597 if (filter_prio)
552 duparg(*argv, "priority"); 598 duparg(*argv, "priority");
553 filter_prio = get_u32(*argv, "priority"); 599 filter_prio = get_u32(*argv, "priority");
554 } else if (arg == ARG_proto) { /* filter::list */ 600 } else
601 if (arg == ARG_proto) { /* filter::list */
555 uint16_t tmp; 602 uint16_t tmp;
556 if (filter_proto) 603 if (filter_proto)
557 duparg(*argv, "protocol"); 604 duparg(*argv, "protocol");
@@ -560,6 +607,7 @@ int tc_main(int argc UNUSED_PARAM, char **argv)
560 filter_proto = tmp; 607 filter_proto = tmp;
561 } 608 }
562 } 609 }
610
563 if (cmd >= CMD_show) { /* show or list */ 611 if (cmd >= CMD_show) { /* show or list */
564 if (obj == OBJ_filter) 612 if (obj == OBJ_filter)
565 msg.tcm_info = TC_H_MAKE(filter_prio<<16, filter_proto); 613 msg.tcm_info = TC_H_MAKE(filter_prio<<16, filter_proto);
diff --git a/networking/tftp.c b/networking/tftp.c
index 73a9829aa..4cd39186a 100644
--- a/networking/tftp.c
+++ b/networking/tftp.c
@@ -208,7 +208,7 @@ struct globals {
208#define G_error_pkt_reason (G.error_pkt[3]) 208#define G_error_pkt_reason (G.error_pkt[3])
209#define G_error_pkt_str ((char*)(G.error_pkt + 4)) 209#define G_error_pkt_str ((char*)(G.error_pkt + 4))
210 210
211#if ENABLE_FEATURE_TFTP_PROGRESS_BAR 211#if ENABLE_FEATURE_TFTP_PROGRESS_BAR && ENABLE_FEATURE_TFTP_BLOCKSIZE
212static void tftp_progress_update(void) 212static void tftp_progress_update(void)
213{ 213{
214 bb_progress_update(&G.pmt, 0, G.pos, G.size); 214 bb_progress_update(&G.pmt, 0, G.pos, G.size);
@@ -227,6 +227,7 @@ static void tftp_progress_done(void)
227 } 227 }
228} 228}
229#else 229#else
230# define tftp_progress_update() ((void)0)
230# define tftp_progress_init() ((void)0) 231# define tftp_progress_init() ((void)0)
231# define tftp_progress_done() ((void)0) 232# define tftp_progress_done() ((void)0)
232#endif 233#endif
diff --git a/networking/tls.c b/networking/tls.c
index fd3cb0dba..da7b6058f 100644
--- a/networking/tls.c
+++ b/networking/tls.c
@@ -84,23 +84,23 @@
84# define dbg_der(...) ((void)0) 84# define dbg_der(...) ((void)0)
85#endif 85#endif
86 86
87#define RECORD_TYPE_CHANGE_CIPHER_SPEC 20 87#define RECORD_TYPE_CHANGE_CIPHER_SPEC 20 /* 0x14 */
88#define RECORD_TYPE_ALERT 21 88#define RECORD_TYPE_ALERT 21 /* 0x15 */
89#define RECORD_TYPE_HANDSHAKE 22 89#define RECORD_TYPE_HANDSHAKE 22 /* 0x16 */
90#define RECORD_TYPE_APPLICATION_DATA 23 90#define RECORD_TYPE_APPLICATION_DATA 23 /* 0x17 */
91 91
92#define HANDSHAKE_HELLO_REQUEST 0 92#define HANDSHAKE_HELLO_REQUEST 0 /* 0x00 */
93#define HANDSHAKE_CLIENT_HELLO 1 93#define HANDSHAKE_CLIENT_HELLO 1 /* 0x01 */
94#define HANDSHAKE_SERVER_HELLO 2 94#define HANDSHAKE_SERVER_HELLO 2 /* 0x02 */
95#define HANDSHAKE_HELLO_VERIFY_REQUEST 3 95#define HANDSHAKE_HELLO_VERIFY_REQUEST 3 /* 0x03 */
96#define HANDSHAKE_NEW_SESSION_TICKET 4 96#define HANDSHAKE_NEW_SESSION_TICKET 4 /* 0x04 */
97#define HANDSHAKE_CERTIFICATE 11 97#define HANDSHAKE_CERTIFICATE 11 /* 0x0b */
98#define HANDSHAKE_SERVER_KEY_EXCHANGE 12 98#define HANDSHAKE_SERVER_KEY_EXCHANGE 12 /* 0x0c */
99#define HANDSHAKE_CERTIFICATE_REQUEST 13 99#define HANDSHAKE_CERTIFICATE_REQUEST 13 /* 0x0d */
100#define HANDSHAKE_SERVER_HELLO_DONE 14 100#define HANDSHAKE_SERVER_HELLO_DONE 14 /* 0x0e */
101#define HANDSHAKE_CERTIFICATE_VERIFY 15 101#define HANDSHAKE_CERTIFICATE_VERIFY 15 /* 0x0f */
102#define HANDSHAKE_CLIENT_KEY_EXCHANGE 16 102#define HANDSHAKE_CLIENT_KEY_EXCHANGE 16 /* 0x10 */
103#define HANDSHAKE_FINISHED 20 103#define HANDSHAKE_FINISHED 20 /* 0x14 */
104 104
105#define SSL_NULL_WITH_NULL_NULL 0x0000 105#define SSL_NULL_WITH_NULL_NULL 0x0000
106#define SSL_RSA_WITH_NULL_MD5 0x0001 106#define SSL_RSA_WITH_NULL_MD5 0x0001
@@ -512,10 +512,12 @@ static void bad_record_die(tls_state_t *tls, const char *expected, int len)
512 bb_error_msg("got bad TLS record (len:%d) while expecting %s", len, expected); 512 bb_error_msg("got bad TLS record (len:%d) while expecting %s", len, expected);
513 if (len > 0) { 513 if (len > 0) {
514 uint8_t *p = tls->inbuf; 514 uint8_t *p = tls->inbuf;
515 while (len > 0) { 515 if (len > 99)
516 len = 99; /* don't flood, a few lines should be enough */
517 do {
516 fprintf(stderr, " %02x", *p++); 518 fprintf(stderr, " %02x", *p++);
517 len--; 519 len--;
518 } 520 } while (len != 0);
519 fputc('\n', stderr); 521 fputc('\n', stderr);
520 } 522 }
521 xfunc_die(); 523 xfunc_die();
@@ -671,9 +673,11 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type)
671 // AES_128_CBC Block 16 16 16 673 // AES_128_CBC Block 16 16 16
672 // AES_256_CBC Block 32 16 16 674 // AES_256_CBC Block 32 16 16
673 675
674 /* Fill IV and padding in outbuf */
675 tls_get_random(buf - AES_BLOCKSIZE, AES_BLOCKSIZE); /* IV */ 676 tls_get_random(buf - AES_BLOCKSIZE, AES_BLOCKSIZE); /* IV */
676 dbg("before crypt: 5 hdr + %u data + %u hash bytes\n", size, tls->MAC_size); 677 dbg("before crypt: 5 hdr + %u data + %u hash bytes\n",
678 size - tls->MAC_size, tls->MAC_size);
679
680 /* Fill IV and padding in outbuf */
677 // RFC is talking nonsense: 681 // RFC is talking nonsense:
678 // "Padding that is added to force the length of the plaintext to be 682 // "Padding that is added to force the length of the plaintext to be
679 // an integral multiple of the block cipher's block length." 683 // an integral multiple of the block cipher's block length."
@@ -773,7 +777,7 @@ static const char *alert_text(int code)
773 return itoa(code); 777 return itoa(code);
774} 778}
775 779
776static int tls_xread_record(tls_state_t *tls) 780static int tls_xread_record(tls_state_t *tls, const char *expected)
777{ 781{
778 struct record_hdr *xhdr; 782 struct record_hdr *xhdr;
779 int sz; 783 int sz;
@@ -796,13 +800,16 @@ static int tls_xread_record(tls_state_t *tls)
796 if (total >= RECHDR_LEN && target == MAX_INBUF) { 800 if (total >= RECHDR_LEN && target == MAX_INBUF) {
797 xhdr = (void*)tls->inbuf; 801 xhdr = (void*)tls->inbuf;
798 target = RECHDR_LEN + (0x100 * xhdr->len16_hi + xhdr->len16_lo); 802 target = RECHDR_LEN + (0x100 * xhdr->len16_hi + xhdr->len16_lo);
799 if (target > MAX_INBUF) { 803
800 /* malformed input (too long): yell and die */ 804 if (target > MAX_INBUF /* malformed input (too long) */
801 tls->buffered_size = 0; 805 || xhdr->proto_maj != TLS_MAJ
802 tls->ofs_to_buffered = total; 806 || xhdr->proto_min != TLS_MIN
803 tls_error_die(tls); 807 ) {
808 sz = total < target ? total : target;
809 if (sz > 24)
810 sz = 24; /* don't flood */
811 bad_record_die(tls, expected, sz);
804 } 812 }
805 /* can also check type/proto_maj/proto_min here */
806 dbg("xhdr type:%d ver:%d.%d len:%d\n", 813 dbg("xhdr type:%d ver:%d.%d len:%d\n",
807 xhdr->type, xhdr->proto_maj, xhdr->proto_min, 814 xhdr->type, xhdr->proto_maj, xhdr->proto_min,
808 0x100 * xhdr->len16_hi + xhdr->len16_lo 815 0x100 * xhdr->len16_hi + xhdr->len16_lo
@@ -1137,13 +1144,11 @@ static void find_key_in_der_cert(tls_state_t *tls, uint8_t *der, int len)
1137static int tls_xread_handshake_block(tls_state_t *tls, int min_len) 1144static int tls_xread_handshake_block(tls_state_t *tls, int min_len)
1138{ 1145{
1139 struct record_hdr *xhdr; 1146 struct record_hdr *xhdr;
1140 int len = tls_xread_record(tls); 1147 int len = tls_xread_record(tls, "handshake record");
1141 1148
1142 xhdr = (void*)tls->inbuf; 1149 xhdr = (void*)tls->inbuf;
1143 if (len < min_len 1150 if (len < min_len
1144 || xhdr->type != RECORD_TYPE_HANDSHAKE 1151 || xhdr->type != RECORD_TYPE_HANDSHAKE
1145 || xhdr->proto_maj != TLS_MAJ
1146 || xhdr->proto_min != TLS_MIN
1147 ) { 1152 ) {
1148 bad_record_die(tls, "handshake record", len); 1153 bad_record_die(tls, "handshake record", len);
1149 } 1154 }
@@ -1195,7 +1200,9 @@ static void send_client_hello_and_alloc_hsd(tls_state_t *tls, const char *sni)
1195// 0023 0000 - session_ticket 1200// 0023 0000 - session_ticket
1196// 000a 0008 0006001700180019 - supported_groups 1201// 000a 0008 0006001700180019 - supported_groups
1197// 000b 0002 0100 - ec_point_formats 1202// 000b 0002 0100 - ec_point_formats
1198// 000d 0016 00140401040305010503060106030301030302010203 - signature_algorithms 1203// 000d 0016 0014 0401 0403 0501 0503 0601 0603 0301 0303 0201 0203 - signature_algorithms
1204// wolfssl library sends this option, RFC 7627 (closes a security weakness, some servers may require it. TODO?):
1205// 0017 0000 - extended master secret
1199 }; 1206 };
1200 struct client_hello *record; 1207 struct client_hello *record;
1201 int len; 1208 int len;
@@ -1354,7 +1361,7 @@ static void get_server_cert(tls_state_t *tls)
1354 xhdr = (void*)tls->inbuf; 1361 xhdr = (void*)tls->inbuf;
1355 certbuf = (void*)(xhdr + 1); 1362 certbuf = (void*)(xhdr + 1);
1356 if (certbuf[0] != HANDSHAKE_CERTIFICATE) 1363 if (certbuf[0] != HANDSHAKE_CERTIFICATE)
1357 tls_error_die(tls); 1364 bad_record_die(tls, "certificate", len);
1358 dbg("<< CERTIFICATE\n"); 1365 dbg("<< CERTIFICATE\n");
1359 // 4392 bytes: 1366 // 4392 bytes:
1360 // 0b 00|11|24 00|11|21 00|05|b0 30|82|05|ac|30|82|04|94|a0|03|02|01|02|02|11|00|9f|85|bf|66|4b|0c|dd|af|ca|50|86|79|50|1b|2b|e4|30|0d... 1367 // 0b 00|11|24 00|11|21 00|05|b0 30|82|05|ac|30|82|04|94|a0|03|02|01|02|02|11|00|9f|85|bf|66|4b|0c|dd|af|ca|50|86|79|50|1b|2b|e4|30|0d...
@@ -1611,6 +1618,7 @@ void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni)
1611 // <------- Finished 1618 // <------- Finished
1612 // Application Data <------> Application Data 1619 // Application Data <------> Application Data
1613 int len; 1620 int len;
1621 int got_cert_req;
1614 1622
1615 send_client_hello_and_alloc_hsd(tls, sni); 1623 send_client_hello_and_alloc_hsd(tls, sni);
1616 get_server_hello(tls); 1624 get_server_hello(tls);
@@ -1638,7 +1646,8 @@ void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni)
1638 len = tls_xread_handshake_block(tls, 4); 1646 len = tls_xread_handshake_block(tls, 4);
1639 } 1647 }
1640 1648
1641 if (tls->inbuf[RECHDR_LEN] == HANDSHAKE_CERTIFICATE_REQUEST) { 1649 got_cert_req = (tls->inbuf[RECHDR_LEN] == HANDSHAKE_CERTIFICATE_REQUEST);
1650 if (got_cert_req) {
1642 dbg("<< CERTIFICATE_REQUEST\n"); 1651 dbg("<< CERTIFICATE_REQUEST\n");
1643 // RFC 5246: "If no suitable certificate is available, 1652 // RFC 5246: "If no suitable certificate is available,
1644 // the client MUST send a certificate message containing no 1653 // the client MUST send a certificate message containing no
@@ -1647,7 +1656,9 @@ void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni)
1647 // Client certificates are sent using the Certificate structure 1656 // Client certificates are sent using the Certificate structure
1648 // defined in Section 7.4.2." 1657 // defined in Section 7.4.2."
1649 // (i.e. the same format as server certs) 1658 // (i.e. the same format as server certs)
1650 send_empty_client_cert(tls); 1659
1660 /*send_empty_client_cert(tls); - WRONG (breaks handshake hash calc) */
1661 /* need to hash _all_ server replies first, up to ServerHelloDone */
1651 len = tls_xread_handshake_block(tls, 4); 1662 len = tls_xread_handshake_block(tls, 4);
1652 } 1663 }
1653 1664
@@ -1657,6 +1668,9 @@ void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni)
1657 // 0e 000000 (len:0) 1668 // 0e 000000 (len:0)
1658 dbg("<< SERVER_HELLO_DONE\n"); 1669 dbg("<< SERVER_HELLO_DONE\n");
1659 1670
1671 if (got_cert_req)
1672 send_empty_client_cert(tls);
1673
1660 send_client_key_exchange(tls); 1674 send_client_key_exchange(tls);
1661 1675
1662 send_change_cipher_spec(tls); 1676 send_change_cipher_spec(tls);
@@ -1667,7 +1681,7 @@ void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni)
1667 send_client_finished(tls); 1681 send_client_finished(tls);
1668 1682
1669 /* Get CHANGE_CIPHER_SPEC */ 1683 /* Get CHANGE_CIPHER_SPEC */
1670 len = tls_xread_record(tls); 1684 len = tls_xread_record(tls, "switch to encrypted traffic");
1671 if (len != 1 || memcmp(tls->inbuf, rec_CHANGE_CIPHER_SPEC, 6) != 0) 1685 if (len != 1 || memcmp(tls->inbuf, rec_CHANGE_CIPHER_SPEC, 6) != 0)
1672 bad_record_die(tls, "switch to encrypted traffic", len); 1686 bad_record_die(tls, "switch to encrypted traffic", len);
1673 dbg("<< CHANGE_CIPHER_SPEC\n"); 1687 dbg("<< CHANGE_CIPHER_SPEC\n");
@@ -1685,9 +1699,9 @@ void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni)
1685 } 1699 }
1686 1700
1687 /* Get (encrypted) FINISHED from the server */ 1701 /* Get (encrypted) FINISHED from the server */
1688 len = tls_xread_record(tls); 1702 len = tls_xread_record(tls, "'server finished'");
1689 if (len < 4 || tls->inbuf[RECHDR_LEN] != HANDSHAKE_FINISHED) 1703 if (len < 4 || tls->inbuf[RECHDR_LEN] != HANDSHAKE_FINISHED)
1690 tls_error_die(tls); 1704 bad_record_die(tls, "'server finished'", len);
1691 dbg("<< FINISHED\n"); 1705 dbg("<< FINISHED\n");
1692 /* application data can be sent/received */ 1706 /* application data can be sent/received */
1693 1707
@@ -1713,7 +1727,7 @@ static void tls_xwrite(tls_state_t *tls, int len)
1713// openssl s_server -key key.pem -cert server.pem -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher NULL 1727// openssl s_server -key key.pem -cert server.pem -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher NULL
1714// openssl s_client -connect 127.0.0.1:4433 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher NULL-SHA256 1728// openssl s_client -connect 127.0.0.1:4433 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher NULL-SHA256
1715 1729
1716void FAST_FUNC tls_run_copy_loop(tls_state_t *tls) 1730void FAST_FUNC tls_run_copy_loop(tls_state_t *tls, unsigned flags)
1717{ 1731{
1718 int inbuf_size; 1732 int inbuf_size;
1719 const int INBUF_STEP = 4 * 1024; 1733 const int INBUF_STEP = 4 * 1024;
@@ -1748,6 +1762,8 @@ void FAST_FUNC tls_run_copy_loop(tls_state_t *tls)
1748 */ 1762 */
1749 pfds[0].fd = -1; 1763 pfds[0].fd = -1;
1750 tls_free_outbuf(tls); /* mem usage optimization */ 1764 tls_free_outbuf(tls); /* mem usage optimization */
1765 if (flags & TLSLOOP_EXIT_ON_LOCAL_EOF)
1766 break;
1751 } else { 1767 } else {
1752 if (nread == inbuf_size) { 1768 if (nread == inbuf_size) {
1753 /* TLS has per record overhead, if input comes fast, 1769 /* TLS has per record overhead, if input comes fast,
@@ -1763,7 +1779,7 @@ void FAST_FUNC tls_run_copy_loop(tls_state_t *tls)
1763 if (pfds[1].revents) { 1779 if (pfds[1].revents) {
1764 dbg("NETWORK HAS DATA\n"); 1780 dbg("NETWORK HAS DATA\n");
1765 read_record: 1781 read_record:
1766 nread = tls_xread_record(tls); 1782 nread = tls_xread_record(tls, "encrypted data");
1767 if (nread < 1) { 1783 if (nread < 1) {
1768 /* TLS protocol has no real concept of one-sided shutdowns: 1784 /* TLS protocol has no real concept of one-sided shutdowns:
1769 * if we get "TLS EOF" from the peer, writes will fail too 1785 * if we get "TLS EOF" from the peer, writes will fail too
@@ -1775,7 +1791,7 @@ void FAST_FUNC tls_run_copy_loop(tls_state_t *tls)
1775 break; 1791 break;
1776 } 1792 }
1777 if (tls->inbuf[0] != RECORD_TYPE_APPLICATION_DATA) 1793 if (tls->inbuf[0] != RECORD_TYPE_APPLICATION_DATA)
1778 bb_error_msg_and_die("unexpected record type %d", tls->inbuf[0]); 1794 bad_record_die(tls, "encrypted data", nread);
1779 xwrite(STDOUT_FILENO, tls->inbuf + RECHDR_LEN, nread); 1795 xwrite(STDOUT_FILENO, tls->inbuf + RECHDR_LEN, nread);
1780 /* We may already have a complete next record buffered, 1796 /* We may already have a complete next record buffered,
1781 * can process it without network reads (and possible blocking) 1797 * can process it without network reads (and possible blocking)
diff --git a/networking/udhcp/Config.src b/networking/udhcp/Config.src
index 8ab8d30ce..50bff2e8c 100644
--- a/networking/udhcp/Config.src
+++ b/networking/udhcp/Config.src
@@ -94,7 +94,7 @@ config FEATURE_UDHCPC_SANITIZEOPT
94config UDHCPC_DEFAULT_SCRIPT 94config UDHCPC_DEFAULT_SCRIPT
95 string "Absolute path to config script" 95 string "Absolute path to config script"
96 default "/usr/share/udhcpc/default.script" 96 default "/usr/share/udhcpc/default.script"
97 depends on UDHCPC 97 depends on UDHCPC || UDHCPC6
98 help 98 help
99 This script is called after udhcpc receives an answer. See 99 This script is called after udhcpc receives an answer. See
100 examples/udhcp for a working example. Normally it is safe 100 examples/udhcp for a working example. Normally it is safe
diff --git a/networking/udhcp/d6_common.h b/networking/udhcp/d6_common.h
index 310550371..e9c0397ae 100644
--- a/networking/udhcp/d6_common.h
+++ b/networking/udhcp/d6_common.h
@@ -133,6 +133,7 @@ struct d6_option {
133struct client6_data_t { 133struct client6_data_t {
134 struct d6_option *server_id; 134 struct d6_option *server_id;
135 struct d6_option *ia_na; 135 struct d6_option *ia_na;
136 struct d6_option *ia_pd;
136 char **env_ptr; 137 char **env_ptr;
137 unsigned env_idx; 138 unsigned env_idx;
138 /* link-local IPv6 address */ 139 /* link-local IPv6 address */
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
index 37ffd064d..35c99e89c 100644
--- a/networking/udhcp/d6_dhcpc.c
+++ b/networking/udhcp/d6_dhcpc.c
@@ -96,6 +96,7 @@ static const char udhcpc6_longopts[] ALIGN1 =
96 "quit\0" No_argument "q" 96 "quit\0" No_argument "q"
97 "release\0" No_argument "R" 97 "release\0" No_argument "R"
98 "request\0" Required_argument "r" 98 "request\0" Required_argument "r"
99 "requestprefix\0" No_argument "d"
99 "script\0" Required_argument "s" 100 "script\0" Required_argument "s"
100 "timeout\0" Required_argument "T" 101 "timeout\0" Required_argument "T"
101 "retries\0" Required_argument "t" 102 "retries\0" Required_argument "t"
@@ -128,8 +129,9 @@ enum {
128 OPT_o = 1 << 12, 129 OPT_o = 1 << 12,
129 OPT_x = 1 << 13, 130 OPT_x = 1 << 13,
130 OPT_f = 1 << 14, 131 OPT_f = 1 << 14,
132 OPT_d = 1 << 15,
131/* The rest has variable bit positions, need to be clever */ 133/* The rest has variable bit positions, need to be clever */
132 OPTBIT_f = 14, 134 OPTBIT_d = 15,
133 USE_FOR_MMU( OPTBIT_b,) 135 USE_FOR_MMU( OPTBIT_b,)
134 ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) 136 ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
135 IF_FEATURE_UDHCP_PORT( OPTBIT_P,) 137 IF_FEATURE_UDHCP_PORT( OPTBIT_P,)
@@ -277,11 +279,11 @@ static void option_to_env(uint8_t *option, uint8_t *option_end)
277 * | | 279 * | |
278 * +-+-+-+-+-+-+-+-+ 280 * +-+-+-+-+-+-+-+-+
279 */ 281 */
280 //move_from_unaligned32(v32, option + 4 + 4); 282 move_from_unaligned32(v32, option + 4 + 4);
281 //*new_env() = xasprintf("lease=%u", (unsigned)v32); 283 *new_env() = xasprintf("ipv6prefix_lease=%u", (unsigned)v32);
282 284
283 sprint_nip6(ipv6str, option + 4 + 4 + 1); 285 sprint_nip6(ipv6str, option + 4 + 4 + 4 + 1);
284 *new_env() = xasprintf("ipv6prefix=%s/%u", ipv6str, (unsigned)(option[4 + 4])); 286 *new_env() = xasprintf("ipv6prefix=%s/%u", ipv6str, (unsigned)(option[4 + 4 + 4]));
285 break; 287 break;
286#if ENABLE_FEATURE_UDHCPC6_RFC3646 288#if ENABLE_FEATURE_UDHCPC6_RFC3646
287 case D6_OPT_DNS_SERVERS: { 289 case D6_OPT_DNS_SERVERS: {
@@ -561,18 +563,33 @@ static NOINLINE int send_d6_discover(uint32_t xid, struct in6_addr *requested_ip
561 563
562 /* Create new IA_NA, optionally with included IAADDR with requested IP */ 564 /* Create new IA_NA, optionally with included IAADDR with requested IP */
563 free(client6_data.ia_na); 565 free(client6_data.ia_na);
564 len = requested_ipv6 ? 2+2+4+4+4 + 2+2+16+4+4 : 2+2+4+4+4; 566 client6_data.ia_na = NULL;
565 client6_data.ia_na = xzalloc(len); 567 if (option_mask32 & OPT_r) {
566 client6_data.ia_na->code = D6_OPT_IA_NA; 568 len = requested_ipv6 ? 2+2+4+4+4 + 2+2+16+4+4 : 2+2+4+4+4;
567 client6_data.ia_na->len = len - 4; 569 client6_data.ia_na = xzalloc(len);
568 *(uint32_t*)client6_data.ia_na->data = rand(); /* IAID */ 570 client6_data.ia_na->code = D6_OPT_IA_NA;
569 if (requested_ipv6) { 571 client6_data.ia_na->len = len - 4;
570 struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4); 572 *(uint32_t*)client6_data.ia_na->data = rand(); /* IAID */
571 iaaddr->code = D6_OPT_IAADDR; 573 if (requested_ipv6) {
572 iaaddr->len = 16+4+4; 574 struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4);
573 memcpy(iaaddr->data, requested_ipv6, 16); 575 iaaddr->code = D6_OPT_IAADDR;
576 iaaddr->len = 16+4+4;
577 memcpy(iaaddr->data, requested_ipv6, 16);
578 }
579 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, len);
580 }
581
582 /* IA_PD */
583 free(client6_data.ia_pd);
584 client6_data.ia_pd = NULL;
585 if (option_mask32 & OPT_d) {
586 len = 2+2+4+4+4;
587 client6_data.ia_pd = xzalloc(len);
588 client6_data.ia_pd->code = D6_OPT_IA_PD;
589 client6_data.ia_pd->len = len - 4;
590 *(uint32_t*)client6_data.ia_pd->data = rand(); /* IAID */
591 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, len);
574 } 592 }
575 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, len);
576 593
577 /* Add options: 594 /* Add options:
578 * "param req" option according to -O, options specified with -x 595 * "param req" option according to -O, options specified with -x
@@ -625,7 +642,11 @@ static NOINLINE int send_d6_select(uint32_t xid)
625 /* server id */ 642 /* server id */
626 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); 643 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
627 /* IA NA (contains requested IP) */ 644 /* IA NA (contains requested IP) */
628 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); 645 if (client6_data.ia_na)
646 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
647 /* IA PD */
648 if (client6_data.ia_pd)
649 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2);
629 650
630 /* Add options: 651 /* Add options:
631 * "param req" option according to -O, options specified with -x 652 * "param req" option according to -O, options specified with -x
@@ -694,7 +715,11 @@ static NOINLINE int send_d6_renew(uint32_t xid, struct in6_addr *server_ipv6, st
694 /* server id */ 715 /* server id */
695 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); 716 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
696 /* IA NA (contains requested IP) */ 717 /* IA NA (contains requested IP) */
697 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); 718 if (client6_data.ia_na)
719 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
720 /* IA PD */
721 if (client6_data.ia_pd)
722 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2);
698 723
699 /* Add options: 724 /* Add options:
700 * "param req" option according to -O, options specified with -x 725 * "param req" option according to -O, options specified with -x
@@ -725,7 +750,11 @@ static int send_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cu
725 /* server id */ 750 /* server id */
726 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); 751 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
727 /* IA NA (contains our current IP) */ 752 /* IA NA (contains our current IP) */
728 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); 753 if (client6_data.ia_na)
754 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
755 /* IA PD */
756 if (client6_data.ia_pd)
757 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2);
729 758
730 bb_error_msg("sending %s", "release"); 759 bb_error_msg("sending %s", "release");
731 return d6_send_kernel_packet( 760 return d6_send_kernel_packet(
@@ -1001,44 +1030,9 @@ static void client_background(void)
1001//usage:# define IF_UDHCP_VERBOSE(...) 1030//usage:# define IF_UDHCP_VERBOSE(...)
1002//usage:#endif 1031//usage:#endif
1003//usage:#define udhcpc6_trivial_usage 1032//usage:#define udhcpc6_trivial_usage
1004//usage: "[-fbnq"IF_UDHCP_VERBOSE("v")"oR] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n" 1033//usage: "[-fbnq"IF_UDHCP_VERBOSE("v")"odR] [-i IFACE] [-r IPv6] [-s PROG] [-p PIDFILE]\n"
1005//usage: " [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]") 1034//usage: " [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]")
1006//usage:#define udhcpc6_full_usage "\n" 1035//usage:#define udhcpc6_full_usage "\n"
1007//usage: IF_LONG_OPTS(
1008//usage: "\n -i,--interface IFACE Interface to use (default eth0)"
1009//usage: "\n -p,--pidfile FILE Create pidfile"
1010//usage: "\n -s,--script PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")"
1011//usage: "\n -B,--broadcast Request broadcast replies"
1012//usage: "\n -t,--retries N Send up to N discover packets"
1013//usage: "\n -T,--timeout N Pause between packets (default 3 seconds)"
1014//usage: "\n -A,--tryagain N Wait N seconds after failure (default 20)"
1015//usage: "\n -f,--foreground Run in foreground"
1016//usage: USE_FOR_MMU(
1017//usage: "\n -b,--background Background if lease is not obtained"
1018//usage: )
1019//usage: "\n -n,--now Exit if lease is not obtained"
1020//usage: "\n -q,--quit Exit after obtaining lease"
1021//usage: "\n -R,--release Release IP on exit"
1022//usage: "\n -S,--syslog Log to syslog too"
1023//usage: IF_FEATURE_UDHCP_PORT(
1024//usage: "\n -P,--client-port N Use port N (default 546)"
1025//usage: )
1026////usage: IF_FEATURE_UDHCPC_ARPING(
1027////usage: "\n -a,--arping Use arping to validate offered address"
1028////usage: )
1029//usage: "\n -O,--request-option OPT Request option OPT from server (cumulative)"
1030//usage: "\n -o,--no-default-options Don't request any options (unless -O is given)"
1031//usage: "\n -r,--request IP Request this IP address"
1032//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)"
1033//usage: "\n Examples of string, numeric, and hex byte opts:"
1034//usage: "\n -x hostname:bbox - option 12"
1035//usage: "\n -x lease:3600 - option 51 (lease time)"
1036//usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)"
1037//usage: IF_UDHCP_VERBOSE(
1038//usage: "\n -v Verbose"
1039//usage: )
1040//usage: )
1041//usage: IF_NOT_LONG_OPTS(
1042//usage: "\n -i IFACE Interface to use (default eth0)" 1036//usage: "\n -i IFACE Interface to use (default eth0)"
1043//usage: "\n -p FILE Create pidfile" 1037//usage: "\n -p FILE Create pidfile"
1044//usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" 1038//usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")"
@@ -1062,7 +1056,8 @@ static void client_background(void)
1062////usage: ) 1056////usage: )
1063//usage: "\n -O OPT Request option OPT from server (cumulative)" 1057//usage: "\n -O OPT Request option OPT from server (cumulative)"
1064//usage: "\n -o Don't request any options (unless -O is given)" 1058//usage: "\n -o Don't request any options (unless -O is given)"
1065//usage: "\n -r IP Request this IP address" 1059//usage: "\n -r IPv6 Request this address ('no' to not request any IP)"
1060//usage: "\n -d Request prefix"
1066//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" 1061//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)"
1067//usage: "\n Examples of string, numeric, and hex byte opts:" 1062//usage: "\n Examples of string, numeric, and hex byte opts:"
1068//usage: "\n -x hostname:bbox - option 12" 1063//usage: "\n -x hostname:bbox - option 12"
@@ -1071,7 +1066,6 @@ static void client_background(void)
1071//usage: IF_UDHCP_VERBOSE( 1066//usage: IF_UDHCP_VERBOSE(
1072//usage: "\n -v Verbose" 1067//usage: "\n -v Verbose"
1073//usage: ) 1068//usage: )
1074//usage: )
1075//usage: "\nSignals:" 1069//usage: "\nSignals:"
1076//usage: "\n USR1 Renew lease" 1070//usage: "\n USR1 Renew lease"
1077//usage: "\n USR2 Release lease" 1071//usage: "\n USR2 Release lease"
@@ -1099,6 +1093,8 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1099 int retval; 1093 int retval;
1100 1094
1101 setup_common_bufsiz(); 1095 setup_common_bufsiz();
1096 /* We want random_xid to be random */
1097 srand(monotonic_us());
1102 1098
1103 /* Default options */ 1099 /* Default options */
1104 IF_FEATURE_UDHCP_PORT(SERVER_PORT6 = 547;) 1100 IF_FEATURE_UDHCP_PORT(SERVER_PORT6 = 547;)
@@ -1109,7 +1105,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1109 /* Parse command line */ 1105 /* Parse command line */
1110 opt = getopt32long(argv, "^" 1106 opt = getopt32long(argv, "^"
1111 /* O,x: list; -T,-t,-A take numeric param */ 1107 /* O,x: list; -T,-t,-A take numeric param */
1112 "i:np:qRr:s:T:+t:+SA:+O:*ox:*f" 1108 "i:np:qRr:s:T:+t:+SA:+O:*ox:*fd"
1113 USE_FOR_MMU("b") 1109 USE_FOR_MMU("b")
1114 ///IF_FEATURE_UDHCPC_ARPING("a") 1110 ///IF_FEATURE_UDHCPC_ARPING("a")
1115 IF_FEATURE_UDHCP_PORT("P:") 1111 IF_FEATURE_UDHCP_PORT("P:")
@@ -1125,10 +1121,15 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1125 IF_UDHCP_VERBOSE(, &dhcp_verbose) 1121 IF_UDHCP_VERBOSE(, &dhcp_verbose)
1126 ); 1122 );
1127 requested_ipv6 = NULL; 1123 requested_ipv6 = NULL;
1124 option_mask32 |= OPT_r;
1128 if (opt & OPT_r) { 1125 if (opt & OPT_r) {
1129 if (inet_pton(AF_INET6, str_r, &ipv6_buf) <= 0) 1126 if (strcmp(str_r, "no") == 0) {
1130 bb_error_msg_and_die("bad IPv6 address '%s'", str_r); 1127 option_mask32 -= OPT_r;
1131 requested_ipv6 = &ipv6_buf; 1128 } else {
1129 if (inet_pton(AF_INET6, str_r, &ipv6_buf) <= 0)
1130 bb_error_msg_and_die("bad IPv6 address '%s'", str_r);
1131 requested_ipv6 = &ipv6_buf;
1132 }
1132 } 1133 }
1133#if ENABLE_FEATURE_UDHCP_PORT 1134#if ENABLE_FEATURE_UDHCP_PORT
1134 if (opt & OPT_P) { 1135 if (opt & OPT_P) {
@@ -1200,16 +1201,12 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1200 1201
1201 /* Make sure fd 0,1,2 are open */ 1202 /* Make sure fd 0,1,2 are open */
1202 bb_sanitize_stdio(); 1203 bb_sanitize_stdio();
1203 /* Equivalent of doing a fflush after every \n */
1204 setlinebuf(stdout);
1205 /* Create pidfile */ 1204 /* Create pidfile */
1206 write_pidfile(client_config.pidfile); 1205 write_pidfile(client_config.pidfile);
1207 /* Goes to stdout (unless NOMMU) and possibly syslog */ 1206 /* Goes to stdout (unless NOMMU) and possibly syslog */
1208 bb_error_msg("started, v"BB_VER); 1207 bb_error_msg("started, v"BB_VER);
1209 /* Set up the signal pipe */ 1208 /* Set up the signal pipe */
1210 udhcp_sp_setup(); 1209 udhcp_sp_setup();
1211 /* We want random_xid to be random... */
1212 srand(monotonic_us());
1213 1210
1214 state = INIT_SELECTING; 1211 state = INIT_SELECTING;
1215 d6_run_script(NULL, "deconfig"); 1212 d6_run_script(NULL, "deconfig");
@@ -1465,8 +1462,12 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1465 case REBINDING: 1462 case REBINDING:
1466 if (packet.d6_msg_type == D6_MSG_REPLY) { 1463 if (packet.d6_msg_type == D6_MSG_REPLY) {
1467 uint32_t lease_seconds; 1464 uint32_t lease_seconds;
1468 struct d6_option *option, *iaaddr; 1465 struct d6_option *option;
1466 unsigned address_timeout;
1467 unsigned prefix_timeout;
1469 type_is_ok: 1468 type_is_ok:
1469 address_timeout = 0;
1470 prefix_timeout = 0;
1470 option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE); 1471 option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE);
1471 if (option && (option->data[0] | option->data[1]) != 0) { 1472 if (option && (option->data[0] | option->data[1]) != 0) {
1472 /* return to init state */ 1473 /* return to init state */
@@ -1589,44 +1590,87 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1589 * . . 1590 * . .
1590 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1591 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1591 */ 1592 */
1592 free(client6_data.ia_na); 1593 if (option_mask32 & OPT_r) {
1593 client6_data.ia_na = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_NA); 1594 struct d6_option *iaaddr;
1594 if (!client6_data.ia_na) { 1595
1595 bb_error_msg("no %s option, ignoring packet", "IA_NA"); 1596 free(client6_data.ia_na);
1596 continue; 1597 client6_data.ia_na = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_NA);
1597 } 1598 if (!client6_data.ia_na) {
1598 if (client6_data.ia_na->len < (4 + 4 + 4) + (2 + 2 + 16 + 4 + 4)) { 1599 bb_error_msg("no %s option, ignoring packet", "IA_NA");
1599 bb_error_msg("IA_NA option is too short:%d bytes", client6_data.ia_na->len); 1600 continue;
1600 continue; 1601 }
1601 } 1602 if (client6_data.ia_na->len < (4 + 4 + 4) + (2 + 2 + 16 + 4 + 4)) {
1602 iaaddr = d6_find_option(client6_data.ia_na->data + 4 + 4 + 4, 1603 bb_error_msg("%s option is too short:%d bytes",
1603 client6_data.ia_na->data + client6_data.ia_na->len, 1604 "IA_NA", client6_data.ia_na->len);
1604 D6_OPT_IAADDR 1605 continue;
1605 ); 1606 }
1606 if (!iaaddr) { 1607 iaaddr = d6_find_option(client6_data.ia_na->data + 4 + 4 + 4,
1607 bb_error_msg("no %s option, ignoring packet", "IAADDR"); 1608 client6_data.ia_na->data + client6_data.ia_na->len,
1608 continue; 1609 D6_OPT_IAADDR
1610 );
1611 if (!iaaddr) {
1612 bb_error_msg("no %s option, ignoring packet", "IAADDR");
1613 continue;
1614 }
1615 if (iaaddr->len < (16 + 4 + 4)) {
1616 bb_error_msg("%s option is too short:%d bytes",
1617 "IAADDR", iaaddr->len);
1618 continue;
1619 }
1620 /* Note: the address is sufficiently aligned for cast:
1621 * we _copied_ IA-NA, and copy is always well-aligned.
1622 */
1623 requested_ipv6 = (struct in6_addr*) iaaddr->data;
1624 move_from_unaligned32(lease_seconds, iaaddr->data + 16 + 4);
1625 lease_seconds = ntohl(lease_seconds);
1626/// TODO: check for 0 lease time?
1627 bb_error_msg("%s obtained, lease time %u",
1628 "IPv6", /*inet_ntoa(temp_addr),*/ (unsigned)lease_seconds);
1629 address_timeout = lease_seconds;
1609 } 1630 }
1610 if (iaaddr->len < (16 + 4 + 4)) { 1631 if (option_mask32 & OPT_d) {
1611 bb_error_msg("IAADDR option is too short:%d bytes", iaaddr->len); 1632 struct d6_option *iaprefix;
1612 continue; 1633
1634 free(client6_data.ia_pd);
1635 client6_data.ia_pd = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_PD);
1636 if (!client6_data.ia_pd) {
1637 bb_error_msg("no %s option, ignoring packet", "IA_PD");
1638 continue;
1639 }
1640 if (client6_data.ia_pd->len < (4 + 4 + 4) + (2 + 2 + 4 + 4 + 1 + 16)) {
1641 bb_error_msg("%s option is too short:%d bytes",
1642 "IA_PD", client6_data.ia_pd->len);
1643 continue;
1644 }
1645 iaprefix = d6_find_option(client6_data.ia_pd->data + 4 + 4 + 4,
1646 client6_data.ia_pd->data + client6_data.ia_pd->len,
1647 D6_OPT_IAPREFIX
1648 );
1649 if (!iaprefix) {
1650 bb_error_msg("no %s option, ignoring packet", "IAPREFIX");
1651 continue;
1652 }
1653 if (iaprefix->len < (4 + 4 + 1 + 16)) {
1654 bb_error_msg("%s option is too short:%d bytes",
1655 "IAPREFIX", iaprefix->len);
1656 continue;
1657 }
1658 move_from_unaligned32(lease_seconds, iaprefix->data + 4);
1659 lease_seconds = ntohl(lease_seconds);
1660 bb_error_msg("%s obtained, lease time %u",
1661 "prefix", /*inet_ntoa(temp_addr),*/ (unsigned)lease_seconds);
1662 prefix_timeout = lease_seconds;
1613 } 1663 }
1614 /* Note: the address is sufficiently aligned for cast: 1664 if (!address_timeout)
1615 * we _copied_ IA-NA, and copy is always well-aligned. 1665 address_timeout = prefix_timeout;
1616 */ 1666 if (!prefix_timeout)
1617 requested_ipv6 = (struct in6_addr*) iaaddr->data; 1667 prefix_timeout = address_timeout;
1618 move_from_unaligned32(lease_seconds, iaaddr->data + 16 + 4); 1668 /* note: "int timeout" will not overflow even with 0xffffffff inputs here: */
1619 lease_seconds = ntohl(lease_seconds); 1669 timeout = (prefix_timeout < address_timeout ? prefix_timeout : address_timeout) / 2;
1620 /* paranoia: must not be too small and not prone to overflows */ 1670 /* paranoia: must not be too small */
1621 if (lease_seconds < 0x10) 1671 if (timeout < 0x10)
1622 lease_seconds = 0x10; 1672 timeout = 0x10;
1623/// TODO: check for 0 lease time?
1624 if (lease_seconds > 0x7fffffff / 1000)
1625 lease_seconds = 0x7fffffff / 1000;
1626 /* enter bound state */ 1673 /* enter bound state */
1627 timeout = lease_seconds / 2;
1628 bb_error_msg("lease obtained, lease time %u",
1629 /*inet_ntoa(temp_addr),*/ (unsigned)lease_seconds);
1630 d6_run_script(&packet, state == REQUESTING ? "bound" : "renew"); 1674 d6_run_script(&packet, state == REQUESTING ? "bound" : "renew");
1631 1675
1632 state = BOUND; 1676 state = BOUND;
diff --git a/networking/udhcp/d6_socket.c b/networking/udhcp/d6_socket.c
index d00c217d6..315c8d98a 100644
--- a/networking/udhcp/d6_socket.c
+++ b/networking/udhcp/d6_socket.c
@@ -16,7 +16,6 @@ int FAST_FUNC d6_read_interface(const char *interface, int *ifindex, struct in6_
16 struct ifaddrs *ifap, *ifa; 16 struct ifaddrs *ifap, *ifa;
17 17
18 getifaddrs(&ifap); 18 getifaddrs(&ifap);
19
20 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 19 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
21 struct sockaddr_in6 *sip6; 20 struct sockaddr_in6 *sip6;
22 21
@@ -29,9 +28,9 @@ int FAST_FUNC d6_read_interface(const char *interface, int *ifindex, struct in6_
29 struct sockaddr_ll *sll = (struct sockaddr_ll*)(ifa->ifa_addr); 28 struct sockaddr_ll *sll = (struct sockaddr_ll*)(ifa->ifa_addr);
30 memcpy(mac, sll->sll_addr, 6); 29 memcpy(mac, sll->sll_addr, 6);
31 log2("MAC %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 30 log2("MAC %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
32 log2("ifindex %d", sll->sll_ifindex);
33 *ifindex = sll->sll_ifindex; 31 *ifindex = sll->sll_ifindex;
34 retval &= (0xf - (1<<0)); 32 log2("ifindex %d", *ifindex);
33 retval &= (3 - (1<<0));
35 } 34 }
36#if 0 35#if 0
37 if (ifa->ifa_addr->sa_family == AF_INET) { 36 if (ifa->ifa_addr->sa_family == AF_INET) {
@@ -54,11 +53,33 @@ int FAST_FUNC d6_read_interface(const char *interface, int *ifindex, struct in6_
54 nip6->s6_addr[12], nip6->s6_addr[13], 53 nip6->s6_addr[12], nip6->s6_addr[13],
55 nip6->s6_addr[14], nip6->s6_addr[15] 54 nip6->s6_addr[14], nip6->s6_addr[15]
56 ); 55 );
57 retval &= (0xf - (1<<1)); 56 retval &= (3 - (1<<1));
58 } 57 }
59 } 58 }
60
61 freeifaddrs(ifap); 59 freeifaddrs(ifap);
60
61 if (retval & (1<<0)) {
62 /* This iface has no MAC (e.g. ppp), generate a random one */
63 struct ifreq ifr;
64 int fd;
65
66 memset(&ifr, 0, sizeof(ifr));
67 strncpy_IFNAMSIZ(ifr.ifr_name, interface);
68 fd = xsocket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
69 if (ioctl(fd, SIOCGIFINDEX, &ifr) == 0) {
70 *ifindex = ifr.ifr_ifindex;
71 log2("ifindex %d", *ifindex);
72 if (((uint32_t*)mac)[0] == 0) {
73 /* invent a fictitious MAC (once) */
74 ((uint32_t*)mac)[0] = rand();
75 ((uint16_t*)mac)[2] = rand();
76 mac[0] &= 0xfc; /* make sure it's not bcast */
77 }
78 retval &= (3 - (1<<0));
79 }
80 close(fd);
81 }
82
62 if (retval == 0) 83 if (retval == 0)
63 return retval; 84 return retval;
64 85
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index 55f21c187..35694fbe3 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -1386,8 +1386,6 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1386 1386
1387 /* Make sure fd 0,1,2 are open */ 1387 /* Make sure fd 0,1,2 are open */
1388 bb_sanitize_stdio(); 1388 bb_sanitize_stdio();
1389 /* Equivalent of doing a fflush after every \n */
1390 setlinebuf(stdout);
1391 /* Create pidfile */ 1389 /* Create pidfile */
1392 write_pidfile(client_config.pidfile); 1390 write_pidfile(client_config.pidfile);
1393 /* Goes to stdout (unless NOMMU) and possibly syslog */ 1391 /* Goes to stdout (unless NOMMU) and possibly syslog */
@@ -1732,8 +1730,10 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1732 /* paranoia: must not be too small and not prone to overflows */ 1730 /* paranoia: must not be too small and not prone to overflows */
1733 if (lease_seconds < 0x10) 1731 if (lease_seconds < 0x10)
1734 lease_seconds = 0x10; 1732 lease_seconds = 0x10;
1735 if (lease_seconds > 0x7fffffff / 1000) 1733 //if (lease_seconds > 0x7fffffff)
1736 lease_seconds = 0x7fffffff / 1000; 1734 // lease_seconds = 0x7fffffff;
1735 //^^^not necessary since "timeout = lease_seconds / 2"
1736 //does not overflow even for 0xffffffff.
1737 } 1737 }
1738#if ENABLE_FEATURE_UDHCPC_ARPING 1738#if ENABLE_FEATURE_UDHCPC_ARPING
1739 if (opt & OPT_a) { 1739 if (opt & OPT_a) {
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c
index 238542bb0..093239536 100644
--- a/networking/udhcp/dhcpd.c
+++ b/networking/udhcp/dhcpd.c
@@ -45,7 +45,7 @@
45#include "dhcpd.h" 45#include "dhcpd.h"
46 46
47/* globals */ 47/* globals */
48struct dyn_lease *g_leases; 48#define g_leases ((struct dyn_lease*)ptr_to_globals)
49/* struct server_config_t server_config is in bb_common_bufsiz1 */ 49/* struct server_config_t server_config is in bb_common_bufsiz1 */
50 50
51/* Takes the address of the pointer to the static_leases linked list, 51/* Takes the address of the pointer to the static_leases linked list,
@@ -856,8 +856,6 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
856 856
857 /* Make sure fd 0,1,2 are open */ 857 /* Make sure fd 0,1,2 are open */
858 bb_sanitize_stdio(); 858 bb_sanitize_stdio();
859 /* Equivalent of doing a fflush after every \n */
860 setlinebuf(stdout);
861 859
862 /* Create pidfile */ 860 /* Create pidfile */
863 write_pidfile(server_config.pidfile); 861 write_pidfile(server_config.pidfile);
@@ -880,7 +878,9 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
880 server_config.max_leases = num_ips; 878 server_config.max_leases = num_ips;
881 } 879 }
882 880
883 g_leases = xzalloc(server_config.max_leases * sizeof(g_leases[0])); 881 /* this sets g_leases */
882 SET_PTR_TO_GLOBALS(xzalloc(server_config.max_leases * sizeof(g_leases[0])));
883
884 read_leases(server_config.lease_file); 884 read_leases(server_config.lease_file);
885 885
886 if (udhcp_read_interface(server_config.interface, 886 if (udhcp_read_interface(server_config.interface,
diff --git a/networking/udhcp/dhcprelay.c b/networking/udhcp/dhcprelay.c
index 4d5644093..86dcb1af0 100644
--- a/networking/udhcp/dhcprelay.c
+++ b/networking/udhcp/dhcprelay.c
@@ -254,7 +254,7 @@ static void pass_to_client(struct dhcp_packet *p, int packet_len, int *fds)
254} 254}
255 255
256int dhcprelay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 256int dhcprelay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
257int dhcprelay_main(int argc, char **argv) 257int dhcprelay_main(int argc UNUSED_PARAM, char **argv)
258{ 258{
259 struct sockaddr_in server_addr; 259 struct sockaddr_in server_addr;
260 char **iface_list; 260 char **iface_list;
@@ -269,11 +269,11 @@ int dhcprelay_main(int argc, char **argv)
269 server_addr.sin_port = htons(SERVER_PORT); 269 server_addr.sin_port = htons(SERVER_PORT);
270 270
271 /* dhcprelay CLIENT_IFACE1[,CLIENT_IFACE2...] SERVER_IFACE [SERVER_IP] */ 271 /* dhcprelay CLIENT_IFACE1[,CLIENT_IFACE2...] SERVER_IFACE [SERVER_IP] */
272 if (argc == 4) { 272 if (!argv[1] || !argv[2])
273 bb_show_usage();
274 if (argv[3]) {
273 if (!inet_aton(argv[3], &server_addr.sin_addr)) 275 if (!inet_aton(argv[3], &server_addr.sin_addr))
274 bb_perror_msg_and_die("bad server IP"); 276 bb_perror_msg_and_die("bad server IP");
275 } else if (argc != 3) {
276 bb_show_usage();
277 } 277 }
278 278
279 iface_list = make_iface_list(argv + 1, &num_sockets); 279 iface_list = make_iface_list(argv + 1, &num_sockets);
diff --git a/networking/wget.c b/networking/wget.c
index 1f5ab8bc2..b9225fac0 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -48,6 +48,7 @@
48//config: 48//config:
49//config:config FEATURE_WGET_HTTPS 49//config:config FEATURE_WGET_HTTPS
50//config: bool "Support HTTPS using internal TLS code" 50//config: bool "Support HTTPS using internal TLS code"
51//it also enables FTPS support, but it's not well tested yet
51//config: default y 52//config: default y
52//config: depends on WGET 53//config: depends on WGET
53//config: select TLS 54//config: select TLS
@@ -176,6 +177,9 @@ struct host_info {
176static const char P_FTP[] ALIGN1 = "ftp"; 177static const char P_FTP[] ALIGN1 = "ftp";
177static const char P_HTTP[] ALIGN1 = "http"; 178static const char P_HTTP[] ALIGN1 = "http";
178#if SSL_SUPPORTED 179#if SSL_SUPPORTED
180# if ENABLE_FEATURE_WGET_HTTPS
181static const char P_FTPS[] ALIGN1 = "ftps";
182# endif
179static const char P_HTTPS[] ALIGN1 = "https"; 183static const char P_HTTPS[] ALIGN1 = "https";
180#endif 184#endif
181 185
@@ -348,15 +352,6 @@ static char *base64enc(const char *str)
348} 352}
349#endif 353#endif
350 354
351static char* sanitize_string(char *s)
352{
353 unsigned char *p = (void *) s;
354 while (*p >= ' ')
355 p++;
356 *p = '\0';
357 return s;
358}
359
360#if ENABLE_FEATURE_WGET_TIMEOUT 355#if ENABLE_FEATURE_WGET_TIMEOUT
361static void alarm_handler(int sig UNUSED_PARAM) 356static void alarm_handler(int sig UNUSED_PARAM)
362{ 357{
@@ -419,22 +414,49 @@ static FILE *open_socket(len_and_sockaddr *lsa)
419 return fp; 414 return fp;
420} 415}
421 416
417/* We balk at any control chars in other side's messages.
418 * This prevents nasty surprises (e.g. ESC sequences) in "Location:" URLs
419 * and error messages.
420 *
421 * The only exception is tabs, which are converted to (one) space:
422 * HTTP's "headers: <whitespace> values" may have those.
423 */
424static char* sanitize_string(char *s)
425{
426 unsigned char *p = (void *) s;
427 while (*p) {
428 if (*p < ' ') {
429 if (*p != '\t')
430 break;
431 *p = ' ';
432 }
433 p++;
434 }
435 *p = '\0';
436 return s;
437}
438
422/* Returns '\n' if it was seen, else '\0'. Trims at first '\r' or '\n' */ 439/* Returns '\n' if it was seen, else '\0'. Trims at first '\r' or '\n' */
423static char fgets_and_trim(FILE *fp, const char *fmt) 440static char fgets_trim_sanitize(FILE *fp, const char *fmt)
424{ 441{
425 char c; 442 char c;
426 char *buf_ptr; 443 char *buf_ptr;
427 444
428 set_alarm(); 445 set_alarm();
429 if (fgets(G.wget_buf, sizeof(G.wget_buf) - 1, fp) == NULL) 446 if (fgets(G.wget_buf, sizeof(G.wget_buf), fp) == NULL)
430 bb_perror_msg_and_die("error getting response"); 447 bb_perror_msg_and_die("error getting response");
431 clear_alarm(); 448 clear_alarm();
432 449
433 buf_ptr = strchrnul(G.wget_buf, '\n'); 450 buf_ptr = strchrnul(G.wget_buf, '\n');
434 c = *buf_ptr; 451 c = *buf_ptr;
452#if 1
453 /* Disallow any control chars: trim at first char < 0x20 */
454 sanitize_string(G.wget_buf);
455#else
435 *buf_ptr = '\0'; 456 *buf_ptr = '\0';
436 buf_ptr = strchrnul(G.wget_buf, '\r'); 457 buf_ptr = strchrnul(G.wget_buf, '\r');
437 *buf_ptr = '\0'; 458 *buf_ptr = '\0';
459#endif
438 460
439 log_io("< %s", G.wget_buf); 461 log_io("< %s", G.wget_buf);
440 462
@@ -461,8 +483,10 @@ static int ftpcmd(const char *s1, const char *s2, FILE *fp)
461#endif 483#endif
462 } 484 }
463 485
486 /* Read until "Nxx something" is received */
487 G.wget_buf[3] = 0;
464 do { 488 do {
465 fgets_and_trim(fp, "%s\n"); 489 fgets_trim_sanitize(fp, "%s\n");
466 } while (!isdigit(G.wget_buf[0]) || G.wget_buf[3] != ' '); 490 } while (!isdigit(G.wget_buf[0]) || G.wget_buf[3] != ' ');
467#if ENABLE_PLATFORM_MINGW32 491#if ENABLE_PLATFORM_MINGW32
468 fseek(fp, 0L, SEEK_CUR); 492 fseek(fp, 0L, SEEK_CUR);
@@ -490,6 +514,12 @@ static void parse_url(const char *src_url, struct host_info *h)
490 h->port = bb_lookup_port(P_FTP, "tcp", 21); 514 h->port = bb_lookup_port(P_FTP, "tcp", 21);
491 } else 515 } else
492#if SSL_SUPPORTED 516#if SSL_SUPPORTED
517# if ENABLE_FEATURE_WGET_HTTPS
518 if (strcmp(url, P_FTPS) == 0) {
519 h->port = bb_lookup_port(P_FTPS, "tcp", 990);
520 h->protocol = P_FTPS;
521 } else
522# endif
493 if (strcmp(url, P_HTTPS) == 0) { 523 if (strcmp(url, P_HTTPS) == 0) {
494 h->port = bb_lookup_port(P_HTTPS, "tcp", 443); 524 h->port = bb_lookup_port(P_HTTPS, "tcp", 443);
495 h->protocol = P_HTTPS; 525 h->protocol = P_HTTPS;
@@ -501,7 +531,7 @@ static void parse_url(const char *src_url, struct host_info *h)
501 h->protocol = P_HTTP; 531 h->protocol = P_HTTP;
502 } else { 532 } else {
503 *p = ':'; 533 *p = ':';
504 bb_error_msg_and_die("not an http or ftp url: %s", sanitize_string(url)); 534 bb_error_msg_and_die("not an http or ftp url: %s", url);
505 } 535 }
506 } else { 536 } else {
507 // GNU wget is user-friendly and falls back to http:// 537 // GNU wget is user-friendly and falls back to http://
@@ -556,13 +586,13 @@ static void parse_url(const char *src_url, struct host_info *h)
556 */ 586 */
557} 587}
558 588
559static char *gethdr(FILE *fp) 589static char *get_sanitized_hdr(FILE *fp)
560{ 590{
561 char *s, *hdrval; 591 char *s, *hdrval;
562 int c; 592 int c;
563 593
564 /* retrieve header line */ 594 /* retrieve header line */
565 c = fgets_and_trim(fp, " %s\n"); 595 c = fgets_trim_sanitize(fp, " %s\n");
566 596
567 /* end of the headers? */ 597 /* end of the headers? */
568 if (G.wget_buf[0] == '\0') 598 if (G.wget_buf[0] == '\0')
@@ -584,7 +614,7 @@ static char *gethdr(FILE *fp)
584 614
585 /* verify we are at the end of the header name */ 615 /* verify we are at the end of the header name */
586 if (*s != ':') 616 if (*s != ':')
587 bb_error_msg_and_die("bad header line: %s", sanitize_string(G.wget_buf)); 617 bb_error_msg_and_die("bad header line: %s", G.wget_buf);
588 618
589 /* locate the start of the header value */ 619 /* locate the start of the header value */
590 *s++ = '\0'; 620 *s++ = '\0';
@@ -608,87 +638,6 @@ static void reset_beg_range_to_zero(void)
608 /* ftruncate(G.output_fd, 0); */ 638 /* ftruncate(G.output_fd, 0); */
609} 639}
610 640
611static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_sockaddr *lsa)
612{
613 FILE *sfp;
614 char *str;
615 int port;
616
617 if (!target->user)
618 target->user = xstrdup("anonymous:busybox@");
619
620 sfp = open_socket(lsa);
621 if (ftpcmd(NULL, NULL, sfp) != 220)
622 bb_error_msg_and_die("%s", sanitize_string(G.wget_buf + 4));
623
624 /*
625 * Splitting username:password pair,
626 * trying to log in
627 */
628 str = strchr(target->user, ':');
629 if (str)
630 *str++ = '\0';
631 switch (ftpcmd("USER ", target->user, sfp)) {
632 case 230:
633 break;
634 case 331:
635 if (ftpcmd("PASS ", str, sfp) == 230)
636 break;
637 /* fall through (failed login) */
638 default:
639 bb_error_msg_and_die("ftp login: %s", sanitize_string(G.wget_buf + 4));
640 }
641
642 ftpcmd("TYPE I", NULL, sfp);
643
644 /*
645 * Querying file size
646 */
647 if (ftpcmd("SIZE ", target->path, sfp) == 213) {
648 G.content_len = BB_STRTOOFF(G.wget_buf + 4, NULL, 10);
649 if (G.content_len < 0 || errno) {
650 bb_error_msg_and_die("SIZE value is garbage");
651 }
652 G.got_clen = 1;
653 }
654
655 /*
656 * Entering passive mode
657 */
658 if (ftpcmd("PASV", NULL, sfp) != 227) {
659 pasv_error:
660 bb_error_msg_and_die("bad response to %s: %s", "PASV", sanitize_string(G.wget_buf));
661 }
662 // Response is "227 garbageN1,N2,N3,N4,P1,P2[)garbage]
663 // Server's IP is N1.N2.N3.N4 (we ignore it)
664 // Server's port for data connection is P1*256+P2
665 str = strrchr(G.wget_buf, ')');
666 if (str) str[0] = '\0';
667 str = strrchr(G.wget_buf, ',');
668 if (!str) goto pasv_error;
669 port = xatou_range(str+1, 0, 255);
670 *str = '\0';
671 str = strrchr(G.wget_buf, ',');
672 if (!str) goto pasv_error;
673 port += xatou_range(str+1, 0, 255) * 256;
674 set_nport(&lsa->u.sa, htons(port));
675
676 *dfpp = open_socket(lsa);
677
678 if (G.beg_range != 0) {
679 sprintf(G.wget_buf, "REST %"OFF_FMT"u", G.beg_range);
680 if (ftpcmd(G.wget_buf, NULL, sfp) == 350)
681 G.content_len -= G.beg_range;
682 else
683 reset_beg_range_to_zero();
684 }
685
686 if (ftpcmd("RETR ", target->path, sfp) > 150)
687 bb_error_msg_and_die("bad response to %s: %s", "RETR", sanitize_string(G.wget_buf));
688
689 return sfp;
690}
691
692#if ENABLE_FEATURE_WGET_OPENSSL 641#if ENABLE_FEATURE_WGET_OPENSSL
693static int spawn_https_helper_openssl(const char *host, unsigned port) 642static int spawn_https_helper_openssl(const char *host, unsigned port)
694{ 643{
@@ -765,7 +714,7 @@ static int spawn_https_helper_openssl(const char *host, unsigned port)
765#endif 714#endif
766 715
767#if ENABLE_FEATURE_WGET_HTTPS 716#if ENABLE_FEATURE_WGET_HTTPS
768static void spawn_ssl_client(const char *host, int network_fd) 717static void spawn_ssl_client(const char *host, int network_fd, int flags)
769{ 718{
770 int sp[2]; 719 int sp[2];
771 int pid; 720 int pid;
@@ -790,17 +739,19 @@ static void spawn_ssl_client(const char *host, int network_fd)
790 tls_state_t *tls = new_tls_state(); 739 tls_state_t *tls = new_tls_state();
791 tls->ifd = tls->ofd = network_fd; 740 tls->ifd = tls->ofd = network_fd;
792 tls_handshake(tls, servername); 741 tls_handshake(tls, servername);
793 tls_run_copy_loop(tls); 742 tls_run_copy_loop(tls, flags);
794 exit(0); 743 exit(0);
795 } else { 744 } else {
796 char *argv[5]; 745 char *argv[6];
746
797 xmove_fd(network_fd, 3); 747 xmove_fd(network_fd, 3);
798 argv[0] = (char*)"ssl_client"; 748 argv[0] = (char*)"ssl_client";
799 argv[1] = (char*)"-s3"; 749 argv[1] = (char*)"-s3";
800 //TODO: if (!is_ip_address(servername))... 750 //TODO: if (!is_ip_address(servername))...
801 argv[2] = (char*)"-n"; 751 argv[2] = (char*)"-n";
802 argv[3] = servername; 752 argv[3] = servername;
803 argv[4] = NULL; 753 argv[4] = (flags & TLSLOOP_EXIT_ON_LOCAL_EOF ? (char*)"-e" : NULL);
754 argv[5] = NULL;
804 BB_EXECVP(argv[0], argv); 755 BB_EXECVP(argv[0], argv);
805 bb_perror_msg_and_die("can't execute '%s'", argv[0]); 756 bb_perror_msg_and_die("can't execute '%s'", argv[0]);
806 } 757 }
@@ -814,6 +765,101 @@ static void spawn_ssl_client(const char *host, int network_fd)
814} 765}
815#endif 766#endif
816 767
768static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_sockaddr *lsa)
769{
770 FILE *sfp;
771 char *str;
772 int port;
773
774 if (!target->user)
775 target->user = xstrdup("anonymous:busybox@");
776
777 sfp = open_socket(lsa);
778#if ENABLE_FEATURE_WGET_HTTPS
779 if (target->protocol == P_FTPS)
780 spawn_ssl_client(target->host, fileno(sfp), TLSLOOP_EXIT_ON_LOCAL_EOF);
781#endif
782
783 if (ftpcmd(NULL, NULL, sfp) != 220)
784 bb_error_msg_and_die("%s", G.wget_buf);
785 /* note: ftpcmd() sanitizes G.wget_buf, ok to print */
786
787 /*
788 * Splitting username:password pair,
789 * trying to log in
790 */
791 str = strchr(target->user, ':');
792 if (str)
793 *str++ = '\0';
794 switch (ftpcmd("USER ", target->user, sfp)) {
795 case 230:
796 break;
797 case 331:
798 if (ftpcmd("PASS ", str, sfp) == 230)
799 break;
800 /* fall through (failed login) */
801 default:
802 bb_error_msg_and_die("ftp login: %s", G.wget_buf);
803 }
804
805 ftpcmd("TYPE I", NULL, sfp);
806
807 /*
808 * Querying file size
809 */
810 if (ftpcmd("SIZE ", target->path, sfp) == 213) {
811 G.content_len = BB_STRTOOFF(G.wget_buf + 4, NULL, 10);
812 if (G.content_len < 0 || errno) {
813 bb_error_msg_and_die("SIZE value is garbage");
814 }
815 G.got_clen = 1;
816 }
817
818 /*
819 * Entering passive mode
820 */
821 if (ENABLE_FEATURE_IPV6 && ftpcmd("EPSV", NULL, sfp) == 229) {
822 /* good */
823 } else
824 if (ftpcmd("PASV", NULL, sfp) != 227) {
825 pasv_error:
826 bb_error_msg_and_die("bad response to %s: %s", "PASV", G.wget_buf);
827 }
828 port = parse_pasv_epsv(G.wget_buf);
829 if (port < 0)
830 goto pasv_error;
831
832 set_nport(&lsa->u.sa, htons(port));
833
834 *dfpp = open_socket(lsa);
835
836#if ENABLE_FEATURE_WGET_HTTPS
837 if (target->protocol == P_FTPS) {
838 /* "PROT P" enables encryption of data stream.
839 * Without it (or with "PROT C"), data is sent unencrypted.
840 */
841 if (ftpcmd("PROT P", NULL, sfp) == 200)
842 spawn_ssl_client(target->host, fileno(*dfpp), /*flags*/ 0);
843 }
844#endif
845
846 if (G.beg_range != 0) {
847 sprintf(G.wget_buf, "REST %"OFF_FMT"u", G.beg_range);
848 if (ftpcmd(G.wget_buf, NULL, sfp) == 350)
849 G.content_len -= G.beg_range;
850 else
851 reset_beg_range_to_zero();
852 }
853
854//TODO: needs ftp-escaping 0xff and '\n' bytes here.
855//Or disallow '\n' altogether via sanitize_string() in parse_url().
856//But 0xff's are possible in valid utf8 filenames.
857 if (ftpcmd("RETR ", target->path, sfp) > 150)
858 bb_error_msg_and_die("bad response to %s: %s", "RETR", G.wget_buf);
859
860 return sfp;
861}
862
817static void NOINLINE retrieve_file_data(FILE *dfp) 863static void NOINLINE retrieve_file_data(FILE *dfp)
818{ 864{
819#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT 865#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
@@ -930,9 +976,9 @@ static void NOINLINE retrieve_file_data(FILE *dfp)
930 if (!G.chunked) 976 if (!G.chunked)
931 break; 977 break;
932 978
933 fgets_and_trim(dfp, NULL); /* Eat empty line */ 979 fgets_trim_sanitize(dfp, NULL); /* Eat empty line */
934 get_clen: 980 get_clen:
935 fgets_and_trim(dfp, NULL); 981 fgets_trim_sanitize(dfp, NULL);
936 G.content_len = STRTOOFF(G.wget_buf, NULL, 16); 982 G.content_len = STRTOOFF(G.wget_buf, NULL, 16);
937 /* FIXME: error check? */ 983 /* FIXME: error check? */
938 if (G.content_len == 0) 984 if (G.content_len == 0)
@@ -987,7 +1033,7 @@ static void download_one_url(const char *url)
987 /* Use the proxy if necessary */ 1033 /* Use the proxy if necessary */
988 use_proxy = (strcmp(G.proxy_flag, "off") != 0); 1034 use_proxy = (strcmp(G.proxy_flag, "off") != 0);
989 if (use_proxy) { 1035 if (use_proxy) {
990 proxy = getenv(target.protocol == P_FTP ? "ftp_proxy" : "http_proxy"); 1036 proxy = getenv(target.protocol[0] == 'f' ? "ftp_proxy" : "http_proxy");
991//FIXME: what if protocol is https? Ok to use http_proxy? 1037//FIXME: what if protocol is https? Ok to use http_proxy?
992 use_proxy = (proxy && proxy[0]); 1038 use_proxy = (proxy && proxy[0]);
993 if (use_proxy) 1039 if (use_proxy)
@@ -1048,7 +1094,7 @@ static void download_one_url(const char *url)
1048 /*G.content_len = 0; - redundant, got_clen = 0 is enough */ 1094 /*G.content_len = 0; - redundant, got_clen = 0 is enough */
1049 G.got_clen = 0; 1095 G.got_clen = 0;
1050 G.chunked = 0; 1096 G.chunked = 0;
1051 if (use_proxy || target.protocol != P_FTP) { 1097 if (use_proxy || target.protocol[0] != 'f' /*not ftp[s]*/) {
1052 /* 1098 /*
1053 * HTTP session 1099 * HTTP session
1054 */ 1100 */
@@ -1066,7 +1112,7 @@ static void download_one_url(const char *url)
1066# if ENABLE_FEATURE_WGET_HTTPS 1112# if ENABLE_FEATURE_WGET_HTTPS
1067 if (fd < 0) { /* no openssl? try internal */ 1113 if (fd < 0) { /* no openssl? try internal */
1068 sfp = open_socket(lsa); 1114 sfp = open_socket(lsa);
1069 spawn_ssl_client(server.host, fileno(sfp)); 1115 spawn_ssl_client(server.host, fileno(sfp), /*flags*/ 0);
1070 goto socket_opened; 1116 goto socket_opened;
1071 } 1117 }
1072# else 1118# else
@@ -1083,7 +1129,7 @@ static void download_one_url(const char *url)
1083 /* Only internal TLS support is configured */ 1129 /* Only internal TLS support is configured */
1084 sfp = open_socket(lsa); 1130 sfp = open_socket(lsa);
1085 if (target.protocol == P_HTTPS) 1131 if (target.protocol == P_HTTPS)
1086 spawn_ssl_client(server.host, fileno(sfp)); 1132 spawn_ssl_client(server.host, fileno(sfp), /*flags*/ 0);
1087#else 1133#else
1088 /* ssl (https) support is not configured */ 1134 /* ssl (https) support is not configured */
1089 sfp = open_socket(lsa); 1135 sfp = open_socket(lsa);
@@ -1162,7 +1208,7 @@ static void download_one_url(const char *url)
1162 * Retrieve HTTP response line and check for "200" status code. 1208 * Retrieve HTTP response line and check for "200" status code.
1163 */ 1209 */
1164 read_response: 1210 read_response:
1165 fgets_and_trim(sfp, " %s\n"); 1211 fgets_trim_sanitize(sfp, " %s\n");
1166 1212
1167 str = G.wget_buf; 1213 str = G.wget_buf;
1168 str = skip_non_whitespace(str); 1214 str = skip_non_whitespace(str);
@@ -1173,7 +1219,7 @@ static void download_one_url(const char *url)
1173 switch (status) { 1219 switch (status) {
1174 case 0: 1220 case 0:
1175 case 100: 1221 case 100:
1176 while (gethdr(sfp) != NULL) 1222 while (get_sanitized_hdr(sfp) != NULL)
1177 /* eat all remaining headers */; 1223 /* eat all remaining headers */;
1178 goto read_response; 1224 goto read_response;
1179 1225
@@ -1237,13 +1283,13 @@ However, in real world it was observed that some web servers
1237 /* Partial Content even though we did not ask for it??? */ 1283 /* Partial Content even though we did not ask for it??? */
1238 /* fall through */ 1284 /* fall through */
1239 default: 1285 default:
1240 bb_error_msg_and_die("server returned error: %s", sanitize_string(G.wget_buf)); 1286 bb_error_msg_and_die("server returned error: %s", G.wget_buf);
1241 } 1287 }
1242 1288
1243 /* 1289 /*
1244 * Retrieve HTTP headers. 1290 * Retrieve HTTP headers.
1245 */ 1291 */
1246 while ((str = gethdr(sfp)) != NULL) { 1292 while ((str = get_sanitized_hdr(sfp)) != NULL) {
1247 static const char keywords[] ALIGN1 = 1293 static const char keywords[] ALIGN1 =
1248 "content-length\0""transfer-encoding\0""location\0"; 1294 "content-length\0""transfer-encoding\0""location\0";
1249 enum { 1295 enum {
@@ -1251,7 +1297,7 @@ However, in real world it was observed that some web servers
1251 }; 1297 };
1252 smalluint key; 1298 smalluint key;
1253 1299
1254 /* gethdr converted "FOO:" string to lowercase */ 1300 /* get_sanitized_hdr converted "FOO:" string to lowercase */
1255 1301
1256 /* strip trailing whitespace */ 1302 /* strip trailing whitespace */
1257 char *s = strchrnul(str, '\0') - 1; 1303 char *s = strchrnul(str, '\0') - 1;
@@ -1263,14 +1309,14 @@ However, in real world it was observed that some web servers
1263 if (key == KEY_content_length) { 1309 if (key == KEY_content_length) {
1264 G.content_len = BB_STRTOOFF(str, NULL, 10); 1310 G.content_len = BB_STRTOOFF(str, NULL, 10);
1265 if (G.content_len < 0 || errno) { 1311 if (G.content_len < 0 || errno) {
1266 bb_error_msg_and_die("content-length %s is garbage", sanitize_string(str)); 1312 bb_error_msg_and_die("content-length %s is garbage", str);
1267 } 1313 }
1268 G.got_clen = 1; 1314 G.got_clen = 1;
1269 continue; 1315 continue;
1270 } 1316 }
1271 if (key == KEY_transfer_encoding) { 1317 if (key == KEY_transfer_encoding) {
1272 if (strcmp(str_tolower(str), "chunked") != 0) 1318 if (strcmp(str_tolower(str), "chunked") != 0)
1273 bb_error_msg_and_die("transfer encoding '%s' is not supported", sanitize_string(str)); 1319 bb_error_msg_and_die("transfer encoding '%s' is not supported", str);
1274 G.chunked = 1; 1320 G.chunked = 1;
1275 } 1321 }
1276 if (key == KEY_location && status >= 300) { 1322 if (key == KEY_location && status >= 300) {
@@ -1279,7 +1325,7 @@ However, in real world it was observed that some web servers
1279 fclose(sfp); 1325 fclose(sfp);
1280 if (str[0] == '/') { 1326 if (str[0] == '/') {
1281 free(redirected_path); 1327 free(redirected_path);
1282 target.path = redirected_path = xstrdup(str+1); 1328 target.path = redirected_path = xstrdup(str + 1);
1283 /* lsa stays the same: it's on the same server */ 1329 /* lsa stays the same: it's on the same server */
1284 } else { 1330 } else {
1285 parse_url(str, &target); 1331 parse_url(str, &target);
@@ -1326,7 +1372,7 @@ However, in real world it was observed that some web servers
1326 /* It's ftp. Close data connection properly */ 1372 /* It's ftp. Close data connection properly */
1327 fclose(dfp); 1373 fclose(dfp);
1328 if (ftpcmd(NULL, NULL, sfp) != 226) 1374 if (ftpcmd(NULL, NULL, sfp) != 226)
1329 bb_error_msg_and_die("ftp error: %s", sanitize_string(G.wget_buf + 4)); 1375 bb_error_msg_and_die("ftp error: %s", G.wget_buf);
1330 /* ftpcmd("QUIT", NULL, sfp); - why bother? */ 1376 /* ftpcmd("QUIT", NULL, sfp); - why bother? */
1331 } 1377 }
1332 fclose(sfp); 1378 fclose(sfp);
diff --git a/procps/kill.c b/procps/kill.c
index 24cc903fc..c95afb8b3 100644
--- a/procps/kill.c
+++ b/procps/kill.c
@@ -108,7 +108,10 @@ int kill_main(int argc UNUSED_PARAM, char **argv)
108{ 108{
109 char *arg; 109 char *arg;
110 pid_t pid; 110 pid_t pid;
111 int signo = SIGTERM, errors = 0, quiet = 0; 111 int signo = SIGTERM, errors = 0;
112#if ENABLE_KILL || ENABLE_KILLALL
113 int quiet = 0;
114#endif
112 115
113#if KILL_APPLET_CNT == 1 116#if KILL_APPLET_CNT == 1
114# define is_killall ENABLE_KILLALL 117# define is_killall ENABLE_KILLALL
@@ -170,7 +173,9 @@ int kill_main(int argc UNUSED_PARAM, char **argv)
170 173
171 /* The -q quiet option */ 174 /* The -q quiet option */
172 if (is_killall && arg[1] == 'q' && arg[2] == '\0') { 175 if (is_killall && arg[1] == 'q' && arg[2] == '\0') {
176#if ENABLE_KILL || ENABLE_KILLALL
173 quiet = 1; 177 quiet = 1;
178#endif
174 arg = *++argv; 179 arg = *++argv;
175 if (!arg) 180 if (!arg)
176 bb_show_usage(); 181 bb_show_usage();
diff --git a/procps/mpstat.c b/procps/mpstat.c
index b1ac09d75..3c72f2705 100644
--- a/procps/mpstat.c
+++ b/procps/mpstat.c
@@ -840,7 +840,7 @@ static int get_irqcpu_nr(const char *f, int max_irqs)
840//usage: "\n -u Report CPU utilization" 840//usage: "\n -u Report CPU utilization"
841 841
842int mpstat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 842int mpstat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
843int mpstat_main(int UNUSED_PARAM argc, char **argv) 843int mpstat_main(int argc UNUSED_PARAM, char **argv)
844{ 844{
845 char *opt_irq_fmt; 845 char *opt_irq_fmt;
846 char *opt_set_cpu; 846 char *opt_set_cpu;
diff --git a/procps/powertop.c b/procps/powertop.c
index 2872035cf..004b4ce19 100644
--- a/procps/powertop.c
+++ b/procps/powertop.c
@@ -686,7 +686,7 @@ static void show_timerstats(void)
686//usage: "Analyze power consumption on Intel-based laptops" 686//usage: "Analyze power consumption on Intel-based laptops"
687 687
688int powertop_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 688int powertop_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
689int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) 689int powertop_main(int argc UNUSED_PARAM, char UNUSED_PARAM **argv)
690{ 690{
691 ullong cur_usage[MAX_CSTATE_COUNT]; 691 ullong cur_usage[MAX_CSTATE_COUNT];
692 ullong cur_duration[MAX_CSTATE_COUNT]; 692 ullong cur_duration[MAX_CSTATE_COUNT];
diff --git a/runit/svlogd.c b/runit/svlogd.c
index dfd7e38a0..412290ca9 100644
--- a/runit/svlogd.c
+++ b/runit/svlogd.c
@@ -140,15 +140,22 @@ log message, you can use a pattern like this instead
140//usage:#define svlogd_full_usage "\n\n" 140//usage:#define svlogd_full_usage "\n\n"
141//usage: "Read log data from stdin and write to rotated log files in DIRs" 141//usage: "Read log data from stdin and write to rotated log files in DIRs"
142//usage: "\n" 142//usage: "\n"
143//usage: "\n""-r C Replace non-printable characters with C"
144//usage: "\n""-R CHARS Also replace CHARS with C (default _)"
145//usage: "\n""-t Timestamp with @tai64n"
146//usage: "\n""-tt Timestamp with yyyy-mm-dd_hh:mm:ss.sssss"
147//usage: "\n""-ttt Timestamp with yyyy-mm-ddThh:mm:ss.sssss"
148//usage: "\n""-v Verbose"
149//usage: "\n"
143//usage: "\n""DIR/config file modifies behavior:" 150//usage: "\n""DIR/config file modifies behavior:"
144//usage: "\n""sSIZE - when to rotate logs" 151//usage: "\n""sSIZE - when to rotate logs (default 1000000, 0 disables)"
145//usage: "\n""nNUM - number of files to retain" 152//usage: "\n""nNUM - number of files to retain"
146/*usage: "\n""NNUM - min number files to retain" - confusing */ 153///////: "\n""NNUM - min number files to retain" - confusing
147/*usage: "\n""tSEC - rotate file if it get SEC seconds old" - confusing */ 154///////: "\n""tSEC - rotate file if it get SEC seconds old" - confusing
148//usage: "\n""!PROG - process rotated log with PROG" 155//usage: "\n""!PROG - process rotated log with PROG"
149/*usage: "\n""uIPADDR - send log over UDP" - unsupported */ 156///////: "\n""uIPADDR - send log over UDP" - unsupported
150/*usage: "\n""UIPADDR - send log over UDP and DONT log" - unsupported */ 157///////: "\n""UIPADDR - send log over UDP and DONT log" - unsupported
151/*usage: "\n""pPFX - prefix each line with PFX" - unsupported */ 158///////: "\n""pPFX - prefix each line with PFX" - unsupported
152//usage: "\n""+,-PATTERN - (de)select line for logging" 159//usage: "\n""+,-PATTERN - (de)select line for logging"
153//usage: "\n""E,ePATTERN - (de)select line for stderr" 160//usage: "\n""E,ePATTERN - (de)select line for stderr"
154 161
diff --git a/scripts/randomtest b/scripts/randomtest
index 1809838a4..635978338 100755
--- a/scripts/randomtest
+++ b/scripts/randomtest
@@ -52,6 +52,7 @@ echo '# CONFIG_RFKILL is not set' >>.config
52if test x"$LIBC" = x"glibc"; then 52if test x"$LIBC" = x"glibc"; then
53 cat .config \ 53 cat .config \
54 | grep -v CONFIG_STATIC \ 54 | grep -v CONFIG_STATIC \
55 | grep -v CONFIG_FEATURE_LIBBUSYBOX_STATIC \
55 \ 56 \
56 | grep -v CONFIG_FEATURE_2_4_MODULES \ 57 | grep -v CONFIG_FEATURE_2_4_MODULES \
57 | grep -v CONFIG_FEATURE_USE_BSS_TAIL \ 58 | grep -v CONFIG_FEATURE_USE_BSS_TAIL \
@@ -59,6 +60,7 @@ if test x"$LIBC" = x"glibc"; then
59 >.config.new 60 >.config.new
60 mv .config.new .config 61 mv .config.new .config
61 echo '# CONFIG_STATIC is not set' >>.config 62 echo '# CONFIG_STATIC is not set' >>.config
63 echo '# CONFIG_FEATURE_LIBBUSYBOX_STATIC is not set' >>.config
62 # newer glibc (at least 2.23) no longer supply query_module() ABI. 64 # newer glibc (at least 2.23) no longer supply query_module() ABI.
63 # People who target 2.4 kernels would likely use older glibc (and older bbox). 65 # People who target 2.4 kernels would likely use older glibc (and older bbox).
64 echo '# CONFIG_FEATURE_2_4_MODULES is not set' >>.config 66 echo '# CONFIG_FEATURE_2_4_MODULES is not set' >>.config
diff --git a/scripts/randomtest.loop b/scripts/randomtest.loop
index 4d14b652f..edfbc5c58 100755
--- a/scripts/randomtest.loop
+++ b/scripts/randomtest.loop
@@ -66,6 +66,7 @@ while sleep 1; do
66 continue 66 continue
67 fi 67 fi
68 fi 68 fi
69 grep -i 'warning:' "$dir/make.log"
69 rm -rf -- "$dir" 70 rm -rf -- "$dir"
70 let cnt++ 71 let cnt++
71done 72done
diff --git a/shell/ash.c b/shell/ash.c
index 81845dc60..36ddda1bc 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -66,6 +66,22 @@
66//config: default y 66//config: default y
67//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH 67//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
68//config: 68//config:
69//config:config ASH_BASH_SOURCE_CURDIR
70//config: bool "'source' and '.' builtins search current directory after $PATH"
71//config: default n # do not encourage non-standard behavior
72//config: depends on ASH_BASH_COMPAT
73//config: help
74//config: This is not compliant with standards. Avoid if possible.
75//config:
76//config:config ASH_BASH_NOT_FOUND_HOOK
77//config: bool "command_not_found_handle hook support"
78//config: default y
79//config: depends on ASH_BASH_COMPAT
80//config: help
81//config: Enable support for the 'command_not_found_handle' hook function,
82//config: from GNU bash, which allows for alternative command not found
83//config: handling.
84//config:
69//config:config ASH_JOB_CONTROL 85//config:config ASH_JOB_CONTROL
70//config: bool "Job control" 86//config: bool "Job control"
71//config: default y 87//config: default y
@@ -278,6 +294,19 @@ typedef long arith_t;
278# error "Do not even bother, ash will not run on NOMMU machine" 294# error "Do not even bother, ash will not run on NOMMU machine"
279#endif 295#endif
280 296
297/* We use a trick to have more optimized code (fewer pointer reloads):
298 * ash.c: extern struct globals *const ash_ptr_to_globals;
299 * ash_ptr_hack.c: struct globals *ash_ptr_to_globals;
300 * This way, compiler in ash.c knows the pointer can not change.
301 *
302 * However, this may break on weird arches or toolchains. In this case,
303 * set "-DBB_GLOBAL_CONST=''" in CONFIG_EXTRA_CFLAGS to disable
304 * this optimization.
305 */
306#ifndef BB_GLOBAL_CONST
307# define BB_GLOBAL_CONST const
308#endif
309
281#if ENABLE_PLATFORM_MINGW32 310#if ENABLE_PLATFORM_MINGW32
282union node; 311union node;
283struct strlist; 312struct strlist;
@@ -393,6 +422,8 @@ struct globals_misc {
393 /* shell level: 0 for the main shell, 1 for its children, and so on */ 422 /* shell level: 0 for the main shell, 1 for its children, and so on */
394 int shlvl; 423 int shlvl;
395#define rootshell (!shlvl) 424#define rootshell (!shlvl)
425 int errlinno;
426
396 char *minusc; /* argument to -c option */ 427 char *minusc; /* argument to -c option */
397 428
398 char *curdir; // = nullstr; /* current working directory */ 429 char *curdir; // = nullstr; /* current working directory */
@@ -469,13 +500,14 @@ struct globals_misc {
469#endif 500#endif
470 pid_t backgndpid; /* pid of last background process */ 501 pid_t backgndpid; /* pid of last background process */
471}; 502};
472extern struct globals_misc *const ash_ptr_to_globals_misc; 503extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc;
473#define G_misc (*ash_ptr_to_globals_misc) 504#define G_misc (*ash_ptr_to_globals_misc)
474#define exitstatus (G_misc.exitstatus ) 505#define exitstatus (G_misc.exitstatus )
475#define back_exitstatus (G_misc.back_exitstatus ) 506#define back_exitstatus (G_misc.back_exitstatus )
476#define job_warning (G_misc.job_warning) 507#define job_warning (G_misc.job_warning)
477#define rootpid (G_misc.rootpid ) 508#define rootpid (G_misc.rootpid )
478#define shlvl (G_misc.shlvl ) 509#define shlvl (G_misc.shlvl )
510#define errlinno (G_misc.errlinno )
479#define minusc (G_misc.minusc ) 511#define minusc (G_misc.minusc )
480#define curdir (G_misc.curdir ) 512#define curdir (G_misc.curdir )
481#define physdir (G_misc.physdir ) 513#define physdir (G_misc.physdir )
@@ -810,6 +842,7 @@ union node;
810 842
811struct ncmd { 843struct ncmd {
812 smallint type; /* Nxxxx */ 844 smallint type; /* Nxxxx */
845 int linno;
813 union node *assign; 846 union node *assign;
814 union node *args; 847 union node *args;
815 union node *redirect; 848 union node *redirect;
@@ -823,6 +856,7 @@ struct npipe {
823 856
824struct nredir { 857struct nredir {
825 smallint type; 858 smallint type;
859 int linno;
826 union node *n; 860 union node *n;
827 union node *redirect; 861 union node *redirect;
828}; 862};
@@ -842,6 +876,7 @@ struct nif {
842 876
843struct nfor { 877struct nfor {
844 smallint type; 878 smallint type;
879 int linno;
845 union node *args; 880 union node *args;
846 union node *body; 881 union node *body;
847 char *var; 882 char *var;
@@ -849,6 +884,7 @@ struct nfor {
849 884
850struct ncase { 885struct ncase {
851 smallint type; 886 smallint type;
887 int linno;
852 union node *expr; 888 union node *expr;
853 union node *cases; 889 union node *cases;
854}; 890};
@@ -860,6 +896,13 @@ struct nclist {
860 union node *body; 896 union node *body;
861}; 897};
862 898
899struct ndefun {
900 smallint type;
901 int linno;
902 char *text;
903 union node *body;
904};
905
863struct narg { 906struct narg {
864 smallint type; 907 smallint type;
865 union node *next; 908 union node *next;
@@ -911,6 +954,7 @@ union node {
911 struct nfor nfor; 954 struct nfor nfor;
912 struct ncase ncase; 955 struct ncase ncase;
913 struct nclist nclist; 956 struct nclist nclist;
957 struct ndefun ndefun;
914 struct narg narg; 958 struct narg narg;
915 struct nfile nfile; 959 struct nfile nfile;
916 struct ndup ndup; 960 struct ndup ndup;
@@ -1340,7 +1384,6 @@ struct parsefile {
1340 1384
1341static struct parsefile basepf; /* top level input file */ 1385static struct parsefile basepf; /* top level input file */
1342static struct parsefile *g_parsefile = &basepf; /* current input file */ 1386static struct parsefile *g_parsefile = &basepf; /* current input file */
1343static int startlinno; /* line # where last token started */
1344static char *commandname; /* currently executing command */ 1387static char *commandname; /* currently executing command */
1345 1388
1346 1389
@@ -1354,7 +1397,7 @@ ash_vmsg(const char *msg, va_list ap)
1354 if (strcmp(arg0, commandname)) 1397 if (strcmp(arg0, commandname))
1355 fprintf(stderr, "%s: ", commandname); 1398 fprintf(stderr, "%s: ", commandname);
1356 if (!iflag || g_parsefile->pf_fd > 0) 1399 if (!iflag || g_parsefile->pf_fd > 0)
1357 fprintf(stderr, "line %d: ", startlinno); 1400 fprintf(stderr, "line %d: ", errlinno);
1358 } 1401 }
1359 vfprintf(stderr, msg, ap); 1402 vfprintf(stderr, msg, ap);
1360 newline_and_flush(stderr); 1403 newline_and_flush(stderr);
@@ -1407,6 +1450,7 @@ static void raise_error_syntax(const char *) NORETURN;
1407static void 1450static void
1408raise_error_syntax(const char *msg) 1451raise_error_syntax(const char *msg)
1409{ 1452{
1453 errlinno = g_parsefile->linno;
1410 ash_msg_and_raise_error("syntax error: %s", msg); 1454 ash_msg_and_raise_error("syntax error: %s", msg);
1411 /* NOTREACHED */ 1455 /* NOTREACHED */
1412} 1456}
@@ -1529,7 +1573,7 @@ struct globals_memstack {
1529 size_t g_stacknleft; // = MINSIZE; 1573 size_t g_stacknleft; // = MINSIZE;
1530 struct stack_block stackbase; 1574 struct stack_block stackbase;
1531}; 1575};
1532extern struct globals_memstack *const ash_ptr_to_globals_memstack; 1576extern struct globals_memstack *BB_GLOBAL_CONST ash_ptr_to_globals_memstack;
1533#define G_memstack (*ash_ptr_to_globals_memstack) 1577#define G_memstack (*ash_ptr_to_globals_memstack)
1534#define g_stackp (G_memstack.g_stackp ) 1578#define g_stackp (G_memstack.g_stackp )
1535#define g_stacknxt (G_memstack.g_stacknxt ) 1579#define g_stacknxt (G_memstack.g_stacknxt )
@@ -1619,7 +1663,7 @@ sstrdup(const char *p)
1619 return memcpy(stalloc(len), p, len); 1663 return memcpy(stalloc(len), p, len);
1620} 1664}
1621 1665
1622static inline void 1666static ALWAYS_INLINE void
1623grabstackblock(size_t len) 1667grabstackblock(size_t len)
1624{ 1668{
1625 stalloc(len); 1669 stalloc(len);
@@ -2094,6 +2138,7 @@ static const struct {
2094#if ENABLE_ASH_GETOPTS 2138#if ENABLE_ASH_GETOPTS
2095 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset }, 2139 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
2096#endif 2140#endif
2141 { VSTRFIXED|VTEXTFIXED , NULL /* inited to linenovar */, NULL },
2097#if ENABLE_ASH_RANDOM_SUPPORT 2142#if ENABLE_ASH_RANDOM_SUPPORT
2098 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random }, 2143 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
2099#endif 2144#endif
@@ -2114,25 +2159,18 @@ struct globals_var {
2114 int preverrout_fd; /* stderr fd: usually 2, unless redirect moved it */ 2159 int preverrout_fd; /* stderr fd: usually 2, unless redirect moved it */
2115 struct var *vartab[VTABSIZE]; 2160 struct var *vartab[VTABSIZE];
2116 struct var varinit[ARRAY_SIZE(varinit_data)]; 2161 struct var varinit[ARRAY_SIZE(varinit_data)];
2162 int lineno;
2163 char linenovar[sizeof("LINENO=") + sizeof(int)*3];
2117}; 2164};
2118extern struct globals_var *const ash_ptr_to_globals_var; 2165extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var;
2119#define G_var (*ash_ptr_to_globals_var) 2166#define G_var (*ash_ptr_to_globals_var)
2120#define shellparam (G_var.shellparam ) 2167#define shellparam (G_var.shellparam )
2121//#define redirlist (G_var.redirlist ) 2168//#define redirlist (G_var.redirlist )
2122#define preverrout_fd (G_var.preverrout_fd) 2169#define preverrout_fd (G_var.preverrout_fd)
2123#define vartab (G_var.vartab ) 2170#define vartab (G_var.vartab )
2124#define varinit (G_var.varinit ) 2171#define varinit (G_var.varinit )
2125#define INIT_G_var() do { \ 2172#define lineno (G_var.lineno )
2126 unsigned i; \ 2173#define linenovar (G_var.linenovar )
2127 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
2128 barrier(); \
2129 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
2130 varinit[i].flags = varinit_data[i].flags; \
2131 varinit[i].var_text = varinit_data[i].var_text; \
2132 varinit[i].var_func = varinit_data[i].var_func; \
2133 } \
2134} while (0)
2135
2136#define vifs varinit[0] 2174#define vifs varinit[0]
2137#if ENABLE_ASH_MAIL 2175#if ENABLE_ASH_MAIL
2138# define vmail (&vifs)[1] 2176# define vmail (&vifs)[1]
@@ -2146,14 +2184,28 @@ extern struct globals_var *const ash_ptr_to_globals_var;
2146#define vps4 (&vps2)[1] 2184#define vps4 (&vps2)[1]
2147#if ENABLE_ASH_GETOPTS 2185#if ENABLE_ASH_GETOPTS
2148# define voptind (&vps4)[1] 2186# define voptind (&vps4)[1]
2187# define vlineno (&voptind)[1]
2149# if ENABLE_ASH_RANDOM_SUPPORT 2188# if ENABLE_ASH_RANDOM_SUPPORT
2150# define vrandom (&voptind)[1] 2189# define vrandom (&vlineno)[1]
2151# endif 2190# endif
2152#else 2191#else
2192# define vlineno (&vps4)[1]
2153# if ENABLE_ASH_RANDOM_SUPPORT 2193# if ENABLE_ASH_RANDOM_SUPPORT
2154# define vrandom (&vps4)[1] 2194# define vrandom (&vlineno)[1]
2155# endif 2195# endif
2156#endif 2196#endif
2197#define INIT_G_var() do { \
2198 unsigned i; \
2199 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
2200 barrier(); \
2201 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
2202 varinit[i].flags = varinit_data[i].flags; \
2203 varinit[i].var_text = varinit_data[i].var_text; \
2204 varinit[i].var_func = varinit_data[i].var_func; \
2205 } \
2206 strcpy(linenovar, "LINENO="); \
2207 vlineno.var_text = linenovar; \
2208} while (0)
2157 2209
2158/* 2210/*
2159 * The following macros access the values of the above variables. 2211 * The following macros access the values of the above variables.
@@ -2289,8 +2341,12 @@ lookupvar(const char *name)
2289 if (v->flags & VDYNAMIC) 2341 if (v->flags & VDYNAMIC)
2290 v->var_func(NULL); 2342 v->var_func(NULL);
2291#endif 2343#endif
2292 if (!(v->flags & VUNSET)) 2344 if (!(v->flags & VUNSET)) {
2345 if (v == &vlineno && v->var_text == linenovar) {
2346 fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
2347 }
2293 return var_end(v->var_text); 2348 return var_end(v->var_text);
2349 }
2294 } 2350 }
2295 return NULL; 2351 return NULL;
2296} 2352}
@@ -5125,7 +5181,7 @@ cmdtxt(union node *n)
5125 p = "; done"; 5181 p = "; done";
5126 goto dodo; 5182 goto dodo;
5127 case NDEFUN: 5183 case NDEFUN:
5128 cmdputs(n->narg.text); 5184 cmdputs(n->ndefun.text);
5129 p = "() { ... }"; 5185 p = "() { ... }";
5130 goto dotail2; 5186 goto dotail2;
5131 case NCMD: 5187 case NCMD:
@@ -6151,6 +6207,26 @@ ash_arith(const char *s)
6151 return result; 6207 return result;
6152} 6208}
6153#endif 6209#endif
6210#if BASH_SUBSTR
6211# if ENABLE_FEATURE_SH_MATH
6212static int substr_atoi(const char *s)
6213{
6214 arith_t t = ash_arith(s);
6215 if (sizeof(t) > sizeof(int)) {
6216 /* clamp very large or very large negative nums for ${v:N:M}:
6217 * else "${v:0:0x100000001}" would work as "${v:0:1}"
6218 */
6219 if (t > INT_MAX)
6220 t = INT_MAX;
6221 if (t < INT_MIN)
6222 t = INT_MIN;
6223 }
6224 return t;
6225}
6226# else
6227# define substr_atoi(s) number(s)
6228# endif
6229#endif
6154 6230
6155/* 6231/*
6156 * expandarg flags 6232 * expandarg flags
@@ -6182,7 +6258,6 @@ ash_arith(const char *s)
6182#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ 6258#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
6183#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */ 6259#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
6184#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ 6260#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
6185#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
6186 6261
6187/* Add CTLESC when necessary. */ 6262/* Add CTLESC when necessary. */
6188#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT) 6263#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT)
@@ -6363,8 +6438,12 @@ esclen(const char *start, const char *p)
6363/* 6438/*
6364 * Remove any CTLESC characters from a string. 6439 * Remove any CTLESC characters from a string.
6365 */ 6440 */
6441#if !BASH_PATTERN_SUBST
6442#define rmescapes(str, flag, slash_position) \
6443 rmescapes(str, flag)
6444#endif
6366static char * 6445static char *
6367rmescapes(char *str, int flag) 6446rmescapes(char *str, int flag, int *slash_position)
6368{ 6447{
6369 static const char qchars[] ALIGN1 = { 6448 static const char qchars[] ALIGN1 = {
6370 IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' }; 6449 IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
@@ -6373,9 +6452,8 @@ rmescapes(char *str, int flag)
6373 unsigned inquotes; 6452 unsigned inquotes;
6374 unsigned protect_against_glob; 6453 unsigned protect_against_glob;
6375 unsigned globbing; 6454 unsigned globbing;
6376 IF_BASH_PATTERN_SUBST(unsigned slash = flag & RMESCAPE_SLASH;)
6377 6455
6378 p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash)); 6456 p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash_position));
6379 if (!p) 6457 if (!p)
6380 return str; 6458 return str;
6381 6459
@@ -6455,10 +6533,11 @@ rmescapes(char *str, int flag)
6455 goto copy; 6533 goto copy;
6456 } 6534 }
6457#if BASH_PATTERN_SUBST 6535#if BASH_PATTERN_SUBST
6458 else if (*p == '/' && slash) { 6536 else if (slash_position && p == str + *slash_position) {
6459 /* stop handling globbing and mark location of slash */ 6537 /* stop handling globbing */
6460 globbing = slash = 0; 6538 globbing = 0;
6461 *p = CTLESC; 6539 *slash_position = q - r;
6540 slash_position = NULL;
6462 } 6541 }
6463#endif 6542#endif
6464 protect_against_glob = globbing; 6543 protect_against_glob = globbing;
@@ -6482,7 +6561,7 @@ rmescapes(char *str, int flag)
6482static char * 6561static char *
6483preglob(const char *pattern, int flag) 6562preglob(const char *pattern, int flag)
6484{ 6563{
6485 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB); 6564 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB, NULL);
6486} 6565}
6487 6566
6488/* 6567/*
@@ -6837,7 +6916,7 @@ expari(int flag)
6837 expdest = p; 6916 expdest = p;
6838 6917
6839 if (flag & QUOTES_ESC) 6918 if (flag & QUOTES_ESC)
6840 rmescapes(p + 1, 0); 6919 rmescapes(p + 1, 0, NULL);
6841 6920
6842 len = cvtnum(ash_arith(p + 1)); 6921 len = cvtnum(ash_arith(p + 1));
6843 6922
@@ -7125,20 +7204,58 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
7125 char *rmesc, *rmescend; 7204 char *rmesc, *rmescend;
7126 char *str; 7205 char *str;
7127 int amount, resetloc; 7206 int amount, resetloc;
7207 int argstr_flags;
7128 IF_BASH_PATTERN_SUBST(int workloc;) 7208 IF_BASH_PATTERN_SUBST(int workloc;)
7129 IF_BASH_PATTERN_SUBST(char *repl = NULL;) 7209 IF_BASH_PATTERN_SUBST(int slash_pos;)
7210 IF_BASH_PATTERN_SUBST(char *repl;)
7130 int zero; 7211 int zero;
7131 char *(*scan)(char*, char*, char*, char*, int, int); 7212 char *(*scan)(char*, char*, char*, char*, int, int);
7132 7213
7133 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)", 7214 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
7134 // p, varname, strloc, subtype, startloc, varflags, quotes); 7215 // p, varname, strloc, subtype, startloc, varflags, quotes);
7135 7216
7136 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ? 7217#if BASH_PATTERN_SUBST
7137 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0) 7218 /* For "${v/pattern/repl}", we must find the delimiter _before_
7138 ); 7219 * argstr() call expands possible variable references in pattern:
7220 * think about "v=a; a=a/; echo ${v/$a/r}" case.
7221 */
7222 repl = NULL;
7223 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
7224 /* Find '/' and replace with NUL */
7225 repl = p;
7226 for (;;) {
7227 /* Handle escaped slashes, e.g. "${v/\//_}" (they are CTLESC'ed by this point) */
7228 if (*repl == '\0') {
7229 repl = NULL;
7230 break;
7231 }
7232 if (*repl == '/') {
7233 *repl = '\0';
7234 break;
7235 }
7236 if ((unsigned char)*repl == CTLESC && repl[1])
7237 repl++;
7238 repl++;
7239 }
7240 }
7241#endif
7242 argstr_flags = EXP_TILDE;
7243 if (subtype != VSASSIGN && subtype != VSQUESTION)
7244 argstr_flags |= (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE);
7245 argstr(p, argstr_flags);
7246#if BASH_PATTERN_SUBST
7247 slash_pos = -1;
7248 if (repl) {
7249 slash_pos = expdest - ((char *)stackblock() + strloc);
7250 STPUTC('/', expdest);
7251 argstr(repl + 1, argstr_flags);
7252 *repl = '/';
7253 }
7254#endif
7139 STPUTC('\0', expdest); 7255 STPUTC('\0', expdest);
7140 argbackq = saveargbackq; 7256 argbackq = saveargbackq;
7141 startp = (char *)stackblock() + startloc; 7257 startp = (char *)stackblock() + startloc;
7258 //bb_error_msg("str1:'%s'", (char *)stackblock() + strloc);
7142 7259
7143 switch (subtype) { 7260 switch (subtype) {
7144 case VSASSIGN: 7261 case VSASSIGN:
@@ -7158,13 +7275,10 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
7158 7275
7159 loc = str = stackblock() + strloc; 7276 loc = str = stackblock() + strloc;
7160 7277
7161# if !ENABLE_FEATURE_SH_MATH
7162# define ash_arith number
7163# endif
7164 /* Read POS in ${var:POS:LEN} */ 7278 /* Read POS in ${var:POS:LEN} */
7165 colon = strchr(loc, ':'); 7279 colon = strchr(loc, ':');
7166 if (colon) *colon = '\0'; 7280 if (colon) *colon = '\0';
7167 pos = ash_arith(loc); 7281 pos = substr_atoi(loc);
7168 if (colon) *colon = ':'; 7282 if (colon) *colon = ':';
7169 7283
7170 /* Read LEN in ${var:POS:LEN} */ 7284 /* Read LEN in ${var:POS:LEN} */
@@ -7172,7 +7286,6 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
7172 /* *loc != '\0', guaranteed by parser */ 7286 /* *loc != '\0', guaranteed by parser */
7173 if (quotes) { 7287 if (quotes) {
7174 char *ptr; 7288 char *ptr;
7175
7176 /* Adjust the length by the number of escapes */ 7289 /* Adjust the length by the number of escapes */
7177 for (ptr = startp; ptr < (str - 1); ptr++) { 7290 for (ptr = startp; ptr < (str - 1); ptr++) {
7178 if ((unsigned char)*ptr == CTLESC) { 7291 if ((unsigned char)*ptr == CTLESC) {
@@ -7184,19 +7297,15 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
7184 orig_len = len; 7297 orig_len = len;
7185 if (*loc++ == ':') { 7298 if (*loc++ == ':') {
7186 /* ${var::LEN} */ 7299 /* ${var::LEN} */
7187 len = ash_arith(loc); 7300 len = substr_atoi(loc);
7188 } else { 7301 } else {
7189 /* Skip POS in ${var:POS:LEN} */ 7302 /* Skip POS in ${var:POS:LEN} */
7190 len = orig_len; 7303 len = orig_len;
7191 while (*loc && *loc != ':') { 7304 while (*loc && *loc != ':')
7192 loc++; 7305 loc++;
7193 } 7306 if (*loc++ == ':')
7194 if (*loc++ == ':') { 7307 len = substr_atoi(loc);
7195 len = ash_arith(loc);
7196 }
7197 } 7308 }
7198# undef ash_arith
7199
7200 if (pos < 0) { 7309 if (pos < 0) {
7201 /* ${VAR:$((-n)):l} starts n chars from the end */ 7310 /* ${VAR:$((-n)):l} starts n chars from the end */
7202 pos = orig_len + pos; 7311 pos = orig_len + pos;
@@ -7236,6 +7345,8 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
7236 resetloc = expdest - (char *)stackblock(); 7345 resetloc = expdest - (char *)stackblock();
7237 7346
7238#if BASH_PATTERN_SUBST 7347#if BASH_PATTERN_SUBST
7348 repl = NULL;
7349
7239 /* We'll comeback here if we grow the stack while handling 7350 /* We'll comeback here if we grow the stack while handling
7240 * a VSREPLACE or VSREPLACEALL, since our pointers into the 7351 * a VSREPLACE or VSREPLACEALL, since our pointers into the
7241 * stack will need rebasing, and we'll need to remove our work 7352 * stack will need rebasing, and we'll need to remove our work
@@ -7250,8 +7361,10 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
7250 7361
7251 rmesc = startp; 7362 rmesc = startp;
7252 rmescend = (char *)stackblock() + strloc; 7363 rmescend = (char *)stackblock() + strloc;
7364 //bb_error_msg("str7:'%s'", rmescend);
7253 if (quotes) { 7365 if (quotes) {
7254 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW); 7366//TODO: how to handle slash_pos here if string changes (shortens?)
7367 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW, NULL);
7255 if (rmesc != startp) { 7368 if (rmesc != startp) {
7256 rmescend = expdest; 7369 rmescend = expdest;
7257 startp = (char *)stackblock() + startloc; 7370 startp = (char *)stackblock() + startloc;
@@ -7264,12 +7377,13 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
7264 * The result is a_\_z_c (not a\_\_z_c)! 7377 * The result is a_\_z_c (not a\_\_z_c)!
7265 * 7378 *
7266 * The search pattern and replace string treat backslashes differently! 7379 * The search pattern and replace string treat backslashes differently!
7267 * RMESCAPE_SLASH causes preglob to work differently on the pattern 7380 * "&slash_pos" causes rmescapes() to work differently on the pattern
7268 * and string. It's only used on the first call. 7381 * and string. It's only used on the first call.
7269 */ 7382 */
7270 preglob(str, IF_BASH_PATTERN_SUBST( 7383 //bb_error_msg("str8:'%s' slash_pos:%d", str, slash_pos);
7271 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ? 7384 rmescapes(str, RMESCAPE_GLOB,
7272 RMESCAPE_SLASH : ) 0); 7385 repl ? NULL : (slash_pos < 0 ? NULL : &slash_pos)
7386 );
7273 7387
7274#if BASH_PATTERN_SUBST 7388#if BASH_PATTERN_SUBST
7275 workloc = expdest - (char *)stackblock(); 7389 workloc = expdest - (char *)stackblock();
@@ -7278,11 +7392,12 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
7278 char *idx, *end; 7392 char *idx, *end;
7279 7393
7280 if (!repl) { 7394 if (!repl) {
7281 repl = strchr(str, CTLESC); 7395 //bb_error_msg("str9:'%s' slash_pos:%d", str, slash_pos);
7282 if (repl) 7396 repl = nullstr;
7397 if (slash_pos >= 0) {
7398 repl = str + slash_pos;
7283 *repl++ = '\0'; 7399 *repl++ = '\0';
7284 else 7400 }
7285 repl = nullstr;
7286 } 7401 }
7287 //bb_error_msg("str:'%s' repl:'%s'", str, repl); 7402 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
7288 7403
@@ -7802,7 +7917,7 @@ expandmeta(struct strlist *str /*, int flag*/)
7802 INT_ON; 7917 INT_ON;
7803 nometa: 7918 nometa:
7804 *exparg.lastp = str; 7919 *exparg.lastp = str;
7805 rmescapes(str->text, 0); 7920 rmescapes(str->text, 0, NULL);
7806 exparg.lastp = &str->next; 7921 exparg.lastp = &str->next;
7807 break; 7922 break;
7808 default: /* GLOB_NOSPACE */ 7923 default: /* GLOB_NOSPACE */
@@ -8031,7 +8146,7 @@ expandmeta(struct strlist *str /*, int flag*/)
8031 */ 8146 */
8032 nometa: 8147 nometa:
8033 *exparg.lastp = str; 8148 *exparg.lastp = str;
8034 rmescapes(str->text, 0); 8149 rmescapes(str->text, 0, NULL);
8035 exparg.lastp = &str->next; 8150 exparg.lastp = &str->next;
8036 } else { 8151 } else {
8037 *exparg.lastp = NULL; 8152 *exparg.lastp = NULL;
@@ -8970,6 +9085,10 @@ calcsize(union node *n)
8970 IF_PLATFORM_MINGW32(nodeptrsize += 3); 9085 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8971 break; 9086 break;
8972 case NDEFUN: 9087 case NDEFUN:
9088 calcsize(n->ndefun.body);
9089 funcstringsize += strlen(n->ndefun.text) + 1;
9090 IF_PLATFORM_MINGW32(nodeptrsize += 2);
9091 break;
8973 case NARG: 9092 case NARG:
8974 sizenodelist(n->narg.backquote); 9093 sizenodelist(n->narg.backquote);
8975 funcstringsize += strlen(n->narg.text) + 1; 9094 funcstringsize += strlen(n->narg.text) + 1;
@@ -9067,6 +9186,7 @@ copynode(union node *n)
9067 new->ncmd.redirect = copynode(n->ncmd.redirect); 9186 new->ncmd.redirect = copynode(n->ncmd.redirect);
9068 new->ncmd.args = copynode(n->ncmd.args); 9187 new->ncmd.args = copynode(n->ncmd.args);
9069 new->ncmd.assign = copynode(n->ncmd.assign); 9188 new->ncmd.assign = copynode(n->ncmd.assign);
9189 new->ncmd.linno = n->ncmd.linno;
9070 SAVE_PTR3(new->ncmd.redirect,new->ncmd.args, new->ncmd.assign); 9190 SAVE_PTR3(new->ncmd.redirect,new->ncmd.args, new->ncmd.assign);
9071 break; 9191 break;
9072 case NPIPE: 9192 case NPIPE:
@@ -9079,6 +9199,7 @@ copynode(union node *n)
9079 case NSUBSHELL: 9199 case NSUBSHELL:
9080 new->nredir.redirect = copynode(n->nredir.redirect); 9200 new->nredir.redirect = copynode(n->nredir.redirect);
9081 new->nredir.n = copynode(n->nredir.n); 9201 new->nredir.n = copynode(n->nredir.n);
9202 new->nredir.linno = n->nredir.linno;
9082 SAVE_PTR2(new->nredir.redirect,new->nredir.n); 9203 SAVE_PTR2(new->nredir.redirect,new->nredir.n);
9083 break; 9204 break;
9084 case NAND: 9205 case NAND:
@@ -9100,11 +9221,13 @@ copynode(union node *n)
9100 new->nfor.var = nodeckstrdup(n->nfor.var); 9221 new->nfor.var = nodeckstrdup(n->nfor.var);
9101 new->nfor.body = copynode(n->nfor.body); 9222 new->nfor.body = copynode(n->nfor.body);
9102 new->nfor.args = copynode(n->nfor.args); 9223 new->nfor.args = copynode(n->nfor.args);
9224 new->nfor.linno = n->nfor.linno;
9103 SAVE_PTR3(new->nfor.var,new->nfor.body,new->nfor.args); 9225 SAVE_PTR3(new->nfor.var,new->nfor.body,new->nfor.args);
9104 break; 9226 break;
9105 case NCASE: 9227 case NCASE:
9106 new->ncase.cases = copynode(n->ncase.cases); 9228 new->ncase.cases = copynode(n->ncase.cases);
9107 new->ncase.expr = copynode(n->ncase.expr); 9229 new->ncase.expr = copynode(n->ncase.expr);
9230 new->ncase.linno = n->ncase.linno;
9108 SAVE_PTR2(new->ncase.cases,new->ncase.expr); 9231 SAVE_PTR2(new->ncase.cases,new->ncase.expr);
9109 break; 9232 break;
9110 case NCLIST: 9233 case NCLIST:
@@ -9114,6 +9237,11 @@ copynode(union node *n)
9114 SAVE_PTR3(new->nclist.body,new->nclist.pattern,new->nclist.next); 9237 SAVE_PTR3(new->nclist.body,new->nclist.pattern,new->nclist.next);
9115 break; 9238 break;
9116 case NDEFUN: 9239 case NDEFUN:
9240 new->ndefun.body = copynode(n->ndefun.body);
9241 new->ndefun.text = nodeckstrdup(n->ndefun.text);
9242 new->ndefun.linno = n->ndefun.linno;
9243 SAVE_PTR2(new->ndefun.body,new->ndefun.text);
9244 break;
9117 case NARG: 9245 case NARG:
9118 new->narg.backquote = copynodelist(n->narg.backquote); 9246 new->narg.backquote = copynodelist(n->narg.backquote);
9119 new->narg.text = nodeckstrdup(n->narg.text); 9247 new->narg.text = nodeckstrdup(n->narg.text);
@@ -9190,7 +9318,7 @@ defun(union node *func)
9190 INT_OFF; 9318 INT_OFF;
9191 entry.cmdtype = CMDFUNCTION; 9319 entry.cmdtype = CMDFUNCTION;
9192 entry.u.func = copyfunc(func); 9320 entry.u.func = copyfunc(func);
9193 addcmdentry(func->narg.text, &entry); 9321 addcmdentry(func->ndefun.text, &entry);
9194 INT_ON; 9322 INT_ON;
9195} 9323}
9196 9324
@@ -9200,8 +9328,8 @@ defun(union node *func)
9200#define SKIPFUNC (1 << 2) 9328#define SKIPFUNC (1 << 2)
9201static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ 9329static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
9202static int skipcount; /* number of levels to skip */ 9330static int skipcount; /* number of levels to skip */
9203static int funcnest; /* depth of function calls */
9204static int loopnest; /* current loop nesting level */ 9331static int loopnest; /* current loop nesting level */
9332static int funcline; /* starting line number of current function, or 0 if not in a function */
9205 9333
9206/* Forward decl way out to parsing code - dotrap needs it */ 9334/* Forward decl way out to parsing code - dotrap needs it */
9207static int evalstring(char *s, int flags); 9335static int evalstring(char *s, int flags);
@@ -9296,6 +9424,9 @@ evaltree(union node *n, int flags)
9296 status = !evaltree(n->nnot.com, EV_TESTED); 9424 status = !evaltree(n->nnot.com, EV_TESTED);
9297 goto setstatus; 9425 goto setstatus;
9298 case NREDIR: 9426 case NREDIR:
9427 errlinno = lineno = n->nredir.linno;
9428 if (funcline)
9429 lineno -= funcline - 1;
9299 expredir(n->nredir.redirect); 9430 expredir(n->nredir.redirect);
9300 pushredir(n->nredir.redirect); 9431 pushredir(n->nredir.redirect);
9301 status = redirectsafe(n->nredir.redirect, REDIR_PUSH); 9432 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
@@ -9450,6 +9581,10 @@ evalfor(union node *n, int flags)
9450 struct stackmark smark; 9581 struct stackmark smark;
9451 int status = 0; 9582 int status = 0;
9452 9583
9584 errlinno = lineno = n->ncase.linno;
9585 if (funcline)
9586 lineno -= funcline - 1;
9587
9453 setstackmark(&smark); 9588 setstackmark(&smark);
9454 arglist.list = NULL; 9589 arglist.list = NULL;
9455 arglist.lastp = &arglist.list; 9590 arglist.lastp = &arglist.list;
@@ -9481,6 +9616,10 @@ evalcase(union node *n, int flags)
9481 struct stackmark smark; 9616 struct stackmark smark;
9482 int status = 0; 9617 int status = 0;
9483 9618
9619 errlinno = lineno = n->ncase.linno;
9620 if (funcline)
9621 lineno -= funcline - 1;
9622
9484 setstackmark(&smark); 9623 setstackmark(&smark);
9485 arglist.list = NULL; 9624 arglist.list = NULL;
9486 arglist.lastp = &arglist.list; 9625 arglist.lastp = &arglist.list;
@@ -9516,6 +9655,10 @@ evalsubshell(union node *n, int flags)
9516 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */ 9655 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
9517 int status; 9656 int status;
9518 9657
9658 errlinno = lineno = n->nredir.linno;
9659 if (funcline)
9660 lineno -= funcline - 1;
9661
9519 expredir(n->nredir.redirect); 9662 expredir(n->nredir.redirect);
9520 if (!backgnd && (flags & EV_EXIT) && !may_have_traps) 9663 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
9521 goto nofork; 9664 goto nofork;
@@ -9846,8 +9989,10 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
9846 struct jmploc *volatile savehandler; 9989 struct jmploc *volatile savehandler;
9847 struct jmploc jmploc; 9990 struct jmploc jmploc;
9848 int e; 9991 int e;
9992 int savefuncline;
9849 9993
9850 saveparam = shellparam; 9994 saveparam = shellparam;
9995 savefuncline = funcline;
9851 savehandler = exception_handler; 9996 savehandler = exception_handler;
9852 e = setjmp(jmploc.loc); 9997 e = setjmp(jmploc.loc);
9853 if (e) { 9998 if (e) {
@@ -9857,7 +10002,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
9857 exception_handler = &jmploc; 10002 exception_handler = &jmploc;
9858 shellparam.malloced = 0; 10003 shellparam.malloced = 0;
9859 func->count++; 10004 func->count++;
9860 funcnest++; 10005 funcline = func->n.ndefun.linno;
9861 INT_ON; 10006 INT_ON;
9862 shellparam.nparam = argc - 1; 10007 shellparam.nparam = argc - 1;
9863 shellparam.p = argv + 1; 10008 shellparam.p = argv + 1;
@@ -9866,11 +10011,11 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
9866 shellparam.optoff = -1; 10011 shellparam.optoff = -1;
9867#endif 10012#endif
9868 pushlocalvars(); 10013 pushlocalvars();
9869 evaltree(func->n.narg.next, flags & EV_TESTED); 10014 evaltree(func->n.ndefun.body, flags & EV_TESTED);
9870 poplocalvars(0); 10015 poplocalvars(0);
9871 funcdone: 10016 funcdone:
9872 INT_OFF; 10017 INT_OFF;
9873 funcnest--; 10018 funcline = savefuncline;
9874 freefunc(func); 10019 freefunc(func);
9875 freeparam(&shellparam); 10020 freeparam(&shellparam);
9876 shellparam = saveparam; 10021 shellparam = saveparam;
@@ -10235,6 +10380,10 @@ evalcommand(union node *cmd, int flags)
10235 char **nargv; 10380 char **nargv;
10236 smallint cmd_is_exec; 10381 smallint cmd_is_exec;
10237 10382
10383 errlinno = lineno = cmd->ncmd.linno;
10384 if (funcline)
10385 lineno -= funcline - 1;
10386
10238 /* First expand the arguments. */ 10387 /* First expand the arguments. */
10239 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); 10388 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
10240 setstackmark(&smark); 10389 setstackmark(&smark);
@@ -10280,7 +10429,7 @@ evalcommand(union node *cmd, int flags)
10280 *nargv = NULL; 10429 *nargv = NULL;
10281 10430
10282 lastarg = NULL; 10431 lastarg = NULL;
10283 if (iflag && funcnest == 0 && argc > 0) 10432 if (iflag && funcline == 0 && argc > 0)
10284 lastarg = nargv[-1]; 10433 lastarg = nargv[-1];
10285 10434
10286 expredir(cmd->ncmd.redirect); 10435 expredir(cmd->ncmd.redirect);
@@ -10410,7 +10559,9 @@ evalcommand(union node *cmd, int flags)
10410 switch (cmdentry.cmdtype) { 10559 switch (cmdentry.cmdtype) {
10411 default: { 10560 default: {
10412 10561
10413#if ENABLE_FEATURE_SH_NOFORK 10562#if ENABLE_FEATURE_SH_STANDALONE \
10563 && ENABLE_FEATURE_SH_NOFORK \
10564 && NUM_APPLETS > 1
10414/* (1) BUG: if variables are set, we need to fork, or save/restore them 10565/* (1) BUG: if variables are set, we need to fork, or save/restore them
10415 * around run_nofork_applet() call. 10566 * around run_nofork_applet() call.
10416 * (2) Should this check also be done in forkshell()? 10567 * (2) Should this check also be done in forkshell()?
@@ -11341,7 +11492,7 @@ shiftcmd(int argc UNUSED_PARAM, char **argv)
11341 if (argv[1]) 11492 if (argv[1])
11342 n = number(argv[1]); 11493 n = number(argv[1]);
11343 if (n > shellparam.nparam) 11494 if (n > shellparam.nparam)
11344 n = 0; /* bash compat, was = shellparam.nparam; */ 11495 return 1;
11345 INT_OFF; 11496 INT_OFF;
11346 shellparam.nparam -= n; 11497 shellparam.nparam -= n;
11347 for (ap1 = shellparam.p; --n >= 0; ap1++) { 11498 for (ap1 = shellparam.p; --n >= 0; ap1++) {
@@ -11811,7 +11962,7 @@ parsefname(void)
11811 if (quoteflag == 0) 11962 if (quoteflag == 0)
11812 n->type = NXHERE; 11963 n->type = NXHERE;
11813 TRACE(("Here document %d\n", n->type)); 11964 TRACE(("Here document %d\n", n->type));
11814 rmescapes(wordtext, 0); 11965 rmescapes(wordtext, 0, NULL);
11815 here->eofmark = wordtext; 11966 here->eofmark = wordtext;
11816 here->next = NULL; 11967 here->next = NULL;
11817 if (heredoclist == NULL) 11968 if (heredoclist == NULL)
@@ -11836,6 +11987,7 @@ simplecmd(void)
11836 union node *vars, **vpp; 11987 union node *vars, **vpp;
11837 union node **rpp, *redir; 11988 union node **rpp, *redir;
11838 int savecheckkwd; 11989 int savecheckkwd;
11990 int savelinno;
11839#if BASH_TEST2 11991#if BASH_TEST2
11840 smallint double_brackets_flag = 0; 11992 smallint double_brackets_flag = 0;
11841#endif 11993#endif
@@ -11849,6 +12001,7 @@ simplecmd(void)
11849 rpp = &redir; 12001 rpp = &redir;
11850 12002
11851 savecheckkwd = CHKALIAS; 12003 savecheckkwd = CHKALIAS;
12004 savelinno = g_parsefile->linno;
11852 for (;;) { 12005 for (;;) {
11853 int t; 12006 int t;
11854 checkkwd = savecheckkwd; 12007 checkkwd = savecheckkwd;
@@ -11938,7 +12091,9 @@ simplecmd(void)
11938 } 12091 }
11939 n->type = NDEFUN; 12092 n->type = NDEFUN;
11940 checkkwd = CHKNL | CHKKWD | CHKALIAS; 12093 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11941 n->narg.next = parse_command(); 12094 n->ndefun.text = n->narg.text;
12095 n->ndefun.linno = g_parsefile->linno;
12096 n->ndefun.body = parse_command();
11942 return n; 12097 return n;
11943 } 12098 }
11944 IF_BASH_FUNCTION(function_flag = 0;) 12099 IF_BASH_FUNCTION(function_flag = 0;)
@@ -11954,6 +12109,7 @@ simplecmd(void)
11954 *rpp = NULL; 12109 *rpp = NULL;
11955 n = stzalloc(sizeof(struct ncmd)); 12110 n = stzalloc(sizeof(struct ncmd));
11956 n->type = NCMD; 12111 n->type = NCMD;
12112 n->ncmd.linno = savelinno;
11957 n->ncmd.args = args; 12113 n->ncmd.args = args;
11958 n->ncmd.assign = vars; 12114 n->ncmd.assign = vars;
11959 n->ncmd.redirect = redir; 12115 n->ncmd.redirect = redir;
@@ -11969,10 +12125,13 @@ parse_command(void)
11969 union node *redir, **rpp; 12125 union node *redir, **rpp;
11970 union node **rpp2; 12126 union node **rpp2;
11971 int t; 12127 int t;
12128 int savelinno;
11972 12129
11973 redir = NULL; 12130 redir = NULL;
11974 rpp2 = &redir; 12131 rpp2 = &redir;
11975 12132
12133 savelinno = g_parsefile->linno;
12134
11976 switch (readtoken()) { 12135 switch (readtoken()) {
11977 default: 12136 default:
11978 raise_error_unexpected_syntax(-1); 12137 raise_error_unexpected_syntax(-1);
@@ -12023,6 +12182,7 @@ parse_command(void)
12023 raise_error_syntax("bad for loop variable"); 12182 raise_error_syntax("bad for loop variable");
12024 n1 = stzalloc(sizeof(struct nfor)); 12183 n1 = stzalloc(sizeof(struct nfor));
12025 n1->type = NFOR; 12184 n1->type = NFOR;
12185 n1->nfor.linno = savelinno;
12026 n1->nfor.var = wordtext; 12186 n1->nfor.var = wordtext;
12027 checkkwd = CHKNL | CHKKWD | CHKALIAS; 12187 checkkwd = CHKNL | CHKKWD | CHKALIAS;
12028 if (readtoken() == TIN) { 12188 if (readtoken() == TIN) {
@@ -12063,6 +12223,7 @@ parse_command(void)
12063 case TCASE: 12223 case TCASE:
12064 n1 = stzalloc(sizeof(struct ncase)); 12224 n1 = stzalloc(sizeof(struct ncase));
12065 n1->type = NCASE; 12225 n1->type = NCASE;
12226 n1->ncase.linno = savelinno;
12066 if (readtoken() != TWORD) 12227 if (readtoken() != TWORD)
12067 raise_error_unexpected_syntax(TWORD); 12228 raise_error_unexpected_syntax(TWORD);
12068 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg)); 12229 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
@@ -12114,6 +12275,7 @@ parse_command(void)
12114 case TLP: 12275 case TLP:
12115 n1 = stzalloc(sizeof(struct nredir)); 12276 n1 = stzalloc(sizeof(struct nredir));
12116 n1->type = NSUBSHELL; 12277 n1->type = NSUBSHELL;
12278 n1->nredir.linno = savelinno;
12117 n1->nredir.n = list(0); 12279 n1->nredir.n = list(0);
12118 /*n1->nredir.redirect = NULL; - stzalloc did it */ 12280 /*n1->nredir.redirect = NULL; - stzalloc did it */
12119 t = TRP; 12281 t = TRP;
@@ -12147,6 +12309,7 @@ parse_command(void)
12147 if (n1->type != NSUBSHELL) { 12309 if (n1->type != NSUBSHELL) {
12148 n2 = stzalloc(sizeof(struct nredir)); 12310 n2 = stzalloc(sizeof(struct nredir));
12149 n2->type = NREDIR; 12311 n2->type = NREDIR;
12312 n2->nredir.linno = savelinno;
12150 n2->nredir.n = n1; 12313 n2->nredir.n = n1;
12151 n1 = n2; 12314 n1 = n2;
12152 } 12315 }
@@ -12245,10 +12408,8 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
12245 IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */ 12408 IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */
12246 IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */ 12409 IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
12247 int dqvarnest; /* levels of variables expansion within double quotes */ 12410 int dqvarnest; /* levels of variables expansion within double quotes */
12248
12249 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;) 12411 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
12250 12412
12251 startlinno = g_parsefile->linno;
12252 bqlist = NULL; 12413 bqlist = NULL;
12253 quotef = 0; 12414 quotef = 0;
12254 IF_FEATURE_SH_MATH(prevsyntax = 0;) 12415 IF_FEATURE_SH_MATH(prevsyntax = 0;)
@@ -12425,7 +12586,6 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
12425 if (syntax != BASESYNTAX && eofmark == NULL) 12586 if (syntax != BASESYNTAX && eofmark == NULL)
12426 raise_error_syntax("unterminated quoted string"); 12587 raise_error_syntax("unterminated quoted string");
12427 if (varnest != 0) { 12588 if (varnest != 0) {
12428 startlinno = g_parsefile->linno;
12429 /* { */ 12589 /* { */
12430 raise_error_syntax("missing '}'"); 12590 raise_error_syntax("missing '}'");
12431 } 12591 }
@@ -12817,7 +12977,6 @@ parsebackq: {
12817 12977
12818 case PEOF: 12978 case PEOF:
12819 IF_ASH_ALIAS(case PEOA:) 12979 IF_ASH_ALIAS(case PEOA:)
12820 startlinno = g_parsefile->linno;
12821 raise_error_syntax("EOF in backquote substitution"); 12980 raise_error_syntax("EOF in backquote substitution");
12822 12981
12823 case '\n': 12982 case '\n':
@@ -12899,8 +13058,6 @@ parsearith: {
12899 * quoted. 13058 * quoted.
12900 * If the token is TREDIR, then we set redirnode to a structure containing 13059 * If the token is TREDIR, then we set redirnode to a structure containing
12901 * the redirection. 13060 * the redirection.
12902 * In all cases, the variable startlinno is set to the number of the line
12903 * on which the token starts.
12904 * 13061 *
12905 * [Change comment: here documents and internal procedures] 13062 * [Change comment: here documents and internal procedures]
12906 * [Readtoken shouldn't have any arguments. Perhaps we should make the 13063 * [Readtoken shouldn't have any arguments. Perhaps we should make the
@@ -12938,7 +13095,6 @@ xxreadtoken(void)
12938 return lasttoken; 13095 return lasttoken;
12939 } 13096 }
12940 setprompt_if(needprompt, 2); 13097 setprompt_if(needprompt, 2);
12941 startlinno = g_parsefile->linno;
12942 for (;;) { /* until token or start of word found */ 13098 for (;;) { /* until token or start of word found */
12943 c = pgetc(); 13099 c = pgetc();
12944 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA)) 13100 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
@@ -12999,7 +13155,6 @@ xxreadtoken(void)
12999 return lasttoken; 13155 return lasttoken;
13000 } 13156 }
13001 setprompt_if(needprompt, 2); 13157 setprompt_if(needprompt, 2);
13002 startlinno = g_parsefile->linno;
13003 for (;;) { /* until token or start of word found */ 13158 for (;;) { /* until token or start of word found */
13004 c = pgetc(); 13159 c = pgetc();
13005 switch (c) { 13160 switch (c) {
@@ -13391,10 +13546,14 @@ find_dot_file(char *name)
13391 if (fullname != name) 13546 if (fullname != name)
13392 stunalloc(fullname); 13547 stunalloc(fullname);
13393 } 13548 }
13549 /* not found in PATH */
13394 13550
13395 /* not found in the PATH */ 13551#if ENABLE_ASH_BASH_SOURCE_CURDIR
13552 return name;
13553#else
13396 ash_msg_and_raise_error("%s: not found", name); 13554 ash_msg_and_raise_error("%s: not found", name);
13397 /* NOTREACHED */ 13555 /* NOTREACHED */
13556#endif
13398} 13557}
13399 13558
13400static int FAST_FUNC 13559static int FAST_FUNC
@@ -13689,8 +13848,21 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
13689 /* We failed. If there was an entry for this command, delete it */ 13848 /* We failed. If there was an entry for this command, delete it */
13690 if (cmdp && updatetbl) 13849 if (cmdp && updatetbl)
13691 delete_cmd_entry(); 13850 delete_cmd_entry();
13692 if (act & DO_ERR) 13851 if (act & DO_ERR) {
13852#if ENABLE_ASH_BASH_NOT_FOUND_HOOK
13853 struct tblentry *hookp = cmdlookup("command_not_found_handle", 0);
13854 if (hookp && hookp->cmdtype == CMDFUNCTION) {
13855 char *argv[3];
13856 argv[0] = (char*) "command_not_found_handle";
13857 argv[1] = name;
13858 argv[2] = NULL;
13859 evalfun(hookp->param.func, 2, argv, 0);
13860 entry->cmdtype = CMDUNKNOWN;
13861 return;
13862 }
13863#endif
13693 ash_msg("%s: %s", name, errmsg(e, "not found")); 13864 ash_msg("%s: %s", name, errmsg(e, "not found"));
13865 }
13694 entry->cmdtype = CMDUNKNOWN; 13866 entry->cmdtype = CMDUNKNOWN;
13695 return; 13867 return;
13696 13868
diff --git a/shell/ash_LINENO.patch b/shell/ash_LINENO.patch
deleted file mode 100644
index a71549d6a..000000000
--- a/shell/ash_LINENO.patch
+++ /dev/null
@@ -1,498 +0,0 @@
1This patch is a backport from dash of the combination of:
2 [SHELL] Add preliminary LINENO support
3 [VAR] Fix varinit ordering that broke fc
4 [SHELL] Improve LINENO support
5
6Applies cleanly on top of:
7 commit 9832bbaba966f0e52e183f10cd93fad7f8f643fe
8 Date: Tue Aug 15 15:44:41 2017 +0200
9
10Testsuite needs some tweaks (line numbers in some messages change).
11
12Unfortunately, it is somewhat big:
13
14function old new delta
15parse_command 1581 1658 +77
16calcsize 203 272 +69
17copynode 195 257 +62
18lookupvar 59 108 +49
19evaltree 494 534 +40
20evalfor 152 187 +35
21evalcase 278 313 +35
22evalcommand 1547 1581 +34
23evalsubshell 169 199 +30
24linenovar - 22 +22
25raise_error_syntax 11 29 +18
26evalfun 266 280 +14
27varinit_data 96 108 +12
28cmdtxt 626 631 +5
29lineno - 4 +4
30funcline - 4 +4
31ash_vmsg 144 141 -3
32startlinno 4 - -4
33funcnest 4 - -4
34xxreadtoken 272 259 -13
35readtoken1 2635 2594 -41
36------------------------------------------------------------------------------
37(add/remove: 3/2 grow/shrink: 13/3 up/down: 510/-65) Total: 445 bytes
38 text data bss dec hex filename
39 912030 563 5844 918437 e03a5 busybox_old
40 912473 587 5844 918904 e0578 busybox_unstripped
41
42diff --git a/shell/ash.c b/shell/ash.c
43index 703802f..93a3814 100644
44--- a/shell/ash.c
45+++ b/shell/ash.c
46@@ -312,6 +312,8 @@ struct globals_misc {
47 /* shell level: 0 for the main shell, 1 for its children, and so on */
48 int shlvl;
49 #define rootshell (!shlvl)
50+ int errlinno;
51+
52 char *minusc; /* argument to -c option */
53
54 char *curdir; // = nullstr; /* current working directory */
55@@ -389,6 +391,7 @@ extern struct globals_misc *const ash_ptr_to_globals_misc;
56 #define job_warning (G_misc.job_warning)
57 #define rootpid (G_misc.rootpid )
58 #define shlvl (G_misc.shlvl )
59+#define errlinno (G_misc.errlinno )
60 #define minusc (G_misc.minusc )
61 #define curdir (G_misc.curdir )
62 #define physdir (G_misc.physdir )
63@@ -723,6 +726,7 @@ union node;
64
65 struct ncmd {
66 smallint type; /* Nxxxx */
67+ int linno;
68 union node *assign;
69 union node *args;
70 union node *redirect;
71@@ -736,6 +740,7 @@ struct npipe {
72
73 struct nredir {
74 smallint type;
75+ int linno;
76 union node *n;
77 union node *redirect;
78 };
79@@ -755,6 +760,7 @@ struct nif {
80
81 struct nfor {
82 smallint type;
83+ int linno;
84 union node *args;
85 union node *body;
86 char *var;
87@@ -762,6 +768,7 @@ struct nfor {
88
89 struct ncase {
90 smallint type;
91+ int linno;
92 union node *expr;
93 union node *cases;
94 };
95@@ -773,6 +780,13 @@ struct nclist {
96 union node *body;
97 };
98
99+struct ndefun {
100+ smallint type;
101+ int linno;
102+ char *text;
103+ union node *body;
104+};
105+
106 struct narg {
107 smallint type;
108 union node *next;
109@@ -824,6 +838,7 @@ union node {
110 struct nfor nfor;
111 struct ncase ncase;
112 struct nclist nclist;
113+ struct ndefun ndefun;
114 struct narg narg;
115 struct nfile nfile;
116 struct ndup ndup;
117@@ -1253,7 +1268,6 @@ struct parsefile {
118
119 static struct parsefile basepf; /* top level input file */
120 static struct parsefile *g_parsefile = &basepf; /* current input file */
121-static int startlinno; /* line # where last token started */
122 static char *commandname; /* currently executing command */
123
124
125@@ -1267,7 +1281,7 @@ ash_vmsg(const char *msg, va_list ap)
126 if (strcmp(arg0, commandname))
127 fprintf(stderr, "%s: ", commandname);
128 if (!iflag || g_parsefile->pf_fd > 0)
129- fprintf(stderr, "line %d: ", startlinno);
130+ fprintf(stderr, "line %d: ", errlinno);
131 }
132 vfprintf(stderr, msg, ap);
133 newline_and_flush(stderr);
134@@ -1327,6 +1341,7 @@ static void raise_error_syntax(const char *) NORETURN;
135 static void
136 raise_error_syntax(const char *msg)
137 {
138+ errlinno = g_parsefile->linno;
139 ash_msg_and_raise_error("syntax error: %s", msg);
140 /* NOTREACHED */
141 }
142@@ -1993,6 +2008,9 @@ static void changepath(const char *) FAST_FUNC;
143 static void change_random(const char *) FAST_FUNC;
144 #endif
145
146+static int lineno;
147+static char linenovar[sizeof("LINENO=%d") + sizeof(int)*3] = "LINENO=";
148+
149 static const struct {
150 int flags;
151 const char *var_text;
152@@ -2014,6 +2032,7 @@ static const struct {
153 #if ENABLE_ASH_GETOPTS
154 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
155 #endif
156+ { VSTRFIXED|VTEXTFIXED , linenovar , NULL },
157 #if ENABLE_ASH_RANDOM_SUPPORT
158 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
159 #endif
160@@ -2066,12 +2085,14 @@ extern struct globals_var *const ash_ptr_to_globals_var;
161 #define vps4 (&vps2)[1]
162 #if ENABLE_ASH_GETOPTS
163 # define voptind (&vps4)[1]
164+# define vlineno (&voptind)[1]
165 # if ENABLE_ASH_RANDOM_SUPPORT
166-# define vrandom (&voptind)[1]
167+# define vrandom (&vlineno)[1]
168 # endif
169 #else
170+# define vlineno (&vps4)[1]
171 # if ENABLE_ASH_RANDOM_SUPPORT
172-# define vrandom (&vps4)[1]
173+# define vrandom (&vlineno)[1]
174 # endif
175 #endif
176
177@@ -2209,8 +2230,12 @@ lookupvar(const char *name)
178 if (v->flags & VDYNAMIC)
179 v->var_func(NULL);
180 #endif
181- if (!(v->flags & VUNSET))
182+ if (!(v->flags & VUNSET)) {
183+ if (v == &vlineno && v->var_text == linenovar) {
184+ fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
185+ }
186 return var_end(v->var_text);
187+ }
188 }
189 return NULL;
190 }
191@@ -4783,7 +4808,7 @@ cmdtxt(union node *n)
192 p = "; done";
193 goto dodo;
194 case NDEFUN:
195- cmdputs(n->narg.text);
196+ cmdputs(n->ndefun.text);
197 p = "() { ... }";
198 goto dotail2;
199 case NCMD:
200@@ -8551,6 +8576,9 @@ calcsize(int funcblocksize, union node *n)
201 funcblocksize = calcsize(funcblocksize, n->nclist.next);
202 break;
203 case NDEFUN:
204+ funcblocksize = calcsize(funcblocksize, n->ndefun.body);
205+ funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1);
206+ break;
207 case NARG:
208 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
209 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
210@@ -8626,6 +8654,7 @@ copynode(union node *n)
211 new->ncmd.redirect = copynode(n->ncmd.redirect);
212 new->ncmd.args = copynode(n->ncmd.args);
213 new->ncmd.assign = copynode(n->ncmd.assign);
214+ new->ncmd.linno = n->ncmd.linno;
215 break;
216 case NPIPE:
217 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
218@@ -8636,6 +8665,7 @@ copynode(union node *n)
219 case NSUBSHELL:
220 new->nredir.redirect = copynode(n->nredir.redirect);
221 new->nredir.n = copynode(n->nredir.n);
222+ new->nredir.linno = n->nredir.linno;
223 break;
224 case NAND:
225 case NOR:
226@@ -8654,10 +8684,12 @@ copynode(union node *n)
227 new->nfor.var = nodeckstrdup(n->nfor.var);
228 new->nfor.body = copynode(n->nfor.body);
229 new->nfor.args = copynode(n->nfor.args);
230+ new->nfor.linno = n->nfor.linno;
231 break;
232 case NCASE:
233 new->ncase.cases = copynode(n->ncase.cases);
234 new->ncase.expr = copynode(n->ncase.expr);
235+ new->ncase.linno = n->ncase.linno;
236 break;
237 case NCLIST:
238 new->nclist.body = copynode(n->nclist.body);
239@@ -8665,6 +8697,10 @@ copynode(union node *n)
240 new->nclist.next = copynode(n->nclist.next);
241 break;
242 case NDEFUN:
243+ new->ndefun.body = copynode(n->ndefun.body);
244+ new->ndefun.text = nodeckstrdup(n->ndefun.text);
245+ new->ndefun.linno = n->ndefun.linno;
246+ break;
247 case NARG:
248 new->narg.backquote = copynodelist(n->narg.backquote);
249 new->narg.text = nodeckstrdup(n->narg.text);
250@@ -8733,7 +8769,7 @@ defun(union node *func)
251 INT_OFF;
252 entry.cmdtype = CMDFUNCTION;
253 entry.u.func = copyfunc(func);
254- addcmdentry(func->narg.text, &entry);
255+ addcmdentry(func->ndefun.text, &entry);
256 INT_ON;
257 }
258
259@@ -8743,8 +8779,8 @@ defun(union node *func)
260 #define SKIPFUNC (1 << 2)
261 static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
262 static int skipcount; /* number of levels to skip */
263-static int funcnest; /* depth of function calls */
264 static int loopnest; /* current loop nesting level */
265+static int funcline; /* starting line number of current function, or 0 if not in a function */
266
267 /* Forward decl way out to parsing code - dotrap needs it */
268 static int evalstring(char *s, int flags);
269@@ -8839,6 +8875,9 @@ evaltree(union node *n, int flags)
270 status = !evaltree(n->nnot.com, EV_TESTED);
271 goto setstatus;
272 case NREDIR:
273+ errlinno = lineno = n->nredir.linno;
274+ if (funcline)
275+ lineno -= funcline - 1;
276 expredir(n->nredir.redirect);
277 pushredir(n->nredir.redirect);
278 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
279@@ -8993,6 +9032,10 @@ evalfor(union node *n, int flags)
280 struct stackmark smark;
281 int status = 0;
282
283+ errlinno = lineno = n->ncase.linno;
284+ if (funcline)
285+ lineno -= funcline - 1;
286+
287 setstackmark(&smark);
288 arglist.list = NULL;
289 arglist.lastp = &arglist.list;
290@@ -9024,6 +9067,10 @@ evalcase(union node *n, int flags)
291 struct stackmark smark;
292 int status = 0;
293
294+ errlinno = lineno = n->ncase.linno;
295+ if (funcline)
296+ lineno -= funcline - 1;
297+
298 setstackmark(&smark);
299 arglist.list = NULL;
300 arglist.lastp = &arglist.list;
301@@ -9058,6 +9105,10 @@ evalsubshell(union node *n, int flags)
302 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
303 int status;
304
305+ errlinno = lineno = n->nredir.linno;
306+ if (funcline)
307+ lineno -= funcline - 1;
308+
309 expredir(n->nredir.redirect);
310 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
311 goto nofork;
312@@ -9365,8 +9416,10 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
313 struct jmploc *volatile savehandler;
314 struct jmploc jmploc;
315 int e;
316+ int savefuncline;
317
318 saveparam = shellparam;
319+ savefuncline = funcline;
320 savehandler = exception_handler;
321 e = setjmp(jmploc.loc);
322 if (e) {
323@@ -9376,7 +9429,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
324 exception_handler = &jmploc;
325 shellparam.malloced = 0;
326 func->count++;
327- funcnest++;
328+ funcline = func->n.ndefun.linno;
329 INT_ON;
330 shellparam.nparam = argc - 1;
331 shellparam.p = argv + 1;
332@@ -9385,11 +9438,11 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
333 shellparam.optoff = -1;
334 #endif
335 pushlocalvars();
336- evaltree(func->n.narg.next, flags & EV_TESTED);
337+ evaltree(func->n.ndefun.body, flags & EV_TESTED);
338 poplocalvars(0);
339 funcdone:
340 INT_OFF;
341- funcnest--;
342+ funcline = savefuncline;
343 freefunc(func);
344 freeparam(&shellparam);
345 shellparam = saveparam;
346@@ -9753,6 +9806,10 @@ evalcommand(union node *cmd, int flags)
347 char **nargv;
348 smallint cmd_is_exec;
349
350+ errlinno = lineno = cmd->ncmd.linno;
351+ if (funcline)
352+ lineno -= funcline - 1;
353+
354 /* First expand the arguments. */
355 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
356 setstackmark(&smark);
357@@ -9798,7 +9855,7 @@ evalcommand(union node *cmd, int flags)
358 *nargv = NULL;
359
360 lastarg = NULL;
361- if (iflag && funcnest == 0 && argc > 0)
362+ if (iflag && funcline == 0 && argc > 0)
363 lastarg = nargv[-1];
364
365 expredir(cmd->ncmd.redirect);
366@@ -11317,6 +11374,7 @@ simplecmd(void)
367 union node *vars, **vpp;
368 union node **rpp, *redir;
369 int savecheckkwd;
370+ int savelinno;
371 #if BASH_TEST2
372 smallint double_brackets_flag = 0;
373 #endif
374@@ -11330,6 +11388,7 @@ simplecmd(void)
375 rpp = &redir;
376
377 savecheckkwd = CHKALIAS;
378+ savelinno = g_parsefile->linno;
379 for (;;) {
380 int t;
381 checkkwd = savecheckkwd;
382@@ -11419,7 +11478,9 @@ simplecmd(void)
383 }
384 n->type = NDEFUN;
385 checkkwd = CHKNL | CHKKWD | CHKALIAS;
386- n->narg.next = parse_command();
387+ n->ndefun.text = n->narg.text;
388+ n->ndefun.linno = g_parsefile->linno;
389+ n->ndefun.body = parse_command();
390 return n;
391 }
392 IF_BASH_FUNCTION(function_flag = 0;)
393@@ -11435,6 +11496,7 @@ simplecmd(void)
394 *rpp = NULL;
395 n = stzalloc(sizeof(struct ncmd));
396 n->type = NCMD;
397+ n->ncmd.linno = savelinno;
398 n->ncmd.args = args;
399 n->ncmd.assign = vars;
400 n->ncmd.redirect = redir;
401@@ -11450,10 +11512,13 @@ parse_command(void)
402 union node *redir, **rpp;
403 union node **rpp2;
404 int t;
405+ int savelinno;
406
407 redir = NULL;
408 rpp2 = &redir;
409
410+ savelinno = g_parsefile->linno;
411+
412 switch (readtoken()) {
413 default:
414 raise_error_unexpected_syntax(-1);
415@@ -11504,6 +11569,7 @@ parse_command(void)
416 raise_error_syntax("bad for loop variable");
417 n1 = stzalloc(sizeof(struct nfor));
418 n1->type = NFOR;
419+ n1->nfor.linno = savelinno;
420 n1->nfor.var = wordtext;
421 checkkwd = CHKNL | CHKKWD | CHKALIAS;
422 if (readtoken() == TIN) {
423@@ -11544,6 +11610,7 @@ parse_command(void)
424 case TCASE:
425 n1 = stzalloc(sizeof(struct ncase));
426 n1->type = NCASE;
427+ n1->ncase.linno = savelinno;
428 if (readtoken() != TWORD)
429 raise_error_unexpected_syntax(TWORD);
430 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
431@@ -11595,6 +11662,7 @@ parse_command(void)
432 case TLP:
433 n1 = stzalloc(sizeof(struct nredir));
434 n1->type = NSUBSHELL;
435+ n1->nredir.linno = savelinno;
436 n1->nredir.n = list(0);
437 /*n1->nredir.redirect = NULL; - stzalloc did it */
438 t = TRP;
439@@ -11628,6 +11696,7 @@ parse_command(void)
440 if (n1->type != NSUBSHELL) {
441 n2 = stzalloc(sizeof(struct nredir));
442 n2->type = NREDIR;
443+ n2->nredir.linno = savelinno;
444 n2->nredir.n = n1;
445 n1 = n2;
446 }
447@@ -11726,10 +11795,8 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
448 IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */
449 IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
450 int dqvarnest; /* levels of variables expansion within double quotes */
451-
452 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
453
454- startlinno = g_parsefile->linno;
455 bqlist = NULL;
456 quotef = 0;
457 IF_FEATURE_SH_MATH(prevsyntax = 0;)
458@@ -11906,7 +11973,6 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
459 if (syntax != BASESYNTAX && eofmark == NULL)
460 raise_error_syntax("unterminated quoted string");
461 if (varnest != 0) {
462- startlinno = g_parsefile->linno;
463 /* { */
464 raise_error_syntax("missing '}'");
465 }
466@@ -12298,7 +12364,6 @@ parsebackq: {
467
468 case PEOF:
469 IF_ASH_ALIAS(case PEOA:)
470- startlinno = g_parsefile->linno;
471 raise_error_syntax("EOF in backquote substitution");
472
473 case '\n':
474@@ -12380,8 +12445,6 @@ parsearith: {
475 * quoted.
476 * If the token is TREDIR, then we set redirnode to a structure containing
477 * the redirection.
478- * In all cases, the variable startlinno is set to the number of the line
479- * on which the token starts.
480 *
481 * [Change comment: here documents and internal procedures]
482 * [Readtoken shouldn't have any arguments. Perhaps we should make the
483@@ -12419,7 +12482,6 @@ xxreadtoken(void)
484 return lasttoken;
485 }
486 setprompt_if(needprompt, 2);
487- startlinno = g_parsefile->linno;
488 for (;;) { /* until token or start of word found */
489 c = pgetc();
490 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
491@@ -12480,7 +12542,6 @@ xxreadtoken(void)
492 return lasttoken;
493 }
494 setprompt_if(needprompt, 2);
495- startlinno = g_parsefile->linno;
496 for (;;) { /* until token or start of word found */
497 c = pgetc();
498 switch (c) {
diff --git a/shell/ash_test/ash-arith/arith-postinc.right b/shell/ash_test/ash-arith/arith-postinc.right
new file mode 100644
index 000000000..c95ce02bf
--- /dev/null
+++ b/shell/ash_test/ash-arith/arith-postinc.right
@@ -0,0 +1,5 @@
11 1
21 1
31 1
41 1
5Ok:0
diff --git a/shell/ash_test/ash-arith/arith-postinc.tests b/shell/ash_test/ash-arith/arith-postinc.tests
new file mode 100755
index 000000000..3fd9bfed5
--- /dev/null
+++ b/shell/ash_test/ash-arith/arith-postinc.tests
@@ -0,0 +1,5 @@
1echo 1 $((0++1))
2echo 1 $((0--1))
3x=-1; echo 1 $((0-$x))
4x=+1; echo 1 $((0+$x))
5echo Ok:$?
diff --git a/shell/ash_test/ash-arith/arith.right b/shell/ash_test/ash-arith/arith.right
index 9b9ca8e2f..6936f1269 100644
--- a/shell/ash_test/ash-arith/arith.right
+++ b/shell/ash_test/ash-arith/arith.right
@@ -126,6 +126,10 @@ ghi
126./arith2.sub: line 5: arithmetic syntax error 126./arith2.sub: line 5: arithmetic syntax error
1275 5 1275 5
1281 1 1281 1
1296 6
1302 2
1313 3
1321 1
1294 4 1334 4
1300 0 1340 0
131./arith2.sub: line 42: arithmetic syntax error 135./arith2.sub: line 42: arithmetic syntax error
diff --git a/shell/ash_test/ash-arith/arith2.sub b/shell/ash_test/ash-arith/arith2.sub
index f7e3c9235..9105059db 100755
--- a/shell/ash_test/ash-arith/arith2.sub
+++ b/shell/ash_test/ash-arith/arith2.sub
@@ -23,14 +23,14 @@
23echo 5 $(( 4 + ++a )) 23echo 5 $(( 4 + ++a ))
24echo 1 $a 24echo 1 $a
25 25
26# ash doesn't handle it right... 26# this is treated as 4 + ++a
27#ash# echo 6 $(( 4+++a )) 27echo 6 $(( 4+++a ))
28#ash# echo 2 $a 28echo 2 $a
29 a=2 29 a=2
30 30
31# ash doesn't handle it right... 31# this is treated as 4 - --a
32#ash# echo 3 $(( 4---a )) 32echo 3 $(( 4---a ))
33#ash# echo 1 $a 33echo 1 $a
34 a=1 34 a=1
35 35
36echo 4 $(( 4 - -- a )) 36echo 4 $(( 4 - -- a ))
diff --git a/shell/ash_test/ash-misc/control_char1.right b/shell/ash_test/ash-misc/control_char1.right
new file mode 100644
index 000000000..6f8c2533c
--- /dev/null
+++ b/shell/ash_test/ash-misc/control_char1.right
@@ -0,0 +1,3 @@
1
2b#c
3Done:0
diff --git a/shell/ash_test/ash-misc/control_char1.tests b/shell/ash_test/ash-misc/control_char1.tests
new file mode 100755
index 000000000..0cfe60141
--- /dev/null
+++ b/shell/ash_test/ash-misc/control_char1.tests
@@ -0,0 +1,3 @@
1echo 
2echo 'b#c'
3echo Done:$?
diff --git a/shell/ash_test/ash-misc/control_char2.right b/shell/ash_test/ash-misc/control_char2.right
new file mode 100644
index 000000000..9498b420d
--- /dev/null
+++ b/shell/ash_test/ash-misc/control_char2.right
@@ -0,0 +1,2 @@
1
2Done:0
diff --git a/shell/ash_test/ash-misc/control_char2.tests b/shell/ash_test/ash-misc/control_char2.tests
new file mode 100755
index 000000000..e77d7a1a6
--- /dev/null
+++ b/shell/ash_test/ash-misc/control_char2.tests
@@ -0,0 +1,3 @@
1c=`printf '\3'`
2eval "echo $c"
3echo Done:$?
diff --git a/shell/ash_test/ash-misc/for_with_bslashes.right b/shell/ash_test/ash-misc/for_with_bslashes.right
index 02d96692c..cd8501050 100644
--- a/shell/ash_test/ash-misc/for_with_bslashes.right
+++ b/shell/ash_test/ash-misc/for_with_bslashes.right
@@ -5,4 +5,5 @@ b"c
5b'c 5b'c
6b$c 6b$c
7b`true`c 7b`true`c
8b#c
8Zero:0 9Zero:0
diff --git a/shell/ash_test/ash-misc/for_with_bslashes.tests b/shell/ash_test/ash-misc/for_with_bslashes.tests
index 363f3d85b..8acd9808a 100755
--- a/shell/ash_test/ash-misc/for_with_bslashes.tests
+++ b/shell/ash_test/ash-misc/for_with_bslashes.tests
@@ -1,9 +1,5 @@
1# UNFIXED BUG. 1# last word contains ^C character.
2# commented-out words contain ^C character. 2for a in 'a' 'b\c' 'b\\c' 'b"c' "b'c" 'b$c' 'b`true`c' 'b#c'
3# It's a SPECIAL_VAR_SYMBOL, for now hush does not escape it.
4# When it is fixed, update this test.
5
6for a in 'a' 'b\c' 'b\\c' 'b"c' "b'c" 'b$c' 'b`true`c' ### 'b#c'
7do 3do
8 echo $a 4 echo $a
9done 5done
diff --git a/shell/ash_test/ash-psubst/emptytick.right b/shell/ash_test/ash-psubst/emptytick.right
index 7629deba6..459c4f735 100644
--- a/shell/ash_test/ash-psubst/emptytick.right
+++ b/shell/ash_test/ash-psubst/emptytick.right
@@ -1,8 +1,8 @@
10 10
20 20
3./emptytick.tests: line 3: : Permission denied 3./emptytick.tests: line 1: : Permission denied
4127 4127
5./emptytick.tests: line 4: : Permission denied 5./emptytick.tests: line 1: : Permission denied
6127 6127
70 70
80 80
diff --git a/shell/ash_test/ash-quoting/mode_x.right b/shell/ash_test/ash-quoting/mode_x.right
index c2dd3550c..d1f670af6 100644
--- a/shell/ash_test/ash-quoting/mode_x.right
+++ b/shell/ash_test/ash-quoting/mode_x.right
@@ -3,8 +3,8 @@
3+ true '%s\n' one 'two '"'"'three' four 3+ true '%s\n' one 'two '"'"'three' four
4+ this=command 4+ this=command
5+ 'this=command' 5+ 'this=command'
6./mode_x.tests: line 1: this=command: not found 6./mode_x.tests: line 10: this=command: not found
7+ true 7+ true
8+ true 8+ true
9+ 'if' true 9+ 'if' true
10./mode_x.tests: line 1: if: not found 10./mode_x.tests: line 14: if: not found
diff --git a/shell/ash_test/ash-vars/param_expand_bash_substring.right b/shell/ash_test/ash-vars/param_expand_bash_substring.right
index 9ad6dbcad..687dd9002 100644
--- a/shell/ash_test/ash-vars/param_expand_bash_substring.right
+++ b/shell/ash_test/ash-vars/param_expand_bash_substring.right
@@ -3,6 +3,7 @@ SHELL: line 1: syntax error: bad substitution
3SHELL: line 1: syntax error: bad substitution 3SHELL: line 1: syntax error: bad substitution
4SHELL: line 1: syntax error: bad substitution 4SHELL: line 1: syntax error: bad substitution
5SHELL: line 1: syntax error: missing '}' 5SHELL: line 1: syntax error: missing '}'
60
61 =|| 71 =||
71:1 =|| 81:1 =||
81:1:2=|| 91:1:2=||
diff --git a/shell/ash_test/ash-vars/param_expand_bash_substring.tests b/shell/ash_test/ash-vars/param_expand_bash_substring.tests
index cce9f123e..512da351b 100755
--- a/shell/ash_test/ash-vars/param_expand_bash_substring.tests
+++ b/shell/ash_test/ash-vars/param_expand_bash_substring.tests
@@ -11,7 +11,7 @@ export var=0123456789
11"$THIS_SH" -c 'echo ${var:}' SHELL 11"$THIS_SH" -c 'echo ${var:}' SHELL
12 12
13# then some funky ones 13# then some funky ones
14# UNFIXED BUG: this should work: "$THIS_SH" -c 'echo ${?:0}' 14"$THIS_SH" -c 'echo ${?:0}' SHELL
15 15
16# now some valid ones 16# now some valid ones
17set --; echo "1 =|${1}|" 17set --; echo "1 =|${1}|"
diff --git a/shell/ash_test/ash-vars/var_bash_repl_empty_pattern.right b/shell/ash_test/ash-vars/var_bash_repl_empty_pattern.right
new file mode 100644
index 000000000..d400a7e31
--- /dev/null
+++ b/shell/ash_test/ash-vars/var_bash_repl_empty_pattern.right
@@ -0,0 +1,2 @@
1v
2Ok:0
diff --git a/shell/ash_test/ash-vars/var_bash_repl_empty_pattern.tests b/shell/ash_test/ash-vars/var_bash_repl_empty_pattern.tests
new file mode 100755
index 000000000..6e8aa2afa
--- /dev/null
+++ b/shell/ash_test/ash-vars/var_bash_repl_empty_pattern.tests
@@ -0,0 +1,3 @@
1v=v
2echo ${v//}
3echo Ok:$?
diff --git a/shell/ash_test/ash-vars/var_bash_repl_empty_var.right b/shell/ash_test/ash-vars/var_bash_repl_empty_var.right
new file mode 100644
index 000000000..892916783
--- /dev/null
+++ b/shell/ash_test/ash-vars/var_bash_repl_empty_var.right
@@ -0,0 +1,2 @@
1
2Ok:0
diff --git a/shell/ash_test/ash-vars/var_bash_repl_empty_var.tests b/shell/ash_test/ash-vars/var_bash_repl_empty_var.tests
new file mode 100755
index 000000000..73a43d38e
--- /dev/null
+++ b/shell/ash_test/ash-vars/var_bash_repl_empty_var.tests
@@ -0,0 +1,3 @@
1v=''
2echo ${v/*/w}
3echo Ok:$?
diff --git a/shell/hush.c b/shell/hush.c
index 708555ac4..8f1017e3c 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -47,17 +47,13 @@
47 * follow IFS rules more precisely, including update semantics 47 * follow IFS rules more precisely, including update semantics
48 * tilde expansion 48 * tilde expansion
49 * aliases 49 * aliases
50 * builtins mandated by standards we don't support: 50 * "command" missing features:
51 * [un]alias, command, fc: 51 * command -p CMD: run CMD using default $PATH
52 * command -v CMD: print "/path/to/CMD" 52 * (can use this to override standalone shell as well?)
53 * prints "CMD" for builtins
54 * prints "alias ALIAS='EXPANSION'" for aliases
55 * prints nothing and sets $? to 1 if not found
56 * command -V CMD: print "CMD is /path/CMD|a shell builtin|etc"
57 * command [-p] CMD: run CMD, even if a function CMD also exists
58 * (can use this to override standalone shell as well)
59 * -p: use default $PATH
60 * command BLTIN: disables special-ness (e.g. errors do not abort) 53 * command BLTIN: disables special-ness (e.g. errors do not abort)
54 * command -V CMD1 CMD2 CMD3 (multiple args) (not in standard)
55 * builtins mandated by standards we don't support:
56 * [un]alias, fc:
61 * fc -l[nr] [BEG] [END]: list range of commands in history 57 * fc -l[nr] [BEG] [END]: list range of commands in history
62 * fc [-e EDITOR] [BEG] [END]: edit/rerun range of commands 58 * fc [-e EDITOR] [BEG] [END]: edit/rerun range of commands
63 * fc -s [PAT=REP] [CMD]: rerun CMD, replacing PAT with REP 59 * fc -s [PAT=REP] [CMD]: rerun CMD, replacing PAT with REP
@@ -124,6 +120,18 @@
124//config: help 120//config: help
125//config: Enable {abc,def} extension. 121//config: Enable {abc,def} extension.
126//config: 122//config:
123//config:config HUSH_LINENO_VAR
124//config: bool "$LINENO variable"
125//config: default y
126//config: depends on HUSH_BASH_COMPAT
127//config:
128//config:config HUSH_BASH_SOURCE_CURDIR
129//config: bool "'source' and '.' builtins search current directory after $PATH"
130//config: default n # do not encourage non-standard behavior
131//config: depends on HUSH_BASH_COMPAT
132//config: help
133//config: This is not compliant with standards. Avoid if possible.
134//config:
127//config:config HUSH_INTERACTIVE 135//config:config HUSH_INTERACTIVE
128//config: bool "Interactive mode" 136//config: bool "Interactive mode"
129//config: default y 137//config: default y
@@ -253,6 +261,11 @@
253//config: default y 261//config: default y
254//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 262//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH
255//config: 263//config:
264//config:config HUSH_COMMAND
265//config: bool "command builtin"
266//config: default y
267//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH
268//config:
256//config:config HUSH_TRAP 269//config:config HUSH_TRAP
257//config: bool "trap builtin" 270//config: bool "trap builtin"
258//config: default y 271//config: default y
@@ -462,7 +475,10 @@
462# define MINUS_PLUS_EQUAL_QUESTION ("%#:-=+?" + 3) 475# define MINUS_PLUS_EQUAL_QUESTION ("%#:-=+?" + 3)
463#endif 476#endif
464 477
465#define SPECIAL_VAR_SYMBOL 3 478#define SPECIAL_VAR_SYMBOL_STR "\3"
479#define SPECIAL_VAR_SYMBOL 3
480/* The "variable" with name "\1" emits string "\3". Testcase: "echo ^C" */
481#define SPECIAL_VAR_QUOTED_SVS 1
466 482
467struct variable; 483struct variable;
468 484
@@ -608,6 +624,9 @@ typedef enum redir_type {
608struct command { 624struct command {
609 pid_t pid; /* 0 if exited */ 625 pid_t pid; /* 0 if exited */
610 int assignment_cnt; /* how many argv[i] are assignments? */ 626 int assignment_cnt; /* how many argv[i] are assignments? */
627#if ENABLE_HUSH_LINENO_VAR
628 unsigned lineno;
629#endif
611 smallint cmd_type; /* CMD_xxx */ 630 smallint cmd_type; /* CMD_xxx */
612#define CMD_NORMAL 0 631#define CMD_NORMAL 0
613#define CMD_SUBSHELL 1 632#define CMD_SUBSHELL 1
@@ -927,6 +946,10 @@ struct globals {
927 unsigned handled_SIGCHLD; 946 unsigned handled_SIGCHLD;
928 smallint we_have_children; 947 smallint we_have_children;
929#endif 948#endif
949#if ENABLE_HUSH_LINENO_VAR
950 unsigned lineno;
951 char *lineno_var;
952#endif
930 struct FILE_list *FILE_list; 953 struct FILE_list *FILE_list;
931 /* Which signals have non-DFL handler (even with no traps set)? 954 /* Which signals have non-DFL handler (even with no traps set)?
932 * Set at the start to: 955 * Set at the start to:
@@ -1924,7 +1947,7 @@ static void hush_exit(int exitcode)
1924 if (G.exiting <= 0 && G_traps && G_traps[0] && G_traps[0][0]) { 1947 if (G.exiting <= 0 && G_traps && G_traps[0] && G_traps[0][0]) {
1925 char *argv[3]; 1948 char *argv[3];
1926 /* argv[0] is unused */ 1949 /* argv[0] is unused */
1927 argv[1] = G_traps[0]; 1950 argv[1] = xstrdup(G_traps[0]); /* copy, since EXIT trap handler may modify G_traps[0] */
1928 argv[2] = NULL; 1951 argv[2] = NULL;
1929 G.exiting = 1; /* prevent EXIT trap recursion */ 1952 G.exiting = 1; /* prevent EXIT trap recursion */
1930 /* Note: G_traps[0] is not cleared! 1953 /* Note: G_traps[0] is not cleared!
@@ -1985,10 +2008,12 @@ static int check_and_run_traps(void)
1985 smalluint save_rcode; 2008 smalluint save_rcode;
1986 char *argv[3]; 2009 char *argv[3];
1987 /* argv[0] is unused */ 2010 /* argv[0] is unused */
1988 argv[1] = G_traps[sig]; 2011 argv[1] = xstrdup(G_traps[sig]);
2012 /* why strdup? trap can modify itself: trap 'trap "echo oops" INT' INT */
1989 argv[2] = NULL; 2013 argv[2] = NULL;
1990 save_rcode = G.last_exitcode; 2014 save_rcode = G.last_exitcode;
1991 builtin_eval(argv); 2015 builtin_eval(argv);
2016 free(argv[1]);
1992//FIXME: shouldn't it be set to 128 + sig instead? 2017//FIXME: shouldn't it be set to 128 + sig instead?
1993 G.last_exitcode = save_rcode; 2018 G.last_exitcode = save_rcode;
1994 last_sig = sig; 2019 last_sig = sig;
@@ -2131,6 +2156,13 @@ static int set_local_var(char *str, unsigned flags)
2131 } 2156 }
2132 2157
2133 name_len = eq_sign - str + 1; /* including '=' */ 2158 name_len = eq_sign - str + 1; /* including '=' */
2159#if ENABLE_HUSH_LINENO_VAR
2160 if (G.lineno_var) {
2161 if (name_len == 7 && strncmp("LINENO", str, 6) == 0)
2162 G.lineno_var = NULL;
2163 }
2164#endif
2165
2134 var_pp = &G.top_var; 2166 var_pp = &G.top_var;
2135 while ((cur = *var_pp) != NULL) { 2167 while ((cur = *var_pp) != NULL) {
2136 if (strncmp(cur->varstr, str, name_len) != 0) { 2168 if (strncmp(cur->varstr, str, name_len) != 0) {
@@ -2252,10 +2284,16 @@ static int unset_local_var_len(const char *name, int name_len)
2252 2284
2253 if (!name) 2285 if (!name)
2254 return EXIT_SUCCESS; 2286 return EXIT_SUCCESS;
2287
2255#if ENABLE_HUSH_GETOPTS 2288#if ENABLE_HUSH_GETOPTS
2256 if (name_len == 6 && strncmp(name, "OPTIND", 6) == 0) 2289 if (name_len == 6 && strncmp(name, "OPTIND", 6) == 0)
2257 G.getopt_count = 0; 2290 G.getopt_count = 0;
2258#endif 2291#endif
2292#if ENABLE_HUSH_LINENO_VAR
2293 if (name_len == 6 && G.lineno_var && strncmp(name, "LINENO", 6) == 0)
2294 G.lineno_var = NULL;
2295#endif
2296
2259 var_pp = &G.top_var; 2297 var_pp = &G.top_var;
2260 while ((cur = *var_pp) != NULL) { 2298 while ((cur = *var_pp) != NULL) {
2261 if (strncmp(cur->varstr, name, name_len) == 0 && cur->varstr[name_len] == '=') { 2299 if (strncmp(cur->varstr, name, name_len) == 0 && cur->varstr[name_len] == '=') {
@@ -2278,7 +2316,7 @@ static int unset_local_var_len(const char *name, int name_len)
2278 return EXIT_SUCCESS; 2316 return EXIT_SUCCESS;
2279} 2317}
2280 2318
2281#if ENABLE_HUSH_UNSET 2319#if ENABLE_HUSH_UNSET || ENABLE_HUSH_GETOPTS
2282static int unset_local_var(const char *name) 2320static int unset_local_var(const char *name)
2283{ 2321{
2284 return unset_local_var_len(name, strlen(name)); 2322 return unset_local_var_len(name, strlen(name));
@@ -2300,7 +2338,7 @@ static void unset_vars(char **strings)
2300 free(strings); 2338 free(strings);
2301} 2339}
2302 2340
2303#if BASH_HOSTNAME_VAR || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_READ 2341#if BASH_HOSTNAME_VAR || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_READ || ENABLE_HUSH_GETOPTS
2304static void FAST_FUNC set_local_var_from_halves(const char *name, const char *val) 2342static void FAST_FUNC set_local_var_from_halves(const char *name, const char *val)
2305{ 2343{
2306 char *var = xasprintf("%s=%s", name, val); 2344 char *var = xasprintf("%s=%s", name, val);
@@ -2574,6 +2612,12 @@ static int i_getch(struct in_str *i)
2574 out: 2612 out:
2575 debug_printf("file_get: got '%c' %d\n", ch, ch); 2613 debug_printf("file_get: got '%c' %d\n", ch, ch);
2576 i->last_char = ch; 2614 i->last_char = ch;
2615#if ENABLE_HUSH_LINENO_VAR
2616 if (ch == '\n') {
2617 G.lineno++;
2618 debug_printf_parse("G.lineno++ = %u\n", G.lineno);
2619 }
2620#endif
2577 return ch; 2621 return ch;
2578} 2622}
2579 2623
@@ -3374,8 +3418,13 @@ static void debug_print_tree(struct pipe *pi, int lvl)
3374 3418
3375 pin = 0; 3419 pin = 0;
3376 while (pi) { 3420 while (pi) {
3377 fdprintf(2, "%*spipe %d res_word=%s followup=%d %s\n", lvl*2, "", 3421 fdprintf(2, "%*spipe %d %sres_word=%s followup=%d %s\n",
3378 pin, RES[pi->res_word], pi->followup, PIPE[pi->followup]); 3422 lvl*2, "",
3423 pin,
3424 (IF_HAS_KEYWORDS(pi->pi_inverted ? "! " :) ""),
3425 RES[pi->res_word],
3426 pi->followup, PIPE[pi->followup]
3427 );
3379 prn = 0; 3428 prn = 0;
3380 while (prn < pi->num_cmds) { 3429 while (prn < pi->num_cmds) {
3381 struct command *command = &pi->cmds[prn]; 3430 struct command *command = &pi->cmds[prn];
@@ -3384,6 +3433,9 @@ static void debug_print_tree(struct pipe *pi, int lvl)
3384 fdprintf(2, "%*s cmd %d assignment_cnt:%d", 3433 fdprintf(2, "%*s cmd %d assignment_cnt:%d",
3385 lvl*2, "", prn, 3434 lvl*2, "", prn,
3386 command->assignment_cnt); 3435 command->assignment_cnt);
3436#if ENABLE_HUSH_LINENO_VAR
3437 fdprintf(2, " LINENO:%u", command->lineno);
3438#endif
3387 if (command->group) { 3439 if (command->group) {
3388 fdprintf(2, " group %s: (argv=%p)%s%s\n", 3440 fdprintf(2, " group %s: (argv=%p)%s%s\n",
3389 CMDTYPE[command->cmd_type], 3441 CMDTYPE[command->cmd_type],
@@ -3456,6 +3508,10 @@ static int done_command(struct parse_context *ctx)
3456 ctx->command = command = &pi->cmds[pi->num_cmds]; 3508 ctx->command = command = &pi->cmds[pi->num_cmds];
3457 clear_and_ret: 3509 clear_and_ret:
3458 memset(command, 0, sizeof(*command)); 3510 memset(command, 0, sizeof(*command));
3511#if ENABLE_HUSH_LINENO_VAR
3512 command->lineno = G.lineno;
3513 debug_printf_parse("command->lineno = G.lineno (%u)\n", G.lineno);
3514#endif
3459 return pi->num_cmds; /* used only for 0/nonzero check */ 3515 return pi->num_cmds; /* used only for 0/nonzero check */
3460} 3516}
3461 3517
@@ -3643,9 +3699,9 @@ static const struct reserved_combo* match_reserved_word(o_string *word)
3643 } 3699 }
3644 return NULL; 3700 return NULL;
3645} 3701}
3646/* Return 0: not a keyword, 1: keyword 3702/* Return NULL: not a keyword, else: keyword
3647 */ 3703 */
3648static int reserved_word(o_string *word, struct parse_context *ctx) 3704static const struct reserved_combo* reserved_word(o_string *word, struct parse_context *ctx)
3649{ 3705{
3650# if ENABLE_HUSH_CASE 3706# if ENABLE_HUSH_CASE
3651 static const struct reserved_combo reserved_match = { 3707 static const struct reserved_combo reserved_match = {
@@ -3658,7 +3714,7 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
3658 return 0; 3714 return 0;
3659 r = match_reserved_word(word); 3715 r = match_reserved_word(word);
3660 if (!r) 3716 if (!r)
3661 return 0; 3717 return r; /* NULL */
3662 3718
3663 debug_printf("found reserved word %s, res %d\n", r->literal, r->res); 3719 debug_printf("found reserved word %s, res %d\n", r->literal, r->res);
3664# if ENABLE_HUSH_CASE 3720# if ENABLE_HUSH_CASE
@@ -3673,7 +3729,7 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
3673 ctx->ctx_res_w = RES_SNTX; 3729 ctx->ctx_res_w = RES_SNTX;
3674 } 3730 }
3675 ctx->ctx_inverted = 1; 3731 ctx->ctx_inverted = 1;
3676 return 1; 3732 return r;
3677 } 3733 }
3678 if (r->flag & FLAG_START) { 3734 if (r->flag & FLAG_START) {
3679 struct parse_context *old; 3735 struct parse_context *old;
@@ -3685,7 +3741,7 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
3685 } else if (/*ctx->ctx_res_w == RES_NONE ||*/ !(ctx->old_flag & (1 << r->res))) { 3741 } else if (/*ctx->ctx_res_w == RES_NONE ||*/ !(ctx->old_flag & (1 << r->res))) {
3686 syntax_error_at(word->data); 3742 syntax_error_at(word->data);
3687 ctx->ctx_res_w = RES_SNTX; 3743 ctx->ctx_res_w = RES_SNTX;
3688 return 1; 3744 return r;
3689 } else { 3745 } else {
3690 /* "{...} fi" is ok. "{...} if" is not 3746 /* "{...} fi" is ok. "{...} if" is not
3691 * Example: 3747 * Example:
@@ -3735,7 +3791,7 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
3735 *ctx = *old; /* physical copy */ 3791 *ctx = *old; /* physical copy */
3736 free(old); 3792 free(old);
3737 } 3793 }
3738 return 1; 3794 return r;
3739} 3795}
3740#endif /* HAS_KEYWORDS */ 3796#endif /* HAS_KEYWORDS */
3741 3797
@@ -3801,9 +3857,26 @@ static int done_word(o_string *word, struct parse_context *ctx)
3801 && ctx->ctx_res_w != RES_CASE 3857 && ctx->ctx_res_w != RES_CASE
3802# endif 3858# endif
3803 ) { 3859 ) {
3804 int reserved = reserved_word(word, ctx); 3860 const struct reserved_combo *reserved;
3805 debug_printf_parse("checking for reserved-ness: %d\n", reserved); 3861 reserved = reserved_word(word, ctx);
3862 debug_printf_parse("checking for reserved-ness: %d\n", !!reserved);
3806 if (reserved) { 3863 if (reserved) {
3864# if ENABLE_HUSH_LINENO_VAR
3865/* Case:
3866 * "while ...; do
3867 * cmd ..."
3868 * If we don't close the pipe _now_, immediately after "do", lineno logic
3869 * sees "cmd" as starting at "do" - i.e., at the previous line.
3870 */
3871 if (0
3872 IF_HUSH_IF(|| reserved->res == RES_THEN)
3873 IF_HUSH_IF(|| reserved->res == RES_ELIF)
3874 IF_HUSH_IF(|| reserved->res == RES_ELSE)
3875 IF_HUSH_LOOPS(|| reserved->res == RES_DO)
3876 ) {
3877 done_pipe(ctx, PIPE_SEQ);
3878 }
3879# endif
3807 o_reset_to_empty_unquoted(word); 3880 o_reset_to_empty_unquoted(word);
3808 debug_printf_parse("done_word return %d\n", 3881 debug_printf_parse("done_word return %d\n",
3809 (ctx->ctx_res_w == RES_SNTX)); 3882 (ctx->ctx_res_w == RES_SNTX));
@@ -3840,21 +3913,6 @@ static int done_word(o_string *word, struct parse_context *ctx)
3840 word->o_assignment = MAYBE_ASSIGNMENT; 3913 word->o_assignment = MAYBE_ASSIGNMENT;
3841 } 3914 }
3842 debug_printf_parse("word->o_assignment='%s'\n", assignment_flag[word->o_assignment]); 3915 debug_printf_parse("word->o_assignment='%s'\n", assignment_flag[word->o_assignment]);
3843
3844 if (word->has_quoted_part
3845 /* optimization: and if it's ("" or '') or ($v... or `cmd`...): */
3846 && (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL)
3847 /* (otherwise it's known to be not empty and is already safe) */
3848 ) {
3849 /* exclude "$@" - it can expand to no word despite "" */
3850 char *p = word->data;
3851 while (p[0] == SPECIAL_VAR_SYMBOL
3852 && (p[1] & 0x7f) == '@'
3853 && p[2] == SPECIAL_VAR_SYMBOL
3854 ) {
3855 p += 3;
3856 }
3857 }
3858 command->argv = add_string_to_strings(command->argv, xstrdup(word->data)); 3916 command->argv = add_string_to_strings(command->argv, xstrdup(word->data));
3859 debug_print_strings("word appended to argv", command->argv); 3917 debug_print_strings("word appended to argv", command->argv);
3860 } 3918 }
@@ -4503,9 +4561,10 @@ static int parse_dollar(o_string *as_string,
4503 4561
4504 debug_printf_parse("parse_dollar entered: ch='%c'\n", ch); 4562 debug_printf_parse("parse_dollar entered: ch='%c'\n", ch);
4505 if (isalpha(ch)) { 4563 if (isalpha(ch)) {
4564 make_var:
4506 ch = i_getch(input); 4565 ch = i_getch(input);
4507 nommu_addchr(as_string, ch); 4566 nommu_addchr(as_string, ch);
4508 make_var: 4567 /*make_var1:*/
4509 o_addchr(dest, SPECIAL_VAR_SYMBOL); 4568 o_addchr(dest, SPECIAL_VAR_SYMBOL);
4510 while (1) { 4569 while (1) {
4511 debug_printf_parse(": '%c'\n", ch); 4570 debug_printf_parse(": '%c'\n", ch);
@@ -4698,19 +4757,22 @@ static int parse_dollar(o_string *as_string,
4698 } 4757 }
4699#endif 4758#endif
4700 case '_': 4759 case '_':
4760 goto make_var;
4761#if 0
4762 /* TODO: $_ and $-: */
4763 /* $_ Shell or shell script name; or last argument of last command
4764 * (if last command wasn't a pipe; if it was, bash sets $_ to "");
4765 * but in command's env, set to full pathname used to invoke it */
4766 /* $- Option flags set by set builtin or shell options (-i etc) */
4701 ch = i_getch(input); 4767 ch = i_getch(input);
4702 nommu_addchr(as_string, ch); 4768 nommu_addchr(as_string, ch);
4703 ch = i_peek_and_eat_bkslash_nl(input); 4769 ch = i_peek_and_eat_bkslash_nl(input);
4704 if (isalnum(ch)) { /* it's $_name or $_123 */ 4770 if (isalnum(ch)) { /* it's $_name or $_123 */
4705 ch = '_'; 4771 ch = '_';
4706 goto make_var; 4772 goto make_var1;
4707 } 4773 }
4708 /* else: it's $_ */ 4774 /* else: it's $_ */
4709 /* TODO: $_ and $-: */ 4775#endif
4710 /* $_ Shell or shell script name; or last argument of last command
4711 * (if last command wasn't a pipe; if it was, bash sets $_ to "");
4712 * but in command's env, set to full pathname used to invoke it */
4713 /* $- Option flags set by set builtin or shell options (-i etc) */
4714 default: 4776 default:
4715 o_addQchr(dest, '$'); 4777 o_addQchr(dest, '$');
4716 } 4778 }
@@ -4914,7 +4976,8 @@ static struct pipe *parse_stream(char **pstring,
4914 next = i_peek(input); 4976 next = i_peek(input);
4915 4977
4916 is_special = "{}<>;&|()#'" /* special outside of "str" */ 4978 is_special = "{}<>;&|()#'" /* special outside of "str" */
4917 "\\$\"" IF_HUSH_TICK("`"); /* always special */ 4979 "\\$\"" IF_HUSH_TICK("`") /* always special */
4980 SPECIAL_VAR_SYMBOL_STR;
4918 /* Are { and } special here? */ 4981 /* Are { and } special here? */
4919 if (ctx.command->argv /* word [word]{... - non-special */ 4982 if (ctx.command->argv /* word [word]{... - non-special */
4920 || dest.length /* word{... - non-special */ 4983 || dest.length /* word{... - non-special */
@@ -4948,6 +5011,22 @@ static struct pipe *parse_stream(char **pstring,
4948 } 5011 }
4949 5012
4950 if (is_blank) { 5013 if (is_blank) {
5014#if ENABLE_HUSH_LINENO_VAR
5015/* Case:
5016 * "while ...; do<whitespace><newline>
5017 * cmd ..."
5018 * would think that "cmd" starts in <whitespace> -
5019 * i.e., at the previous line.
5020 * We need to skip all whitespace before newlines.
5021 */
5022 while (ch != '\n') {
5023 next = i_peek(input);
5024 if (next != ' ' && next != '\t' && next != '\n')
5025 break; /* next char is not ws */
5026 ch = i_getch(input);
5027 }
5028 /* ch == last eaten whitespace char */
5029#endif
4951 if (done_word(&dest, &ctx)) { 5030 if (done_word(&dest, &ctx)) {
4952 goto parse_error; 5031 goto parse_error;
4953 } 5032 }
@@ -5186,8 +5265,14 @@ static struct pipe *parse_stream(char **pstring,
5186 /* Note: nommu_addchr(&ctx.as_string, ch) is already done */ 5265 /* Note: nommu_addchr(&ctx.as_string, ch) is already done */
5187 5266
5188 switch (ch) { 5267 switch (ch) {
5189 case '#': /* non-comment #: "echo a#b" etc */ 5268 case SPECIAL_VAR_SYMBOL:
5190 o_addQchr(&dest, ch); 5269 /* Convert raw ^C to corresponding special variable reference */
5270 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
5271 o_addchr(&dest, SPECIAL_VAR_QUOTED_SVS);
5272 /* fall through */
5273 case '#':
5274 /* non-comment #: "echo a#b" etc */
5275 o_addchr(&dest, ch);
5191 break; 5276 break;
5192 case '\\': 5277 case '\\':
5193 if (next == EOF) { 5278 if (next == EOF) {
@@ -5229,6 +5314,11 @@ static struct pipe *parse_stream(char **pstring,
5229 nommu_addchr(&ctx.as_string, ch); 5314 nommu_addchr(&ctx.as_string, ch);
5230 if (ch == '\'') 5315 if (ch == '\'')
5231 break; 5316 break;
5317 if (ch == SPECIAL_VAR_SYMBOL) {
5318 /* Convert raw ^C to corresponding special variable reference */
5319 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
5320 o_addchr(&dest, SPECIAL_VAR_QUOTED_SVS);
5321 }
5232 o_addqchr(&dest, ch); 5322 o_addqchr(&dest, ch);
5233 } 5323 }
5234 } 5324 }
@@ -5534,7 +5624,7 @@ static int expand_on_ifs(int *ended_with_ifs, o_string *output, int n, const cha
5534static char *encode_then_expand_string(const char *str, int process_bkslash, int do_unbackslash) 5624static char *encode_then_expand_string(const char *str, int process_bkslash, int do_unbackslash)
5535{ 5625{
5536#if !BASH_PATTERN_SUBST 5626#if !BASH_PATTERN_SUBST
5537 const int do_unbackslash = 1; 5627 enum { do_unbackslash = 1 };
5538#endif 5628#endif
5539 char *exp_str; 5629 char *exp_str;
5540 struct in_str input; 5630 struct in_str input;
@@ -5610,6 +5700,10 @@ static char *replace_pattern(char *val, const char *pattern, const char *repl, c
5610 unsigned res_len = 0; 5700 unsigned res_len = 0;
5611 unsigned repl_len = strlen(repl); 5701 unsigned repl_len = strlen(repl);
5612 5702
5703 /* Null pattern never matches, including if "var" is empty */
5704 if (!pattern[0])
5705 return result; /* NULL, no replaces happened */
5706
5613 while (1) { 5707 while (1) {
5614 int size; 5708 int size;
5615 char *s = strstr_pattern(val, pattern, &size); 5709 char *s = strstr_pattern(val, pattern, &size);
@@ -5640,9 +5734,9 @@ static char *replace_pattern(char *val, const char *pattern, const char *repl, c
5640 */ 5734 */
5641static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, char **pp) 5735static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, char **pp)
5642{ 5736{
5643 const char *val = NULL; 5737 const char *val;
5644 char *to_be_freed = NULL; 5738 char *to_be_freed;
5645 char *p = *pp; 5739 char *p;
5646 char *var; 5740 char *var;
5647 char first_char; 5741 char first_char;
5648 char exp_op; 5742 char exp_op;
@@ -5651,6 +5745,9 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
5651 char *exp_word = exp_word; /* for compiler */ 5745 char *exp_word = exp_word; /* for compiler */
5652 char arg0; 5746 char arg0;
5653 5747
5748 val = NULL;
5749 to_be_freed = NULL;
5750 p = *pp;
5654 *p = '\0'; /* replace trailing SPECIAL_VAR_SYMBOL */ 5751 *p = '\0'; /* replace trailing SPECIAL_VAR_SYMBOL */
5655 var = arg; 5752 var = arg;
5656 exp_saveptr = arg[1] ? strchr(VAR_ENCODED_SUBST_OPS, arg[1]) : NULL; 5753 exp_saveptr = arg[1] ? strchr(VAR_ENCODED_SUBST_OPS, arg[1]) : NULL;
@@ -5773,8 +5870,6 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
5773 * and if // is used, it is encoded as \: 5870 * and if // is used, it is encoded as \:
5774 * var\pattern<SPECIAL_VAR_SYMBOL>repl<SPECIAL_VAR_SYMBOL> 5871 * var\pattern<SPECIAL_VAR_SYMBOL>repl<SPECIAL_VAR_SYMBOL>
5775 */ 5872 */
5776 /* Empty variable always gives nothing: */
5777 // "v=''; echo ${v/*/w}" prints "", not "w"
5778 if (val && val[0]) { 5873 if (val && val[0]) {
5779 /* pattern uses non-standard expansion. 5874 /* pattern uses non-standard expansion.
5780 * repl should be unbackslashed and globbed 5875 * repl should be unbackslashed and globbed
@@ -5810,6 +5905,13 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
5810 val = to_be_freed; 5905 val = to_be_freed;
5811 free(pattern); 5906 free(pattern);
5812 free(repl); 5907 free(repl);
5908 } else {
5909 /* Empty variable always gives nothing */
5910 // "v=''; echo ${v/*/w}" prints "", not "w"
5911 /* Just skip "replace" part */
5912 *p++ = SPECIAL_VAR_SYMBOL;
5913 p = strchr(p, SPECIAL_VAR_SYMBOL);
5914 *p = '\0';
5813 } 5915 }
5814 } 5916 }
5815#endif /* BASH_PATTERN_SUBST */ 5917#endif /* BASH_PATTERN_SUBST */
@@ -6041,6 +6143,11 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
6041 arg++; 6143 arg++;
6042 cant_be_null = 0x80; 6144 cant_be_null = 0x80;
6043 break; 6145 break;
6146 case SPECIAL_VAR_QUOTED_SVS:
6147 /* <SPECIAL_VAR_SYMBOL><SPECIAL_VAR_QUOTED_SVS><SPECIAL_VAR_SYMBOL> */
6148 arg++;
6149 val = SPECIAL_VAR_SYMBOL_STR;
6150 break;
6044#if ENABLE_HUSH_TICK 6151#if ENABLE_HUSH_TICK
6045 case '`': /* <SPECIAL_VAR_SYMBOL>`cmd<SPECIAL_VAR_SYMBOL> */ 6152 case '`': /* <SPECIAL_VAR_SYMBOL>`cmd<SPECIAL_VAR_SYMBOL> */
6046 *p = '\0'; /* replace trailing <SPECIAL_VAR_SYMBOL> */ 6153 *p = '\0'; /* replace trailing <SPECIAL_VAR_SYMBOL> */
@@ -6199,7 +6306,7 @@ static char *expand_string_to_string(const char *str, int do_unbackslash)
6199 return (char*)list; 6306 return (char*)list;
6200} 6307}
6201 6308
6202/* Used for "eval" builtin and case string */ 6309#if ENABLE_HUSH_CASE
6203static char* expand_strvec_to_string(char **argv) 6310static char* expand_strvec_to_string(char **argv)
6204{ 6311{
6205 char **list; 6312 char **list;
@@ -6221,6 +6328,7 @@ static char* expand_strvec_to_string(char **argv)
6221 debug_printf_expand("strvec_to_string='%s'\n", (char*)list); 6328 debug_printf_expand("strvec_to_string='%s'\n", (char*)list);
6222 return (char*)list; 6329 return (char*)list;
6223} 6330}
6331#endif
6224 6332
6225static char **expand_assignments(char **argv, int count) 6333static char **expand_assignments(char **argv, int count)
6226{ 6334{
@@ -6513,8 +6621,17 @@ static void parse_and_run_string(const char *s)
6513static void parse_and_run_file(FILE *f) 6621static void parse_and_run_file(FILE *f)
6514{ 6622{
6515 struct in_str input; 6623 struct in_str input;
6624#if ENABLE_HUSH_LINENO_VAR
6625 unsigned sv;
6626
6627 sv = G.lineno;
6628 G.lineno = 1;
6629#endif
6516 setup_file_in_str(&input, f); 6630 setup_file_in_str(&input, f);
6517 parse_and_run_stream(&input, ';'); 6631 parse_and_run_stream(&input, ';');
6632#if ENABLE_HUSH_LINENO_VAR
6633 G.lineno = sv;
6634#endif
6518} 6635}
6519 6636
6520#if ENABLE_HUSH_TICK 6637#if ENABLE_HUSH_TICK
@@ -7330,6 +7447,32 @@ static void dump_cmd_in_x_mode(char **argv)
7330# define dump_cmd_in_x_mode(argv) ((void)0) 7447# define dump_cmd_in_x_mode(argv) ((void)0)
7331#endif 7448#endif
7332 7449
7450#if ENABLE_HUSH_COMMAND
7451static void if_command_vV_print_and_exit(char opt_vV, char *cmd, const char *explanation)
7452{
7453 char *to_free;
7454
7455 if (!opt_vV)
7456 return;
7457
7458 to_free = NULL;
7459 if (!explanation) {
7460 char *path = getenv("PATH");
7461 explanation = to_free = find_executable(cmd, &path); /* path == NULL is ok */
7462 if (!explanation)
7463 _exit(1); /* PROG was not found */
7464 if (opt_vV != 'V')
7465 cmd = to_free; /* -v PROG prints "/path/to/PROG" */
7466 }
7467 printf((opt_vV == 'V') ? "%s is %s\n" : "%s\n", cmd, explanation);
7468 free(to_free);
7469 fflush_all();
7470 _exit(0);
7471}
7472#else
7473# define if_command_vV_print_and_exit(a,b,c) ((void)0)
7474#endif
7475
7333#if BB_MMU 7476#if BB_MMU
7334#define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \ 7477#define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \
7335 pseudo_exec_argv(argv, assignment_cnt, argv_expanded) 7478 pseudo_exec_argv(argv, assignment_cnt, argv_expanded)
@@ -7350,7 +7493,11 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
7350 char **argv, int assignment_cnt, 7493 char **argv, int assignment_cnt,
7351 char **argv_expanded) 7494 char **argv_expanded)
7352{ 7495{
7496 const struct built_in_command *x;
7353 char **new_env; 7497 char **new_env;
7498#if ENABLE_HUSH_COMMAND
7499 char opt_vV = 0;
7500#endif
7354 7501
7355 new_env = expand_assignments(argv, assignment_cnt); 7502 new_env = expand_assignments(argv, assignment_cnt);
7356 dump_cmd_in_x_mode(new_env); 7503 dump_cmd_in_x_mode(new_env);
@@ -7399,21 +7546,58 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
7399 } 7546 }
7400#endif 7547#endif
7401 7548
7549#if ENABLE_HUSH_COMMAND
7550 /* "command BAR": run BAR without looking it up among functions
7551 * "command -v BAR": print "BAR" or "/path/to/BAR"; or exit 1
7552 * "command -V BAR": print "BAR is {a function,a shell builtin,/path/to/BAR}"
7553 */
7554 while (strcmp(argv[0], "command") == 0 && argv[1]) {
7555 char *p;
7556
7557 argv++;
7558 p = *argv;
7559 if (p[0] != '-' || !p[1])
7560 continue; /* bash allows "command command command [-OPT] BAR" */
7561
7562 for (;;) {
7563 p++;
7564 switch (*p) {
7565 case '\0':
7566 argv++;
7567 p = *argv;
7568 if (p[0] != '-' || !p[1])
7569 goto after_opts;
7570 continue; /* next arg is also -opts, process it too */
7571 case 'v':
7572 case 'V':
7573 opt_vV = *p;
7574 continue;
7575 default:
7576 bb_error_msg_and_die("%s: %s: invalid option", "command", argv[0]);
7577 }
7578 }
7579 }
7580 after_opts:
7581# if ENABLE_HUSH_FUNCTIONS
7582 if (opt_vV && find_function(argv[0]))
7583 if_command_vV_print_and_exit(opt_vV, argv[0], "a function");
7584# endif
7585#endif
7586
7402 /* Check if the command matches any of the builtins. 7587 /* Check if the command matches any of the builtins.
7403 * Depending on context, this might be redundant. But it's 7588 * Depending on context, this might be redundant. But it's
7404 * easier to waste a few CPU cycles than it is to figure out 7589 * easier to waste a few CPU cycles than it is to figure out
7405 * if this is one of those cases. 7590 * if this is one of those cases.
7406 */ 7591 */
7407 { 7592 /* Why "BB_MMU ? :" difference in logic? -
7408 /* On NOMMU, it is more expensive to re-execute shell 7593 * On NOMMU, it is more expensive to re-execute shell
7409 * just in order to run echo or test builtin. 7594 * just in order to run echo or test builtin.
7410 * It's better to skip it here and run corresponding 7595 * It's better to skip it here and run corresponding
7411 * non-builtin later. */ 7596 * non-builtin later. */
7412 const struct built_in_command *x; 7597 x = BB_MMU ? find_builtin(argv[0]) : find_builtin1(argv[0]);
7413 x = BB_MMU ? find_builtin(argv[0]) : find_builtin1(argv[0]); 7598 if (x) {
7414 if (x) { 7599 if_command_vV_print_and_exit(opt_vV, argv[0], "a shell builtin");
7415 exec_builtin(&nommu_save->argv_from_re_execing, x, argv); 7600 exec_builtin(&nommu_save->argv_from_re_execing, x, argv);
7416 }
7417 } 7601 }
7418 7602
7419#if ENABLE_FEATURE_SH_STANDALONE 7603#if ENABLE_FEATURE_SH_STANDALONE
@@ -7421,6 +7605,7 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
7421 { 7605 {
7422 int a = find_applet_by_name(argv[0]); 7606 int a = find_applet_by_name(argv[0]);
7423 if (a >= 0) { 7607 if (a >= 0) {
7608 if_command_vV_print_and_exit(opt_vV, argv[0], "an applet");
7424# if BB_MMU /* see above why on NOMMU it is not allowed */ 7609# if BB_MMU /* see above why on NOMMU it is not allowed */
7425 if (APPLET_IS_NOEXEC(a)) { 7610 if (APPLET_IS_NOEXEC(a)) {
7426 /* Do not leak open fds from opened script files etc. 7611 /* Do not leak open fds from opened script files etc.
@@ -7450,6 +7635,7 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
7450#if ENABLE_FEATURE_SH_STANDALONE || BB_MMU 7635#if ENABLE_FEATURE_SH_STANDALONE || BB_MMU
7451 skip: 7636 skip:
7452#endif 7637#endif
7638 if_command_vV_print_and_exit(opt_vV, argv[0], NULL);
7453 execvp_or_die(argv); 7639 execvp_or_die(argv);
7454} 7640}
7455 7641
@@ -7992,6 +8178,11 @@ static NOINLINE int run_pipe(struct pipe *pi)
7992 char **new_env = NULL; 8178 char **new_env = NULL;
7993 struct variable *old_vars = NULL; 8179 struct variable *old_vars = NULL;
7994 8180
8181#if ENABLE_HUSH_LINENO_VAR
8182 if (G.lineno_var)
8183 strcpy(G.lineno_var + sizeof("LINENO=")-1, utoa(command->lineno));
8184#endif
8185
7995 if (argv[command->assignment_cnt] == NULL) { 8186 if (argv[command->assignment_cnt] == NULL) {
7996 /* Assignments, but no command */ 8187 /* Assignments, but no command */
7997 /* Ensure redirects take effect (that is, create files). 8188 /* Ensure redirects take effect (that is, create files).
@@ -8139,7 +8330,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
8139 return rcode; 8330 return rcode;
8140 } 8331 }
8141 8332
8142 if (ENABLE_FEATURE_SH_NOFORK) { 8333 if (ENABLE_FEATURE_SH_NOFORK && NUM_APPLETS > 1) {
8143 int n = find_applet_by_name(argv_expanded[0]); 8334 int n = find_applet_by_name(argv_expanded[0]);
8144 if (n >= 0 && APPLET_IS_NOFORK(n)) { 8335 if (n >= 0 && APPLET_IS_NOFORK(n)) {
8145 rcode = redirect_and_varexp_helper(&new_env, &old_vars, command, &squirrel, argv_expanded); 8336 rcode = redirect_and_varexp_helper(&new_env, &old_vars, command, &squirrel, argv_expanded);
@@ -8196,6 +8387,11 @@ static NOINLINE int run_pipe(struct pipe *pi)
8196 if (cmd_no < pi->num_cmds) 8387 if (cmd_no < pi->num_cmds)
8197 xpiped_pair(pipefds); 8388 xpiped_pair(pipefds);
8198 8389
8390#if ENABLE_HUSH_LINENO_VAR
8391 if (G.lineno_var)
8392 strcpy(G.lineno_var + sizeof("LINENO=")-1, utoa(command->lineno));
8393#endif
8394
8199 command->pid = BB_MMU ? fork() : vfork(); 8395 command->pid = BB_MMU ? fork() : vfork();
8200 if (!command->pid) { /* child */ 8396 if (!command->pid) { /* child */
8201#if ENABLE_HUSH_JOB 8397#if ENABLE_HUSH_JOB
@@ -8387,7 +8583,10 @@ static int run_list(struct pipe *pi)
8387 rword, cond_code, last_rword); 8583 rword, cond_code, last_rword);
8388 8584
8389 sv_errexit_depth = G.errexit_depth; 8585 sv_errexit_depth = G.errexit_depth;
8390 if (IF_HAS_KEYWORDS(rword == RES_IF || rword == RES_ELIF ||) 8586 if (
8587#if ENABLE_HUSH_IF
8588 rword == RES_IF || rword == RES_ELIF ||
8589#endif
8391 pi->followup != PIPE_SEQ 8590 pi->followup != PIPE_SEQ
8392 ) { 8591 ) {
8393 G.errexit_depth++; 8592 G.errexit_depth++;
@@ -8828,17 +9027,19 @@ int hush_main(int argc, char **argv)
8828#if !BB_MMU 9027#if !BB_MMU
8829 G.argv0_for_re_execing = argv[0]; 9028 G.argv0_for_re_execing = argv[0];
8830#endif 9029#endif
9030
8831 /* Deal with HUSH_VERSION */ 9031 /* Deal with HUSH_VERSION */
9032 debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION");
9033 unsetenv("HUSH_VERSION"); /* in case it exists in initial env */
8832 shell_ver = xzalloc(sizeof(*shell_ver)); 9034 shell_ver = xzalloc(sizeof(*shell_ver));
8833 shell_ver->flg_export = 1; 9035 shell_ver->flg_export = 1;
8834 shell_ver->flg_read_only = 1; 9036 shell_ver->flg_read_only = 1;
8835 /* Code which handles ${var<op>...} needs writable values for all variables, 9037 /* Code which handles ${var<op>...} needs writable values for all variables,
8836 * therefore we xstrdup: */ 9038 * therefore we xstrdup: */
8837 shell_ver->varstr = xstrdup(hush_version_str); 9039 shell_ver->varstr = xstrdup(hush_version_str);
9040
8838 /* Create shell local variables from the values 9041 /* Create shell local variables from the values
8839 * currently living in the environment */ 9042 * currently living in the environment */
8840 debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION");
8841 unsetenv("HUSH_VERSION"); /* in case it exists in initial env */
8842 G.top_var = shell_ver; 9043 G.top_var = shell_ver;
8843 cur_var = G.top_var; 9044 cur_var = G.top_var;
8844 e = environ; 9045 e = environ;
@@ -8904,6 +9105,14 @@ int hush_main(int argc, char **argv)
8904 */ 9105 */
8905#endif 9106#endif
8906 9107
9108#if ENABLE_HUSH_LINENO_VAR
9109 if (ENABLE_HUSH_LINENO_VAR) {
9110 char *p = xasprintf("LINENO=%*s", (int)(sizeof(int)*3), "");
9111 set_local_var(p, /*flags*/ 0);
9112 G.lineno_var = p; /* can't assign before set_local_var("LINENO=...") */
9113 }
9114#endif
9115
8907#if ENABLE_FEATURE_EDITING 9116#if ENABLE_FEATURE_EDITING
8908 G.line_input_state = new_line_input_t(FOR_SHELL); 9117 G.line_input_state = new_line_input_t(FOR_SHELL);
8909#endif 9118#endif
@@ -9346,13 +9555,34 @@ static int FAST_FUNC builtin_eval(char **argv)
9346 int rcode = EXIT_SUCCESS; 9555 int rcode = EXIT_SUCCESS;
9347 9556
9348 argv = skip_dash_dash(argv); 9557 argv = skip_dash_dash(argv);
9349 if (*argv) { 9558 if (argv[0]) {
9350 char *str = expand_strvec_to_string(argv); 9559 char *str = NULL;
9560
9561 if (argv[1]) {
9562 /* "The eval utility shall construct a command by
9563 * concatenating arguments together, separating
9564 * each with a <space> character."
9565 */
9566 char *p;
9567 unsigned len = 0;
9568 char **pp = argv;
9569 do
9570 len += strlen(*pp) + 1;
9571 while (*++pp);
9572 str = p = xmalloc(len);
9573 pp = argv;
9574 do {
9575 p = stpcpy(p, *pp);
9576 *p++ = ' ';
9577 } while (*++pp);
9578 p[-1] = '\0';
9579 }
9580
9351 /* bash: 9581 /* bash:
9352 * eval "echo Hi; done" ("done" is syntax error): 9582 * eval "echo Hi; done" ("done" is syntax error):
9353 * "echo Hi" will not execute too. 9583 * "echo Hi" will not execute too.
9354 */ 9584 */
9355 parse_and_run_string(str); 9585 parse_and_run_string(str ? str : argv[0]);
9356 free(str); 9586 free(str);
9357 rcode = G.last_exitcode; 9587 rcode = G.last_exitcode;
9358 } 9588 }
@@ -9855,7 +10085,7 @@ static int FAST_FUNC builtin_set(char **argv)
9855 10085
9856 /* Nothing known, so abort */ 10086 /* Nothing known, so abort */
9857 error: 10087 error:
9858 bb_error_msg("set: %s: invalid option", arg); 10088 bb_error_msg("%s: %s: invalid option", "set", arg);
9859 return EXIT_FAILURE; 10089 return EXIT_FAILURE;
9860} 10090}
9861#endif 10091#endif
@@ -10038,6 +10268,11 @@ static int FAST_FUNC builtin_source(char **argv)
10038 arg_path = find_in_path(filename); 10268 arg_path = find_in_path(filename);
10039 if (arg_path) 10269 if (arg_path)
10040 filename = arg_path; 10270 filename = arg_path;
10271 else if (!ENABLE_HUSH_BASH_SOURCE_CURDIR) {
10272 errno = ENOENT;
10273 bb_simple_perror_msg(filename);
10274 return EXIT_FAILURE;
10275 }
10041 } 10276 }
10042 input = remember_FILE(fopen_or_warn(filename, "r")); 10277 input = remember_FILE(fopen_or_warn(filename, "r"));
10043 free(arg_path); 10278 free(arg_path);
diff --git a/shell/hush_test/hush-arith/arith-postinc.right b/shell/hush_test/hush-arith/arith-postinc.right
new file mode 100644
index 000000000..c95ce02bf
--- /dev/null
+++ b/shell/hush_test/hush-arith/arith-postinc.right
@@ -0,0 +1,5 @@
11 1
21 1
31 1
41 1
5Ok:0
diff --git a/shell/hush_test/hush-arith/arith-postinc.tests b/shell/hush_test/hush-arith/arith-postinc.tests
new file mode 100755
index 000000000..3fd9bfed5
--- /dev/null
+++ b/shell/hush_test/hush-arith/arith-postinc.tests
@@ -0,0 +1,5 @@
1echo 1 $((0++1))
2echo 1 $((0--1))
3x=-1; echo 1 $((0-$x))
4x=+1; echo 1 $((0+$x))
5echo Ok:$?
diff --git a/shell/hush_test/hush-arith/arith.right b/shell/hush_test/hush-arith/arith.right
index 8a201fb3b..c48e468a5 100644
--- a/shell/hush_test/hush-arith/arith.right
+++ b/shell/hush_test/hush-arith/arith.right
@@ -135,6 +135,10 @@ hush: arithmetic syntax error
135hush: arithmetic syntax error 135hush: arithmetic syntax error
1365 5 1365 5
1371 1 1371 1
1386 6
1392 2
1403 3
1411 1
1384 4 1424 4
1390 0 1430 0
140hush: arithmetic syntax error 144hush: arithmetic syntax error
diff --git a/shell/hush_test/hush-arith/arith2.sub b/shell/hush_test/hush-arith/arith2.sub
index f7e3c9235..9105059db 100755
--- a/shell/hush_test/hush-arith/arith2.sub
+++ b/shell/hush_test/hush-arith/arith2.sub
@@ -23,14 +23,14 @@
23echo 5 $(( 4 + ++a )) 23echo 5 $(( 4 + ++a ))
24echo 1 $a 24echo 1 $a
25 25
26# ash doesn't handle it right... 26# this is treated as 4 + ++a
27#ash# echo 6 $(( 4+++a )) 27echo 6 $(( 4+++a ))
28#ash# echo 2 $a 28echo 2 $a
29 a=2 29 a=2
30 30
31# ash doesn't handle it right... 31# this is treated as 4 - --a
32#ash# echo 3 $(( 4---a )) 32echo 3 $(( 4---a ))
33#ash# echo 1 $a 33echo 1 $a
34 a=1 34 a=1
35 35
36echo 4 $(( 4 - -- a )) 36echo 4 $(( 4 - -- a ))
diff --git a/shell/hush_test/hush-misc/command2.right b/shell/hush_test/hush-misc/command2.right
new file mode 100644
index 000000000..e3214f0a9
--- /dev/null
+++ b/shell/hush_test/hush-misc/command2.right
@@ -0,0 +1,2 @@
1test1
2hush: can't execute './test2.sh': Permission denied
diff --git a/shell/hush_test/hush-misc/command2.tests b/shell/hush_test/hush-misc/command2.tests
new file mode 100755
index 000000000..9d9de9a89
--- /dev/null
+++ b/shell/hush_test/hush-misc/command2.tests
@@ -0,0 +1,6 @@
1echo "echo test1; ./test2.sh" >test1.sh
2echo "echo test2" >test2.sh
3
4command . ./test1.sh
5
6rm -f test1.sh test2.sh
diff --git a/shell/hush_test/hush-misc/control_char1.right b/shell/hush_test/hush-misc/control_char1.right
new file mode 100644
index 000000000..6f8c2533c
--- /dev/null
+++ b/shell/hush_test/hush-misc/control_char1.right
@@ -0,0 +1,3 @@
1
2b#c
3Done:0
diff --git a/shell/hush_test/hush-misc/control_char1.tests b/shell/hush_test/hush-misc/control_char1.tests
new file mode 100755
index 000000000..0cfe60141
--- /dev/null
+++ b/shell/hush_test/hush-misc/control_char1.tests
@@ -0,0 +1,3 @@
1echo 
2echo 'b#c'
3echo Done:$?
diff --git a/shell/hush_test/hush-misc/control_char2.right b/shell/hush_test/hush-misc/control_char2.right
new file mode 100644
index 000000000..9498b420d
--- /dev/null
+++ b/shell/hush_test/hush-misc/control_char2.right
@@ -0,0 +1,2 @@
1
2Done:0
diff --git a/shell/hush_test/hush-misc/control_char2.tests b/shell/hush_test/hush-misc/control_char2.tests
new file mode 100755
index 000000000..e77d7a1a6
--- /dev/null
+++ b/shell/hush_test/hush-misc/control_char2.tests
@@ -0,0 +1,3 @@
1c=`printf '\3'`
2eval "echo $c"
3echo Done:$?
diff --git a/shell/hush_test/hush-misc/for_with_bslashes.right b/shell/hush_test/hush-misc/for_with_bslashes.right
index 02d96692c..cd8501050 100644
--- a/shell/hush_test/hush-misc/for_with_bslashes.right
+++ b/shell/hush_test/hush-misc/for_with_bslashes.right
@@ -5,4 +5,5 @@ b"c
5b'c 5b'c
6b$c 6b$c
7b`true`c 7b`true`c
8b#c
8Zero:0 9Zero:0
diff --git a/shell/hush_test/hush-misc/for_with_bslashes.tests b/shell/hush_test/hush-misc/for_with_bslashes.tests
index 363f3d85b..8acd9808a 100755
--- a/shell/hush_test/hush-misc/for_with_bslashes.tests
+++ b/shell/hush_test/hush-misc/for_with_bslashes.tests
@@ -1,9 +1,5 @@
1# UNFIXED BUG. 1# last word contains ^C character.
2# commented-out words contain ^C character. 2for a in 'a' 'b\c' 'b\\c' 'b"c' "b'c" 'b$c' 'b`true`c' 'b#c'
3# It's a SPECIAL_VAR_SYMBOL, for now hush does not escape it.
4# When it is fixed, update this test.
5
6for a in 'a' 'b\c' 'b\\c' 'b"c' "b'c" 'b$c' 'b`true`c' ### 'b#c'
7do 3do
8 echo $a 4 echo $a
9done 5done
diff --git a/shell/hush_test/hush-vars/param_expand_bash_substring.right b/shell/hush_test/hush-vars/param_expand_bash_substring.right
index 2f4c51d06..a3cb549f7 100644
--- a/shell/hush_test/hush-vars/param_expand_bash_substring.right
+++ b/shell/hush_test/hush-vars/param_expand_bash_substring.right
@@ -3,6 +3,7 @@ hush: syntax error: unterminated ${name}
3hush: syntax error: unterminated ${name} 3hush: syntax error: unterminated ${name}
4hush: syntax error: unterminated ${name} 4hush: syntax error: unterminated ${name}
50123456789 50123456789
60
61 =|| 71 =||
71:1 =|| 81:1 =||
81:1:2=|| 91:1:2=||
diff --git a/shell/hush_test/hush-vars/param_expand_bash_substring.tests b/shell/hush_test/hush-vars/param_expand_bash_substring.tests
index cce9f123e..512da351b 100755
--- a/shell/hush_test/hush-vars/param_expand_bash_substring.tests
+++ b/shell/hush_test/hush-vars/param_expand_bash_substring.tests
@@ -11,7 +11,7 @@ export var=0123456789
11"$THIS_SH" -c 'echo ${var:}' SHELL 11"$THIS_SH" -c 'echo ${var:}' SHELL
12 12
13# then some funky ones 13# then some funky ones
14# UNFIXED BUG: this should work: "$THIS_SH" -c 'echo ${?:0}' 14"$THIS_SH" -c 'echo ${?:0}' SHELL
15 15
16# now some valid ones 16# now some valid ones
17set --; echo "1 =|${1}|" 17set --; echo "1 =|${1}|"
diff --git a/shell/hush_test/hush-vars/var_LINENO1.right b/shell/hush_test/hush-vars/var_LINENO1.right
new file mode 100644
index 000000000..31e1a4478
--- /dev/null
+++ b/shell/hush_test/hush-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/hush_test/hush-vars/var_LINENO1.tests b/shell/hush_test/hush-vars/var_LINENO1.tests
new file mode 100755
index 000000000..851b52cf5
--- /dev/null
+++ b/shell/hush_test/hush-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_test/hush-vars/var_bash_repl_empty_pattern.right b/shell/hush_test/hush-vars/var_bash_repl_empty_pattern.right
new file mode 100644
index 000000000..d400a7e31
--- /dev/null
+++ b/shell/hush_test/hush-vars/var_bash_repl_empty_pattern.right
@@ -0,0 +1,2 @@
1v
2Ok:0
diff --git a/shell/hush_test/hush-vars/var_bash_repl_empty_pattern.tests b/shell/hush_test/hush-vars/var_bash_repl_empty_pattern.tests
new file mode 100755
index 000000000..6e8aa2afa
--- /dev/null
+++ b/shell/hush_test/hush-vars/var_bash_repl_empty_pattern.tests
@@ -0,0 +1,3 @@
1v=v
2echo ${v//}
3echo Ok:$?
diff --git a/shell/hush_test/hush-vars/var_bash_repl_empty_var.right b/shell/hush_test/hush-vars/var_bash_repl_empty_var.right
new file mode 100644
index 000000000..892916783
--- /dev/null
+++ b/shell/hush_test/hush-vars/var_bash_repl_empty_var.right
@@ -0,0 +1,2 @@
1
2Ok:0
diff --git a/shell/hush_test/hush-vars/var_bash_repl_empty_var.tests b/shell/hush_test/hush-vars/var_bash_repl_empty_var.tests
new file mode 100755
index 000000000..73a43d38e
--- /dev/null
+++ b/shell/hush_test/hush-vars/var_bash_repl_empty_var.tests
@@ -0,0 +1,3 @@
1v=''
2echo ${v/*/w}
3echo Ok:$?
diff --git a/shell/math.c b/shell/math.c
index f01f24362..611b3beab 100644
--- a/shell/math.c
+++ b/shell/math.c
@@ -598,10 +598,24 @@ evaluate_string(arith_state_t *math_state, const char *expr)
598 } 598 }
599 599
600 /* Should be an operator */ 600 /* Should be an operator */
601
602 /* Special case: NUM-- and NUM++ are not recognized if NUM
603 * is a literal number, not a variable. IOW:
604 * "a+++v" is a++ + v.
605 * "7+++v" is 7 + ++v, not 7++ + v.
606 */
607 if (lasttok == TOK_NUM && !numstackptr[-1].var /* number literal */
608 && (expr[0] == '+' || expr[0] == '-')
609 && (expr[1] == expr[0])
610 ) {
611 //bb_error_msg("special %c%c", expr[0], expr[0]);
612 op = (expr[0] == '+' ? TOK_ADD : TOK_SUB);
613 expr += 1;
614 goto tok_found1;
615 }
616
601 p = op_tokens; 617 p = op_tokens;
602 while (1) { 618 while (1) {
603// TODO: bash allows 7+++v, treats it as 7 + ++v
604// we treat it as 7++ + v and reject
605 /* Compare expr to current op_tokens[] element */ 619 /* Compare expr to current op_tokens[] element */
606 const char *e = expr; 620 const char *e = expr;
607 while (1) { 621 while (1) {
@@ -627,6 +641,7 @@ evaluate_string(arith_state_t *math_state, const char *expr)
627 } 641 }
628 tok_found: 642 tok_found:
629 op = p[1]; /* fetch TOK_foo value */ 643 op = p[1]; /* fetch TOK_foo value */
644 tok_found1:
630 /* NB: expr now points past the operator */ 645 /* NB: expr now points past the operator */
631 646
632 /* post grammar: a++ reduce to num */ 647 /* post grammar: a++ reduce to num */
diff --git a/size_single_applets.sh b/size_single_applets.sh
index 0fa56e09e..ee16d4de7 100755
--- a/size_single_applets.sh
+++ b/size_single_applets.sh
@@ -22,7 +22,7 @@ for app; do
22 } 22 }
23 test $mintext -gt $text && { 23 test $mintext -gt $text && {
24 mintext=$text 24 mintext=$text
25 echo "New mintext from $app: $mintext" 25 echo "# New mintext from $app: $mintext"
26 } 26 }
27 eval "text_${app}=$text" 27 eval "text_${app}=$text"
28done 28done
@@ -31,7 +31,7 @@ for app; do
31 b="busybox_${app}" 31 b="busybox_${app}"
32 test -f "$b" || continue 32 test -f "$b" || continue
33 eval "text=\$text_${app}" 33 eval "text=\$text_${app}"
34 echo "$app adds $((text-mintext))" 34 echo "# $app adds $((text-mintext))"
35done 35done
36 36
37grep ^IF_ include/applets.h \ 37grep ^IF_ include/applets.h \
@@ -60,7 +60,7 @@ grep ^IF_ include/applets.h \
60 sz_frac=$(( (sz - sz_kb*1000) )) 60 sz_frac=$(( (sz - sz_kb*1000) ))
61 sz_f=$((sz_frac / 100)) 61 sz_f=$((sz_frac / 100))
62 62
63 echo -n "sed 's/bool \"$name *(*[0-9tinykbytes .]*)*\"/" 63 echo -n "sed 's/bool \"$name"'[" ](*[0-9tinykbytes .]*)*"*$/'
64 if test "$sz_kb" -ge 10; then 64 if test "$sz_kb" -ge 10; then
65 echo -n "bool \"$name (${sz_kb} kb)\"" 65 echo -n "bool \"$name (${sz_kb} kb)\""
66 elif test "$sz_kb" -gt 0 -a "$sz_f" = 0; then 66 elif test "$sz_kb" -gt 0 -a "$sz_f" = 0; then
diff --git a/testsuite/awk.tests b/testsuite/awk.tests
index 82937bc10..ad0583afb 100755
--- a/testsuite/awk.tests
+++ b/testsuite/awk.tests
@@ -261,6 +261,25 @@ end d
261" \ 261" \
262 "" "" 262 "" ""
263 263
264prg='
265BEGIN{
266cnt = 0
267a[cnt] = "zeroth"
268a[++cnt] = "first"
269delete a[cnt--]
270print cnt
271print "[0]:" a[0]
272print "[1]:" a[1]
273}'
274testing "awk 'delete a[v--]' evaluates v-- once" \
275 "awk '$prg'" \
276 "\
2770
278[0]:zeroth
279[1]:
280" \
281 "" ""
282
264testing "awk handles empty ()" \ 283testing "awk handles empty ()" \
265 "awk 'BEGIN {print()}' 2>&1" "awk: cmd. line:1: Empty sequence\n" "" "" 284 "awk 'BEGIN {print()}' 2>&1" "awk: cmd. line:1: Empty sequence\n" "" ""
266 285
diff --git a/testsuite/busybox.tests b/testsuite/busybox.tests
index 545cad5c0..beb17440c 100755
--- a/testsuite/busybox.tests
+++ b/testsuite/busybox.tests
@@ -5,6 +5,7 @@
5# Licensed under GPLv2, see file LICENSE in this source tree. 5# Licensed under GPLv2, see file LICENSE in this source tree.
6 6
7. ./testing.sh 7. ./testing.sh
8test -f "$bindir/.config" && . "$bindir/.config"
8 9
9ln -s `which busybox` unknown 10ln -s `which busybox` unknown
10 11
@@ -18,29 +19,24 @@ test x"$CONFIG_BUSYBOX" = x"y" \
18 19
19HELPDUMP=`true | busybox 2>&1 | cat` 20HELPDUMP=`true | busybox 2>&1 | cat`
20 21
21# We need to test under calling the binary under other names.
22
23optional FEATURE_VERBOSE_USAGE 22optional FEATURE_VERBOSE_USAGE
24testing "busybox --help busybox" "true | busybox --help busybox 2>&1 | cat" "$HELPDUMP\n\n" "" "" 23testing "busybox --help busybox" "true | busybox --help busybox 2>&1 | cat" "$HELPDUMP\n" "" ""
25SKIP= 24SKIP=
26 25
27ln -s `which busybox` busybox-suffix 26ln -s `which busybox` busybox-suffix
28for i in busybox ./busybox-suffix 27for i in busybox ./busybox-suffix
29do 28do
30 # The gratuitous "\n"s are due to a shell idiosyncrasy: 29 testing "$i" "$i 2>&1 | cat" "$HELPDUMP\n" "" ""
31 # environment variables seem to strip trailing whitespace.
32
33 testing "" "$i" "$HELPDUMP\n\n" "" ""
34 30
35 testing "$i unknown" "$i unknown 2>&1" \ 31 testing "$i unknown" "$i unknown 2>&1" \
36 "unknown: applet not found\n" "" "" 32 "unknown: applet not found\n" "" ""
37 33
38 testing "$i --help" "$i --help 2>&1" "$HELPDUMP\n\n" "" "" 34 testing "$i --help" "$i --help 2>&1" "$HELPDUMP\n" "" ""
39 35
40 optional FEATURE_VERBOSE_USAGE CAT 36 optional FEATURE_VERBOSE_USAGE CAT
41 testing "" "$i cat" "moo" "" "moo" 37 testing "" "$i cat" "moo" "" "moo"
42 testing "$i --help cat" "$i --help cat 2>&1 | grep print" \ 38 testing "$i --help cat" "$i --help cat 2>&1 | grep Print" \
43 "Concatenate FILEs and print them to stdout\n" "" "" 39 "Print FILEs to stdout\n" "" ""
44 SKIP= 40 SKIP=
45 41
46 testing "$i --help unknown" "$i --help unknown 2>&1" \ 42 testing "$i --help unknown" "$i --help unknown 2>&1" \
diff --git a/testsuite/bzcat.tests b/testsuite/bzcat.tests
index 0ae530dc7..32c1c5d7f 100755
--- a/testsuite/bzcat.tests
+++ b/testsuite/bzcat.tests
@@ -1,5 +1,7 @@
1#!/bin/sh 1#!/bin/sh
2 2
3test -f "$bindir/.config" && . "$bindir/.config"
4
3FAILCOUNT=0 5FAILCOUNT=0
4 6
5bb="busybox " 7bb="busybox "
@@ -73,7 +75,7 @@ done
73 75
74# "input" file is bzipped file with "a\n" data 76# "input" file is bzipped file with "a\n" data
75testing "bzcat can print many files" \ 77testing "bzcat can print many files" \
76"$ECHO -ne '$hexdump' | bzcat input input; echo \$?" \ 78"bzcat input input; echo \$?" \
77"\ 79"\
78a 80a
79a 81a
@@ -86,7 +88,7 @@ a
86 88
87# "input" file is bzipped zero byte file 89# "input" file is bzipped zero byte file
88testing "bzcat can handle compressed zero-length bzip2 files" \ 90testing "bzcat can handle compressed zero-length bzip2 files" \
89"$ECHO -ne '$hexdump' | bzcat input input; echo \$?" \ 91"bzcat input input; echo \$?" \
90"0\n" \ 92"0\n" \
91"\x42\x5a\x68\x39\x17\x72\x45\x38\x50\x90\x00\x00\x00\x00" "" 93"\x42\x5a\x68\x39\x17\x72\x45\x38\x50\x90\x00\x00\x00\x00" ""
92 94
@@ -95,7 +97,7 @@ testing "bzcat can handle compressed zero-length bzip2 files" \
95# "input" file is compressed (.Z) file with "a\n" data 97# "input" file is compressed (.Z) file with "a\n" data
96test x"$CONFIG_UNCOMPRESS" = x"y" && \ 98test x"$CONFIG_UNCOMPRESS" = x"y" && \
97testing "zcat can print many files" \ 99testing "zcat can print many files" \
98"$ECHO -ne '$hexdump' | zcat input input; echo \$?" \ 100"zcat input input; echo \$?" \
99"\ 101"\
100a 102a
101a 103a
@@ -107,7 +109,7 @@ a
107# "input" file is compressed (.Z) zero byte file 109# "input" file is compressed (.Z) zero byte file
108test x"$CONFIG_UNCOMPRESS" = x"y" && \ 110test x"$CONFIG_UNCOMPRESS" = x"y" && \
109testing "zcat can handle compressed zero-length (.Z) files" \ 111testing "zcat can handle compressed zero-length (.Z) files" \
110"$ECHO -ne '$hexdump' | zcat input input; echo \$?" \ 112"zcat input input; echo \$?" \
111"0\n" \ 113"0\n" \
112"\x1f\x9d\x90\x00" "" 114"\x1f\x9d\x90\x00" ""
113 115
diff --git a/util-linux/cal.c b/util-linux/cal.c
index 10df0ae8b..a4a20d5f0 100644
--- a/util-linux/cal.c
+++ b/util-linux/cal.c
@@ -16,7 +16,8 @@
16//config: help 16//config: help
17//config: cal is used to display a monthly calendar. 17//config: cal is used to display a monthly calendar.
18 18
19//applet:IF_CAL(APPLET(cal, BB_DIR_USR_BIN, BB_SUID_DROP)) 19//applet:IF_CAL(APPLET_NOEXEC(cal, cal, BB_DIR_USR_BIN, BB_SUID_DROP, cal))
20/* NOEXEC despite rare cases when it can be a "runner" (e.g. cal -n12000 takes you into years 30xx) */
20 21
21//kbuild:lib-$(CONFIG_CAL) += cal.o 22//kbuild:lib-$(CONFIG_CAL) += cal.o
22 23
diff --git a/util-linux/chrt.c b/util-linux/chrt.c
index 2712ea3e3..45459d940 100644
--- a/util-linux/chrt.c
+++ b/util-linux/chrt.c
@@ -9,7 +9,7 @@
9//config: bool "chrt (4.4 kb)" 9//config: bool "chrt (4.4 kb)"
10//config: default y 10//config: default y
11//config: help 11//config: help
12//config: manipulate real-time attributes of a process. 12//config: Manipulate real-time attributes of a process.
13//config: This requires sched_{g,s}etparam support in your libc. 13//config: This requires sched_{g,s}etparam support in your libc.
14 14
15//applet:IF_CHRT(APPLET_NOEXEC(chrt, chrt, BB_DIR_USR_BIN, BB_SUID_DROP, chrt)) 15//applet:IF_CHRT(APPLET_NOEXEC(chrt, chrt, BB_DIR_USR_BIN, BB_SUID_DROP, chrt))
@@ -17,13 +17,15 @@
17//kbuild:lib-$(CONFIG_CHRT) += chrt.o 17//kbuild:lib-$(CONFIG_CHRT) += chrt.o
18 18
19//usage:#define chrt_trivial_usage 19//usage:#define chrt_trivial_usage
20//usage: "[-prfom] [PRIO] [PID | PROG ARGS]" 20//usage: "[-prfombi] [PRIO] [PID | PROG ARGS]"
21//usage:#define chrt_full_usage "\n\n" 21//usage:#define chrt_full_usage "\n\n"
22//usage: "Change scheduling priority and class for a process\n" 22//usage: "Change scheduling priority and class for a process\n"
23//usage: "\n -p Operate on PID" 23//usage: "\n -p Operate on PID"
24//usage: "\n -r Set SCHED_RR class" 24//usage: "\n -r Set SCHED_RR class"
25//usage: "\n -f Set SCHED_FIFO class" 25//usage: "\n -f Set SCHED_FIFO class"
26//usage: "\n -o Set SCHED_OTHER class" 26//usage: "\n -o Set SCHED_OTHER class"
27//usage: "\n -b Set SCHED_BATCH class"
28//usage: "\n -i Set SCHED_IDLE class"
27//usage: "\n -m Show min/max priorities" 29//usage: "\n -m Show min/max priorities"
28//usage: 30//usage:
29//usage:#define chrt_example_usage 31//usage:#define chrt_example_usage
@@ -33,20 +35,22 @@
33 35
34#include <sched.h> 36#include <sched.h>
35#include "libbb.h" 37#include "libbb.h"
38#ifndef SCHED_IDLE
39# define SCHED_IDLE 5
40#endif
36 41
37static const struct { 42static const struct {
38 int policy;
39 char name[sizeof("SCHED_OTHER")]; 43 char name[sizeof("SCHED_OTHER")];
40} policies[] = { 44} policies[] = {
41 {SCHED_OTHER, "SCHED_OTHER"}, 45 { "SCHED_OTHER" }, /* 0:SCHED_OTHER */
42 {SCHED_FIFO, "SCHED_FIFO"}, 46 { "SCHED_FIFO" }, /* 1:SCHED_FIFO */
43 {SCHED_RR, "SCHED_RR"} 47 { "SCHED_RR" }, /* 2:SCHED_RR */
48 { "SCHED_BATCH" }, /* 3:SCHED_BATCH */
49 { "" }, /* 4:SCHED_ISO */
50 { "SCHED_IDLE" }, /* 5:SCHED_IDLE */
51 /* 6:SCHED_DEADLINE */
44}; 52};
45 53
46//TODO: add
47// -b, SCHED_BATCH
48// -i, SCHED_IDLE
49
50static void show_min_max(int pol) 54static void show_min_max(int pol)
51{ 55{
52 const char *fmt = "%s min/max priority\t: %u/%u\n"; 56 const char *fmt = "%s min/max priority\t: %u/%u\n";
@@ -64,6 +68,8 @@ static void show_min_max(int pol)
64#define OPT_r (1<<2) 68#define OPT_r (1<<2)
65#define OPT_f (1<<3) 69#define OPT_f (1<<3)
66#define OPT_o (1<<4) 70#define OPT_o (1<<4)
71#define OPT_b (1<<5)
72#define OPT_i (1<<6)
67 73
68int chrt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 74int chrt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
69int chrt_main(int argc UNUSED_PARAM, char **argv) 75int chrt_main(int argc UNUSED_PARAM, char **argv)
@@ -76,20 +82,30 @@ int chrt_main(int argc UNUSED_PARAM, char **argv)
76 const char *current_new; 82 const char *current_new;
77 int policy = SCHED_RR; 83 int policy = SCHED_RR;
78 84
79 /* only one policy accepted */ 85 opt = getopt32(argv, "^"
80 opt = getopt32(argv, "^+" "mprfo" "\0" "r--fo:f--ro:o--rf"); 86 "+" "mprfobi"
87 "\0"
88 /* only one policy accepted: */
89 "r--fobi:f--robi:o--rfbi:b--rfoi:i--rfob"
90 );
81 if (opt & OPT_m) { /* print min/max and exit */ 91 if (opt & OPT_m) { /* print min/max and exit */
92 show_min_max(SCHED_OTHER);
82 show_min_max(SCHED_FIFO); 93 show_min_max(SCHED_FIFO);
83 show_min_max(SCHED_RR); 94 show_min_max(SCHED_RR);
84 show_min_max(SCHED_OTHER); 95 show_min_max(SCHED_BATCH);
96 show_min_max(SCHED_IDLE);
85 fflush_stdout_and_exit(EXIT_SUCCESS); 97 fflush_stdout_and_exit(EXIT_SUCCESS);
86 } 98 }
87 if (opt & OPT_r) 99 //if (opt & OPT_r)
88 policy = SCHED_RR; 100 // policy = SCHED_RR; - default, already set
89 if (opt & OPT_f) 101 if (opt & OPT_f)
90 policy = SCHED_FIFO; 102 policy = SCHED_FIFO;
91 if (opt & OPT_o) 103 if (opt & OPT_o)
92 policy = SCHED_OTHER; 104 policy = SCHED_OTHER;
105 if (opt & OPT_b)
106 policy = SCHED_BATCH;
107 if (opt & OPT_i)
108 policy = SCHED_IDLE;
93 109
94 argv += optind; 110 argv += optind;
95 if (!argv[0]) 111 if (!argv[0])
@@ -131,12 +147,9 @@ int chrt_main(int argc UNUSED_PARAM, char **argv)
131 current_new += 8; 147 current_new += 8;
132 } 148 }
133 149
134 /* from the manpage of sched_getscheduler: 150 sp.sched_priority = xstrtou_range(priority, 0,
135 [...] sched_priority can have a value in the range 0 to 99. 151 sched_get_priority_min(policy), sched_get_priority_max(policy)
136 [...] SCHED_OTHER or SCHED_BATCH must be assigned static priority 0. 152 );
137 [...] SCHED_FIFO or SCHED_RR can have static priority in 1..99 range.
138 */
139 sp.sched_priority = xstrtou_range(priority, 0, policy != SCHED_OTHER ? 1 : 0, 99);
140 153
141 if (sched_setscheduler(pid, policy, &sp) < 0) 154 if (sched_setscheduler(pid, policy, &sp) < 0)
142 bb_perror_msg_and_die("can't %cet pid %d's policy", 's', (int)pid); 155 bb_perror_msg_and_die("can't %cet pid %d's policy", 's', (int)pid);
diff --git a/util-linux/fdisk_gpt.c b/util-linux/fdisk_gpt.c
index 45d2aa6e7..cdb90627d 100644
--- a/util-linux/fdisk_gpt.c
+++ b/util-linux/fdisk_gpt.c
@@ -177,7 +177,7 @@ check_gpt_label(void)
177 177
178 init_unicode(); 178 init_unicode();
179 if (!global_crc32_table) { 179 if (!global_crc32_table) {
180 global_crc32_table = crc32_filltable(NULL, 0); 180 global_crc32_new_table_le();
181 } 181 }
182 182
183 crc = SWAP_LE32(gpt_hdr->hdr_crc32); 183 crc = SWAP_LE32(gpt_hdr->hdr_crc32);
diff --git a/util-linux/renice.c b/util-linux/renice.c
index 70c494b3d..46704591f 100644
--- a/util-linux/renice.c
+++ b/util-linux/renice.c
@@ -6,7 +6,6 @@
6 * 6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */ 8 */
9
10/* Notes: 9/* Notes:
11 * Setting an absolute priority was obsoleted in SUSv2 and removed 10 * Setting an absolute priority was obsoleted in SUSv2 and removed
12 * in SUSv3. However, the common linux version of renice does 11 * in SUSv3. However, the common linux version of renice does
@@ -42,10 +41,6 @@
42#include "libbb.h" 41#include "libbb.h"
43#include <sys/resource.h> 42#include <sys/resource.h>
44 43
45void BUG_bad_PRIO_PROCESS(void);
46void BUG_bad_PRIO_PGRP(void);
47void BUG_bad_PRIO_USER(void);
48
49int renice_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 44int renice_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
50int renice_main(int argc UNUSED_PARAM, char **argv) 45int renice_main(int argc UNUSED_PARAM, char **argv)
51{ 46{
@@ -59,12 +54,9 @@ int renice_main(int argc UNUSED_PARAM, char **argv)
59 char *arg; 54 char *arg;
60 55
61 /* Yes, they are not #defines in glibc 2.4! #if won't work */ 56 /* Yes, they are not #defines in glibc 2.4! #if won't work */
62 if (PRIO_PROCESS < CHAR_MIN || PRIO_PROCESS > CHAR_MAX) 57 BUILD_BUG_ON(PRIO_PROCESS < CHAR_MIN || PRIO_PROCESS > CHAR_MAX);
63 BUG_bad_PRIO_PROCESS(); 58 BUILD_BUG_ON(PRIO_PGRP < CHAR_MIN || PRIO_PGRP > CHAR_MAX);
64 if (PRIO_PGRP < CHAR_MIN || PRIO_PGRP > CHAR_MAX) 59 BUILD_BUG_ON(PRIO_USER < CHAR_MIN || PRIO_USER > CHAR_MAX);
65 BUG_bad_PRIO_PGRP();
66 if (PRIO_USER < CHAR_MIN || PRIO_USER > CHAR_MAX)
67 BUG_bad_PRIO_USER();
68 60
69 arg = *++argv; 61 arg = *++argv;
70 62
@@ -102,6 +94,7 @@ int renice_main(int argc UNUSED_PARAM, char **argv)
102 /* Process an ID arg. */ 94 /* Process an ID arg. */
103 if (which == PRIO_USER) { 95 if (which == PRIO_USER) {
104 struct passwd *p; 96 struct passwd *p;
97 /* NB: use of getpwnam makes it risky to be NOFORK, switch to getpwnam_r? */
105 p = getpwnam(arg); 98 p = getpwnam(arg);
106 if (!p) { 99 if (!p) {
107 bb_error_msg("unknown user %s", arg); 100 bb_error_msg("unknown user %s", arg);
diff --git a/util-linux/umount.c b/util-linux/umount.c
index a6405dfcc..b45cd8a6b 100644
--- a/util-linux/umount.c
+++ b/util-linux/umount.c
@@ -81,8 +81,8 @@ static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
81} 81}
82#endif 82#endif
83 83
84/* ignored: -v -t -i */ 84/* ignored: -c -v -t -i */
85#define OPTION_STRING "fldnra" "vt:i" 85#define OPTION_STRING "fldnra" "cvt:i"
86#define OPT_FORCE (1 << 0) // Same as MNT_FORCE 86#define OPT_FORCE (1 << 0) // Same as MNT_FORCE
87#define OPT_LAZY (1 << 1) // Same as MNT_DETACH 87#define OPT_LAZY (1 << 1) // Same as MNT_DETACH
88#define OPT_FREELOOP (1 << 2) 88#define OPT_FREELOOP (1 << 2)
diff --git a/util-linux/volume_id/lfs.c b/util-linux/volume_id/lfs.c
new file mode 100644
index 000000000..1a2a2987f
--- /dev/null
+++ b/util-linux/volume_id/lfs.c
@@ -0,0 +1,62 @@
1/*
2 * volume_id - reads filesystem label and uuid
3 *
4 * Copyright (C) 2018 Sven-Göran Bergh <sgb@systemaxion.se>
5 *
6 * Licensed under GPLv2, see file LICENSE in this source tree.
7 */
8//config:config FEATURE_VOLUMEID_LFS
9//config: bool "LittleFS filesystem"
10//config: default y
11//config: depends on VOLUMEID && FEATURE_BLKID_TYPE
12//config: help
13//config: LittleFS is a small fail-safe filesystem designed for embedded
14//config: systems. It has strong copy-on-write guarantees and storage on disk
15//config: is always kept in a valid state. It also provides a form of dynamic
16//config: wear levelling for systems that can not fit a full flash translation
17//config: layer.
18
19//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_LFS) += lfs.o
20
21#include "volume_id_internal.h"
22
23#define LFS_SB1_OFFSET 0x10
24#define LFS_MAGIC_NAME "littlefs"
25#define LFS_MAGIC_LEN 8
26
27// The superblock is stored in the first metadata pair, i.e the first two blocks.
28struct lfs_super_block { // A block in a metadata pair
29// /* 0x00 */ uint32_t rev_count; // Revision count
30// /* 0x04 */ uint32_t dir_size; // Directory size
31// /* 0x08 */ uint64_t tail_ptr; // Tail pointer
32/* 0x10 */ uint8_t entry_type; // Entry type
33/* 0x11 */ uint8_t entry_len; // Entry length
34/* 0x12 */ uint8_t att_len; // Attribute length
35/* 0x13 */ uint8_t name_len; // Name length
36/* 0x14 */ uint64_t root_dir; // Root directory
37/* 0x1C */ uint32_t block_size; // Block size
38/* 0x20 */ uint32_t block_count; // Block count
39/* 0x24 */ uint16_t ver_major; // Version major
40/* 0x26 */ uint16_t ver_minor; // Version minor
41/* 0x28 */ uint8_t magic[LFS_MAGIC_LEN]; // Magic string "littlefs"
42// /* 0x30 */ uint32_t crc; // CRC-32 checksum
43} PACKED;
44
45int FAST_FUNC volume_id_probe_lfs(struct volume_id *id /*,uint64_t off*/)
46{
47 struct lfs_super_block *sb;
48
49 // Go for primary super block (ignore second sb)
50 dbg("lfs: probing at offset 0x%x", LFS_SB1_OFFSET);
51 sb = volume_id_get_buffer(id, LFS_SB1_OFFSET, sizeof(*sb));
52
53 if (!sb)
54 return -1;
55
56 if (memcmp(sb->magic, LFS_MAGIC_NAME, LFS_MAGIC_LEN) != 0)
57 return -1;
58
59 IF_FEATURE_BLKID_TYPE(id->type = LFS_MAGIC_NAME);
60
61 return 0;
62}
diff --git a/util-linux/volume_id/volume_id.c b/util-linux/volume_id/volume_id.c
index 85315ced6..c3f07a741 100644
--- a/util-linux/volume_id/volume_id.c
+++ b/util-linux/volume_id/volume_id.c
@@ -97,6 +97,9 @@ static const probe_fptr fs1[] = {
97#if ENABLE_FEATURE_VOLUMEID_EXFAT 97#if ENABLE_FEATURE_VOLUMEID_EXFAT
98 volume_id_probe_exfat, 98 volume_id_probe_exfat,
99#endif 99#endif
100#if ENABLE_FEATURE_VOLUMEID_LFS
101 volume_id_probe_lfs,
102#endif
100#if ENABLE_FEATURE_VOLUMEID_MAC 103#if ENABLE_FEATURE_VOLUMEID_MAC
101 volume_id_probe_mac_partition_map, 104 volume_id_probe_mac_partition_map,
102#endif 105#endif
diff --git a/util-linux/volume_id/volume_id_internal.h b/util-linux/volume_id/volume_id_internal.h
index 0eaea9b34..ada18339d 100644
--- a/util-linux/volume_id/volume_id_internal.h
+++ b/util-linux/volume_id/volume_id_internal.h
@@ -187,6 +187,8 @@ int FAST_FUNC volume_id_probe_iso9660(struct volume_id *id /*,uint64_t off*/);
187 187
188int FAST_FUNC volume_id_probe_jfs(struct volume_id *id /*,uint64_t off*/); 188int FAST_FUNC volume_id_probe_jfs(struct volume_id *id /*,uint64_t off*/);
189 189
190int FAST_FUNC volume_id_probe_lfs(struct volume_id *id /*,uint64_t off*/);
191
190int FAST_FUNC volume_id_probe_linux_swap(struct volume_id *id /*,uint64_t off*/); 192int FAST_FUNC volume_id_probe_linux_swap(struct volume_id *id /*,uint64_t off*/);
191 193
192int FAST_FUNC volume_id_probe_luks(struct volume_id *id /*,uint64_t off*/); 194int FAST_FUNC volume_id_probe_luks(struct volume_id *id /*,uint64_t off*/);