aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2014-12-14 14:20:56 +0000
committerRon Yorston <rmy@pobox.com>2014-12-14 14:20:56 +0000
commit6d6d18d45c145899fce3a39553771cf0af671f30 (patch)
tree1936d18cbf61b9e0989464aad0a11c52cbeff7b7
parent0c204dc07b718244c360e0b84df66ce0a012e14f (diff)
parentacb8be721768b54075a51d1859d390904a0f1f6c (diff)
downloadbusybox-w32-6d6d18d45c145899fce3a39553771cf0af671f30.tar.gz
busybox-w32-6d6d18d45c145899fce3a39553771cf0af671f30.tar.bz2
busybox-w32-6d6d18d45c145899fce3a39553771cf0af671f30.zip
Merge branch 'busybox' into merge
Conflicts: archival/libarchive/open_transformer.c libbb/lineedit.c miscutils/man.c
-rw-r--r--.gitignore1
-rw-r--r--Config.in13
-rw-r--r--archival/bbunzip.c51
-rw-r--r--archival/bzip2.c2
-rw-r--r--archival/gzip.c2
-rw-r--r--archival/libarchive/decompress_bunzip2.c11
-rw-r--r--archival/libarchive/decompress_gunzip.c42
-rw-r--r--archival/libarchive/decompress_uncompress.c12
-rw-r--r--archival/libarchive/decompress_unlzma.c12
-rw-r--r--archival/libarchive/decompress_unxz.c8
-rw-r--r--archival/libarchive/get_header_tar_bz2.c2
-rw-r--r--archival/libarchive/get_header_tar_gz.c2
-rw-r--r--archival/libarchive/get_header_tar_lzma.c2
-rw-r--r--archival/libarchive/open_transformer.c212
-rw-r--r--archival/lzop.c2
-rw-r--r--archival/tar.c70
-rw-r--r--archival/unzip.c14
-rw-r--r--docs/logging_and_backgrounding.txt2
-rw-r--r--include/bb_archive.h50
-rw-r--r--include/libbb.h11
-rw-r--r--init/init.c50
-rw-r--r--libbb/Kbuild.src3
-rw-r--r--libbb/appletlib.c6
-rw-r--r--libbb/bbunit.c2
-rw-r--r--libbb/copyfd.c87
-rw-r--r--libbb/lineedit.c8
-rw-r--r--libbb/logenv.c24
-rw-r--r--libbb/sysconf.c2
-rw-r--r--miscutils/flashcp.c2
-rw-r--r--miscutils/man.c96
-rw-r--r--modutils/modprobe.c11
-rw-r--r--networking/Config.src8
-rw-r--r--networking/httpd.c6
-rw-r--r--networking/libiproute/iproute.c18
-rw-r--r--networking/udhcp/arpping.c10
-rw-r--r--networking/udhcp/common.h3
-rw-r--r--networking/udhcp/dhcpc.c17
-rw-r--r--networking/udhcp/dhcpd.c17
-rw-r--r--networking/udhcp/dhcpd.h2
-rw-r--r--networking/udhcp/files.c14
-rw-r--r--networking/udhcp/leases.c11
-rw-r--r--networking/zcip.c35
-rw-r--r--shell/ash.c10
-rw-r--r--shell/math.c27
44 files changed, 645 insertions, 345 deletions
diff --git a/.gitignore b/.gitignore
index cae1d53dd..01400a678 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,3 +42,4 @@ core
42# 42#
43/busybox.links 43/busybox.links
44/runtest-tempdir-links 44/runtest-tempdir-links
45/testsuite/echo-ne
diff --git a/Config.in b/Config.in
index 61e4088bf..c6aad4210 100644
--- a/Config.in
+++ b/Config.in
@@ -278,6 +278,19 @@ config PAM
278 Use PAM in some busybox applets (currently login and httpd) instead 278 Use PAM in some busybox applets (currently login and httpd) instead
279 of direct access to password database. 279 of direct access to password database.
280 280
281config FEATURE_USE_SENDFILE
282 bool "Use sendfile system call"
283 default y
284 select PLATFORM_LINUX
285 help
286 When enabled, busybox will use the kernel sendfile() function
287 instead of read/write loops to copy data between file descriptors
288 (for example, cp command does this a lot).
289 If sendfile() doesn't work, copying code falls back to read/write
290 loop. sendfile() was originally implemented for faster I/O
291 from files to sockets, but since Linux 2.6.33 it was extended
292 to work for many more file types.
293
281config LONG_OPTS 294config LONG_OPTS
282 bool "Support for --long-options" 295 bool "Support for --long-options"
283 default y 296 default y
diff --git a/archival/bbunzip.c b/archival/bbunzip.c
index 4d417f3f1..a859ef201 100644
--- a/archival/bbunzip.c
+++ b/archival/bbunzip.c
@@ -39,7 +39,7 @@ char* FAST_FUNC append_ext(char *filename, const char *expected_ext)
39} 39}
40 40
41int FAST_FUNC bbunpack(char **argv, 41int FAST_FUNC bbunpack(char **argv,
42 IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(transformer_aux_data_t *aux), 42 IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(transformer_state_t *xstate),
43 char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext), 43 char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext),
44 const char *expected_ext 44 const char *expected_ext
45) 45)
@@ -48,7 +48,7 @@ int FAST_FUNC bbunpack(char **argv,
48 IF_DESKTOP(long long) int status = 0; 48 IF_DESKTOP(long long) int status = 0;
49 char *filename, *new_name; 49 char *filename, *new_name;
50 smallint exitcode = 0; 50 smallint exitcode = 0;
51 transformer_aux_data_t aux; 51 transformer_state_t xstate;
52 52
53 do { 53 do {
54 /* NB: new_name is *maybe* malloc'ed! */ 54 /* NB: new_name is *maybe* malloc'ed! */
@@ -120,9 +120,11 @@ int FAST_FUNC bbunpack(char **argv,
120 } 120 }
121 121
122 if (!(option_mask32 & SEAMLESS_MAGIC)) { 122 if (!(option_mask32 & SEAMLESS_MAGIC)) {
123 init_transformer_aux_data(&aux); 123 init_transformer_state(&xstate);
124 aux.check_signature = 1; 124 xstate.check_signature = 1;
125 status = unpacker(&aux); 125 /*xstate.src_fd = STDIN_FILENO; - already is */
126 xstate.dst_fd = STDOUT_FILENO;
127 status = unpacker(&xstate);
126 if (status < 0) 128 if (status < 0)
127 exitcode = 1; 129 exitcode = 1;
128 } else { 130 } else {
@@ -141,10 +143,10 @@ int FAST_FUNC bbunpack(char **argv,
141 unsigned new_name_len; 143 unsigned new_name_len;
142 144
143 /* TODO: restore other things? */ 145 /* TODO: restore other things? */
144 if (aux.mtime != 0) { 146 if (xstate.mtime != 0) {
145 struct timeval times[2]; 147 struct timeval times[2];
146 148
147 times[1].tv_sec = times[0].tv_sec = aux.mtime; 149 times[1].tv_sec = times[0].tv_sec = xstate.mtime;
148 times[1].tv_usec = times[0].tv_usec = 0; 150 times[1].tv_usec = times[0].tv_usec = 0;
149 /* Note: we closed it first. 151 /* Note: we closed it first.
150 * On some systems calling utimes 152 * On some systems calling utimes
@@ -228,18 +230,13 @@ char* FAST_FUNC make_new_name_generic(char *filename, const char *expected_ext)
228//applet:IF_UNCOMPRESS(APPLET(uncompress, BB_DIR_BIN, BB_SUID_DROP)) 230//applet:IF_UNCOMPRESS(APPLET(uncompress, BB_DIR_BIN, BB_SUID_DROP))
229//kbuild:lib-$(CONFIG_UNCOMPRESS) += bbunzip.o 231//kbuild:lib-$(CONFIG_UNCOMPRESS) += bbunzip.o
230#if ENABLE_UNCOMPRESS 232#if ENABLE_UNCOMPRESS
231static
232IF_DESKTOP(long long) int FAST_FUNC unpack_uncompress(transformer_aux_data_t *aux)
233{
234 return unpack_Z_stream(aux, STDIN_FILENO, STDOUT_FILENO);
235}
236int uncompress_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 233int uncompress_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
237int uncompress_main(int argc UNUSED_PARAM, char **argv) 234int uncompress_main(int argc UNUSED_PARAM, char **argv)
238{ 235{
239 getopt32(argv, "cf"); 236 getopt32(argv, "cf");
240 argv += optind; 237 argv += optind;
241 238
242 return bbunpack(argv, unpack_uncompress, make_new_name_generic, "Z"); 239 return bbunpack(argv, unpack_Z_stream, make_new_name_generic, "Z");
243} 240}
244#endif 241#endif
245 242
@@ -326,11 +323,6 @@ char* FAST_FUNC make_new_name_gunzip(char *filename, const char *expected_ext UN
326 } 323 }
327 return filename; 324 return filename;
328} 325}
329static
330IF_DESKTOP(long long) int FAST_FUNC unpack_gunzip(transformer_aux_data_t *aux)
331{
332 return unpack_gz_stream(aux, STDIN_FILENO, STDOUT_FILENO);
333}
334/* 326/*
335 * Linux kernel build uses gzip -d -n. We accept and ignore it. 327 * Linux kernel build uses gzip -d -n. We accept and ignore it.
336 * Man page says: 328 * Man page says:
@@ -357,7 +349,7 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv)
357 if (applet_name[1] == 'c') 349 if (applet_name[1] == 'c')
358 option_mask32 |= OPT_STDOUT | SEAMLESS_MAGIC; 350 option_mask32 |= OPT_STDOUT | SEAMLESS_MAGIC;
359 351
360 return bbunpack(argv, unpack_gunzip, make_new_name_gunzip, /*unused:*/ NULL); 352 return bbunpack(argv, unpack_gz_stream, make_new_name_gunzip, /*unused:*/ NULL);
361} 353}
362#endif 354#endif
363 355
@@ -397,11 +389,6 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv)
397//kbuild:lib-$(CONFIG_BZIP2) += bbunzip.o 389//kbuild:lib-$(CONFIG_BZIP2) += bbunzip.o
398//kbuild:lib-$(CONFIG_BUNZIP2) += bbunzip.o 390//kbuild:lib-$(CONFIG_BUNZIP2) += bbunzip.o
399#if ENABLE_BUNZIP2 391#if ENABLE_BUNZIP2
400static
401IF_DESKTOP(long long) int FAST_FUNC unpack_bunzip2(transformer_aux_data_t *aux)
402{
403 return unpack_bz2_stream(aux, STDIN_FILENO, STDOUT_FILENO);
404}
405int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 392int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
406int bunzip2_main(int argc UNUSED_PARAM, char **argv) 393int bunzip2_main(int argc UNUSED_PARAM, char **argv)
407{ 394{
@@ -410,7 +397,7 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv)
410 if (applet_name[2] == 'c') /* bzcat */ 397 if (applet_name[2] == 'c') /* bzcat */
411 option_mask32 |= OPT_STDOUT; 398 option_mask32 |= OPT_STDOUT;
412 399
413 return bbunpack(argv, unpack_bunzip2, make_new_name_generic, "bz2"); 400 return bbunpack(argv, unpack_bz2_stream, make_new_name_generic, "bz2");
414} 401}
415#endif 402#endif
416 403
@@ -496,11 +483,6 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv)
496//applet:IF_LZMA(APPLET_ODDNAME(lzma, unlzma, BB_DIR_USR_BIN, BB_SUID_DROP, lzma)) 483//applet:IF_LZMA(APPLET_ODDNAME(lzma, unlzma, BB_DIR_USR_BIN, BB_SUID_DROP, lzma))
497//kbuild:lib-$(CONFIG_UNLZMA) += bbunzip.o 484//kbuild:lib-$(CONFIG_UNLZMA) += bbunzip.o
498#if ENABLE_UNLZMA 485#if ENABLE_UNLZMA
499static
500IF_DESKTOP(long long) int FAST_FUNC unpack_unlzma(transformer_aux_data_t *aux)
501{
502 return unpack_lzma_stream(aux, STDIN_FILENO, STDOUT_FILENO);
503}
504int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 486int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
505int unlzma_main(int argc UNUSED_PARAM, char **argv) 487int unlzma_main(int argc UNUSED_PARAM, char **argv)
506{ 488{
@@ -515,7 +497,7 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv)
515 option_mask32 |= OPT_STDOUT; 497 option_mask32 |= OPT_STDOUT;
516 498
517 argv += optind; 499 argv += optind;
518 return bbunpack(argv, unpack_unlzma, make_new_name_generic, "lzma"); 500 return bbunpack(argv, unpack_lzma_stream, make_new_name_generic, "lzma");
519} 501}
520#endif 502#endif
521 503
@@ -539,11 +521,6 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv)
539//applet:IF_XZ(APPLET_ODDNAME(xz, unxz, BB_DIR_USR_BIN, BB_SUID_DROP, xz)) 521//applet:IF_XZ(APPLET_ODDNAME(xz, unxz, BB_DIR_USR_BIN, BB_SUID_DROP, xz))
540//kbuild:lib-$(CONFIG_UNXZ) += bbunzip.o 522//kbuild:lib-$(CONFIG_UNXZ) += bbunzip.o
541#if ENABLE_UNXZ 523#if ENABLE_UNXZ
542static
543IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(transformer_aux_data_t *aux)
544{
545 return unpack_xz_stream(aux, STDIN_FILENO, STDOUT_FILENO);
546}
547int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 524int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
548int unxz_main(int argc UNUSED_PARAM, char **argv) 525int unxz_main(int argc UNUSED_PARAM, char **argv)
549{ 526{
@@ -558,6 +535,6 @@ int unxz_main(int argc UNUSED_PARAM, char **argv)
558 option_mask32 |= OPT_STDOUT; 535 option_mask32 |= OPT_STDOUT;
559 536
560 argv += optind; 537 argv += optind;
561 return bbunpack(argv, unpack_unxz, make_new_name_generic, "xz"); 538 return bbunpack(argv, unpack_xz_stream, make_new_name_generic, "xz");
562} 539}
563#endif 540#endif
diff --git a/archival/bzip2.c b/archival/bzip2.c
index f7718b411..47fa29af3 100644
--- a/archival/bzip2.c
+++ b/archival/bzip2.c
@@ -127,7 +127,7 @@ IF_DESKTOP(long long) int bz_write(bz_stream *strm, void* rbuf, ssize_t rlen, vo
127} 127}
128 128
129static 129static
130IF_DESKTOP(long long) int FAST_FUNC compressStream(transformer_aux_data_t *aux UNUSED_PARAM) 130IF_DESKTOP(long long) int FAST_FUNC compressStream(transformer_state_t *xstate UNUSED_PARAM)
131{ 131{
132 IF_DESKTOP(long long) int total; 132 IF_DESKTOP(long long) int total;
133 ssize_t count; 133 ssize_t count;
diff --git a/archival/gzip.c b/archival/gzip.c
index 1e779c9c3..a93d2175a 100644
--- a/archival/gzip.c
+++ b/archival/gzip.c
@@ -2042,7 +2042,7 @@ static void zip(ulg time_stamp)
2042 2042
2043/* ======================================================================== */ 2043/* ======================================================================== */
2044static 2044static
2045IF_DESKTOP(long long) int FAST_FUNC pack_gzip(transformer_aux_data_t *aux UNUSED_PARAM) 2045IF_DESKTOP(long long) int FAST_FUNC pack_gzip(transformer_state_t *xstate UNUSED_PARAM)
2046{ 2046{
2047 struct stat s; 2047 struct stat s;
2048 2048
diff --git a/archival/libarchive/decompress_bunzip2.c b/archival/libarchive/decompress_bunzip2.c
index 6396fe40d..fe5953da2 100644
--- a/archival/libarchive/decompress_bunzip2.c
+++ b/archival/libarchive/decompress_bunzip2.c
@@ -731,7 +731,7 @@ void FAST_FUNC dealloc_bunzip(bunzip_data *bd)
731 731
732/* Decompress src_fd to dst_fd. Stops at end of bzip data, not end of file. */ 732/* Decompress src_fd to dst_fd. Stops at end of bzip data, not end of file. */
733IF_DESKTOP(long long) int FAST_FUNC 733IF_DESKTOP(long long) int FAST_FUNC
734unpack_bz2_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) 734unpack_bz2_stream(transformer_state_t *xstate)
735{ 735{
736 IF_DESKTOP(long long total_written = 0;) 736 IF_DESKTOP(long long total_written = 0;)
737 bunzip_data *bd; 737 bunzip_data *bd;
@@ -739,14 +739,14 @@ unpack_bz2_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
739 int i; 739 int i;
740 unsigned len; 740 unsigned len;
741 741
742 if (check_signature16(aux, src_fd, BZIP2_MAGIC)) 742 if (check_signature16(xstate, BZIP2_MAGIC))
743 return -1; 743 return -1;
744 744
745 outbuf = xmalloc(IOBUF_SIZE); 745 outbuf = xmalloc(IOBUF_SIZE);
746 len = 0; 746 len = 0;
747 while (1) { /* "Process one BZ... stream" loop */ 747 while (1) { /* "Process one BZ... stream" loop */
748 748
749 i = start_bunzip(&bd, src_fd, outbuf + 2, len); 749 i = start_bunzip(&bd, xstate->src_fd, outbuf + 2, len);
750 750
751 if (i == 0) { 751 if (i == 0) {
752 while (1) { /* "Produce some output bytes" loop */ 752 while (1) { /* "Produce some output bytes" loop */
@@ -756,8 +756,7 @@ unpack_bz2_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
756 i = IOBUF_SIZE - i; /* number of bytes produced */ 756 i = IOBUF_SIZE - i; /* number of bytes produced */
757 if (i == 0) /* EOF? */ 757 if (i == 0) /* EOF? */
758 break; 758 break;
759 if (i != full_write(dst_fd, outbuf, i)) { 759 if (i != transformer_write(xstate, outbuf, i)) {
760 bb_error_msg("short write");
761 i = RETVAL_SHORT_WRITE; 760 i = RETVAL_SHORT_WRITE;
762 goto release_mem; 761 goto release_mem;
763 } 762 }
@@ -790,7 +789,7 @@ unpack_bz2_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
790 len = bd->inbufCount - bd->inbufPos; 789 len = bd->inbufCount - bd->inbufPos;
791 memcpy(outbuf, &bd->inbuf[bd->inbufPos], len); 790 memcpy(outbuf, &bd->inbuf[bd->inbufPos], len);
792 if (len < 2) { 791 if (len < 2) {
793 if (safe_read(src_fd, outbuf + len, 2 - len) != 2 - len) 792 if (safe_read(xstate->src_fd, outbuf + len, 2 - len) != 2 - len)
794 break; 793 break;
795 len = 2; 794 len = 2;
796 } 795 }
diff --git a/archival/libarchive/decompress_gunzip.c b/archival/libarchive/decompress_gunzip.c
index 7c6f38ec3..1360abef7 100644
--- a/archival/libarchive/decompress_gunzip.c
+++ b/archival/libarchive/decompress_gunzip.c
@@ -971,7 +971,7 @@ static int inflate_get_next_window(STATE_PARAM_ONLY)
971 971
972/* Called from unpack_gz_stream() and inflate_unzip() */ 972/* Called from unpack_gz_stream() and inflate_unzip() */
973static IF_DESKTOP(long long) int 973static IF_DESKTOP(long long) int
974inflate_unzip_internal(STATE_PARAM int in, int out) 974inflate_unzip_internal(STATE_PARAM transformer_state_t *xstate)
975{ 975{
976 IF_DESKTOP(long long) int n = 0; 976 IF_DESKTOP(long long) int n = 0;
977 ssize_t nwrote; 977 ssize_t nwrote;
@@ -980,7 +980,7 @@ inflate_unzip_internal(STATE_PARAM int in, int out)
980 gunzip_window = xmalloc(GUNZIP_WSIZE); 980 gunzip_window = xmalloc(GUNZIP_WSIZE);
981 gunzip_outbuf_count = 0; 981 gunzip_outbuf_count = 0;
982 gunzip_bytes_out = 0; 982 gunzip_bytes_out = 0;
983 gunzip_src_fd = in; 983 gunzip_src_fd = xstate->src_fd;
984 984
985 /* (re) initialize state */ 985 /* (re) initialize state */
986 method = -1; 986 method = -1;
@@ -1002,9 +1002,8 @@ inflate_unzip_internal(STATE_PARAM int in, int out)
1002 1002
1003 while (1) { 1003 while (1) {
1004 int r = inflate_get_next_window(PASS_STATE_ONLY); 1004 int r = inflate_get_next_window(PASS_STATE_ONLY);
1005 nwrote = full_write(out, gunzip_window, gunzip_outbuf_count); 1005 nwrote = transformer_write(xstate, gunzip_window, gunzip_outbuf_count);
1006 if (nwrote != (ssize_t)gunzip_outbuf_count) { 1006 if (nwrote == (ssize_t)-1) {
1007 bb_perror_msg("write");
1008 n = -1; 1007 n = -1;
1009 goto ret; 1008 goto ret;
1010 } 1009 }
@@ -1034,22 +1033,22 @@ inflate_unzip_internal(STATE_PARAM int in, int out)
1034/* For unzip */ 1033/* For unzip */
1035 1034
1036IF_DESKTOP(long long) int FAST_FUNC 1035IF_DESKTOP(long long) int FAST_FUNC
1037inflate_unzip(transformer_aux_data_t *aux, int in, int out) 1036inflate_unzip(transformer_state_t *xstate)
1038{ 1037{
1039 IF_DESKTOP(long long) int n; 1038 IF_DESKTOP(long long) int n;
1040 DECLARE_STATE; 1039 DECLARE_STATE;
1041 1040
1042 ALLOC_STATE; 1041 ALLOC_STATE;
1043 1042
1044 to_read = aux->bytes_in; 1043 to_read = xstate->bytes_in;
1045// bytebuffer_max = 0x8000; 1044// bytebuffer_max = 0x8000;
1046 bytebuffer_offset = 4; 1045 bytebuffer_offset = 4;
1047 bytebuffer = xmalloc(bytebuffer_max); 1046 bytebuffer = xmalloc(bytebuffer_max);
1048 n = inflate_unzip_internal(PASS_STATE in, out); 1047 n = inflate_unzip_internal(PASS_STATE xstate);
1049 free(bytebuffer); 1048 free(bytebuffer);
1050 1049
1051 aux->crc32 = gunzip_crc; 1050 xstate->crc32 = gunzip_crc;
1052 aux->bytes_out = gunzip_bytes_out; 1051 xstate->bytes_out = gunzip_bytes_out;
1053 DEALLOC_STATE; 1052 DEALLOC_STATE;
1054 return n; 1053 return n;
1055} 1054}
@@ -1107,7 +1106,7 @@ static uint32_t buffer_read_le_u32(STATE_PARAM_ONLY)
1107 return res; 1106 return res;
1108} 1107}
1109 1108
1110static int check_header_gzip(STATE_PARAM transformer_aux_data_t *aux) 1109static int check_header_gzip(STATE_PARAM transformer_state_t *xstate)
1111{ 1110{
1112 union { 1111 union {
1113 unsigned char raw[8]; 1112 unsigned char raw[8];
@@ -1169,8 +1168,7 @@ static int check_header_gzip(STATE_PARAM transformer_aux_data_t *aux)
1169 } 1168 }
1170 } 1169 }
1171 1170
1172 if (aux) 1171 xstate->mtime = SWAP_LE32(header.formatted.mtime);
1173 aux->mtime = SWAP_LE32(header.formatted.mtime);
1174 1172
1175 /* Read the header checksum */ 1173 /* Read the header checksum */
1176 if (header.formatted.flags & 0x02) { 1174 if (header.formatted.flags & 0x02) {
@@ -1182,27 +1180,27 @@ static int check_header_gzip(STATE_PARAM transformer_aux_data_t *aux)
1182} 1180}
1183 1181
1184IF_DESKTOP(long long) int FAST_FUNC 1182IF_DESKTOP(long long) int FAST_FUNC
1185unpack_gz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) 1183unpack_gz_stream(transformer_state_t *xstate)
1186{ 1184{
1187 uint32_t v32; 1185 uint32_t v32;
1188 IF_DESKTOP(long long) int total, n; 1186 IF_DESKTOP(long long) int total, n;
1189 DECLARE_STATE; 1187 DECLARE_STATE;
1190 1188
1191#if !ENABLE_FEATURE_SEAMLESS_Z 1189#if !ENABLE_FEATURE_SEAMLESS_Z
1192 if (check_signature16(aux, src_fd, GZIP_MAGIC)) 1190 if (check_signature16(xstate, GZIP_MAGIC))
1193 return -1; 1191 return -1;
1194#else 1192#else
1195 if (aux && aux->check_signature) { 1193 if (xstate->check_signature) {
1196 uint16_t magic2; 1194 uint16_t magic2;
1197 1195
1198 if (full_read(src_fd, &magic2, 2) != 2) { 1196 if (full_read(xstate->src_fd, &magic2, 2) != 2) {
1199 bad_magic: 1197 bad_magic:
1200 bb_error_msg("invalid magic"); 1198 bb_error_msg("invalid magic");
1201 return -1; 1199 return -1;
1202 } 1200 }
1203 if (magic2 == COMPRESS_MAGIC) { 1201 if (magic2 == COMPRESS_MAGIC) {
1204 aux->check_signature = 0; 1202 xstate->check_signature = 0;
1205 return unpack_Z_stream(aux, src_fd, dst_fd); 1203 return unpack_Z_stream(xstate);
1206 } 1204 }
1207 if (magic2 != GZIP_MAGIC) 1205 if (magic2 != GZIP_MAGIC)
1208 goto bad_magic; 1206 goto bad_magic;
@@ -1215,16 +1213,16 @@ unpack_gz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
1215 to_read = -1; 1213 to_read = -1;
1216// bytebuffer_max = 0x8000; 1214// bytebuffer_max = 0x8000;
1217 bytebuffer = xmalloc(bytebuffer_max); 1215 bytebuffer = xmalloc(bytebuffer_max);
1218 gunzip_src_fd = src_fd; 1216 gunzip_src_fd = xstate->src_fd;
1219 1217
1220 again: 1218 again:
1221 if (!check_header_gzip(PASS_STATE aux)) { 1219 if (!check_header_gzip(PASS_STATE xstate)) {
1222 bb_error_msg("corrupted data"); 1220 bb_error_msg("corrupted data");
1223 total = -1; 1221 total = -1;
1224 goto ret; 1222 goto ret;
1225 } 1223 }
1226 1224
1227 n = inflate_unzip_internal(PASS_STATE src_fd, dst_fd); 1225 n = inflate_unzip_internal(PASS_STATE xstate);
1228 if (n < 0) { 1226 if (n < 0) {
1229 total = -1; 1227 total = -1;
1230 goto ret; 1228 goto ret;
diff --git a/archival/libarchive/decompress_uncompress.c b/archival/libarchive/decompress_uncompress.c
index 53c27080f..496d864a7 100644
--- a/archival/libarchive/decompress_uncompress.c
+++ b/archival/libarchive/decompress_uncompress.c
@@ -73,7 +73,7 @@
73 */ 73 */
74 74
75IF_DESKTOP(long long) int FAST_FUNC 75IF_DESKTOP(long long) int FAST_FUNC
76unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) 76unpack_Z_stream(transformer_state_t *xstate)
77{ 77{
78 IF_DESKTOP(long long total_written = 0;) 78 IF_DESKTOP(long long total_written = 0;)
79 IF_DESKTOP(long long) int retval = -1; 79 IF_DESKTOP(long long) int retval = -1;
@@ -102,7 +102,7 @@ unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
102 /* block compress mode -C compatible with 2.0 */ 102 /* block compress mode -C compatible with 2.0 */
103 int block_mode; /* = BLOCK_MODE; */ 103 int block_mode; /* = BLOCK_MODE; */
104 104
105 if (check_signature16(aux, src_fd, COMPRESS_MAGIC)) 105 if (check_signature16(xstate, COMPRESS_MAGIC))
106 return -1; 106 return -1;
107 107
108 inbuf = xzalloc(IBUFSIZ + 64); 108 inbuf = xzalloc(IBUFSIZ + 64);
@@ -114,7 +114,7 @@ unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
114 114
115 /* xread isn't good here, we have to return - caller may want 115 /* xread isn't good here, we have to return - caller may want
116 * to do some cleanup (e.g. delete incomplete unpacked file etc) */ 116 * to do some cleanup (e.g. delete incomplete unpacked file etc) */
117 if (full_read(src_fd, inbuf, 1) != 1) { 117 if (full_read(xstate->src_fd, inbuf, 1) != 1) {
118 bb_error_msg("short read"); 118 bb_error_msg("short read");
119 goto err; 119 goto err;
120 } 120 }
@@ -166,7 +166,7 @@ unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
166 } 166 }
167 167
168 if (insize < (int) (IBUFSIZ + 64) - IBUFSIZ) { 168 if (insize < (int) (IBUFSIZ + 64) - IBUFSIZ) {
169 rsize = safe_read(src_fd, inbuf + insize, IBUFSIZ); 169 rsize = safe_read(xstate->src_fd, inbuf + insize, IBUFSIZ);
170 if (rsize < 0) 170 if (rsize < 0)
171 bb_error_msg_and_die(bb_msg_read_error); 171 bb_error_msg_and_die(bb_msg_read_error);
172 insize += rsize; 172 insize += rsize;
@@ -274,7 +274,7 @@ unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
274 } 274 }
275 275
276 if (outpos >= OBUFSIZ) { 276 if (outpos >= OBUFSIZ) {
277 xwrite(dst_fd, outbuf, outpos); 277 xtransformer_write(xstate, outbuf, outpos);
278 IF_DESKTOP(total_written += outpos;) 278 IF_DESKTOP(total_written += outpos;)
279 outpos = 0; 279 outpos = 0;
280 } 280 }
@@ -301,7 +301,7 @@ unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
301 } while (rsize > 0); 301 } while (rsize > 0);
302 302
303 if (outpos > 0) { 303 if (outpos > 0) {
304 xwrite(dst_fd, outbuf, outpos); 304 xtransformer_write(xstate, outbuf, outpos);
305 IF_DESKTOP(total_written += outpos;) 305 IF_DESKTOP(total_written += outpos;)
306 } 306 }
307 307
diff --git a/archival/libarchive/decompress_unlzma.c b/archival/libarchive/decompress_unlzma.c
index 3d99e1388..c8622f97b 100644
--- a/archival/libarchive/decompress_unlzma.c
+++ b/archival/libarchive/decompress_unlzma.c
@@ -206,7 +206,7 @@ enum {
206 206
207 207
208IF_DESKTOP(long long) int FAST_FUNC 208IF_DESKTOP(long long) int FAST_FUNC
209unpack_lzma_stream(transformer_aux_data_t *aux UNUSED_PARAM, int src_fd, int dst_fd) 209unpack_lzma_stream(transformer_state_t *xstate)
210{ 210{
211 IF_DESKTOP(long long total_written = 0;) 211 IF_DESKTOP(long long total_written = 0;)
212 lzma_header_t header; 212 lzma_header_t header;
@@ -223,7 +223,7 @@ unpack_lzma_stream(transformer_aux_data_t *aux UNUSED_PARAM, int src_fd, int dst
223 int state = 0; 223 int state = 0;
224 uint32_t rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1; 224 uint32_t rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
225 225
226 if (full_read(src_fd, &header, sizeof(header)) != sizeof(header) 226 if (full_read(xstate->src_fd, &header, sizeof(header)) != sizeof(header)
227 || header.pos >= (9 * 5 * 5) 227 || header.pos >= (9 * 5 * 5)
228 ) { 228 ) {
229 bb_error_msg("bad lzma header"); 229 bb_error_msg("bad lzma header");
@@ -258,7 +258,7 @@ unpack_lzma_stream(transformer_aux_data_t *aux UNUSED_PARAM, int src_fd, int dst
258 p[i] = (1 << RC_MODEL_TOTAL_BITS) >> 1; 258 p[i] = (1 << RC_MODEL_TOTAL_BITS) >> 1;
259 } 259 }
260 260
261 rc = rc_init(src_fd); /*, RC_BUFFER_SIZE); */ 261 rc = rc_init(xstate->src_fd); /*, RC_BUFFER_SIZE); */
262 262
263 while (global_pos + buffer_pos < header.dst_size) { 263 while (global_pos + buffer_pos < header.dst_size) {
264 int pos_state = (buffer_pos + global_pos) & pos_state_mask; 264 int pos_state = (buffer_pos + global_pos) & pos_state_mask;
@@ -306,7 +306,7 @@ unpack_lzma_stream(transformer_aux_data_t *aux UNUSED_PARAM, int src_fd, int dst
306 if (buffer_pos == header.dict_size) { 306 if (buffer_pos == header.dict_size) {
307 buffer_pos = 0; 307 buffer_pos = 0;
308 global_pos += header.dict_size; 308 global_pos += header.dict_size;
309 if (full_write(dst_fd, buffer, header.dict_size) != (ssize_t)header.dict_size) 309 if (transformer_write(xstate, buffer, header.dict_size) != (ssize_t)header.dict_size)
310 goto bad; 310 goto bad;
311 IF_DESKTOP(total_written += header.dict_size;) 311 IF_DESKTOP(total_written += header.dict_size;)
312 } 312 }
@@ -440,7 +440,7 @@ unpack_lzma_stream(transformer_aux_data_t *aux UNUSED_PARAM, int src_fd, int dst
440 if (buffer_pos == header.dict_size) { 440 if (buffer_pos == header.dict_size) {
441 buffer_pos = 0; 441 buffer_pos = 0;
442 global_pos += header.dict_size; 442 global_pos += header.dict_size;
443 if (full_write(dst_fd, buffer, header.dict_size) != (ssize_t)header.dict_size) 443 if (transformer_write(xstate, buffer, header.dict_size) != (ssize_t)header.dict_size)
444 goto bad; 444 goto bad;
445 IF_DESKTOP(total_written += header.dict_size;) 445 IF_DESKTOP(total_written += header.dict_size;)
446 } 446 }
@@ -455,7 +455,7 @@ unpack_lzma_stream(transformer_aux_data_t *aux UNUSED_PARAM, int src_fd, int dst
455 { 455 {
456 IF_NOT_DESKTOP(int total_written = 0; /* success */) 456 IF_NOT_DESKTOP(int total_written = 0; /* success */)
457 IF_DESKTOP(total_written += buffer_pos;) 457 IF_DESKTOP(total_written += buffer_pos;)
458 if (full_write(dst_fd, buffer, buffer_pos) != (ssize_t)buffer_pos) { 458 if (transformer_write(xstate, buffer, buffer_pos) != (ssize_t)buffer_pos) {
459 bad: 459 bad:
460 total_written = -1; /* failure */ 460 total_written = -1; /* failure */
461 } 461 }
diff --git a/archival/libarchive/decompress_unxz.c b/archival/libarchive/decompress_unxz.c
index 986b7b191..1f408abfd 100644
--- a/archival/libarchive/decompress_unxz.c
+++ b/archival/libarchive/decompress_unxz.c
@@ -38,7 +38,7 @@ static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc)
38#include "unxz/xz_dec_stream.c" 38#include "unxz/xz_dec_stream.c"
39 39
40IF_DESKTOP(long long) int FAST_FUNC 40IF_DESKTOP(long long) int FAST_FUNC
41unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) 41unpack_xz_stream(transformer_state_t *xstate)
42{ 42{
43 enum xz_ret xz_result; 43 enum xz_ret xz_result;
44 struct xz_buf iobuf; 44 struct xz_buf iobuf;
@@ -55,7 +55,7 @@ unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
55 iobuf.out = membuf + BUFSIZ; 55 iobuf.out = membuf + BUFSIZ;
56 iobuf.out_size = BUFSIZ; 56 iobuf.out_size = BUFSIZ;
57 57
58 if (!aux || aux->check_signature == 0) { 58 if (!xstate || xstate->check_signature == 0) {
59 /* Preload XZ file signature */ 59 /* Preload XZ file signature */
60 strcpy((char*)membuf, HEADER_MAGIC); 60 strcpy((char*)membuf, HEADER_MAGIC);
61 iobuf.in_size = HEADER_MAGIC_SIZE; 61 iobuf.in_size = HEADER_MAGIC_SIZE;
@@ -67,7 +67,7 @@ unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
67 xz_result = X_OK; 67 xz_result = X_OK;
68 while (1) { 68 while (1) {
69 if (iobuf.in_pos == iobuf.in_size) { 69 if (iobuf.in_pos == iobuf.in_size) {
70 int rd = safe_read(src_fd, membuf, BUFSIZ); 70 int rd = safe_read(xstate->src_fd, membuf, BUFSIZ);
71 if (rd < 0) { 71 if (rd < 0) {
72 bb_error_msg(bb_msg_read_error); 72 bb_error_msg(bb_msg_read_error);
73 total = -1; 73 total = -1;
@@ -104,7 +104,7 @@ unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
104// bb_error_msg("<in pos:%d size:%d out pos:%d size:%d r:%d", 104// bb_error_msg("<in pos:%d size:%d out pos:%d size:%d r:%d",
105// iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size, xz_result); 105// iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size, xz_result);
106 if (iobuf.out_pos) { 106 if (iobuf.out_pos) {
107 xwrite(dst_fd, iobuf.out, iobuf.out_pos); 107 xtransformer_write(xstate, iobuf.out, iobuf.out_pos);
108 IF_DESKTOP(total += iobuf.out_pos;) 108 IF_DESKTOP(total += iobuf.out_pos;)
109 iobuf.out_pos = 0; 109 iobuf.out_pos = 0;
110 } 110 }
diff --git a/archival/libarchive/get_header_tar_bz2.c b/archival/libarchive/get_header_tar_bz2.c
index 0ee00df53..78f78a858 100644
--- a/archival/libarchive/get_header_tar_bz2.c
+++ b/archival/libarchive/get_header_tar_bz2.c
@@ -11,7 +11,7 @@ char FAST_FUNC get_header_tar_bz2(archive_handle_t *archive_handle)
11 /* Can't lseek over pipes */ 11 /* Can't lseek over pipes */
12 archive_handle->seek = seek_by_read; 12 archive_handle->seek = seek_by_read;
13 13
14 open_transformer_with_sig(archive_handle->src_fd, unpack_bz2_stream, "bunzip2"); 14 fork_transformer_with_sig(archive_handle->src_fd, unpack_bz2_stream, "bunzip2");
15 archive_handle->offset = 0; 15 archive_handle->offset = 0;
16 while (get_header_tar(archive_handle) == EXIT_SUCCESS) 16 while (get_header_tar(archive_handle) == EXIT_SUCCESS)
17 continue; 17 continue;
diff --git a/archival/libarchive/get_header_tar_gz.c b/archival/libarchive/get_header_tar_gz.c
index 03284342b..b11f503dc 100644
--- a/archival/libarchive/get_header_tar_gz.c
+++ b/archival/libarchive/get_header_tar_gz.c
@@ -11,7 +11,7 @@ char FAST_FUNC get_header_tar_gz(archive_handle_t *archive_handle)
11 /* Can't lseek over pipes */ 11 /* Can't lseek over pipes */
12 archive_handle->seek = seek_by_read; 12 archive_handle->seek = seek_by_read;
13 13
14 open_transformer_with_sig(archive_handle->src_fd, unpack_gz_stream, "gunzip"); 14 fork_transformer_with_sig(archive_handle->src_fd, unpack_gz_stream, "gunzip");
15 archive_handle->offset = 0; 15 archive_handle->offset = 0;
16 while (get_header_tar(archive_handle) == EXIT_SUCCESS) 16 while (get_header_tar(archive_handle) == EXIT_SUCCESS)
17 continue; 17 continue;
diff --git a/archival/libarchive/get_header_tar_lzma.c b/archival/libarchive/get_header_tar_lzma.c
index d565a217d..d228cbc13 100644
--- a/archival/libarchive/get_header_tar_lzma.c
+++ b/archival/libarchive/get_header_tar_lzma.c
@@ -14,7 +14,7 @@ char FAST_FUNC get_header_tar_lzma(archive_handle_t *archive_handle)
14 /* Can't lseek over pipes */ 14 /* Can't lseek over pipes */
15 archive_handle->seek = seek_by_read; 15 archive_handle->seek = seek_by_read;
16 16
17 open_transformer_with_sig(archive_handle->src_fd, unpack_lzma_stream, "unlzma"); 17 fork_transformer_with_sig(archive_handle->src_fd, unpack_lzma_stream, "unlzma");
18 archive_handle->offset = 0; 18 archive_handle->offset = 0;
19 while (get_header_tar(archive_handle) == EXIT_SUCCESS) 19 while (get_header_tar(archive_handle) == EXIT_SUCCESS)
20 continue; 20 continue;
diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c
index 7e0d1dd02..0a8c657b7 100644
--- a/archival/libarchive/open_transformer.c
+++ b/archival/libarchive/open_transformer.c
@@ -6,19 +6,19 @@
6#include "libbb.h" 6#include "libbb.h"
7#include "bb_archive.h" 7#include "bb_archive.h"
8 8
9void FAST_FUNC init_transformer_aux_data(transformer_aux_data_t *aux) 9void FAST_FUNC init_transformer_state(transformer_state_t *xstate)
10{ 10{
11 memset(aux, 0, sizeof(*aux)); 11 memset(xstate, 0, sizeof(*xstate));
12} 12}
13 13
14int FAST_FUNC check_signature16(transformer_aux_data_t *aux, int src_fd, unsigned magic16) 14int FAST_FUNC check_signature16(transformer_state_t *xstate, unsigned magic16)
15{ 15{
16 if (aux && aux->check_signature) { 16 if (xstate->check_signature) {
17 uint16_t magic2; 17 uint16_t magic2;
18 if (full_read(src_fd, &magic2, 2) != 2 || magic2 != magic16) { 18 if (full_read(xstate->src_fd, &magic2, 2) != 2 || magic2 != magic16) {
19 bb_error_msg("invalid magic"); 19 bb_error_msg("invalid magic");
20#if 0 /* possible future extension */ 20#if 0 /* possible future extension */
21 if (aux->check_signature > 1) 21 if (xstate->check_signature > 1)
22 xfunc_die(); 22 xfunc_die();
23#endif 23#endif
24 return -1; 24 return -1;
@@ -27,9 +27,48 @@ int FAST_FUNC check_signature16(transformer_aux_data_t *aux, int src_fd, unsigne
27 return 0; 27 return 0;
28} 28}
29 29
30ssize_t FAST_FUNC transformer_write(transformer_state_t *xstate, const void *buf, size_t bufsize)
31{
32 ssize_t nwrote;
30 33
31#if SEAMLESS_COMPRESSION 34 if (xstate->mem_output_size_max != 0) {
35 size_t pos = xstate->mem_output_size;
36 size_t size;
37
38 size = (xstate->mem_output_size += bufsize);
39 if (size > xstate->mem_output_size_max) {
40 free(xstate->mem_output_buf);
41 xstate->mem_output_buf = NULL;
42 bb_perror_msg("buffer %u too small", (unsigned)xstate->mem_output_size_max);
43 nwrote = -1;
44 goto ret;
45 }
46 xstate->mem_output_buf = xrealloc(xstate->mem_output_buf, size + 1);
47 memcpy(xstate->mem_output_buf + pos, buf, bufsize);
48 xstate->mem_output_buf[size] = '\0';
49 nwrote = bufsize;
50 } else {
51 nwrote = full_write(xstate->dst_fd, buf, bufsize);
52 if (nwrote != (ssize_t)bufsize) {
53 bb_perror_msg("write");
54 nwrote = -1;
55 goto ret;
56 }
57 }
58 ret:
59 return nwrote;
60}
61
62ssize_t FAST_FUNC xtransformer_write(transformer_state_t *xstate, const void *buf, size_t bufsize)
63{
64 ssize_t nwrote = transformer_write(xstate, buf, bufsize);
65 if (nwrote != (ssize_t)bufsize) {
66 xfunc_die();
67 }
68 return nwrote;
69}
32 70
71#if SEAMLESS_COMPRESSION
33void check_errors_in_children(int signo) 72void check_errors_in_children(int signo)
34{ 73{
35 int status; 74 int status;
@@ -63,12 +102,12 @@ void check_errors_in_children(int signo)
63 102
64/* transformer(), more than meets the eye */ 103/* transformer(), more than meets the eye */
65#if BB_MMU 104#if BB_MMU
66void FAST_FUNC open_transformer(int fd, 105void FAST_FUNC fork_transformer(int fd,
67 int check_signature, 106 int check_signature,
68 IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd) 107 IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_state_t *xstate)
69) 108)
70#else 109#else
71void FAST_FUNC open_transformer(int fd, const char *transform_prog) 110void FAST_FUNC fork_transformer(int fd, const char *transform_prog)
72#endif 111#endif
73{ 112{
74 struct fd_pair fd_pipe; 113 struct fd_pair fd_pipe;
@@ -83,10 +122,12 @@ void FAST_FUNC open_transformer(int fd, const char *transform_prog)
83#if BB_MMU 122#if BB_MMU
84 { 123 {
85 IF_DESKTOP(long long) int r; 124 IF_DESKTOP(long long) int r;
86 transformer_aux_data_t aux; 125 transformer_state_t xstate;
87 init_transformer_aux_data(&aux); 126 init_transformer_state(&xstate);
88 aux.check_signature = check_signature; 127 xstate.check_signature = check_signature;
89 r = transformer(&aux, fd, fd_pipe.wr); 128 xstate.src_fd = fd;
129 xstate.dst_fd = fd_pipe.wr;
130 r = transformer(&xstate);
90 if (ENABLE_FEATURE_CLEAN_UP) { 131 if (ENABLE_FEATURE_CLEAN_UP) {
91 close(fd_pipe.wr); /* send EOF */ 132 close(fd_pipe.wr); /* send EOF */
92 close(fd); 133 close(fd);
@@ -118,16 +159,19 @@ void FAST_FUNC open_transformer(int fd, const char *transform_prog)
118/* Used by e.g. rpm which gives us a fd without filename, 159/* Used by e.g. rpm which gives us a fd without filename,
119 * thus we can't guess the format from filename's extension. 160 * thus we can't guess the format from filename's extension.
120 */ 161 */
121int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed) 162static transformer_state_t *setup_transformer_on_fd(int fd, int fail_if_not_compressed)
122{ 163{
123 union { 164 union {
124 uint8_t b[4]; 165 uint8_t b[4];
125 uint16_t b16[2]; 166 uint16_t b16[2];
126 uint32_t b32[1]; 167 uint32_t b32[1];
127 } magic; 168 } magic;
128 int offset = -2; 169 int offset;
129 USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd);) 170 transformer_state_t *xstate;
130 USE_FOR_NOMMU(const char *xformer_prog;) 171
172 offset = -2;
173 xstate = xzalloc(sizeof(*xstate));
174 xstate->src_fd = fd;
131 175
132 /* .gz and .bz2 both have 2-byte signature, and their 176 /* .gz and .bz2 both have 2-byte signature, and their
133 * unpack_XXX_stream wants this header skipped. */ 177 * unpack_XXX_stream wants this header skipped. */
@@ -135,15 +179,15 @@ int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed)
135 if (ENABLE_FEATURE_SEAMLESS_GZ 179 if (ENABLE_FEATURE_SEAMLESS_GZ
136 && magic.b16[0] == GZIP_MAGIC 180 && magic.b16[0] == GZIP_MAGIC
137 ) { 181 ) {
138 USE_FOR_MMU(xformer = unpack_gz_stream;) 182 xstate->xformer = unpack_gz_stream;
139 USE_FOR_NOMMU(xformer_prog = "gunzip";) 183 USE_FOR_NOMMU(xstate->xformer_prog = "gunzip";)
140 goto found_magic; 184 goto found_magic;
141 } 185 }
142 if (ENABLE_FEATURE_SEAMLESS_BZ2 186 if (ENABLE_FEATURE_SEAMLESS_BZ2
143 && magic.b16[0] == BZIP2_MAGIC 187 && magic.b16[0] == BZIP2_MAGIC
144 ) { 188 ) {
145 USE_FOR_MMU(xformer = unpack_bz2_stream;) 189 xstate->xformer = unpack_bz2_stream;
146 USE_FOR_NOMMU(xformer_prog = "bunzip2";) 190 USE_FOR_NOMMU(xstate->xformer_prog = "bunzip2";)
147 goto found_magic; 191 goto found_magic;
148 } 192 }
149 if (ENABLE_FEATURE_SEAMLESS_XZ 193 if (ENABLE_FEATURE_SEAMLESS_XZ
@@ -152,8 +196,8 @@ int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed)
152 offset = -6; 196 offset = -6;
153 xread(fd, magic.b32, sizeof(magic.b32[0])); 197 xread(fd, magic.b32, sizeof(magic.b32[0]));
154 if (magic.b32[0] == XZ_MAGIC2) { 198 if (magic.b32[0] == XZ_MAGIC2) {
155 USE_FOR_MMU(xformer = unpack_xz_stream;) 199 xstate->xformer = unpack_xz_stream;
156 USE_FOR_NOMMU(xformer_prog = "unxz";) 200 USE_FOR_NOMMU(xstate->xformer_prog = "unxz";)
157 goto found_magic; 201 goto found_magic;
158 } 202 }
159 } 203 }
@@ -164,52 +208,130 @@ int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed)
164 IF_FEATURE_SEAMLESS_BZ2("/bzip2") 208 IF_FEATURE_SEAMLESS_BZ2("/bzip2")
165 IF_FEATURE_SEAMLESS_XZ("/xz") 209 IF_FEATURE_SEAMLESS_XZ("/xz")
166 " magic"); 210 " magic");
211
212 /* Some callers expect this function to "consume" fd
213 * even if data is not compressed. In this case,
214 * we return a state with trivial transformer.
215 */
216// USE_FOR_MMU(xstate->xformer = copy_stream;)
217// USE_FOR_NOMMU(xstate->xformer_prog = "cat";)
218 /* fall through to seeking bck over bytes we read earlier */
219
220 USE_FOR_NOMMU(found_magic:)
221 /* NOMMU version of fork_transformer execs
222 * an external unzipper that wants
223 * file position at the start of the file.
224 */
167 xlseek(fd, offset, SEEK_CUR); 225 xlseek(fd, offset, SEEK_CUR);
168 return 1;
169 226
170 found_magic: 227 USE_FOR_MMU(found_magic:)
228 /* In MMU case, if magic was found, seeking back is not necessary */
229
230 return xstate;
231}
232
233/* Used by e.g. rpm which gives us a fd without filename,
234 * thus we can't guess the format from filename's extension.
235 */
236int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed)
237{
238 transformer_state_t *xstate = setup_transformer_on_fd(fd, fail_if_not_compressed);
239
240 if (!xstate || !xstate->xformer) {
241 free(xstate);
242 return 1;
243 }
244
171# if BB_MMU 245# if BB_MMU
172 open_transformer_with_no_sig(fd, xformer); 246 fork_transformer_with_no_sig(xstate->src_fd, xstate->xformer);
173# else 247# else
174 /* NOMMU version of open_transformer execs 248 fork_transformer_with_sig(xstate->src_fd, xstate->xformer, xstate->xformer_prog);
175 * an external unzipper that wants
176 * file position at the start of the file */
177 xlseek(fd, offset, SEEK_CUR);
178 open_transformer_with_sig(fd, xformer, xformer_prog);
179# endif 249# endif
250 free(xstate);
180 return 0; 251 return 0;
181} 252}
182 253
183int FAST_FUNC open_zipped(const char *fname, int fail_if_not_compressed) 254static transformer_state_t *open_transformer(const char *fname, int fail_if_not_compressed)
184{ 255{
256 transformer_state_t *xstate;
185 int fd; 257 int fd;
186 258
187 fd = open(fname, O_RDONLY); 259 fd = open(fname, O_RDONLY);
188 if (fd < 0) 260 if (fd < 0)
189 return fd; 261 return NULL;
190 262
191 if (ENABLE_FEATURE_SEAMLESS_LZMA) { 263 if (ENABLE_FEATURE_SEAMLESS_LZMA) {
192 /* .lzma has no header/signature, can only detect it by extension */ 264 /* .lzma has no header/signature, can only detect it by extension */
193 char *sfx = strrchr(fname, '.'); 265 char *sfx = strrchr(fname, '.');
194 if (sfx && strcmp(sfx+1, "lzma") == 0) { 266 if (sfx && strcmp(sfx+1, "lzma") == 0) {
195 open_transformer_with_sig(fd, unpack_lzma_stream, "unlzma"); 267 xstate = xzalloc(sizeof(*xstate));
196 return fd; 268 xstate->src_fd = fd;
269 xstate->xformer = unpack_lzma_stream;
270 USE_FOR_NOMMU(xstate->xformer_prog = "unlzma";)
271 return xstate;
197 } 272 }
198 } 273 }
199 if ((ENABLE_FEATURE_SEAMLESS_GZ) 274
200 || (ENABLE_FEATURE_SEAMLESS_BZ2) 275 xstate = setup_transformer_on_fd(fd, fail_if_not_compressed);
201 || (ENABLE_FEATURE_SEAMLESS_XZ) 276
202 ) { 277 return xstate;
203 setup_unzip_on_fd(fd, fail_if_not_compressed); 278}
279
280int FAST_FUNC open_zipped(const char *fname, int fail_if_not_compressed)
281{
282 int fd;
283 transformer_state_t *xstate;
284
285 xstate = open_transformer(fname, fail_if_not_compressed);
286 if (!xstate)
287 return -1;
288
289 fd = xstate->src_fd;
290 if (xstate->xformer) {
291# if BB_MMU
292 fork_transformer_with_no_sig(xstate->src_fd, xstate->xformer);
293# else
294 fork_transformer_with_sig(xstate->src_fd, xstate->xformer, xstate->xformer_prog);
295# endif
204 } 296 }
297 /* else: the file is not compressed */
205 298
299 free(xstate);
206 return fd; 300 return fd;
207} 301}
208 302
209#endif /* SEAMLESS_COMPRESSION */
210
211void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) 303void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p)
212{ 304{
305# if 1
306 transformer_state_t *xstate;
307 char *image;
308
309 xstate = open_transformer(fname, /*fail_if_not_compressed:*/ 0);
310 if (!xstate) /* file open error */
311 return NULL;
312
313 image = NULL;
314 if (xstate->xformer) {
315 /* In-memory decompression */
316 xstate->mem_output_size_max = maxsz_p ? *maxsz_p : (size_t)(INT_MAX - 4095);
317 xstate->xformer(xstate);
318 if (xstate->mem_output_buf) {
319 image = xstate->mem_output_buf;
320 if (maxsz_p)
321 *maxsz_p = xstate->mem_output_size;
322 }
323 } else {
324 /* File is not compressed */
325 image = xmalloc_read(xstate->src_fd, maxsz_p);
326 }
327
328 if (!image)
329 bb_perror_msg("read error from '%s'", fname);
330 close(xstate->src_fd);
331 free(xstate);
332 return image;
333# else
334 /* This version forks a subprocess - much more expensive */
213 int fd; 335 int fd;
214 char *image; 336 char *image;
215 337
@@ -221,6 +343,8 @@ void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_
221 if (!image) 343 if (!image)
222 bb_perror_msg("read error from '%s'", fname); 344 bb_perror_msg("read error from '%s'", fname);
223 close(fd); 345 close(fd);
224
225 return image; 346 return image;
347# endif
226} 348}
349
350#endif /* SEAMLESS_COMPRESSION */
diff --git a/archival/lzop.c b/archival/lzop.c
index 5062d9300..73d11a705 100644
--- a/archival/lzop.c
+++ b/archival/lzop.c
@@ -1099,7 +1099,7 @@ static char* FAST_FUNC make_new_name_lzop(char *filename, const char *expected_e
1099 return xasprintf("%s.lzo", filename); 1099 return xasprintf("%s.lzo", filename);
1100} 1100}
1101 1101
1102static IF_DESKTOP(long long) int FAST_FUNC pack_lzop(transformer_aux_data_t *aux UNUSED_PARAM) 1102static IF_DESKTOP(long long) int FAST_FUNC pack_lzop(transformer_state_t *xstate UNUSED_PARAM)
1103{ 1103{
1104 if (option_mask32 & OPT_DECOMPRESS) 1104 if (option_mask32 & OPT_DECOMPRESS)
1105 return do_lzo_decompress(); 1105 return do_lzo_decompress();
diff --git a/archival/tar.c b/archival/tar.c
index 63d844a3a..e00ed26a8 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -160,13 +160,6 @@
160#define block_buf bb_common_bufsiz1 160#define block_buf bb_common_bufsiz1
161 161
162 162
163#if !ENABLE_FEATURE_SEAMLESS_GZ && !ENABLE_FEATURE_SEAMLESS_BZ2
164/* Do not pass gzip flag to writeTarFile() */
165#define writeTarFile(tar_fd, verboseFlag, recurseFlags, include, exclude, gzip) \
166 writeTarFile(tar_fd, verboseFlag, recurseFlags, include, exclude)
167#endif
168
169
170#if ENABLE_FEATURE_TAR_CREATE 163#if ENABLE_FEATURE_TAR_CREATE
171 164
172/* 165/*
@@ -623,21 +616,12 @@ static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statb
623 return TRUE; 616 return TRUE;
624} 617}
625 618
626#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 619#if SEAMLESS_COMPRESSION
627# if !(ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2)
628# define vfork_compressor(tar_fd, gzip) vfork_compressor(tar_fd)
629# endif
630/* Don't inline: vfork scares gcc and pessimizes code */ 620/* Don't inline: vfork scares gcc and pessimizes code */
631static void NOINLINE vfork_compressor(int tar_fd, int gzip) 621static void NOINLINE vfork_compressor(int tar_fd, const char *gzip)
632{ 622{
633 pid_t gzipPid; 623 pid_t gzipPid;
634# if ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2 624
635 const char *zip_exec = (gzip == 1) ? "gzip" : "bzip2";
636# elif ENABLE_FEATURE_SEAMLESS_GZ
637 const char *zip_exec = "gzip";
638# else /* only ENABLE_FEATURE_SEAMLESS_BZ2 */
639 const char *zip_exec = "bzip2";
640# endif
641 // On Linux, vfork never unpauses parent early, although standard 625 // On Linux, vfork never unpauses parent early, although standard
642 // allows for that. Do we want to waste bytes checking for it? 626 // allows for that. Do we want to waste bytes checking for it?
643# define WAIT_FOR_CHILD 0 627# define WAIT_FOR_CHILD 0
@@ -651,11 +635,6 @@ static void NOINLINE vfork_compressor(int tar_fd, int gzip)
651 635
652 signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ 636 signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */
653 637
654# if defined(__GNUC__) && __GNUC__
655 /* Avoid vfork clobbering */
656 (void) &zip_exec;
657# endif
658
659 gzipPid = xvfork(); 638 gzipPid = xvfork();
660 639
661 if (gzipPid == 0) { 640 if (gzipPid == 0) {
@@ -671,7 +650,7 @@ static void NOINLINE vfork_compressor(int tar_fd, int gzip)
671 xmove_fd(gzipDataPipe.rd, 0); 650 xmove_fd(gzipDataPipe.rd, 0);
672 xmove_fd(tar_fd, 1); 651 xmove_fd(tar_fd, 1);
673 /* exec gzip/bzip2 program/applet */ 652 /* exec gzip/bzip2 program/applet */
674 BB_EXECLP(zip_exec, zip_exec, "-f", (char *)0); 653 BB_EXECLP(gzip, gzip, "-f", (char *)0);
675 vfork_exec_errno = errno; 654 vfork_exec_errno = errno;
676 _exit(EXIT_FAILURE); 655 _exit(EXIT_FAILURE);
677 } 656 }
@@ -694,16 +673,21 @@ static void NOINLINE vfork_compressor(int tar_fd, int gzip)
694# endif 673# endif
695 if (vfork_exec_errno) { 674 if (vfork_exec_errno) {
696 errno = vfork_exec_errno; 675 errno = vfork_exec_errno;
697 bb_perror_msg_and_die("can't execute '%s'", zip_exec); 676 bb_perror_msg_and_die("can't execute '%s'", gzip);
698 } 677 }
699} 678}
700#endif /* ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 */ 679#endif /* SEAMLESS_COMPRESSION */
701 680
702 681
682#if !SEAMLESS_COMPRESSION
683/* Do not pass gzip flag to writeTarFile() */
684#define writeTarFile(tar_fd, verboseFlag, recurseFlags, include, exclude, gzip) \
685 writeTarFile(tar_fd, verboseFlag, recurseFlags, include, exclude)
686#endif
703/* gcc 4.2.1 inlines it, making code bigger */ 687/* gcc 4.2.1 inlines it, making code bigger */
704static NOINLINE int writeTarFile(int tar_fd, int verboseFlag, 688static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
705 int recurseFlags, const llist_t *include, 689 int recurseFlags, const llist_t *include,
706 const llist_t *exclude, int gzip) 690 const llist_t *exclude, const char *gzip)
707{ 691{
708 int errorFlag = FALSE; 692 int errorFlag = FALSE;
709 struct TarBallInfo tbInfo; 693 struct TarBallInfo tbInfo;
@@ -716,7 +700,7 @@ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
716 * can avoid including the tarball into itself.... */ 700 * can avoid including the tarball into itself.... */
717 xfstat(tbInfo.tarFd, &tbInfo.tarFileStatBuf, "can't stat tar file"); 701 xfstat(tbInfo.tarFd, &tbInfo.tarFileStatBuf, "can't stat tar file");
718 702
719#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 703#if SEAMLESS_COMPRESSION
720 if (gzip) 704 if (gzip)
721 vfork_compressor(tbInfo.tarFd, gzip); 705 vfork_compressor(tbInfo.tarFd, gzip);
722#endif 706#endif
@@ -751,7 +735,7 @@ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
751 if (errorFlag) 735 if (errorFlag)
752 bb_error_msg("error exit delayed from previous errors"); 736 bb_error_msg("error exit delayed from previous errors");
753 737
754#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 738#if SEAMLESS_COMPRESSION
755 if (gzip) { 739 if (gzip) {
756 int status; 740 int status;
757 if (safe_waitpid(-1, &status, 0) == -1) 741 if (safe_waitpid(-1, &status, 0) == -1)
@@ -766,7 +750,7 @@ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
766#else 750#else
767int writeTarFile(int tar_fd, int verboseFlag, 751int writeTarFile(int tar_fd, int verboseFlag,
768 int recurseFlags, const llist_t *include, 752 int recurseFlags, const llist_t *include,
769 const llist_t *exclude, int gzip); 753 const llist_t *exclude, const char *gzip);
770#endif /* FEATURE_TAR_CREATE */ 754#endif /* FEATURE_TAR_CREATE */
771 755
772#if ENABLE_FEATURE_TAR_FROM 756#if ENABLE_FEATURE_TAR_FROM
@@ -1151,18 +1135,24 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
1151 if (base_dir) 1135 if (base_dir)
1152 xchdir(base_dir); 1136 xchdir(base_dir);
1153 1137
1154 //if (SEAMLESS_COMPRESSION || OPT_COMPRESS) 1138 //if (SEAMLESS_COMPRESSION)
1155 // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ 1139 // /* We need to know whether child (gzip/bzip/etc) exits abnormally */
1156 // signal(SIGCHLD, check_errors_in_children); 1140 // signal(SIGCHLD, check_errors_in_children);
1157 1141
1158 /* Create an archive */ 1142 /* Create an archive */
1159 if (opt & OPT_CREATE) { 1143 if (opt & OPT_CREATE) {
1160#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 1144#if SEAMLESS_COMPRESSION
1161 int zipMode = 0; 1145 const char *zipMode = NULL;
1162 if (ENABLE_FEATURE_SEAMLESS_GZ && (opt & OPT_GZIP)) 1146 if (opt & OPT_COMPRESS)
1163 zipMode = 1; 1147 zipMode = "compress";
1164 if (ENABLE_FEATURE_SEAMLESS_BZ2 && (opt & OPT_BZIP2)) 1148 if (opt & OPT_GZIP)
1165 zipMode = 2; 1149 zipMode = "gzip";
1150 if (opt & OPT_BZIP2)
1151 zipMode = "bzip2";
1152 if (opt & OPT_LZMA)
1153 zipMode = "lzma";
1154 if (opt & OPT_XZ)
1155 zipMode = "xz";
1166#endif 1156#endif
1167 /* NB: writeTarFile() closes tar_handle->src_fd */ 1157 /* NB: writeTarFile() closes tar_handle->src_fd */
1168 return writeTarFile(tar_handle->src_fd, verboseFlag, 1158 return writeTarFile(tar_handle->src_fd, verboseFlag,
@@ -1173,7 +1163,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
1173 } 1163 }
1174 1164
1175 if (opt & OPT_ANY_COMPRESS) { 1165 if (opt & OPT_ANY_COMPRESS) {
1176 USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd);) 1166 USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_state_t *xstate);)
1177 USE_FOR_NOMMU(const char *xformer_prog;) 1167 USE_FOR_NOMMU(const char *xformer_prog;)
1178 1168
1179 if (opt & OPT_COMPRESS) 1169 if (opt & OPT_COMPRESS)
@@ -1192,7 +1182,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
1192 USE_FOR_MMU(xformer = unpack_xz_stream;) 1182 USE_FOR_MMU(xformer = unpack_xz_stream;)
1193 USE_FOR_NOMMU(xformer_prog = "unxz";) 1183 USE_FOR_NOMMU(xformer_prog = "unxz";)
1194 1184
1195 open_transformer_with_sig(tar_handle->src_fd, xformer, xformer_prog); 1185 fork_transformer_with_sig(tar_handle->src_fd, xformer, xformer_prog);
1196 /* Can't lseek over pipes */ 1186 /* Can't lseek over pipes */
1197 tar_handle->seek = seek_by_read; 1187 tar_handle->seek = seek_by_read;
1198 /*tar_handle->offset = 0; - already is */ 1188 /*tar_handle->offset = 0; - already is */
diff --git a/archival/unzip.c b/archival/unzip.c
index fcfc9a448..38a07e212 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -280,17 +280,19 @@ static void unzip_extract(zip_header_t *zip_header, int dst_fd)
280 bb_copyfd_exact_size(zip_fd, dst_fd, size); 280 bb_copyfd_exact_size(zip_fd, dst_fd, size);
281 } else { 281 } else {
282 /* Method 8 - inflate */ 282 /* Method 8 - inflate */
283 transformer_aux_data_t aux; 283 transformer_state_t xstate;
284 init_transformer_aux_data(&aux); 284 init_transformer_state(&xstate);
285 aux.bytes_in = zip_header->formatted.cmpsize; 285 xstate.bytes_in = zip_header->formatted.cmpsize;
286 if (inflate_unzip(&aux, zip_fd, dst_fd) < 0) 286 xstate.src_fd = zip_fd;
287 xstate.dst_fd = dst_fd;
288 if (inflate_unzip(&xstate) < 0)
287 bb_error_msg_and_die("inflate error"); 289 bb_error_msg_and_die("inflate error");
288 /* Validate decompression - crc */ 290 /* Validate decompression - crc */
289 if (zip_header->formatted.crc32 != (aux.crc32 ^ 0xffffffffL)) { 291 if (zip_header->formatted.crc32 != (xstate.crc32 ^ 0xffffffffL)) {
290 bb_error_msg_and_die("crc error"); 292 bb_error_msg_and_die("crc error");
291 } 293 }
292 /* Validate decompression - size */ 294 /* Validate decompression - size */
293 if (zip_header->formatted.ucmpsize != aux.bytes_out) { 295 if (zip_header->formatted.ucmpsize != xstate.bytes_out) {
294 /* Don't die. Who knows, maybe len calculation 296 /* Don't die. Who knows, maybe len calculation
295 * was botched somewhere. After all, crc matched! */ 297 * was botched somewhere. After all, crc matched! */
296 bb_error_msg("bad length"); 298 bb_error_msg("bad length");
diff --git a/docs/logging_and_backgrounding.txt b/docs/logging_and_backgrounding.txt
index 7e6885560..c76cd3653 100644
--- a/docs/logging_and_backgrounding.txt
+++ b/docs/logging_and_backgrounding.txt
@@ -45,6 +45,8 @@ udhcpc - auto-backgrounds unless -f after lease is obtained,
45udhcpd - auto-backgrounds and do not log to stderr unless -f, 45udhcpd - auto-backgrounds and do not log to stderr unless -f,
46 otherwise logs to stderr, but option -S makes it log *also* to syslog 46 otherwise logs to stderr, but option -S makes it log *also* to syslog
47zcip - auto-backgrounds and logs *also* to syslog unless -f 47zcip - auto-backgrounds and logs *also* to syslog unless -f
48 behaviour can be overridden with experimental LOGGING env.var
49 (can be set to either "none" or "syslog")
48 50
49Total: 13 applets (+1 obsolete), 51Total: 13 applets (+1 obsolete),
50 4 log to syslog by default (crond fakeidentd inetd zcip), 52 4 log to syslog by default (crond fakeidentd inetd zcip),
diff --git a/include/bb_archive.h b/include/bb_archive.h
index b82cfd83c..a6b166fe3 100644
--- a/include/bb_archive.h
+++ b/include/bb_archive.h
@@ -203,43 +203,57 @@ int read_bunzip(bunzip_data *bd, char *outbuf, int len) FAST_FUNC;
203void dealloc_bunzip(bunzip_data *bd) FAST_FUNC; 203void dealloc_bunzip(bunzip_data *bd) FAST_FUNC;
204 204
205/* Meaning and direction (input/output) of the fields are transformer-specific */ 205/* Meaning and direction (input/output) of the fields are transformer-specific */
206typedef struct transformer_aux_data_t { 206typedef struct transformer_state_t {
207 smallint check_signature; /* most often referenced member */ 207 smallint check_signature; /* most often referenced member */
208
209 IF_DESKTOP(long long) int FAST_FUNC (*xformer)(struct transformer_state_t *xstate);
210 USE_FOR_NOMMU(const char *xformer_prog;)
211
212 /* Source */
213 int src_fd;
214 /* Output */
215 int dst_fd;
216 size_t mem_output_size_max; /* if non-zero, decompress to RAM instead of fd */
217 size_t mem_output_size;
218 char *mem_output_buf;
219
208 off_t bytes_out; 220 off_t bytes_out;
209 off_t bytes_in; /* used in unzip code only: needs to know packed size */ 221 off_t bytes_in; /* used in unzip code only: needs to know packed size */
210 uint32_t crc32; 222 uint32_t crc32;
211 time_t mtime; /* gunzip code may set this on exit */ 223 time_t mtime; /* gunzip code may set this on exit */
212} transformer_aux_data_t; 224} transformer_state_t;
213 225
214void init_transformer_aux_data(transformer_aux_data_t *aux) FAST_FUNC; 226void init_transformer_state(transformer_state_t *xstate) FAST_FUNC;
215int FAST_FUNC check_signature16(transformer_aux_data_t *aux, int src_fd, unsigned magic16) FAST_FUNC; 227ssize_t transformer_write(transformer_state_t *xstate, const void *buf, size_t bufsize) FAST_FUNC;
228ssize_t xtransformer_write(transformer_state_t *xstate, const void *buf, size_t bufsize) FAST_FUNC;
229int check_signature16(transformer_state_t *xstate, unsigned magic16) FAST_FUNC;
216 230
217IF_DESKTOP(long long) int inflate_unzip(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; 231IF_DESKTOP(long long) int inflate_unzip(transformer_state_t *xstate) FAST_FUNC;
218IF_DESKTOP(long long) int unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; 232IF_DESKTOP(long long) int unpack_Z_stream(transformer_state_t *xstate) FAST_FUNC;
219IF_DESKTOP(long long) int unpack_gz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; 233IF_DESKTOP(long long) int unpack_gz_stream(transformer_state_t *xstate) FAST_FUNC;
220IF_DESKTOP(long long) int unpack_bz2_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; 234IF_DESKTOP(long long) int unpack_bz2_stream(transformer_state_t *xstate) FAST_FUNC;
221IF_DESKTOP(long long) int unpack_lzma_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; 235IF_DESKTOP(long long) int unpack_lzma_stream(transformer_state_t *xstate) FAST_FUNC;
222IF_DESKTOP(long long) int unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; 236IF_DESKTOP(long long) int unpack_xz_stream(transformer_state_t *xstate) FAST_FUNC;
223 237
224char* append_ext(char *filename, const char *expected_ext) FAST_FUNC; 238char* append_ext(char *filename, const char *expected_ext) FAST_FUNC;
225int bbunpack(char **argv, 239int bbunpack(char **argv,
226 IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(transformer_aux_data_t *aux), 240 IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(transformer_state_t *xstate),
227 char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext), 241 char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext),
228 const char *expected_ext 242 const char *expected_ext
229) FAST_FUNC; 243) FAST_FUNC;
230 244
231void check_errors_in_children(int signo); 245void check_errors_in_children(int signo);
232#if BB_MMU 246#if BB_MMU
233void open_transformer(int fd, 247void fork_transformer(int fd,
234 int check_signature, 248 int check_signature,
235 IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd) 249 IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_state_t *xstate)
236) FAST_FUNC; 250) FAST_FUNC;
237#define open_transformer_with_sig(fd, transformer, transform_prog) open_transformer((fd), 1, (transformer)) 251#define fork_transformer_with_sig(fd, transformer, transform_prog) fork_transformer((fd), 1, (transformer))
238#define open_transformer_with_no_sig(fd, transformer) open_transformer((fd), 0, (transformer)) 252#define fork_transformer_with_no_sig(fd, transformer) fork_transformer((fd), 0, (transformer))
239#else 253#else
240void open_transformer(int fd, const char *transform_prog) FAST_FUNC; 254void fork_transformer(int fd, const char *transform_prog) FAST_FUNC;
241#define open_transformer_with_sig(fd, transformer, transform_prog) open_transformer((fd), (transform_prog)) 255#define fork_transformer_with_sig(fd, transformer, transform_prog) fork_transformer((fd), (transform_prog))
242/* open_transformer_with_no_sig() does not exist on NOMMU */ 256/* fork_transformer_with_no_sig() does not exist on NOMMU */
243#endif 257#endif
244 258
245 259
diff --git a/include/libbb.h b/include/libbb.h
index 21a56d78f..802779932 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -744,11 +744,14 @@ extern void *xmalloc_open_read_close(const char *filename, size_t *maxsz_p) FAST
744/* Never returns NULL */ 744/* Never returns NULL */
745extern void *xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; 745extern void *xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC;
746 746
747#if defined ARG_MAX 747#if defined(ARG_MAX) && (ARG_MAX >= 60*1024 || !defined(_SC_ARG_MAX))
748/* Use _constant_ maximum if: defined && (big enough || no variable one exists) */
748# define bb_arg_max() ((unsigned)ARG_MAX) 749# define bb_arg_max() ((unsigned)ARG_MAX)
749#elif defined _SC_ARG_MAX 750#elif defined(_SC_ARG_MAX)
751/* Else use variable one (a bit more expensive) */
750unsigned bb_arg_max(void) FAST_FUNC; 752unsigned bb_arg_max(void) FAST_FUNC;
751#else 753#else
754/* If all else fails */
752# define bb_arg_max() ((unsigned)(32 * 1024)) 755# define bb_arg_max() ((unsigned)(32 * 1024))
753#endif 756#endif
754unsigned bb_clk_tck(void) FAST_FUNC; 757unsigned bb_clk_tck(void) FAST_FUNC;
@@ -765,11 +768,12 @@ unsigned bb_clk_tck(void) FAST_FUNC;
765extern int setup_unzip_on_fd(int fd, int fail_if_not_compressed) FAST_FUNC; 768extern int setup_unzip_on_fd(int fd, int fail_if_not_compressed) FAST_FUNC;
766/* Autodetects .gz etc */ 769/* Autodetects .gz etc */
767extern int open_zipped(const char *fname, int fail_if_not_compressed) FAST_FUNC; 770extern int open_zipped(const char *fname, int fail_if_not_compressed) FAST_FUNC;
771extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC;
768#else 772#else
769# define setup_unzip_on_fd(...) (0) 773# define setup_unzip_on_fd(...) (0)
770# define open_zipped(fname, fail_if_not_compressed) open((fname), O_RDONLY); 774# define open_zipped(fname, fail_if_not_compressed) open((fname), O_RDONLY);
775# define xmalloc_open_zipped_read_close(fname, maxsz_p) xmalloc_open_read_close((fname), (maxsz_p))
771#endif 776#endif
772extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC;
773 777
774extern ssize_t safe_write(int fd, const void *buf, size_t count) FAST_FUNC; 778extern ssize_t safe_write(int fd, const void *buf, size_t count) FAST_FUNC;
775// NB: will return short write on error, not -1, 779// NB: will return short write on error, not -1,
@@ -1120,6 +1124,7 @@ extern void bb_perror_nomsg_and_die(void) NORETURN FAST_FUNC;
1120extern void bb_perror_nomsg(void) FAST_FUNC; 1124extern void bb_perror_nomsg(void) FAST_FUNC;
1121extern void bb_info_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC; 1125extern void bb_info_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC;
1122extern void bb_verror_msg(const char *s, va_list p, const char *strerr) FAST_FUNC; 1126extern void bb_verror_msg(const char *s, va_list p, const char *strerr) FAST_FUNC;
1127extern void bb_logenv_override(void) FAST_FUNC;
1123 1128
1124/* We need to export XXX_main from libbusybox 1129/* We need to export XXX_main from libbusybox
1125 * only if we build "individual" binaries 1130 * only if we build "individual" binaries
diff --git a/init/init.c b/init/init.c
index de438be20..d99d68ce4 100644
--- a/init/init.c
+++ b/init/init.c
@@ -822,7 +822,7 @@ static void halt_reboot_pwoff(int sig)
822 822
823/* Handler for QUIT - exec "restart" action, 823/* Handler for QUIT - exec "restart" action,
824 * else (no such action defined) do nothing */ 824 * else (no such action defined) do nothing */
825static void restart_handler(int sig UNUSED_PARAM) 825static void exec_restart_action(void)
826{ 826{
827 struct init_action *a; 827 struct init_action *a;
828 828
@@ -975,6 +975,20 @@ static int check_delayed_sigs(void)
975#endif 975#endif
976 if (sig == SIGINT) 976 if (sig == SIGINT)
977 run_actions(CTRLALTDEL); 977 run_actions(CTRLALTDEL);
978 if (sig == SIGQUIT) {
979 exec_restart_action();
980 /* returns only if no restart action defined */
981 }
982 if ((1 << sig) & (0
983#ifdef SIGPWR
984 + (1 << SIGPWR)
985#endif
986 + (1 << SIGUSR1)
987 + (1 << SIGUSR2)
988 + (1 << SIGTERM)
989 )) {
990 halt_reboot_pwoff(sig);
991 }
978 } 992 }
979} 993}
980 994
@@ -1070,7 +1084,7 @@ int init_main(int argc UNUSED_PARAM, char **argv)
1070 1084
1071#if 0 1085#if 0
1072/* It's 2013, does anyone really still depend on this? */ 1086/* It's 2013, does anyone really still depend on this? */
1073/* If you do, consider adding swapon to sysinot actions then! */ 1087/* If you do, consider adding swapon to sysinit actions then! */
1074/* struct sysinfo is linux-specific */ 1088/* struct sysinfo is linux-specific */
1075# ifdef __linux__ 1089# ifdef __linux__
1076 /* Make sure there is enough memory to do something useful. */ 1090 /* Make sure there is enough memory to do something useful. */
@@ -1134,16 +1148,6 @@ int init_main(int argc UNUSED_PARAM, char **argv)
1134 if (!DEBUG_INIT) { 1148 if (!DEBUG_INIT) {
1135 struct sigaction sa; 1149 struct sigaction sa;
1136 1150
1137 bb_signals(0
1138#ifdef SIGPWR
1139 + (1 << SIGPWR) /* halt */
1140#endif
1141 + (1 << SIGUSR1) /* halt */
1142 + (1 << SIGTERM) /* reboot */
1143 + (1 << SIGUSR2) /* poweroff */
1144 , halt_reboot_pwoff);
1145 signal(SIGQUIT, restart_handler); /* re-exec another init */
1146
1147 /* Stop handler must allow only SIGCONT inside itself */ 1151 /* Stop handler must allow only SIGCONT inside itself */
1148 memset(&sa, 0, sizeof(sa)); 1152 memset(&sa, 0, sizeof(sa));
1149 sigfillset(&sa.sa_mask); 1153 sigfillset(&sa.sa_mask);
@@ -1158,18 +1162,24 @@ int init_main(int argc UNUSED_PARAM, char **argv)
1158 */ 1162 */
1159 sigaction_set(SIGSTOP, &sa); /* pause */ 1163 sigaction_set(SIGSTOP, &sa); /* pause */
1160 1164
1161 /* SIGINT (Ctrl-Alt-Del) must interrupt wait(), 1165 /* These signals must interrupt wait(),
1162 * setting handler without SA_RESTART flag. 1166 * setting handler without SA_RESTART flag.
1163 */ 1167 */
1164 bb_signals_recursive_norestart((1 << SIGINT), record_signo); 1168 bb_signals_recursive_norestart(0
1169 + (1 << SIGINT) /* Ctrl-Alt-Del */
1170 + (1 << SIGQUIT) /* re-exec another init */
1171#ifdef SIGPWR
1172 + (1 << SIGPWR) /* halt */
1173#endif
1174 + (1 << SIGUSR1) /* halt */
1175 + (1 << SIGTERM) /* reboot */
1176 + (1 << SIGUSR2) /* poweroff */
1177#if ENABLE_FEATURE_USE_INITTAB
1178 + (1 << SIGHUP) /* reread /etc/inittab */
1179#endif
1180 , record_signo);
1165 } 1181 }
1166 1182
1167 /* Set up "reread /etc/inittab" handler.
1168 * Handler is set up without SA_RESTART, it will interrupt syscalls.
1169 */
1170 if (!DEBUG_INIT && ENABLE_FEATURE_USE_INITTAB)
1171 bb_signals_recursive_norestart((1 << SIGHUP), record_signo);
1172
1173 /* Now run everything that needs to be run */ 1183 /* Now run everything that needs to be run */
1174 /* First run the sysinit command */ 1184 /* First run the sysinit command */
1175 run_actions(SYSINIT); 1185 run_actions(SYSINIT);
diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src
index 1f2ed36d9..1be87b337 100644
--- a/libbb/Kbuild.src
+++ b/libbb/Kbuild.src
@@ -189,3 +189,6 @@ lib-$(CONFIG_PGREP) += xregcomp.o
189lib-$(CONFIG_PKILL) += xregcomp.o 189lib-$(CONFIG_PKILL) += xregcomp.o
190lib-$(CONFIG_DEVFSD) += xregcomp.o 190lib-$(CONFIG_DEVFSD) += xregcomp.o
191lib-$(CONFIG_FEATURE_FIND_REGEX) += xregcomp.o 191lib-$(CONFIG_FEATURE_FIND_REGEX) += xregcomp.o
192
193# Add the experimental logging functionality, only used by zcip
194lib-$(CONFIG_ZCIP) += logenv.o
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index 2c85062b4..b74b6e724 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -746,7 +746,8 @@ static int busybox_main(char **argv)
746 /*bb_error_msg_and_die("applet not found"); - sucks in printf */ 746 /*bb_error_msg_and_die("applet not found"); - sucks in printf */
747 full_write2_str(applet_name); 747 full_write2_str(applet_name);
748 full_write2_str(": applet not found\n"); 748 full_write2_str(": applet not found\n");
749 xfunc_die(); 749 /* POSIX: "If a command is not found, the exit status shall be 127" */
750 exit(127);
750} 751}
751 752
752void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv) 753void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv)
@@ -870,6 +871,7 @@ int main(int argc UNUSED_PARAM, char **argv)
870 /*bb_error_msg_and_die("applet not found"); - sucks in printf */ 871 /*bb_error_msg_and_die("applet not found"); - sucks in printf */
871 full_write2_str(applet_name); 872 full_write2_str(applet_name);
872 full_write2_str(": applet not found\n"); 873 full_write2_str(": applet not found\n");
873 xfunc_die(); 874 /* POSIX: "If a command is not found, the exit status shall be 127" */
875 exit(127);
874#endif 876#endif
875} 877}
diff --git a/libbb/bbunit.c b/libbb/bbunit.c
index 256014441..4c692d59f 100644
--- a/libbb/bbunit.c
+++ b/libbb/bbunit.c
@@ -77,7 +77,7 @@ int unit_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
77#if WANT_TIMING 77#if WANT_TIMING
78 gettimeofday(&end, NULL); 78 gettimeofday(&end, NULL);
79 timeval_diff(&time_spent, &end, &begin); 79 timeval_diff(&time_spent, &end, &begin);
80 bb_error_msg("Elapsed time %u.%06u seconds" 80 bb_error_msg("Elapsed time %u.%06u seconds",
81 (int)time_spent.tv_sec, 81 (int)time_spent.tv_sec,
82 (int)time_spent.tv_usec); 82 (int)time_spent.tv_usec);
83#endif 83#endif
diff --git a/libbb/copyfd.c b/libbb/copyfd.c
index eda2747f9..7e3531903 100644
--- a/libbb/copyfd.c
+++ b/libbb/copyfd.c
@@ -8,6 +8,20 @@
8 */ 8 */
9 9
10#include "libbb.h" 10#include "libbb.h"
11#if ENABLE_FEATURE_USE_SENDFILE
12# include <sys/sendfile.h>
13#else
14# define sendfile(a,b,c,d) (-1)
15#endif
16
17/*
18 * We were using 0x7fff0000 as sendfile chunk size, but it
19 * was seen to cause largish delays when user tries to ^C a file copy.
20 * Let's use a saner size.
21 * Note: needs to be >= max(CONFIG_FEATURE_COPYBUF_KB),
22 * or else "copy to eof" code will use neddlesly short reads.
23 */
24#define SENDFILE_BIGBUF (16*1024*1024)
11 25
12/* Used by NOFORK applets (e.g. cat) - must not use xmalloc. 26/* Used by NOFORK applets (e.g. cat) - must not use xmalloc.
13 * size < 0 means "ignore write errors", used by tar --to-command 27 * size < 0 means "ignore write errors", used by tar --to-command
@@ -18,12 +32,13 @@ static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size)
18 int status = -1; 32 int status = -1;
19 off_t total = 0; 33 off_t total = 0;
20 bool continue_on_write_error = 0; 34 bool continue_on_write_error = 0;
21#if CONFIG_FEATURE_COPYBUF_KB <= 4 35 ssize_t sendfile_sz;
36#if CONFIG_FEATURE_COPYBUF_KB > 4
37 char *buffer = buffer; /* for compiler */
38 int buffer_size = 0;
39#else
22 char buffer[CONFIG_FEATURE_COPYBUF_KB * 1024]; 40 char buffer[CONFIG_FEATURE_COPYBUF_KB * 1024];
23 enum { buffer_size = sizeof(buffer) }; 41 enum { buffer_size = sizeof(buffer) };
24#else
25 char *buffer;
26 int buffer_size;
27#endif 42#endif
28 43
29 if (size < 0) { 44 if (size < 0) {
@@ -31,46 +46,58 @@ static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size)
31 continue_on_write_error = 1; 46 continue_on_write_error = 1;
32 } 47 }
33 48
34#if CONFIG_FEATURE_COPYBUF_KB > 4
35 if (size > 0 && size <= 4 * 1024)
36 goto use_small_buf;
37 /* We want page-aligned buffer, just in case kernel is clever
38 * and can do page-aligned io more efficiently */
39 buffer = mmap(NULL, CONFIG_FEATURE_COPYBUF_KB * 1024,
40 PROT_READ | PROT_WRITE,
41 MAP_PRIVATE | MAP_ANON,
42 /* ignored: */ -1, 0);
43 buffer_size = CONFIG_FEATURE_COPYBUF_KB * 1024;
44 if (buffer == MAP_FAILED) {
45 use_small_buf:
46 buffer = alloca(4 * 1024);
47 buffer_size = 4 * 1024;
48 }
49#endif
50
51 if (src_fd < 0) 49 if (src_fd < 0)
52 goto out; 50 goto out;
53 51
52 sendfile_sz = !ENABLE_FEATURE_USE_SENDFILE
53 ? 0
54 : SENDFILE_BIGBUF;
54 if (!size) { 55 if (!size) {
55 size = buffer_size; 56 size = SENDFILE_BIGBUF;
56 status = 1; /* copy until eof */ 57 status = 1; /* copy until eof */
57 } 58 }
58 59
59 while (1) { 60 while (1) {
60 ssize_t rd; 61 ssize_t rd;
61 62
62 rd = safe_read(src_fd, buffer, size > buffer_size ? buffer_size : size); 63 if (sendfile_sz) {
63 64 rd = sendfile(dst_fd, src_fd, NULL,
64 if (!rd) { /* eof - all done */ 65 size > sendfile_sz ? sendfile_sz : size);
65 status = 0; 66 if (rd >= 0)
66 break; 67 goto read_ok;
68 sendfile_sz = 0; /* do not try sendfile anymore */
69 }
70#if CONFIG_FEATURE_COPYBUF_KB > 4
71 if (buffer_size == 0) {
72 if (size > 0 && size <= 4 * 1024)
73 goto use_small_buf;
74 /* We want page-aligned buffer, just in case kernel is clever
75 * and can do page-aligned io more efficiently */
76 buffer = mmap(NULL, CONFIG_FEATURE_COPYBUF_KB * 1024,
77 PROT_READ | PROT_WRITE,
78 MAP_PRIVATE | MAP_ANON,
79 /* ignored: */ -1, 0);
80 buffer_size = CONFIG_FEATURE_COPYBUF_KB * 1024;
81 if (buffer == MAP_FAILED) {
82 use_small_buf:
83 buffer = alloca(4 * 1024);
84 buffer_size = 4 * 1024;
85 }
67 } 86 }
87#endif
88 rd = safe_read(src_fd, buffer,
89 size > buffer_size ? buffer_size : size);
68 if (rd < 0) { 90 if (rd < 0) {
69 bb_perror_msg(bb_msg_read_error); 91 bb_perror_msg(bb_msg_read_error);
70 break; 92 break;
71 } 93 }
94 read_ok:
95 if (!rd) { /* eof - all done */
96 status = 0;
97 break;
98 }
72 /* dst_fd == -1 is a fake, else... */ 99 /* dst_fd == -1 is a fake, else... */
73 if (dst_fd >= 0) { 100 if (dst_fd >= 0 && !sendfile_sz) {
74 ssize_t wr = full_write(dst_fd, buffer, rd); 101 ssize_t wr = full_write(dst_fd, buffer, rd);
75 if (wr < rd) { 102 if (wr < rd) {
76 if (!continue_on_write_error) { 103 if (!continue_on_write_error) {
@@ -92,10 +119,8 @@ static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size)
92 } 119 }
93 out: 120 out:
94 121
95#if CONFIG_FEATURE_COPYBUF_KB > 4 122 if (buffer_size > 4 * 1024)
96 if (buffer_size != 4 * 1024)
97 munmap(buffer, buffer_size); 123 munmap(buffer, buffer_size);
98#endif
99 return status ? -1 : total; 124 return status ? -1 : total;
100} 125}
101 126
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 1f5653cb5..3d96a8e9f 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -2316,10 +2316,14 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2316 if (!isatty(0) || !isatty(1)) { 2316 if (!isatty(0) || !isatty(1)) {
2317#else 2317#else
2318 if (tcgetattr(STDIN_FILENO, &initial_settings) < 0 2318 if (tcgetattr(STDIN_FILENO, &initial_settings) < 0
2319 || !(initial_settings.c_lflag & ECHO) 2319 || (initial_settings.c_lflag & (ECHO|ICANON)) == ICANON
2320 ) { 2320 ) {
2321#endif 2321#endif
2322 /* Happens when e.g. stty -echo was run before */ 2322 /* Happens when e.g. stty -echo was run before.
2323 * But if ICANON is not set, we don't come here.
2324 * (example: interactive python ^Z-backgrounded,
2325 * tty is still in "raw mode").
2326 */
2323 parse_and_put_prompt(prompt); 2327 parse_and_put_prompt(prompt);
2324 /* fflush_all(); - done by parse_and_put_prompt */ 2328 /* fflush_all(); - done by parse_and_put_prompt */
2325 if (fgets(command, maxsize, stdin) == NULL) 2329 if (fgets(command, maxsize, stdin) == NULL)
diff --git a/libbb/logenv.c b/libbb/logenv.c
new file mode 100644
index 000000000..66c60bd4e
--- /dev/null
+++ b/libbb/logenv.c
@@ -0,0 +1,24 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 2014 by Fugro Intersite B.V. <m.stam@fugro.nl>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */
9#include "libbb.h"
10
11void FAST_FUNC bb_logenv_override(void)
12{
13 const char* mode = getenv("LOGGING");
14
15 if (!mode)
16 return;
17
18 if (strcmp(mode, "none") == 0)
19 logmode = LOGMODE_NONE;
20#if ENABLE_FEATURE_SYSLOG
21 else if (strcmp(mode, "syslog") == 0)
22 logmode = LOGMODE_SYSLOG;
23#endif
24}
diff --git a/libbb/sysconf.c b/libbb/sysconf.c
index 031901980..cfad9cdc0 100644
--- a/libbb/sysconf.c
+++ b/libbb/sysconf.c
@@ -8,7 +8,7 @@
8 */ 8 */
9#include "libbb.h" 9#include "libbb.h"
10 10
11#if !defined(ARG_MAX) && defined(_SC_ARG_MAX) 11#if !defined(bb_arg_max)
12unsigned FAST_FUNC bb_arg_max(void) 12unsigned FAST_FUNC bb_arg_max(void)
13{ 13{
14 return sysconf(_SC_ARG_MAX); 14 return sysconf(_SC_ARG_MAX);
diff --git a/miscutils/flashcp.c b/miscutils/flashcp.c
index b526566a4..9bc588d14 100644
--- a/miscutils/flashcp.c
+++ b/miscutils/flashcp.c
@@ -21,7 +21,7 @@
21 21
22#define OPT_v (1 << 0) 22#define OPT_v (1 << 0)
23 23
24#define BUFSIZE (8 * 1024) 24#define BUFSIZE (4 * 1024)
25 25
26static void progress(int mode, uoff_t count, uoff_t total) 26static void progress(int mode, uoff_t count, uoff_t total)
27{ 27{
diff --git a/miscutils/man.c b/miscutils/man.c
index 0e0b1cba6..3f389b435 100644
--- a/miscutils/man.c
+++ b/miscutils/man.c
@@ -147,15 +147,55 @@ static int show_manpage(const char *pager, char *man_filename, int man, int leve
147 return run_pipe(pager, man_filename, man, level); 147 return run_pipe(pager, man_filename, man, level);
148} 148}
149 149
150static char **add_MANPATH(char **man_path_list, int *count_mp, char *path)
151{
152 if (path) while (*path) {
153 char *next_path;
154 char **path_element;
155
156#if ENABLE_PLATFORM_MINGW32
157 next_path = next_path_sep(path);
158#else
159 next_path = strchr(path, ':');
160#endif
161 if (next_path) {
162 if (next_path == path) /* "::"? */
163 goto next;
164 *next_path = '\0';
165 }
166 /* Do we already have path? */
167 path_element = man_path_list;
168 if (path_element) while (*path_element) {
169 if (strcmp(*path_element, path) == 0)
170 goto skip;
171 path_element++;
172 }
173 man_path_list = xrealloc_vector(man_path_list, 4, *count_mp);
174 man_path_list[*count_mp] = xstrdup(path);
175 (*count_mp)++;
176 /* man_path_list is NULL terminated */
177 /* man_path_list[*count_mp] = NULL; - xrealloc_vector did it */
178 skip:
179 if (!next_path)
180 break;
181 /* "path" may be a result of getenv(), be nice and don't mangle it */
182 *next_path = ':';
183 next:
184 path = next_path + 1;
185 }
186 return man_path_list;
187}
188
150int man_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 189int man_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
151int man_main(int argc UNUSED_PARAM, char **argv) 190int man_main(int argc UNUSED_PARAM, char **argv)
152{ 191{
153 parser_t *parser; 192 parser_t *parser;
154 const char *pager = ENABLE_LESS ? "less" : "more"; 193 const char *pager = ENABLE_LESS ? "less" : "more";
155 char **man_path_list;
156 char *sec_list; 194 char *sec_list;
157 char *cur_path, *cur_sect; 195 char *cur_path, *cur_sect;
158 int count_mp, cur_mp; 196 char **man_path_list;
197 int count_mp;
198 int cur_mp;
159 int opt, not_found; 199 int opt, not_found;
160 char *token[2]; 200 char *token[2];
161 201
@@ -164,14 +204,20 @@ int man_main(int argc UNUSED_PARAM, char **argv)
164 argv += optind; 204 argv += optind;
165 205
166 sec_list = xstrdup("0p:1:1p:2:3:3p:4:5:6:7:8:9"); 206 sec_list = xstrdup("0p:1:1p:2:3:3p:4:5:6:7:8:9");
167 /* Last valid man_path_list[] is [0x10] */ 207
168 count_mp = 0; 208 count_mp = 0;
169 man_path_list = xzalloc(0x11 * sizeof(man_path_list[0])); 209 man_path_list = add_MANPATH(NULL, &count_mp,
170 man_path_list[0] = getenv("MANPATH"); 210 getenv("MANDATORY_MANPATH"+10) /* "MANPATH" */
171 if (!man_path_list[0]) /* default, may be overridden by /etc/man.conf */ 211 );
212 if (!man_path_list) {
213 /* default, may be overridden by /etc/man.conf */
214 man_path_list = xzalloc(2 * sizeof(man_path_list[0]));
172 man_path_list[0] = (char*)"/usr/man"; 215 man_path_list[0] = (char*)"/usr/man";
173 else 216 /* count_mp stays 0.
174 count_mp++; 217 * Thus, man.conf will overwrite man_path_list[0]
218 * if a path is defined there.
219 */
220 }
175 221
176 /* Parse man.conf[ig] or man_db.conf */ 222 /* Parse man.conf[ig] or man_db.conf */
177 /* man version 1.6f uses man.config */ 223 /* man version 1.6f uses man.config */
@@ -193,39 +239,7 @@ int man_main(int argc UNUSED_PARAM, char **argv)
193 if (strcmp("MANDATORY_MANPATH"+10, token[0]) == 0 /* "MANPATH"? */ 239 if (strcmp("MANDATORY_MANPATH"+10, token[0]) == 0 /* "MANPATH"? */
194 || strcmp("MANDATORY_MANPATH", token[0]) == 0 240 || strcmp("MANDATORY_MANPATH", token[0]) == 0
195 ) { 241 ) {
196 char *path = token[1]; 242 man_path_list = add_MANPATH(man_path_list, &count_mp, token[1]);
197 while (*path) {
198 char *next_path;
199 char **path_element;
200
201#if ENABLE_PLATFORM_MINGW32
202 next_path = next_path_sep(path);
203#else
204 next_path = strchr(path, ':');
205#endif
206 if (next_path) {
207 *next_path = '\0';
208 if (next_path++ == path) /* "::"? */
209 goto next;
210 }
211 /* Do we already have path? */
212 path_element = man_path_list;
213 while (*path_element) {
214 if (strcmp(*path_element, path) == 0)
215 goto skip;
216 path_element++;
217 }
218 man_path_list = xrealloc_vector(man_path_list, 4, count_mp);
219 man_path_list[count_mp] = xstrdup(path);
220 count_mp++;
221 /* man_path_list is NULL terminated */
222 /*man_path_list[count_mp] = NULL; - xrealloc_vector did it */
223 skip:
224 if (!next_path)
225 break;
226 next:
227 path = next_path;
228 }
229 } 243 }
230 if (strcmp("MANSECT", token[0]) == 0) { 244 if (strcmp("MANSECT", token[0]) == 0) {
231 free(sec_list); 245 free(sec_list);
diff --git a/modutils/modprobe.c b/modutils/modprobe.c
index f08f0850d..f0904285b 100644
--- a/modutils/modprobe.c
+++ b/modutils/modprobe.c
@@ -238,6 +238,17 @@ static void add_probe(const char *name)
238{ 238{
239 struct module_entry *m; 239 struct module_entry *m;
240 240
241 /*
242 * get_or_add_modentry() strips path from name and works
243 * on remaining basename.
244 * This would make "rmmod dir/name" and "modprobe dir/name"
245 * to work like "rmmod name" and "modprobe name",
246 * which is wrong, and can be abused via implicit modprobing:
247 * "ifconfig /usbserial up" tries to modprobe netdev-/usbserial.
248 */
249 if (strchr(name, '/'))
250 bb_error_msg_and_die("malformed module name '%s'", name);
251
241 m = get_or_add_modentry(name); 252 m = get_or_add_modentry(name);
242 if (!(option_mask32 & (OPT_REMOVE | OPT_SHOW_DEPS)) 253 if (!(option_mask32 & (OPT_REMOVE | OPT_SHOW_DEPS))
243 && (m->flags & MODULE_FLAG_LOADED) 254 && (m->flags & MODULE_FLAG_LOADED)
diff --git a/networking/Config.src b/networking/Config.src
index e56646917..15a696876 100644
--- a/networking/Config.src
+++ b/networking/Config.src
@@ -181,14 +181,6 @@ config FEATURE_HTTPD_RANGES
181 "Range: bytes=NNN-[MMM]" header. Allows for resuming interrupted 181 "Range: bytes=NNN-[MMM]" header. Allows for resuming interrupted
182 downloads, seeking in multimedia players etc. 182 downloads, seeking in multimedia players etc.
183 183
184config FEATURE_HTTPD_USE_SENDFILE
185 bool "Use sendfile system call"
186 default y
187 depends on HTTPD
188 help
189 When enabled, httpd will use the kernel sendfile() function
190 instead of read/write loop.
191
192config FEATURE_HTTPD_SETUID 184config FEATURE_HTTPD_SETUID
193 bool "Enable -u <user> option" 185 bool "Enable -u <user> option"
194 default y 186 default y
diff --git a/networking/httpd.c b/networking/httpd.c
index 621d9cddc..9cf080401 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -133,7 +133,7 @@
133# include <security/pam_appl.h> 133# include <security/pam_appl.h>
134# include <security/pam_misc.h> 134# include <security/pam_misc.h>
135#endif 135#endif
136#if ENABLE_FEATURE_HTTPD_USE_SENDFILE 136#if ENABLE_FEATURE_USE_SENDFILE
137# include <sys/sendfile.h> 137# include <sys/sendfile.h>
138#endif 138#endif
139/* amount of buffering in a pipe */ 139/* amount of buffering in a pipe */
@@ -1624,7 +1624,7 @@ static NOINLINE void send_file_and_exit(const char *url, int what)
1624#endif 1624#endif
1625 if (what & SEND_HEADERS) 1625 if (what & SEND_HEADERS)
1626 send_headers(HTTP_OK); 1626 send_headers(HTTP_OK);
1627#if ENABLE_FEATURE_HTTPD_USE_SENDFILE 1627#if ENABLE_FEATURE_USE_SENDFILE
1628 { 1628 {
1629 off_t offset = range_start; 1629 off_t offset = range_start;
1630 while (1) { 1630 while (1) {
@@ -1654,7 +1654,7 @@ static NOINLINE void send_file_and_exit(const char *url, int what)
1654 break; 1654 break;
1655 } 1655 }
1656 if (count < 0) { 1656 if (count < 0) {
1657 IF_FEATURE_HTTPD_USE_SENDFILE(fin:) 1657 IF_FEATURE_USE_SENDFILE(fin:)
1658 if (verbose > 1) 1658 if (verbose > 1)
1659 bb_perror_msg("error"); 1659 bb_perror_msg("error");
1660 } 1660 }
diff --git a/networking/libiproute/iproute.c b/networking/libiproute/iproute.c
index ec4d8ba03..170c67b30 100644
--- a/networking/libiproute/iproute.c
+++ b/networking/libiproute/iproute.c
@@ -298,6 +298,19 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
298 if (tb[RTA_PRIORITY]) { 298 if (tb[RTA_PRIORITY]) {
299 printf(" metric %d ", *(uint32_t*)RTA_DATA(tb[RTA_PRIORITY])); 299 printf(" metric %d ", *(uint32_t*)RTA_DATA(tb[RTA_PRIORITY]));
300 } 300 }
301 if (r->rtm_flags & RTNH_F_DEAD) {
302 printf("dead ");
303 }
304 if (r->rtm_flags & RTNH_F_ONLINK) {
305 printf("onlink ");
306 }
307 if (r->rtm_flags & RTNH_F_PERVASIVE) {
308 printf("pervasive ");
309 }
310 if (r->rtm_flags & RTM_F_NOTIFY) {
311 printf("notify ");
312 }
313
301 if (r->rtm_family == AF_INET6) { 314 if (r->rtm_family == AF_INET6) {
302 struct rta_cacheinfo *ci = NULL; 315 struct rta_cacheinfo *ci = NULL;
303 if (tb[RTA_CACHEINFO]) { 316 if (tb[RTA_CACHEINFO]) {
@@ -330,7 +343,7 @@ static int iproute_modify(int cmd, unsigned flags, char **argv)
330{ 343{
331 static const char keywords[] ALIGN1 = 344 static const char keywords[] ALIGN1 =
332 "src\0""via\0""mtu\0""lock\0""protocol\0"IF_FEATURE_IP_RULE("table\0") 345 "src\0""via\0""mtu\0""lock\0""protocol\0"IF_FEATURE_IP_RULE("table\0")
333 "dev\0""oif\0""to\0""metric\0"; 346 "dev\0""oif\0""to\0""metric\0""onlink\0";
334 enum { 347 enum {
335 ARG_src, 348 ARG_src,
336 ARG_via, 349 ARG_via,
@@ -341,6 +354,7 @@ IF_FEATURE_IP_RULE(ARG_table,)
341 ARG_oif, 354 ARG_oif,
342 ARG_to, 355 ARG_to,
343 ARG_metric, 356 ARG_metric,
357 ARG_onlink,
344 }; 358 };
345 enum { 359 enum {
346 gw_ok = 1 << 0, 360 gw_ok = 1 << 0,
@@ -431,6 +445,8 @@ IF_FEATURE_IP_RULE(ARG_table,)
431 NEXT_ARG(); 445 NEXT_ARG();
432 metric = get_u32(*argv, "metric"); 446 metric = get_u32(*argv, "metric");
433 addattr32(&req.n, sizeof(req), RTA_PRIORITY, metric); 447 addattr32(&req.n, sizeof(req), RTA_PRIORITY, metric);
448 } else if (arg == ARG_onlink) {
449 req.r.rtm_flags |= RTNH_F_ONLINK;
434 } else { 450 } else {
435 int type; 451 int type;
436 inet_prefix dst; 452 inet_prefix dst;
diff --git a/networking/udhcp/arpping.c b/networking/udhcp/arpping.c
index b43e52e96..fad2283c3 100644
--- a/networking/udhcp/arpping.c
+++ b/networking/udhcp/arpping.c
@@ -39,7 +39,8 @@ int FAST_FUNC arpping(uint32_t test_nip,
39 const uint8_t *safe_mac, 39 const uint8_t *safe_mac,
40 uint32_t from_ip, 40 uint32_t from_ip,
41 uint8_t *from_mac, 41 uint8_t *from_mac,
42 const char *interface) 42 const char *interface,
43 unsigned timeo)
43{ 44{
44 int timeout_ms; 45 int timeout_ms;
45 struct pollfd pfd[1]; 46 struct pollfd pfd[1];
@@ -48,6 +49,9 @@ int FAST_FUNC arpping(uint32_t test_nip,
48 struct sockaddr addr; /* for interface name */ 49 struct sockaddr addr; /* for interface name */
49 struct arpMsg arp; 50 struct arpMsg arp;
50 51
52 if (!timeo)
53 return 1;
54
51 s = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP)); 55 s = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP));
52 if (s == -1) { 56 if (s == -1) {
53 bb_perror_msg(bb_msg_can_not_create_raw_socket); 57 bb_perror_msg(bb_msg_can_not_create_raw_socket);
@@ -83,7 +87,7 @@ int FAST_FUNC arpping(uint32_t test_nip,
83 } 87 }
84 88
85 /* wait for arp reply, and check it */ 89 /* wait for arp reply, and check it */
86 timeout_ms = 2000; 90 timeout_ms = (int)timeo;
87 do { 91 do {
88 typedef uint32_t aliased_uint32_t FIX_ALIASING; 92 typedef uint32_t aliased_uint32_t FIX_ALIASING;
89 int r; 93 int r;
@@ -124,7 +128,7 @@ int FAST_FUNC arpping(uint32_t test_nip,
124 * this is more under/overflow-resistant 128 * this is more under/overflow-resistant
125 * (people did see overflows here when system time jumps): 129 * (people did see overflows here when system time jumps):
126 */ 130 */
127 } while ((unsigned)timeout_ms <= 2000); 131 } while ((unsigned)timeout_ms <= timeo);
128 132
129 ret: 133 ret:
130 close(s); 134 close(s);
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
index e5e0f2599..d20659e2f 100644
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
@@ -311,7 +311,8 @@ int arpping(uint32_t test_nip,
311 const uint8_t *safe_mac, 311 const uint8_t *safe_mac,
312 uint32_t from_ip, 312 uint32_t from_ip,
313 uint8_t *from_mac, 313 uint8_t *from_mac,
314 const char *interface) FAST_FUNC; 314 const char *interface,
315 unsigned timeo) FAST_FUNC;
315 316
316/* note: ip is a pointer to an IPv6 in network order, possibly misaliged */ 317/* note: ip is a pointer to an IPv6 in network order, possibly misaliged */
317int sprint_nip6(char *dest, /*const char *pre,*/ const uint8_t *ip) FAST_FUNC; 318int sprint_nip6(char *dest, /*const char *pre,*/ const uint8_t *ip) FAST_FUNC;
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index e468b7bbb..35e7c2070 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -54,7 +54,7 @@ static const char udhcpc_longopts[] ALIGN1 =
54 "foreground\0" No_argument "f" 54 "foreground\0" No_argument "f"
55 "background\0" No_argument "b" 55 "background\0" No_argument "b"
56 "broadcast\0" No_argument "B" 56 "broadcast\0" No_argument "B"
57 IF_FEATURE_UDHCPC_ARPING("arping\0" No_argument "a") 57 IF_FEATURE_UDHCPC_ARPING("arping\0" Optional_argument "a")
58 IF_FEATURE_UDHCP_PORT("client-port\0" Required_argument "P") 58 IF_FEATURE_UDHCP_PORT("client-port\0" Required_argument "P")
59 ; 59 ;
60#endif 60#endif
@@ -1150,7 +1150,7 @@ static void client_background(void)
1150//usage:# define IF_UDHCP_VERBOSE(...) 1150//usage:# define IF_UDHCP_VERBOSE(...)
1151//usage:#endif 1151//usage:#endif
1152//usage:#define udhcpc_trivial_usage 1152//usage:#define udhcpc_trivial_usage
1153//usage: "[-fbq"IF_UDHCP_VERBOSE("v")IF_FEATURE_UDHCPC_ARPING("a")"RB] [-t N] [-T SEC] [-A SEC/-n]\n" 1153//usage: "[-fbq"IF_UDHCP_VERBOSE("v")"RB]"IF_FEATURE_UDHCPC_ARPING(" [-a[MSEC]]")" [-t N] [-T SEC] [-A SEC/-n]\n"
1154//usage: " [-i IFACE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-s PROG] [-p PIDFILE]\n" 1154//usage: " [-i IFACE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-s PROG] [-p PIDFILE]\n"
1155//usage: " [-oC] [-r IP] [-V VENDOR] [-F NAME] [-x OPT:VAL]... [-O OPT]..." 1155//usage: " [-oC] [-r IP] [-V VENDOR] [-F NAME] [-x OPT:VAL]... [-O OPT]..."
1156//usage:#define udhcpc_full_usage "\n" 1156//usage:#define udhcpc_full_usage "\n"
@@ -1174,7 +1174,7 @@ static void client_background(void)
1174//usage: ) 1174//usage: )
1175//usage: "\n -S,--syslog Log to syslog too" 1175//usage: "\n -S,--syslog Log to syslog too"
1176//usage: IF_FEATURE_UDHCPC_ARPING( 1176//usage: IF_FEATURE_UDHCPC_ARPING(
1177//usage: "\n -a,--arping Use arping to validate offered address" 1177//usage: "\n -a[MSEC],--arping[=MSEC] Validate offered address with ARP ping"
1178//usage: ) 1178//usage: )
1179//usage: "\n -r,--request IP Request this IP address" 1179//usage: "\n -r,--request IP Request this IP address"
1180//usage: "\n -o,--no-default-options Don't request any options (unless -O is given)" 1180//usage: "\n -o,--no-default-options Don't request any options (unless -O is given)"
@@ -1211,7 +1211,7 @@ static void client_background(void)
1211//usage: ) 1211//usage: )
1212//usage: "\n -S Log to syslog too" 1212//usage: "\n -S Log to syslog too"
1213//usage: IF_FEATURE_UDHCPC_ARPING( 1213//usage: IF_FEATURE_UDHCPC_ARPING(
1214//usage: "\n -a Use arping to validate offered address" 1214//usage: "\n -a[MSEC] Validate offered address with ARP ping"
1215//usage: ) 1215//usage: )
1216//usage: "\n -r IP Request this IP address" 1216//usage: "\n -r IP Request this IP address"
1217//usage: "\n -o Don't request any options (unless -O is given)" 1217//usage: "\n -o Don't request any options (unless -O is given)"
@@ -1238,6 +1238,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1238{ 1238{
1239 uint8_t *message; 1239 uint8_t *message;
1240 const char *str_V, *str_h, *str_F, *str_r; 1240 const char *str_V, *str_h, *str_F, *str_r;
1241 IF_FEATURE_UDHCPC_ARPING(const char *str_a = "2000";)
1241 IF_FEATURE_UDHCP_PORT(char *str_P;) 1242 IF_FEATURE_UDHCP_PORT(char *str_P;)
1242 void *clientid_mac_ptr; 1243 void *clientid_mac_ptr;
1243 llist_t *list_O = NULL; 1244 llist_t *list_O = NULL;
@@ -1252,6 +1253,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1252 int timeout; /* must be signed */ 1253 int timeout; /* must be signed */
1253 unsigned already_waited_sec; 1254 unsigned already_waited_sec;
1254 unsigned opt; 1255 unsigned opt;
1256 IF_FEATURE_UDHCPC_ARPING(unsigned arpping_ms;)
1255 int max_fd; 1257 int max_fd;
1256 int retval; 1258 int retval;
1257 fd_set rfds; 1259 fd_set rfds;
@@ -1269,7 +1271,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1269 IF_LONG_OPTS(applet_long_options = udhcpc_longopts;) 1271 IF_LONG_OPTS(applet_long_options = udhcpc_longopts;)
1270 opt = getopt32(argv, "CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:fB" 1272 opt = getopt32(argv, "CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:fB"
1271 USE_FOR_MMU("b") 1273 USE_FOR_MMU("b")
1272 IF_FEATURE_UDHCPC_ARPING("a") 1274 IF_FEATURE_UDHCPC_ARPING("a::")
1273 IF_FEATURE_UDHCP_PORT("P:") 1275 IF_FEATURE_UDHCP_PORT("P:")
1274 "v" 1276 "v"
1275 , &str_V, &str_h, &str_h, &str_F 1277 , &str_V, &str_h, &str_h, &str_F
@@ -1278,6 +1280,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1278 , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */ 1280 , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */
1279 , &list_O 1281 , &list_O
1280 , &list_x 1282 , &list_x
1283 IF_FEATURE_UDHCPC_ARPING(, &str_a)
1281 IF_FEATURE_UDHCP_PORT(, &str_P) 1284 IF_FEATURE_UDHCP_PORT(, &str_P)
1282 IF_UDHCP_VERBOSE(, &dhcp_verbose) 1285 IF_UDHCP_VERBOSE(, &dhcp_verbose)
1283 ); 1286 );
@@ -1309,6 +1312,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1309 SERVER_PORT = CLIENT_PORT - 1; 1312 SERVER_PORT = CLIENT_PORT - 1;
1310 } 1313 }
1311#endif 1314#endif
1315 IF_FEATURE_UDHCPC_ARPING(arpping_ms = xatou(str_a);)
1312 while (list_O) { 1316 while (list_O) {
1313 char *optstr = llist_pop(&list_O); 1317 char *optstr = llist_pop(&list_O);
1314 unsigned n = bb_strtou(optstr, NULL, 0); 1318 unsigned n = bb_strtou(optstr, NULL, 0);
@@ -1726,7 +1730,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1726 NULL, 1730 NULL,
1727 (uint32_t) 0, 1731 (uint32_t) 0,
1728 client_config.client_mac, 1732 client_config.client_mac,
1729 client_config.interface) 1733 client_config.interface,
1734 arpping_ms)
1730 ) { 1735 ) {
1731 bb_info_msg("Offered address is in use " 1736 bb_info_msg("Offered address is in use "
1732 "(got ARP reply), declining"); 1737 "(got ARP reply), declining");
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c
index a1a7f6b57..4b3ed240c 100644
--- a/networking/udhcp/dhcpd.c
+++ b/networking/udhcp/dhcpd.c
@@ -28,6 +28,7 @@
28//usage: "\n -f Run in foreground" 28//usage: "\n -f Run in foreground"
29//usage: "\n -S Log to syslog too" 29//usage: "\n -S Log to syslog too"
30//usage: "\n -I ADDR Local address" 30//usage: "\n -I ADDR Local address"
31//usage: "\n -a MSEC Timeout for ARP ping (default 2000)"
31//usage: IF_FEATURE_UDHCP_PORT( 32//usage: IF_FEATURE_UDHCP_PORT(
32//usage: "\n -P N Use port N (default 67)" 33//usage: "\n -P N Use port N (default 67)"
33//usage: ) 34//usage: )
@@ -148,7 +149,8 @@ static uint32_t select_lease_time(struct dhcp_packet *packet)
148static NOINLINE void send_offer(struct dhcp_packet *oldpacket, 149static NOINLINE void send_offer(struct dhcp_packet *oldpacket,
149 uint32_t static_lease_nip, 150 uint32_t static_lease_nip,
150 struct dyn_lease *lease, 151 struct dyn_lease *lease,
151 uint8_t *requested_ip_opt) 152 uint8_t *requested_ip_opt,
153 unsigned arpping_ms)
152{ 154{
153 struct dhcp_packet packet; 155 struct dhcp_packet packet;
154 uint32_t lease_time_sec; 156 uint32_t lease_time_sec;
@@ -187,7 +189,7 @@ static NOINLINE void send_offer(struct dhcp_packet *oldpacket,
187 } 189 }
188 else { 190 else {
189 /* Otherwise, find a free IP */ 191 /* Otherwise, find a free IP */
190 packet.yiaddr = find_free_or_expired_nip(oldpacket->chaddr); 192 packet.yiaddr = find_free_or_expired_nip(oldpacket->chaddr, arpping_ms);
191 } 193 }
192 194
193 if (!packet.yiaddr) { 195 if (!packet.yiaddr) {
@@ -304,6 +306,8 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
304 unsigned opt; 306 unsigned opt;
305 struct option_set *option; 307 struct option_set *option;
306 char *str_I = str_I; 308 char *str_I = str_I;
309 const char *str_a = "2000";
310 unsigned arpping_ms;
307 IF_FEATURE_UDHCP_PORT(char *str_P;) 311 IF_FEATURE_UDHCP_PORT(char *str_P;)
308 312
309#if ENABLE_FEATURE_UDHCP_PORT 313#if ENABLE_FEATURE_UDHCP_PORT
@@ -314,9 +318,10 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
314#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 318#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
315 opt_complementary = "vv"; 319 opt_complementary = "vv";
316#endif 320#endif
317 opt = getopt32(argv, "fSI:v" 321 opt = getopt32(argv, "fSI:va:"
318 IF_FEATURE_UDHCP_PORT("P:") 322 IF_FEATURE_UDHCP_PORT("P:")
319 , &str_I 323 , &str_I
324 , &str_a
320 IF_FEATURE_UDHCP_PORT(, &str_P) 325 IF_FEATURE_UDHCP_PORT(, &str_P)
321 IF_UDHCP_VERBOSE(, &dhcp_verbose) 326 IF_UDHCP_VERBOSE(, &dhcp_verbose)
322 ); 327 );
@@ -336,11 +341,13 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
336 free(lsa); 341 free(lsa);
337 } 342 }
338#if ENABLE_FEATURE_UDHCP_PORT 343#if ENABLE_FEATURE_UDHCP_PORT
339 if (opt & 16) { /* -P */ 344 if (opt & 32) { /* -P */
340 SERVER_PORT = xatou16(str_P); 345 SERVER_PORT = xatou16(str_P);
341 CLIENT_PORT = SERVER_PORT + 1; 346 CLIENT_PORT = SERVER_PORT + 1;
342 } 347 }
343#endif 348#endif
349 arpping_ms = xatou(str_a);
350
344 /* Would rather not do read_config before daemonization - 351 /* Would rather not do read_config before daemonization -
345 * otherwise NOMMU machines will parse config twice */ 352 * otherwise NOMMU machines will parse config twice */
346 read_config(argv[0] ? argv[0] : DHCPD_CONF_FILE); 353 read_config(argv[0] ? argv[0] : DHCPD_CONF_FILE);
@@ -498,7 +505,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
498 case DHCPDISCOVER: 505 case DHCPDISCOVER:
499 log1("Received DISCOVER"); 506 log1("Received DISCOVER");
500 507
501 send_offer(&packet, static_lease_nip, lease, requested_ip_opt); 508 send_offer(&packet, static_lease_nip, lease, requested_ip_opt, arpping_ms);
502 break; 509 break;
503 510
504 case DHCPREQUEST: 511 case DHCPREQUEST:
diff --git a/networking/udhcp/dhcpd.h b/networking/udhcp/dhcpd.h
index a77724f20..183e7e24c 100644
--- a/networking/udhcp/dhcpd.h
+++ b/networking/udhcp/dhcpd.h
@@ -100,7 +100,7 @@ struct dyn_lease *add_lease(
100int is_expired_lease(struct dyn_lease *lease) FAST_FUNC; 100int is_expired_lease(struct dyn_lease *lease) FAST_FUNC;
101struct dyn_lease *find_lease_by_mac(const uint8_t *mac) FAST_FUNC; 101struct dyn_lease *find_lease_by_mac(const uint8_t *mac) FAST_FUNC;
102struct dyn_lease *find_lease_by_nip(uint32_t nip) FAST_FUNC; 102struct dyn_lease *find_lease_by_nip(uint32_t nip) FAST_FUNC;
103uint32_t find_free_or_expired_nip(const uint8_t *safe_mac) FAST_FUNC; 103uint32_t find_free_or_expired_nip(const uint8_t *safe_mac, unsigned arpping_ms) FAST_FUNC;
104 104
105 105
106/* Config file parser will pass static lease info to this function 106/* Config file parser will pass static lease info to this function
diff --git a/networking/udhcp/files.c b/networking/udhcp/files.c
index 6840f3c25..1c8808c0f 100644
--- a/networking/udhcp/files.c
+++ b/networking/udhcp/files.c
@@ -189,12 +189,24 @@ void FAST_FUNC read_leases(const char *file)
189 goto ret; 189 goto ret;
190 190
191 while (full_read(fd, &lease, sizeof(lease)) == sizeof(lease)) { 191 while (full_read(fd, &lease, sizeof(lease)) == sizeof(lease)) {
192//FIXME: what if it matches some static lease?
193 uint32_t y = ntohl(lease.lease_nip); 192 uint32_t y = ntohl(lease.lease_nip);
194 if (y >= server_config.start_ip && y <= server_config.end_ip) { 193 if (y >= server_config.start_ip && y <= server_config.end_ip) {
195 signed_leasetime_t expires = ntohl(lease.expires) - (signed_leasetime_t)time_passed; 194 signed_leasetime_t expires = ntohl(lease.expires) - (signed_leasetime_t)time_passed;
195 uint32_t static_nip;
196
196 if (expires <= 0) 197 if (expires <= 0)
197 continue; 198 continue;
199
200 /* Check if there is a different static lease for this IP or MAC */
201 static_nip = get_static_nip_by_mac(server_config.static_leases, lease.lease_mac);
202 if (static_nip) {
203 /* NB: we do not add lease even if static_nip == lease.lease_nip.
204 */
205 continue;
206 }
207 if (is_nip_reserved(server_config.static_leases, lease.lease_nip))
208 continue;
209
198 /* NB: add_lease takes "relative time", IOW, 210 /* NB: add_lease takes "relative time", IOW,
199 * lease duration, not lease deadline. */ 211 * lease duration, not lease deadline. */
200 if (add_lease(lease.lease_mac, lease.lease_nip, 212 if (add_lease(lease.lease_mac, lease.lease_nip,
diff --git a/networking/udhcp/leases.c b/networking/udhcp/leases.c
index c5b60b108..745340ad3 100644
--- a/networking/udhcp/leases.c
+++ b/networking/udhcp/leases.c
@@ -112,7 +112,7 @@ struct dyn_lease* FAST_FUNC find_lease_by_nip(uint32_t nip)
112} 112}
113 113
114/* Check if the IP is taken; if it is, add it to the lease table */ 114/* Check if the IP is taken; if it is, add it to the lease table */
115static int nobody_responds_to_arp(uint32_t nip, const uint8_t *safe_mac) 115static int nobody_responds_to_arp(uint32_t nip, const uint8_t *safe_mac, unsigned arpping_ms)
116{ 116{
117 struct in_addr temp; 117 struct in_addr temp;
118 int r; 118 int r;
@@ -120,7 +120,8 @@ static int nobody_responds_to_arp(uint32_t nip, const uint8_t *safe_mac)
120 r = arpping(nip, safe_mac, 120 r = arpping(nip, safe_mac,
121 server_config.server_nip, 121 server_config.server_nip,
122 server_config.server_mac, 122 server_config.server_mac,
123 server_config.interface); 123 server_config.interface,
124 arpping_ms);
124 if (r) 125 if (r)
125 return r; 126 return r;
126 127
@@ -132,7 +133,7 @@ static int nobody_responds_to_arp(uint32_t nip, const uint8_t *safe_mac)
132} 133}
133 134
134/* Find a new usable (we think) address */ 135/* Find a new usable (we think) address */
135uint32_t FAST_FUNC find_free_or_expired_nip(const uint8_t *safe_mac) 136uint32_t FAST_FUNC find_free_or_expired_nip(const uint8_t *safe_mac, unsigned arpping_ms)
136{ 137{
137 uint32_t addr; 138 uint32_t addr;
138 struct dyn_lease *oldest_lease = NULL; 139 struct dyn_lease *oldest_lease = NULL;
@@ -177,7 +178,7 @@ uint32_t FAST_FUNC find_free_or_expired_nip(const uint8_t *safe_mac)
177 lease = find_lease_by_nip(nip); 178 lease = find_lease_by_nip(nip);
178 if (!lease) { 179 if (!lease) {
179//TODO: DHCP servers do not always sit on the same subnet as clients: should *ping*, not arp-ping! 180//TODO: DHCP servers do not always sit on the same subnet as clients: should *ping*, not arp-ping!
180 if (nobody_responds_to_arp(nip, safe_mac)) 181 if (nobody_responds_to_arp(nip, safe_mac, arpping_ms))
181 return nip; 182 return nip;
182 } else { 183 } else {
183 if (!oldest_lease || lease->expires < oldest_lease->expires) 184 if (!oldest_lease || lease->expires < oldest_lease->expires)
@@ -194,7 +195,7 @@ uint32_t FAST_FUNC find_free_or_expired_nip(const uint8_t *safe_mac)
194 195
195 if (oldest_lease 196 if (oldest_lease
196 && is_expired_lease(oldest_lease) 197 && is_expired_lease(oldest_lease)
197 && nobody_responds_to_arp(oldest_lease->lease_nip, safe_mac) 198 && nobody_responds_to_arp(oldest_lease->lease_nip, safe_mac, arpping_ms)
198 ) { 199 ) {
199 return oldest_lease->lease_nip; 200 return oldest_lease->lease_nip;
200 } 201 }
diff --git a/networking/zcip.c b/networking/zcip.c
index 45d1f7c1c..a3307c5c9 100644
--- a/networking/zcip.c
+++ b/networking/zcip.c
@@ -30,8 +30,12 @@
30//usage: "\n -f Run in foreground" 30//usage: "\n -f Run in foreground"
31//usage: "\n -q Quit after obtaining address" 31//usage: "\n -q Quit after obtaining address"
32//usage: "\n -r 169.254.x.x Request this address first" 32//usage: "\n -r 169.254.x.x Request this address first"
33//usage: "\n -l x.x.0.0 Use this range instead of 169.254"
33//usage: "\n -v Verbose" 34//usage: "\n -v Verbose"
34//usage: "\n" 35//usage: "\n"
36//usage: "\n$LOGGING=none Suppress logging"
37//usage: "\n$LOGGING=syslog Log to syslog"
38//usage: "\n"
35//usage: "\nWith no -q, runs continuously monitoring for ARP conflicts," 39//usage: "\nWith no -q, runs continuously monitoring for ARP conflicts,"
36//usage: "\nexits only on I/O errors (link down etc)" 40//usage: "\nexits only on I/O errors (link down etc)"
37 41
@@ -87,6 +91,7 @@ enum {
87struct globals { 91struct globals {
88 struct sockaddr saddr; 92 struct sockaddr saddr;
89 struct ether_addr eth_addr; 93 struct ether_addr eth_addr;
94 uint32_t localnet_ip;
90} FIX_ALIASING; 95} FIX_ALIASING;
91#define G (*(struct globals*)&bb_common_bufsiz1) 96#define G (*(struct globals*)&bb_common_bufsiz1)
92#define saddr (G.saddr ) 97#define saddr (G.saddr )
@@ -98,14 +103,14 @@ struct globals {
98 * Pick a random link local IP address on 169.254/16, except that 103 * Pick a random link local IP address on 169.254/16, except that
99 * the first and last 256 addresses are reserved. 104 * the first and last 256 addresses are reserved.
100 */ 105 */
101static uint32_t pick(void) 106static uint32_t pick_nip(void)
102{ 107{
103 unsigned tmp; 108 unsigned tmp;
104 109
105 do { 110 do {
106 tmp = rand() & IN_CLASSB_HOST; 111 tmp = rand() & IN_CLASSB_HOST;
107 } while (tmp > (IN_CLASSB_HOST - 0x0200)); 112 } while (tmp > (IN_CLASSB_HOST - 0x0200));
108 return htonl((LINKLOCAL_ADDR + 0x0100) + tmp); 113 return htonl((G.localnet_ip + 0x0100) + tmp);
109} 114}
110 115
111/** 116/**
@@ -197,6 +202,7 @@ int zcip_main(int argc UNUSED_PARAM, char **argv)
197{ 202{
198 int state; 203 int state;
199 char *r_opt; 204 char *r_opt;
205 const char *l_opt = "169.254.0.0";
200 unsigned opts; 206 unsigned opts;
201 207
202 // ugly trick, but I want these zeroed in one go 208 // ugly trick, but I want these zeroed in one go
@@ -231,7 +237,7 @@ int zcip_main(int argc UNUSED_PARAM, char **argv)
231 // parse commandline: prog [options] ifname script 237 // parse commandline: prog [options] ifname script
232 // exactly 2 args; -v accumulates and implies -f 238 // exactly 2 args; -v accumulates and implies -f
233 opt_complementary = "=2:vv:vf"; 239 opt_complementary = "=2:vv:vf";
234 opts = getopt32(argv, "fqr:v", &r_opt, &verbose); 240 opts = getopt32(argv, "fqr:l:v", &r_opt, &l_opt, &verbose);
235#if !BB_MMU 241#if !BB_MMU
236 // on NOMMU reexec early (or else we will rerun things twice) 242 // on NOMMU reexec early (or else we will rerun things twice)
237 if (!FOREGROUND) 243 if (!FOREGROUND)
@@ -246,9 +252,20 @@ int zcip_main(int argc UNUSED_PARAM, char **argv)
246 openlog(applet_name, 0, LOG_DAEMON); 252 openlog(applet_name, 0, LOG_DAEMON);
247 logmode |= LOGMODE_SYSLOG; 253 logmode |= LOGMODE_SYSLOG;
248 } 254 }
255 bb_logenv_override();
256
257 { // -l n.n.n.n
258 struct in_addr net;
259 if (inet_aton(l_opt, &net) == 0
260 || (net.s_addr & htonl(IN_CLASSB_NET)) != net.s_addr
261 ) {
262 bb_error_msg_and_die("invalid network address");
263 }
264 G.localnet_ip = ntohl(net.s_addr);
265 }
249 if (opts & 4) { // -r n.n.n.n 266 if (opts & 4) { // -r n.n.n.n
250 if (inet_aton(r_opt, &ip) == 0 267 if (inet_aton(r_opt, &ip) == 0
251 || (ntohl(ip.s_addr) & IN_CLASSB_NET) != LINKLOCAL_ADDR 268 || (ntohl(ip.s_addr) & IN_CLASSB_NET) != G.localnet_ip
252 ) { 269 ) {
253 bb_error_msg_and_die("invalid link address"); 270 bb_error_msg_and_die("invalid link address");
254 } 271 }
@@ -295,7 +312,7 @@ int zcip_main(int argc UNUSED_PARAM, char **argv)
295 srand(t); 312 srand(t);
296 } 313 }
297 if (ip.s_addr == 0) 314 if (ip.s_addr == 0)
298 ip.s_addr = pick(); 315 ip.s_addr = pick_nip();
299 316
300 // FIXME cases to handle: 317 // FIXME cases to handle:
301 // - zcip already running! 318 // - zcip already running!
@@ -433,7 +450,7 @@ int zcip_main(int argc UNUSED_PARAM, char **argv)
433 default: 450 default:
434 // Invalid, should never happen. Restart the whole protocol. 451 // Invalid, should never happen. Restart the whole protocol.
435 state = PROBE; 452 state = PROBE;
436 ip.s_addr = pick(); 453 ip.s_addr = pick_nip();
437 timeout_ms = 0; 454 timeout_ms = 0;
438 nprobes = 0; 455 nprobes = 0;
439 nclaims = 0; 456 nclaims = 0;
@@ -535,7 +552,7 @@ int zcip_main(int argc UNUSED_PARAM, char **argv)
535 } 552 }
536 553
537 // restart the whole protocol 554 // restart the whole protocol
538 ip.s_addr = pick(); 555 ip.s_addr = pick_nip();
539 timeout_ms = 0; 556 timeout_ms = 0;
540 nprobes = 0; 557 nprobes = 0;
541 nclaims = 0; 558 nclaims = 0;
@@ -561,7 +578,7 @@ int zcip_main(int argc UNUSED_PARAM, char **argv)
561 run(argv, "deconfig", &ip); 578 run(argv, "deconfig", &ip);
562 579
563 // restart the whole protocol 580 // restart the whole protocol
564 ip.s_addr = pick(); 581 ip.s_addr = pick_nip();
565 timeout_ms = 0; 582 timeout_ms = 0;
566 nprobes = 0; 583 nprobes = 0;
567 nclaims = 0; 584 nclaims = 0;
@@ -571,7 +588,7 @@ int zcip_main(int argc UNUSED_PARAM, char **argv)
571 // Invalid, should never happen. Restart the whole protocol. 588 // Invalid, should never happen. Restart the whole protocol.
572 VDBG("invalid state -- starting over\n"); 589 VDBG("invalid state -- starting over\n");
573 state = PROBE; 590 state = PROBE;
574 ip.s_addr = pick(); 591 ip.s_addr = pick_nip();
575 timeout_ms = 0; 592 timeout_ms = 0;
576 nprobes = 0; 593 nprobes = 0;
577 nclaims = 0; 594 nclaims = 0;
diff --git a/shell/ash.c b/shell/ash.c
index 3f3e2f4bc..b95356034 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -6740,7 +6740,15 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
6740 len = number(loc); 6740 len = number(loc);
6741 } 6741 }
6742 } 6742 }
6743 if (pos >= orig_len) { 6743 if (pos < 0) {
6744 /* ${VAR:$((-n)):l} starts n chars from the end */
6745 pos = orig_len + pos;
6746 }
6747 if ((unsigned)pos >= orig_len) {
6748 /* apart from obvious ${VAR:999999:l},
6749 * covers ${VAR:$((-9999999)):l} - result is ""
6750 * (bash-compat)
6751 */
6744 pos = 0; 6752 pos = 0;
6745 len = 0; 6753 len = 0;
6746 } 6754 }
diff --git a/shell/math.c b/shell/math.c
index 3da151137..006221b6a 100644
--- a/shell/math.c
+++ b/shell/math.c
@@ -415,10 +415,29 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_
415 } 415 }
416 else if (right_side_val == 0) 416 else if (right_side_val == 0)
417 return "divide by zero"; 417 return "divide by zero";
418 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN) 418 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN
419 rez /= right_side_val; 419 || op == TOK_REM || op == TOK_REM_ASSIGN) {
420 else if (op == TOK_REM || op == TOK_REM_ASSIGN) 420 /*
421 rez %= right_side_val; 421 * bash 4.2.45 x86 64bit: SEGV on 'echo $((2**63 / -1))'
422 *
423 * MAX_NEGATIVE_INT / -1 = MAX_POSITIVE_INT+1
424 * and thus is not representable.
425 * Some CPUs segfault trying such op.
426 * Others overflow MAX_POSITIVE_INT+1 to
427 * MAX_NEGATIVE_INT (0x7fff+1 = 0x8000).
428 * Make sure to at least not SEGV here:
429 */
430 if (right_side_val == -1
431 && rez << 1 == 0 /* MAX_NEGATIVE_INT or 0 */
432 ) {
433 right_side_val = 1;
434 }
435 if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
436 rez /= right_side_val;
437 else {
438 rez %= right_side_val;
439 }
440 }
422 } 441 }
423 442
424 if (is_assign_op(op)) { 443 if (is_assign_op(op)) {