diff options
author | Ron Yorston <rmy@pobox.com> | 2018-02-13 09:44:44 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2018-02-13 09:44:44 +0000 |
commit | dc19a361bd6c6df30338371532691bbc7f7126bb (patch) | |
tree | 1fb2cd646d54b5f8e425c4f11f3e09fc21d1966b | |
parent | 096aee2bb468d1ab044de36e176ed1f6c7e3674d (diff) | |
parent | 3459024bf404af814cacfe90a0deb719e282ae62 (diff) | |
download | busybox-w32-dc19a361bd6c6df30338371532691bbc7f7126bb.tar.gz busybox-w32-dc19a361bd6c6df30338371532691bbc7f7126bb.tar.bz2 busybox-w32-dc19a361bd6c6df30338371532691bbc7f7126bb.zip |
Merge branch 'busybox' into merge
146 files changed, 2827 insertions, 2127 deletions
@@ -1,5 +1,5 @@ | |||
1 | VERSION = 1 | 1 | VERSION = 1 |
2 | PATCHLEVEL = 28 | 2 | PATCHLEVEL = 29 |
3 | SUBLEVEL = 0 | 3 | SUBLEVEL = 0 |
4 | EXTRAVERSION = .git | 4 | EXTRAVERSION = .git |
5 | NAME = Unnamed | 5 | NAME = 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 |
47 | endif | 47 | endif |
48 | 48 | ||
49 | install-noclobber: INSTALL_OPTS+=--noclobber | ||
50 | install-noclobber: install | ||
51 | |||
49 | uninstall: busybox.links | 52 | uninstall: 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 | |||
72 | bunzip2 - runner | 72 | bunzip2 - runner |
73 | bzcat - runner | 73 | bzcat - runner |
74 | bzip2 - runner | 74 | bzip2 - runner |
75 | cal - runner: cal -n9999 | 75 | cal - noexec. can be runner: cal -n9999 |
76 | cat - runner: cat HUGEFILE | 76 | cat - runner: cat HUGEFILE |
77 | chat - longterm (when used as intended - talking to modem over stdin/out) | 77 | chat - longterm (when used as intended - talking to modem over stdin/out) |
78 | chattr - noexec. runner | 78 | chattr - noexec. runner |
@@ -89,7 +89,7 @@ clear - NOFORK | |||
89 | cmp - runner | 89 | cmp - runner |
90 | comm - runner | 90 | comm - runner |
91 | conspy - interactive, longterm | 91 | conspy - interactive, longterm |
92 | cp - noexec. runner | 92 | cp - noexec. sometimes runner |
93 | cpio - runner | 93 | cpio - runner |
94 | crond - daemon | 94 | crond - daemon |
95 | crontab - longterm (runs $EDITOR), leaks: open+xasprintf | 95 | crontab - longterm (runs $EDITOR), leaks: open+xasprintf |
@@ -255,7 +255,7 @@ mount - suid | |||
255 | mountpoint - noexec. leaks: option -n "print dev name": find_block_device -> readdir+xstrdup | 255 | mountpoint - noexec. leaks: option -n "print dev name": find_block_device -> readdir+xstrdup |
256 | mpstat - longterm: "mpstat 1" runs indefinitely | 256 | mpstat - longterm: "mpstat 1" runs indefinitely |
257 | mt - hardware | 257 | mt - hardware |
258 | mv - noexec candidate, runner | 258 | mv - noexec. sometimes runner |
259 | nameif - noexec. openlog(), leaks: config_open2+ioctl_or_perror_and_die | 259 | nameif - noexec. openlog(), leaks: config_open2+ioctl_or_perror_and_die |
260 | nbd-client - noexec | 260 | nbd-client - noexec |
261 | nc - runner | 261 | nc - 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 | |||
3 | exec >NOFORK_NOEXEC.lst1 | ||
4 | |||
5 | false && 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 | |||
12 | echo === nofork candidate | ||
13 | grep -F 'nofork candidate' NOFORK_NOEXEC.lst \ | ||
14 | |||
15 | echo === noexec candidate | ||
16 | grep -F 'noexec candidate' NOFORK_NOEXEC.lst \ | ||
17 | |||
18 | echo === ^C | ||
19 | grep -F '^C' NOFORK_NOEXEC.lst \ | ||
20 | | grep -F ' - ' \ | ||
21 | |||
22 | echo === talks | ||
23 | grep -F 'talks' NOFORK_NOEXEC.lst \ | ||
24 | | grep -F ' - ' \ | ||
25 | |||
26 | echo === | ||
27 | grep -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 |
10 | fi | 10 | fi |
11 | shift # Keep only remaining options | ||
11 | 12 | ||
12 | # Source the configuration | 13 | # Source the configuration |
13 | . ./.config | 14 | . ./.config |
@@ -21,18 +22,21 @@ scriptwrapper="n" | |||
21 | binaries="n" | 22 | binaries="n" |
22 | cleanup="0" | 23 | cleanup="0" |
23 | noclobber="0" | 24 | noclobber="0" |
24 | case "$2" in | 25 | while [ ${#} -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="";; |
35 | esac | 36 | *) echo "Unknown install option: $1"; exit 1;; |
37 | esac | ||
38 | shift | ||
39 | done | ||
36 | 40 | ||
37 | if [ -n "$DO_INSTALL_LIBS" ] && [ "$DO_INSTALL_LIBS" != "n" ]; then | 41 | if [ -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 | |||
77 | for i in $h; do | 81 | for 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 |
133 | done | 133 | done |
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 */ | ||
25 | enum { | ||
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 | |||
37 | static | 24 | static |
38 | int open_to_or_warn(int to_fd, const char *filename, int flags, int mode) | 25 | int 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; | |||
391 | int gunzip_main(int argc UNUSED_PARAM, char **argv) | 378 | int 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) | |||
455 | int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 442 | int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
456 | int bunzip2_main(int argc UNUSED_PARAM, char **argv) | 443 | int 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) | |||
528 | int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 515 | int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
529 | int unlzma_main(int argc UNUSED_PARAM, char **argv) | 516 | int 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) | |||
596 | int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 583 | int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
597 | int unxz_main(int argc UNUSED_PARAM, char **argv) | 584 | int 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 | */ |
89 | enum { | 110 | enum { |
90 | IOBUF_SIZE = 8 * 1024 | 111 | IOBUF_SIZE = 8 * 1024 |
91 | }; | 112 | }; |
92 | 113 | ||
93 | static 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 | |||
143 | IF_DESKTOP(long long) int FAST_FUNC compressStream(transformer_state_t *xstate UNUSED_PARAM) | 162 | IF_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: |
35 | a: 85.1% -- replaced with a.gz | 20 | a: 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 |
101 | static 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 | |||
316 | struct globals { | 296 | struct 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) | ||
500 | static void put_32bit(ulg n) | 479 | static 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 | } |
495 | static 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 | */ |
542 | static void send_bits(int value, int length) | 536 | static 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 | */ |
586 | static void bi_windup(void) | 591 | static 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: */ | |
686 | static 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 | */ |
1061 | static void gen_codes(ct_data * tree, int max_code); | ||
1062 | static void build_tree(tree_desc * desc); | ||
1063 | static void scan_tree(ct_data * tree, int max_code); | ||
1064 | static void send_tree(ct_data * tree, int max_code); | ||
1065 | static int build_bl_tree(void); | ||
1066 | static void send_all_trees(int lcodes, int dcodes, int blcodes); | ||
1067 | static 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 | */ |
1688 | static ulg flush_block(char *buf, ulg stored_len, int eof) | 1675 | static 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 | ||
1814 | static ulg deflate(void) | 1805 | static 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 | */ |
1923 | static void bi_init(void) | 1912 | static 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 | */ |
1936 | static void lm_init(ush * flagsp) | 1922 | static 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 | |||
2072 | static void zip(void) | 2061 | static 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 | /* ======================================================================== */ |
2106 | static | 2097 | static |
2107 | IF_DESKTOP(long long) int FAST_FUNC pack_gzip(transformer_state_t *xstate UNUSED_PARAM) | 2098 | IF_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 | ||
229 | static | 233 | static |
230 | void fallbackSort(uint32_t* fmap, | 234 | void 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 | /*---------------------------------------------*/ |
368 | static | 375 | static |
369 | NOINLINE | 376 | NOINLINE |
370 | int mainGtU( | 377 | int 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 | */ |
454 | static | 461 | static |
455 | const int32_t incs[14] = { | 462 | const 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 | ||
461 | static | 468 | static |
462 | void mainSimpleSort(uint32_t* ptr, | 469 | void 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 | ||
588 | static NOINLINE | 597 | static NOINLINE |
589 | void mainQSort3(uint32_t* ptr, | 598 | void 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 | ||
723 | static NOINLINE | 732 | static NOINLINE |
724 | void mainSort(EState* state, | 733 | void 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 | */ |
1017 | static NOINLINE | 1027 | static NOINLINE |
1018 | void BZ2_blockSort(EState* s) | 1028 | int32_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) | |||
86 | static | 87 | static |
87 | void BZ2_bzCompressInit(bz_stream *strm, int blockSize100k) | 88 | void 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 | ||
202 | static void | 206 | static int32_t |
203 | BZ2_blockSort(EState*); | 207 | BZ2_blockSort(EState*); |
204 | 208 | ||
205 | static void | 209 | static 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 | |||
50 | void bsFinishWrite(EState* s) | 56 | void 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 | /*---------------------------------------------------*/ |
62 | static | 67 | static |
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 | 69 | ALWAYS_INLINE_5 |
65 | ALWAYS_INLINE | ||
66 | #endif | ||
67 | void bsW(EState* s, int32_t n, uint32_t v) | 70 | void 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: */ | ||
81 | static | ||
82 | ALWAYS_INLINE_5 | ||
83 | void 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: */ | ||
94 | static | ||
95 | ALWAYS_INLINE /* one callsite */ | ||
96 | void 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 | } | ||
107 | static | ||
108 | ALWAYS_INLINE_5 | ||
109 | void 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 | /*---------------------------------------------------*/ |
81 | static | 123 | static ALWAYS_INLINE |
82 | void bsPutU32(EState* s, unsigned u) | 124 | void 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 | /*---------------------------------------------------*/ |
92 | static | 131 | static |
93 | void bsPutU16(EState* s, unsigned u) | 132 | void 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 | |||
106 | void makeMaps_e(EState* s) | 146 | void 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 | */ | ||
172 | static | ||
173 | #if defined __i386__ | ||
174 | NOINLINE | ||
175 | #endif | ||
176 | int 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 | } | ||
120 | static NOINLINE | 193 | static NOINLINE |
121 | void generateMTFValues(EState* s) | 194 | void 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) | |||
249 | static NOINLINE | 300 | static NOINLINE |
250 | void sendMTFValues(EState* s) | 301 | void 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) | |||
605 | static | 676 | static |
606 | void BZ2_compressBlock(EState* s, int is_last_block) | 677 | void 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 */ |
33 | int lzo1x_decompress_safe(const uint8_t* in, unsigned in_len, | 33 | int 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 | ||
143 | static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len, | 143 | static 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 | # |
6 | CONFIG_HAVE_DOT_CONFIG=y | 6 | CONFIG_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 | |||
153 | CONFIG_XZCAT=y | 153 | CONFIG_XZCAT=y |
154 | CONFIG_XZ=y | 154 | CONFIG_XZ=y |
155 | CONFIG_BZIP2=y | 155 | CONFIG_BZIP2=y |
156 | CONFIG_BZIP2_SMALL=8 | ||
156 | CONFIG_FEATURE_BZIP2_DECOMPRESS=y | 157 | CONFIG_FEATURE_BZIP2_DECOMPRESS=y |
157 | CONFIG_CPIO=y | 158 | CONFIG_CPIO=y |
158 | CONFIG_FEATURE_CPIO_O=y | 159 | CONFIG_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 |
773 | CONFIG_FEATURE_LESS_DASHCMD=y | 775 | CONFIG_FEATURE_LESS_DASHCMD=y |
774 | CONFIG_FEATURE_LESS_LINENUMS=y | 776 | CONFIG_FEATURE_LESS_LINENUMS=y |
777 | CONFIG_FEATURE_LESS_RAW=y | ||
778 | CONFIG_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 | |||
1058 | CONFIG_ASH_OPTIMIZE_FOR_SIZE=y | 1064 | CONFIG_ASH_OPTIMIZE_FOR_SIZE=y |
1059 | CONFIG_ASH_INTERNAL_GLOB=y | 1065 | CONFIG_ASH_INTERNAL_GLOB=y |
1060 | CONFIG_ASH_BASH_COMPAT=y | 1066 | CONFIG_ASH_BASH_COMPAT=y |
1067 | # CONFIG_ASH_BASH_SOURCE_CURDIR is not set | ||
1068 | CONFIG_ASH_BASH_NOT_FOUND_HOOK=y | ||
1061 | # CONFIG_ASH_JOB_CONTROL is not set | 1069 | # CONFIG_ASH_JOB_CONTROL is not set |
1062 | CONFIG_ASH_ALIAS=y | 1070 | CONFIG_ASH_ALIAS=y |
1063 | CONFIG_ASH_RANDOM_SUPPORT=y | 1071 | CONFIG_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 | # |
6 | CONFIG_HAVE_DOT_CONFIG=y | 6 | CONFIG_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 | |||
153 | CONFIG_XZCAT=y | 153 | CONFIG_XZCAT=y |
154 | CONFIG_XZ=y | 154 | CONFIG_XZ=y |
155 | CONFIG_BZIP2=y | 155 | CONFIG_BZIP2=y |
156 | CONFIG_BZIP2_SMALL=8 | ||
156 | CONFIG_FEATURE_BZIP2_DECOMPRESS=y | 157 | CONFIG_FEATURE_BZIP2_DECOMPRESS=y |
157 | CONFIG_CPIO=y | 158 | CONFIG_CPIO=y |
158 | CONFIG_FEATURE_CPIO_O=y | 159 | CONFIG_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 |
773 | CONFIG_FEATURE_LESS_DASHCMD=y | 775 | CONFIG_FEATURE_LESS_DASHCMD=y |
774 | CONFIG_FEATURE_LESS_LINENUMS=y | 776 | CONFIG_FEATURE_LESS_LINENUMS=y |
777 | CONFIG_FEATURE_LESS_RAW=y | ||
778 | CONFIG_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 | |||
1058 | CONFIG_ASH_OPTIMIZE_FOR_SIZE=y | 1064 | CONFIG_ASH_OPTIMIZE_FOR_SIZE=y |
1059 | CONFIG_ASH_INTERNAL_GLOB=y | 1065 | CONFIG_ASH_INTERNAL_GLOB=y |
1060 | CONFIG_ASH_BASH_COMPAT=y | 1066 | CONFIG_ASH_BASH_COMPAT=y |
1067 | # CONFIG_ASH_BASH_SOURCE_CURDIR is not set | ||
1068 | CONFIG_ASH_BASH_NOT_FOUND_HOOK=y | ||
1061 | # CONFIG_ASH_JOB_CONTROL is not set | 1069 | # CONFIG_ASH_JOB_CONTROL is not set |
1062 | CONFIG_ASH_ALIAS=y | 1070 | CONFIG_ASH_ALIAS=y |
1063 | CONFIG_ASH_RANDOM_SUPPORT=y | 1071 | CONFIG_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) | |||
168 | int cat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 168 | int cat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
169 | int cat_main(int argc UNUSED_PARAM, char **argv) | 169 | int 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; | |||
31 | int cksum_main(int argc UNUSED_PARAM, char **argv) | 31 | int 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 | ||
140 | static void dd_output_status(int UNUSED_PARAM cur_signal) | 142 | static 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 }; | |||
47 | static const mode_t modes_cubp[] = { S_IFIFO, S_IFCHR, S_IFBLK }; | 47 | static const mode_t modes_cubp[] = { S_IFIFO, S_IFCHR, S_IFBLK }; |
48 | 48 | ||
49 | int mknod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 49 | int mknod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
50 | int mknod_main(int argc, char **argv) | 50 | int 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 | ||
28 | int nice_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 28 | int nice_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
29 | int nice_main(int argc, char **argv) | 29 | int 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 @@ | |||
30 | int which_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 30 | int which_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
31 | int which_main(int argc UNUSED_PARAM, char **argv) | 31 | int 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 | | |
181 | dd compatibility options: | ||
182 | conv=fsync | yes | | | ||
181 | iflag=skip_bytes| yes | | | 183 | iflag=skip_bytes| yes | | |
182 | dd Busybox specific options: | 184 | iflag=fullblock | yes | | |
183 | conv=fsync | ||
184 | 185 | ||
185 | df POSIX options | 186 | df 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 | ||
3147 | int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 3155 | int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
3148 | int awk_main(int argc, char **argv) | 3156 | int 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) | ||
266 | enum { | ||
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 | ||
264 | void check_errors_in_children(int signo); | 279 | void 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") |
439 | extern int remove_file(const char *path, int flags) FAST_FUNC; | 440 | extern 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. */ | |||
658 | int setsockopt_keepalive(int fd) FAST_FUNC; | 659 | int setsockopt_keepalive(int fd) FAST_FUNC; |
659 | int setsockopt_broadcast(int fd) FAST_FUNC; | 660 | int setsockopt_broadcast(int fd) FAST_FUNC; |
660 | int setsockopt_bindtodevice(int fd, const char *iface) FAST_FUNC; | 661 | int setsockopt_bindtodevice(int fd, const char *iface) FAST_FUNC; |
662 | int 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 */ |
662 | unsigned bb_lookup_port(const char *port, const char *protocol, unsigned default_port) FAST_FUNC; | 664 | unsigned bb_lookup_port(const char *port, const char *protocol, unsigned default_port) FAST_FUNC; |
663 | typedef struct len_and_sockaddr { | 665 | typedef 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 | } |
796 | void tls_handshake(tls_state_t *tls, const char *sni) FAST_FUNC; | 798 | void tls_handshake(tls_state_t *tls, const char *sni) FAST_FUNC; |
797 | void tls_run_copy_loop(tls_state_t *tls) FAST_FUNC; | 799 | #define TLSLOOP_EXIT_ON_LOCAL_EOF (1 << 0) |
800 | void tls_run_copy_loop(tls_state_t *tls, unsigned flags) FAST_FUNC; | ||
798 | 801 | ||
799 | 802 | ||
800 | void socket_want_pktinfo(int fd) FAST_FUNC; | 803 | void 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 | ||
810 | uint16_t inet_cksum(uint16_t *addr, int len) FAST_FUNC; | 813 | uint16_t inet_cksum(uint16_t *addr, int len) FAST_FUNC; |
814 | int parse_pasv_epsv(char *buf) FAST_FUNC; | ||
811 | 815 | ||
812 | /* 0 if argv[0] is NULL: */ | 816 | /* 0 if argv[0] is NULL: */ |
813 | unsigned string_array_len(char **argv) FAST_FUNC; | 817 | unsigned string_array_len(char **argv) FAST_FUNC; |
@@ -1966,6 +1970,8 @@ typedef struct md5_ctx_t md5sha_ctx_t; | |||
1966 | 1970 | ||
1967 | extern uint32_t *global_crc32_table; | 1971 | extern uint32_t *global_crc32_table; |
1968 | uint32_t *crc32_filltable(uint32_t *tbl256, int endian) FAST_FUNC; | 1972 | uint32_t *crc32_filltable(uint32_t *tbl256, int endian) FAST_FUNC; |
1973 | uint32_t *crc32_new_table_le(void) FAST_FUNC; | ||
1974 | uint32_t *global_crc32_new_table_le(void) FAST_FUNC; | ||
1969 | uint32_t crc32_block_endian1(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) FAST_FUNC; | 1975 | uint32_t crc32_block_endian1(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) FAST_FUNC; |
1970 | uint32_t crc32_block_endian0(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) FAST_FUNC; | 1976 | uint32_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 |
2049 | extern const char bb_busybox_exec_path[] ALIGN1; | 2055 | extern 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 |
2053 | extern 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 | ||
2062 | extern 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 | ||
2057 | extern const int const_int_0; | 2069 | extern 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 */ |
55 | int lzo1x_decompress_safe(const uint8_t* src, unsigned src_len, | 54 | int 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 */ |
208 | struct init_action { | 208 | struct 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 | ||
216 | static struct init_action *init_action_list = NULL; | 216 | struct globals { |
217 | 217 | struct init_action *init_action_list; | |
218 | #if !ENABLE_FEATURE_INIT_SYSLOG | 218 | #if !ENABLE_FEATURE_INIT_SYSLOG |
219 | static 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 | ||
222 | enum { | 228 | enum { |
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) | |||
1046 | int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 1052 | int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
1047 | int init_main(int argc UNUSED_PARAM, char **argv) | 1053 | int 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 | |||
128 | lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o | 128 | lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o |
129 | 129 | ||
130 | lib-$(CONFIG_NC_110_COMPAT) += udp_io.o | 130 | lib-$(CONFIG_NC_110_COMPAT) += udp_io.o |
131 | lib-$(CONFIG_NETCAT) += udp_io.o | ||
131 | lib-$(CONFIG_DNSD) += udp_io.o | 132 | lib-$(CONFIG_DNSD) += udp_io.o |
132 | lib-$(CONFIG_NTPD) += udp_io.o | 133 | lib-$(CONFIG_NTPD) += udp_io.o |
133 | lib-$(CONFIG_TFTP) += udp_io.o | 134 | lib-$(CONFIG_TFTP) += udp_io.o |
@@ -146,7 +147,8 @@ lib-$(CONFIG_DELGROUP) += update_passwd.o | |||
146 | lib-$(CONFIG_DELUSER) += update_passwd.o | 147 | lib-$(CONFIG_DELUSER) += update_passwd.o |
147 | 148 | ||
148 | lib-$(CONFIG_FTPD) += pw_encrypt.o correct_password.o | 149 | lib-$(CONFIG_FTPD) += pw_encrypt.o correct_password.o |
149 | lib-$(CONFIG_PASSWD) += pw_encrypt.o update_passwd.o obscure.o | 150 | lib-$(CONFIG_PASSWD) += pw_encrypt.o update_passwd.o |
151 | lib-$(CONFIG_FEATURE_PASSWD_WEAK_CHECK) += obscure.o | ||
150 | lib-$(CONFIG_CHPASSWD) += pw_encrypt.o update_passwd.o | 152 | lib-$(CONFIG_CHPASSWD) += pw_encrypt.o update_passwd.o |
151 | lib-$(CONFIG_CRYPTPW) += pw_encrypt.o | 153 | lib-$(CONFIG_CRYPTPW) += pw_encrypt.o |
152 | lib-$(CONFIG_MKPASSWD) += pw_encrypt.o | 154 | lib-$(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 | |||
11 | int 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: */ | ||
45 | uint32_t* FAST_FUNC crc32_new_table_le(void) | ||
46 | { | ||
47 | return crc32_filltable(NULL, 0); | ||
48 | } | ||
49 | uint32_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 | ||
45 | uint32_t FAST_FUNC crc32_block_endian1(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) | 55 | uint32_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 | */ |
79 | int FAST_FUNC executable_exists(const char *filename) | 96 | int 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 |
93 | static bool BB_isalnum_or_underscore(CHAR_T c) { | 93 | static 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; | |||
38 | const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL; | 33 | const 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! */ |
41 | const char bb_PATH_root_path[] ALIGN1 = | 36 | const 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 = | |||
142 | int addgroup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 142 | int addgroup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
143 | int addgroup_main(int argc UNUSED_PARAM, char **argv) | 143 | int 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" | |||
12 | test -f include/applets.h || { echo "No include/applets.h file"; exit 1; } | 12 | test -f include/applets.h || { echo "No include/applets.h file"; exit 1; } |
13 | apps="` | 13 | apps="` |
14 | grep ^IF_ include/applets.h \ | 14 | grep ^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 | ||
47 | enum { | 47 | enum { |
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 | ||
57 | struct globals { | 66 | struct 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 | ||
102 | static int send_pack(struct in_addr *src_addr, | 112 | static 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) | |||
258 | static void | 262 | static void |
259 | cmdio_write_ok(unsigned status) | 263 | cmdio_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) | |||
269 | static void | 273 | static void |
270 | cmdio_write_error(unsigned status) | 274 | cmdio_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 | |||
599 | handle_rest(void) | 603 | handle_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 | ||
159 | static int xconnect_ftpdata(void) | 159 | static 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) { |
165 | TODO: PASV command will not work for IPv6. RFC2428 describes | 164 | /* good */ |
166 | IPv6-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 | ||
169 | in specified protocol. Protocol is 1 for IPv4, 2 for IPv6. | ||
170 | If not specified, defaults to "same as used for control connection". | ||
171 | If server understood you, it should answer "229 <some text>(|||port|)" | ||
172 | where "|" are literal pipe chars and "port" is ASCII decimal port#. | ||
173 | |||
174 | There is also an IPv6-capable replacement for PORT (EPRT), | ||
175 | but we don't need that. | ||
176 | |||
177 | NB: PASV may still work for some servers even over IPv6. | ||
178 | For example, vsftp happily answers | ||
179 | "227 Entering Passive Mode (0,0,0,0,n,n)" and proceeds as usual. | ||
180 | |||
181 | TODO2: 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 | |||
12 | lib-$(CONFIG_SLATTACH) += \ | 12 | lib-$(CONFIG_SLATTACH) += \ |
13 | utils.o | 13 | utils.o |
14 | 14 | ||
15 | lib-$(CONFIG_TC) += \ | ||
16 | libnetlink.o \ | ||
17 | ll_map.o \ | ||
18 | ll_proto.o \ | ||
19 | utils.o | ||
20 | |||
15 | lib-$(CONFIG_IP) += \ | 21 | lib-$(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 | ||
16 | void FAST_FUNC xrtnl_open(struct rtnl_handle *rth/*, unsigned subscriptions*/) | 16 | void 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 | ||
402 | void FAST_FUNC parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) | 399 | void 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 | |||
14 | int 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 | ||
55 | enum | ||
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". */ |
188 | static int prio_parse_opt(int argc, char **argv, struct nlmsghdr *n) | 202 | static int prio_parse_opt(int argc, char **argv, struct nlmsghdr *n) |
189 | { | 203 | { |
190 | return 0; | 204 | return 0; |
191 | } | 205 | } |
206 | #endif | ||
192 | static int prio_print_opt(struct rtattr *opt) | 207 | static 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 */ |
215 | static int cbq_parse_opt(int argc, char **argv, struct nlmsghdr *n) | 231 | static int cbq_parse_opt(int argc, char **argv, struct nlmsghdr *n) |
216 | { | 232 | { |
217 | return 0; | 233 | return 0; |
218 | } | 234 | } |
235 | #endif | ||
219 | static int cbq_print_opt(struct rtattr *opt) | 236 | static 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 | ||
311 | static int print_qdisc(const struct sockaddr_nl *who UNUSED_PARAM, | 328 | static 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 | ||
367 | static int print_class(const struct sockaddr_nl *who UNUSED_PARAM, | 386 | static 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 | ||
435 | static int print_filter(const struct sockaddr_nl *who UNUSED_PARAM, | 456 | static 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 |
212 | static void tftp_progress_update(void) | 212 | static 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 | ||
776 | static int tls_xread_record(tls_state_t *tls) | 780 | static 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) | |||
1137 | static int tls_xread_handshake_block(tls_state_t *tls, int min_len) | 1144 | static 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 | ||
1716 | void FAST_FUNC tls_run_copy_loop(tls_state_t *tls) | 1730 | void 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 | |||
94 | config UDHCPC_DEFAULT_SCRIPT | 94 | config 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 { | |||
133 | struct client6_data_t { | 133 | struct 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 */ |
48 | struct 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 | ||
256 | int dhcprelay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 256 | int dhcprelay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
257 | int dhcprelay_main(int argc, char **argv) | 257 | int 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 { | |||
176 | static const char P_FTP[] ALIGN1 = "ftp"; | 177 | static const char P_FTP[] ALIGN1 = "ftp"; |
177 | static const char P_HTTP[] ALIGN1 = "http"; | 178 | static const char P_HTTP[] ALIGN1 = "http"; |
178 | #if SSL_SUPPORTED | 179 | #if SSL_SUPPORTED |
180 | # if ENABLE_FEATURE_WGET_HTTPS | ||
181 | static const char P_FTPS[] ALIGN1 = "ftps"; | ||
182 | # endif | ||
179 | static const char P_HTTPS[] ALIGN1 = "https"; | 183 | static 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 | ||
351 | static 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 |
361 | static void alarm_handler(int sig UNUSED_PARAM) | 356 | static 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 | */ | ||
424 | static 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' */ |
423 | static char fgets_and_trim(FILE *fp, const char *fmt) | 440 | static 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 | ||
559 | static char *gethdr(FILE *fp) | 589 | static 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 | ||
611 | static 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 |
693 | static int spawn_https_helper_openssl(const char *host, unsigned port) | 642 | static 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 |
768 | static void spawn_ssl_client(const char *host, int network_fd) | 717 | static 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 | ||
768 | static 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 | |||
817 | static void NOINLINE retrieve_file_data(FILE *dfp) | 863 | static 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 | ||
842 | int mpstat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 842 | int mpstat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
843 | int mpstat_main(int UNUSED_PARAM argc, char **argv) | 843 | int 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 | ||
688 | int powertop_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 688 | int powertop_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
689 | int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) | 689 | int 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 | |||
52 | if test x"$LIBC" = x"glibc"; then | 52 | if 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++ |
71 | done | 72 | done |
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 |
282 | union node; | 311 | union node; |
283 | struct strlist; | 312 | struct 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 | }; |
472 | extern struct globals_misc *const ash_ptr_to_globals_misc; | 503 | extern 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 | ||
811 | struct ncmd { | 843 | struct 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 | ||
824 | struct nredir { | 857 | struct 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 | ||
843 | struct nfor { | 877 | struct 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 | ||
850 | struct ncase { | 885 | struct 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 | ||
899 | struct ndefun { | ||
900 | smallint type; | ||
901 | int linno; | ||
902 | char *text; | ||
903 | union node *body; | ||
904 | }; | ||
905 | |||
863 | struct narg { | 906 | struct 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 | ||
1341 | static struct parsefile basepf; /* top level input file */ | 1385 | static struct parsefile basepf; /* top level input file */ |
1342 | static struct parsefile *g_parsefile = &basepf; /* current input file */ | 1386 | static struct parsefile *g_parsefile = &basepf; /* current input file */ |
1343 | static int startlinno; /* line # where last token started */ | ||
1344 | static char *commandname; /* currently executing command */ | 1387 | static 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; | |||
1407 | static void | 1450 | static void |
1408 | raise_error_syntax(const char *msg) | 1451 | raise_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 | }; |
1532 | extern struct globals_memstack *const ash_ptr_to_globals_memstack; | 1576 | extern 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 | ||
1622 | static inline void | 1666 | static ALWAYS_INLINE void |
1623 | grabstackblock(size_t len) | 1667 | grabstackblock(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 | }; |
2118 | extern struct globals_var *const ash_ptr_to_globals_var; | 2165 | extern 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 | ||
6212 | static 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 | ||
6366 | static char * | 6445 | static char * |
6367 | rmescapes(char *str, int flag) | 6446 | rmescapes(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) | |||
6482 | static char * | 6561 | static char * |
6483 | preglob(const char *pattern, int flag) | 6562 | preglob(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) |
9201 | static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ | 9329 | static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ |
9202 | static int skipcount; /* number of levels to skip */ | 9330 | static int skipcount; /* number of levels to skip */ |
9203 | static int funcnest; /* depth of function calls */ | ||
9204 | static int loopnest; /* current loop nesting level */ | 9331 | static int loopnest; /* current loop nesting level */ |
9332 | static 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 */ |
9207 | static int evalstring(char *s, int flags); | 9335 | static 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 | ||
13400 | static int FAST_FUNC | 13559 | static 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 @@ | |||
1 | This 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 | |||
6 | Applies cleanly on top of: | ||
7 | commit 9832bbaba966f0e52e183f10cd93fad7f8f643fe | ||
8 | Date: Tue Aug 15 15:44:41 2017 +0200 | ||
9 | |||
10 | Testsuite needs some tweaks (line numbers in some messages change). | ||
11 | |||
12 | Unfortunately, it is somewhat big: | ||
13 | |||
14 | function old new delta | ||
15 | parse_command 1581 1658 +77 | ||
16 | calcsize 203 272 +69 | ||
17 | copynode 195 257 +62 | ||
18 | lookupvar 59 108 +49 | ||
19 | evaltree 494 534 +40 | ||
20 | evalfor 152 187 +35 | ||
21 | evalcase 278 313 +35 | ||
22 | evalcommand 1547 1581 +34 | ||
23 | evalsubshell 169 199 +30 | ||
24 | linenovar - 22 +22 | ||
25 | raise_error_syntax 11 29 +18 | ||
26 | evalfun 266 280 +14 | ||
27 | varinit_data 96 108 +12 | ||
28 | cmdtxt 626 631 +5 | ||
29 | lineno - 4 +4 | ||
30 | funcline - 4 +4 | ||
31 | ash_vmsg 144 141 -3 | ||
32 | startlinno 4 - -4 | ||
33 | funcnest 4 - -4 | ||
34 | xxreadtoken 272 259 -13 | ||
35 | readtoken1 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 | |||
42 | diff --git a/shell/ash.c b/shell/ash.c | ||
43 | index 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 @@ | |||
1 | 1 1 | ||
2 | 1 1 | ||
3 | 1 1 | ||
4 | 1 1 | ||
5 | Ok: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 @@ | |||
1 | echo 1 $((0++1)) | ||
2 | echo 1 $((0--1)) | ||
3 | x=-1; echo 1 $((0-$x)) | ||
4 | x=+1; echo 1 $((0+$x)) | ||
5 | echo 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 |
127 | 5 5 | 127 | 5 5 |
128 | 1 1 | 128 | 1 1 |
129 | 6 6 | ||
130 | 2 2 | ||
131 | 3 3 | ||
132 | 1 1 | ||
129 | 4 4 | 133 | 4 4 |
130 | 0 0 | 134 | 0 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 @@ | |||
23 | echo 5 $(( 4 + ++a )) | 23 | echo 5 $(( 4 + ++a )) |
24 | echo 1 $a | 24 | echo 1 $a |
25 | 25 | ||
26 | # ash doesn't handle it right... | 26 | # this is treated as 4 + ++a |
27 | #ash# echo 6 $(( 4+++a )) | 27 | echo 6 $(( 4+++a )) |
28 | #ash# echo 2 $a | 28 | echo 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 )) | 32 | echo 3 $(( 4---a )) |
33 | #ash# echo 1 $a | 33 | echo 1 $a |
34 | a=1 | 34 | a=1 |
35 | 35 | ||
36 | echo 4 $(( 4 - -- a )) | 36 | echo 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 | |||
2 | b#c | ||
3 | Done: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 @@ | |||
1 | echo | ||
2 | echo 'b#c' | ||
3 | echo 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 | |||
2 | Done: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 @@ | |||
1 | c=`printf '\3'` | ||
2 | eval "echo $c" | ||
3 | echo 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 | |||
5 | b'c | 5 | b'c |
6 | b$c | 6 | b$c |
7 | b`true`c | 7 | b`true`c |
8 | b#c | ||
8 | Zero:0 | 9 | Zero: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. | 2 | for 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 | |||
6 | for a in 'a' 'b\c' 'b\\c' 'b"c' "b'c" 'b$c' 'b`true`c' ### 'b#c' | ||
7 | do | 3 | do |
8 | echo $a | 4 | echo $a |
9 | done | 5 | done |
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 @@ | |||
1 | 0 | 1 | 0 |
2 | 0 | 2 | 0 |
3 | ./emptytick.tests: line 3: : Permission denied | 3 | ./emptytick.tests: line 1: : Permission denied |
4 | 127 | 4 | 127 |
5 | ./emptytick.tests: line 4: : Permission denied | 5 | ./emptytick.tests: line 1: : Permission denied |
6 | 127 | 6 | 127 |
7 | 0 | 7 | 0 |
8 | 0 | 8 | 0 |
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 | |||
3 | SHELL: line 1: syntax error: bad substitution | 3 | SHELL: line 1: syntax error: bad substitution |
4 | SHELL: line 1: syntax error: bad substitution | 4 | SHELL: line 1: syntax error: bad substitution |
5 | SHELL: line 1: syntax error: missing '}' | 5 | SHELL: line 1: syntax error: missing '}' |
6 | 0 | ||
6 | 1 =|| | 7 | 1 =|| |
7 | 1:1 =|| | 8 | 1:1 =|| |
8 | 1:1:2=|| | 9 | 1: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 |
17 | set --; echo "1 =|${1}|" | 17 | set --; 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 @@ | |||
1 | v | ||
2 | Ok: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 @@ | |||
1 | v=v | ||
2 | echo ${v//} | ||
3 | echo 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 | |||
2 | Ok: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 @@ | |||
1 | v='' | ||
2 | echo ${v/*/w} | ||
3 | echo 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 | ||
467 | struct variable; | 483 | struct variable; |
468 | 484 | ||
@@ -608,6 +624,9 @@ typedef enum redir_type { | |||
608 | struct command { | 624 | struct 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 |
2282 | static int unset_local_var(const char *name) | 2320 | static 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 |
2304 | static void FAST_FUNC set_local_var_from_halves(const char *name, const char *val) | 2342 | static 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 | */ |
3648 | static int reserved_word(o_string *word, struct parse_context *ctx) | 3704 | static 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 | |||
5534 | static char *encode_then_expand_string(const char *str, int process_bkslash, int do_unbackslash) | 5624 | static 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 | */ |
5641 | static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, char **pp) | 5735 | static 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 |
6203 | static char* expand_strvec_to_string(char **argv) | 6310 | static 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 | ||
6225 | static char **expand_assignments(char **argv, int count) | 6333 | static char **expand_assignments(char **argv, int count) |
6226 | { | 6334 | { |
@@ -6513,8 +6621,17 @@ static void parse_and_run_string(const char *s) | |||
6513 | static void parse_and_run_file(FILE *f) | 6621 | static 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 | ||
7451 | static 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 @@ | |||
1 | 1 1 | ||
2 | 1 1 | ||
3 | 1 1 | ||
4 | 1 1 | ||
5 | Ok: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 @@ | |||
1 | echo 1 $((0++1)) | ||
2 | echo 1 $((0--1)) | ||
3 | x=-1; echo 1 $((0-$x)) | ||
4 | x=+1; echo 1 $((0+$x)) | ||
5 | echo 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 | |||
135 | hush: arithmetic syntax error | 135 | hush: arithmetic syntax error |
136 | 5 5 | 136 | 5 5 |
137 | 1 1 | 137 | 1 1 |
138 | 6 6 | ||
139 | 2 2 | ||
140 | 3 3 | ||
141 | 1 1 | ||
138 | 4 4 | 142 | 4 4 |
139 | 0 0 | 143 | 0 0 |
140 | hush: arithmetic syntax error | 144 | hush: 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 @@ | |||
23 | echo 5 $(( 4 + ++a )) | 23 | echo 5 $(( 4 + ++a )) |
24 | echo 1 $a | 24 | echo 1 $a |
25 | 25 | ||
26 | # ash doesn't handle it right... | 26 | # this is treated as 4 + ++a |
27 | #ash# echo 6 $(( 4+++a )) | 27 | echo 6 $(( 4+++a )) |
28 | #ash# echo 2 $a | 28 | echo 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 )) | 32 | echo 3 $(( 4---a )) |
33 | #ash# echo 1 $a | 33 | echo 1 $a |
34 | a=1 | 34 | a=1 |
35 | 35 | ||
36 | echo 4 $(( 4 - -- a )) | 36 | echo 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 @@ | |||
1 | test1 | ||
2 | hush: 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 @@ | |||
1 | echo "echo test1; ./test2.sh" >test1.sh | ||
2 | echo "echo test2" >test2.sh | ||
3 | |||
4 | command . ./test1.sh | ||
5 | |||
6 | rm -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 | |||
2 | b#c | ||
3 | Done: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 @@ | |||
1 | echo | ||
2 | echo 'b#c' | ||
3 | echo 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 | |||
2 | Done: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 @@ | |||
1 | c=`printf '\3'` | ||
2 | eval "echo $c" | ||
3 | echo 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 | |||
5 | b'c | 5 | b'c |
6 | b$c | 6 | b$c |
7 | b`true`c | 7 | b`true`c |
8 | b#c | ||
8 | Zero:0 | 9 | Zero: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. | 2 | for 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 | |||
6 | for a in 'a' 'b\c' 'b\\c' 'b"c' "b'c" 'b$c' 'b`true`c' ### 'b#c' | ||
7 | do | 3 | do |
8 | echo $a | 4 | echo $a |
9 | done | 5 | done |
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} | |||
3 | hush: syntax error: unterminated ${name} | 3 | hush: syntax error: unterminated ${name} |
4 | hush: syntax error: unterminated ${name} | 4 | hush: syntax error: unterminated ${name} |
5 | 0123456789 | 5 | 0123456789 |
6 | 0 | ||
6 | 1 =|| | 7 | 1 =|| |
7 | 1:1 =|| | 8 | 1:1 =|| |
8 | 1:1:2=|| | 9 | 1: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 |
17 | set --; echo "1 =|${1}|" | 17 | set --; 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 @@ | |||
1 | 2:2 | ||
2 | 3:3 | ||
3 | 4:4 | ||
4 | 5:5 | ||
5 | 2:2 | ||
6 | 3:3 | ||
7 | 4:4 | ||
8 | 5: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 @@ | |||
1 | env | grep LINENO | ||
2 | echo 2:$LINENO | ||
3 | echo 3:$LINENO >&2 \ | ||
4 | | { sleep 0.1; echo 4:$LINENO; } | ||
5 | echo 5:$LINENO | ||
6 | test "$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 @@ | |||
1 | v | ||
2 | Ok: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 @@ | |||
1 | v=v | ||
2 | echo ${v//} | ||
3 | echo 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 | |||
2 | Ok: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 @@ | |||
1 | v='' | ||
2 | echo ${v/*/w} | ||
3 | echo 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" |
28 | done | 28 | done |
@@ -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))" |
35 | done | 35 | done |
36 | 36 | ||
37 | grep ^IF_ include/applets.h \ | 37 | grep ^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 | ||
264 | prg=' | ||
265 | BEGIN{ | ||
266 | cnt = 0 | ||
267 | a[cnt] = "zeroth" | ||
268 | a[++cnt] = "first" | ||
269 | delete a[cnt--] | ||
270 | print cnt | ||
271 | print "[0]:" a[0] | ||
272 | print "[1]:" a[1] | ||
273 | }' | ||
274 | testing "awk 'delete a[v--]' evaluates v-- once" \ | ||
275 | "awk '$prg'" \ | ||
276 | "\ | ||
277 | 0 | ||
278 | [0]:zeroth | ||
279 | [1]: | ||
280 | " \ | ||
281 | "" "" | ||
282 | |||
264 | testing "awk handles empty ()" \ | 283 | testing "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 |
8 | test -f "$bindir/.config" && . "$bindir/.config" | ||
8 | 9 | ||
9 | ln -s `which busybox` unknown | 10 | ln -s `which busybox` unknown |
10 | 11 | ||
@@ -18,29 +19,24 @@ test x"$CONFIG_BUSYBOX" = x"y" \ | |||
18 | 19 | ||
19 | HELPDUMP=`true | busybox 2>&1 | cat` | 20 | HELPDUMP=`true | busybox 2>&1 | cat` |
20 | 21 | ||
21 | # We need to test under calling the binary under other names. | ||
22 | |||
23 | optional FEATURE_VERBOSE_USAGE | 22 | optional FEATURE_VERBOSE_USAGE |
24 | testing "busybox --help busybox" "true | busybox --help busybox 2>&1 | cat" "$HELPDUMP\n\n" "" "" | 23 | testing "busybox --help busybox" "true | busybox --help busybox 2>&1 | cat" "$HELPDUMP\n" "" "" |
25 | SKIP= | 24 | SKIP= |
26 | 25 | ||
27 | ln -s `which busybox` busybox-suffix | 26 | ln -s `which busybox` busybox-suffix |
28 | for i in busybox ./busybox-suffix | 27 | for i in busybox ./busybox-suffix |
29 | do | 28 | do |
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 | ||
3 | test -f "$bindir/.config" && . "$bindir/.config" | ||
4 | |||
3 | FAILCOUNT=0 | 5 | FAILCOUNT=0 |
4 | 6 | ||
5 | bb="busybox " | 7 | bb="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 |
75 | testing "bzcat can print many files" \ | 77 | testing "bzcat can print many files" \ |
76 | "$ECHO -ne '$hexdump' | bzcat input input; echo \$?" \ | 78 | "bzcat input input; echo \$?" \ |
77 | "\ | 79 | "\ |
78 | a | 80 | a |
79 | a | 81 | a |
@@ -86,7 +88,7 @@ a | |||
86 | 88 | ||
87 | # "input" file is bzipped zero byte file | 89 | # "input" file is bzipped zero byte file |
88 | testing "bzcat can handle compressed zero-length bzip2 files" \ | 90 | testing "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 |
96 | test x"$CONFIG_UNCOMPRESS" = x"y" && \ | 98 | test x"$CONFIG_UNCOMPRESS" = x"y" && \ |
97 | testing "zcat can print many files" \ | 99 | testing "zcat can print many files" \ |
98 | "$ECHO -ne '$hexdump' | zcat input input; echo \$?" \ | 100 | "zcat input input; echo \$?" \ |
99 | "\ | 101 | "\ |
100 | a | 102 | a |
101 | a | 103 | a |
@@ -107,7 +109,7 @@ a | |||
107 | # "input" file is compressed (.Z) zero byte file | 109 | # "input" file is compressed (.Z) zero byte file |
108 | test x"$CONFIG_UNCOMPRESS" = x"y" && \ | 110 | test x"$CONFIG_UNCOMPRESS" = x"y" && \ |
109 | testing "zcat can handle compressed zero-length (.Z) files" \ | 111 | testing "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 | ||
37 | static const struct { | 42 | static 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 | |||
50 | static void show_min_max(int pol) | 54 | static 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 | ||
68 | int chrt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 74 | int chrt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
69 | int chrt_main(int argc UNUSED_PARAM, char **argv) | 75 | int 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 | ||
45 | void BUG_bad_PRIO_PROCESS(void); | ||
46 | void BUG_bad_PRIO_PGRP(void); | ||
47 | void BUG_bad_PRIO_USER(void); | ||
48 | |||
49 | int renice_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 44 | int renice_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
50 | int renice_main(int argc UNUSED_PARAM, char **argv) | 45 | int 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. | ||
28 | struct 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 | |||
45 | int 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 | ||
188 | int FAST_FUNC volume_id_probe_jfs(struct volume_id *id /*,uint64_t off*/); | 188 | int FAST_FUNC volume_id_probe_jfs(struct volume_id *id /*,uint64_t off*/); |
189 | 189 | ||
190 | int FAST_FUNC volume_id_probe_lfs(struct volume_id *id /*,uint64_t off*/); | ||
191 | |||
190 | int FAST_FUNC volume_id_probe_linux_swap(struct volume_id *id /*,uint64_t off*/); | 192 | int FAST_FUNC volume_id_probe_linux_swap(struct volume_id *id /*,uint64_t off*/); |
191 | 193 | ||
192 | int FAST_FUNC volume_id_probe_luks(struct volume_id *id /*,uint64_t off*/); | 194 | int FAST_FUNC volume_id_probe_luks(struct volume_id *id /*,uint64_t off*/); |