From 9f41271f3ce82e0f7196c2442614ef4e9d360928 Mon Sep 17 00:00:00 2001 From: Michel Stam Date: Thu, 30 Oct 2014 11:59:04 +0100 Subject: udhcpd: add option for tweaking arpping Some clients have a very short timeout for sending the DHCP DISCOVER, shorter than the arpping timeout of 2000 milliseconds that udhcpd uses by default. This patch allows tweaking the timeout, or disabling of arpping altogether, at the risk of handing out addresses which are already in use. function old new delta udhcpd_main 1460 1501 +41 udhcpc_main 2814 2851 +37 packed_usage 29957 29974 +17 arpping 477 493 +16 find_free_or_expired_nip 161 174 +13 send_offer 285 292 +7 nobody_responds_to_arp 85 89 +4 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 7/0 up/down: 135/0) Total: 135 bytes Signed-off-by: Michel Stam Signed-off-by: Denys Vlasenko --- networking/udhcp/arpping.c | 10 +++++++--- networking/udhcp/common.h | 3 ++- networking/udhcp/dhcpc.c | 17 +++++++++++------ networking/udhcp/dhcpd.c | 17 ++++++++++++----- networking/udhcp/dhcpd.h | 2 +- networking/udhcp/leases.c | 11 ++++++----- 6 files changed, 39 insertions(+), 21 deletions(-) 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, const uint8_t *safe_mac, uint32_t from_ip, uint8_t *from_mac, - const char *interface) + const char *interface, + unsigned timeo) { int timeout_ms; struct pollfd pfd[1]; @@ -48,6 +49,9 @@ int FAST_FUNC arpping(uint32_t test_nip, struct sockaddr addr; /* for interface name */ struct arpMsg arp; + if (!timeo) + return 1; + s = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP)); if (s == -1) { bb_perror_msg(bb_msg_can_not_create_raw_socket); @@ -83,7 +87,7 @@ int FAST_FUNC arpping(uint32_t test_nip, } /* wait for arp reply, and check it */ - timeout_ms = 2000; + timeout_ms = (int)timeo; do { typedef uint32_t aliased_uint32_t FIX_ALIASING; int r; @@ -124,7 +128,7 @@ int FAST_FUNC arpping(uint32_t test_nip, * this is more under/overflow-resistant * (people did see overflows here when system time jumps): */ - } while ((unsigned)timeout_ms <= 2000); + } while ((unsigned)timeout_ms <= timeo); ret: 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, const uint8_t *safe_mac, uint32_t from_ip, uint8_t *from_mac, - const char *interface) FAST_FUNC; + const char *interface, + unsigned timeo) FAST_FUNC; /* note: ip is a pointer to an IPv6 in network order, possibly misaliged */ int 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 = "foreground\0" No_argument "f" "background\0" No_argument "b" "broadcast\0" No_argument "B" - IF_FEATURE_UDHCPC_ARPING("arping\0" No_argument "a") + IF_FEATURE_UDHCPC_ARPING("arping\0" Optional_argument "a") IF_FEATURE_UDHCP_PORT("client-port\0" Required_argument "P") ; #endif @@ -1150,7 +1150,7 @@ static void client_background(void) //usage:# define IF_UDHCP_VERBOSE(...) //usage:#endif //usage:#define udhcpc_trivial_usage -//usage: "[-fbq"IF_UDHCP_VERBOSE("v")IF_FEATURE_UDHCPC_ARPING("a")"RB] [-t N] [-T SEC] [-A SEC/-n]\n" +//usage: "[-fbq"IF_UDHCP_VERBOSE("v")"RB]"IF_FEATURE_UDHCPC_ARPING(" [-a[MSEC]]")" [-t N] [-T SEC] [-A SEC/-n]\n" //usage: " [-i IFACE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-s PROG] [-p PIDFILE]\n" //usage: " [-oC] [-r IP] [-V VENDOR] [-F NAME] [-x OPT:VAL]... [-O OPT]..." //usage:#define udhcpc_full_usage "\n" @@ -1174,7 +1174,7 @@ static void client_background(void) //usage: ) //usage: "\n -S,--syslog Log to syslog too" //usage: IF_FEATURE_UDHCPC_ARPING( -//usage: "\n -a,--arping Use arping to validate offered address" +//usage: "\n -a[MSEC],--arping[=MSEC] Validate offered address with ARP ping" //usage: ) //usage: "\n -r,--request IP Request this IP address" //usage: "\n -o,--no-default-options Don't request any options (unless -O is given)" @@ -1211,7 +1211,7 @@ static void client_background(void) //usage: ) //usage: "\n -S Log to syslog too" //usage: IF_FEATURE_UDHCPC_ARPING( -//usage: "\n -a Use arping to validate offered address" +//usage: "\n -a[MSEC] Validate offered address with ARP ping" //usage: ) //usage: "\n -r IP Request this IP address" //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) { uint8_t *message; const char *str_V, *str_h, *str_F, *str_r; + IF_FEATURE_UDHCPC_ARPING(const char *str_a = "2000";) IF_FEATURE_UDHCP_PORT(char *str_P;) void *clientid_mac_ptr; llist_t *list_O = NULL; @@ -1252,6 +1253,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) int timeout; /* must be signed */ unsigned already_waited_sec; unsigned opt; + IF_FEATURE_UDHCPC_ARPING(unsigned arpping_ms;) int max_fd; int retval; fd_set rfds; @@ -1269,7 +1271,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) IF_LONG_OPTS(applet_long_options = udhcpc_longopts;) opt = getopt32(argv, "CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:fB" USE_FOR_MMU("b") - IF_FEATURE_UDHCPC_ARPING("a") + IF_FEATURE_UDHCPC_ARPING("a::") IF_FEATURE_UDHCP_PORT("P:") "v" , &str_V, &str_h, &str_h, &str_F @@ -1278,6 +1280,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */ , &list_O , &list_x + IF_FEATURE_UDHCPC_ARPING(, &str_a) IF_FEATURE_UDHCP_PORT(, &str_P) IF_UDHCP_VERBOSE(, &dhcp_verbose) ); @@ -1309,6 +1312,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) SERVER_PORT = CLIENT_PORT - 1; } #endif + IF_FEATURE_UDHCPC_ARPING(arpping_ms = xatou(str_a);) while (list_O) { char *optstr = llist_pop(&list_O); unsigned n = bb_strtou(optstr, NULL, 0); @@ -1726,7 +1730,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) NULL, (uint32_t) 0, client_config.client_mac, - client_config.interface) + client_config.interface, + arpping_ms) ) { bb_info_msg("Offered address is in use " "(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 @@ //usage: "\n -f Run in foreground" //usage: "\n -S Log to syslog too" //usage: "\n -I ADDR Local address" +//usage: "\n -a MSEC Timeout for ARP ping (default 2000)" //usage: IF_FEATURE_UDHCP_PORT( //usage: "\n -P N Use port N (default 67)" //usage: ) @@ -148,7 +149,8 @@ static uint32_t select_lease_time(struct dhcp_packet *packet) static NOINLINE void send_offer(struct dhcp_packet *oldpacket, uint32_t static_lease_nip, struct dyn_lease *lease, - uint8_t *requested_ip_opt) + uint8_t *requested_ip_opt, + unsigned arpping_ms) { struct dhcp_packet packet; uint32_t lease_time_sec; @@ -187,7 +189,7 @@ static NOINLINE void send_offer(struct dhcp_packet *oldpacket, } else { /* Otherwise, find a free IP */ - packet.yiaddr = find_free_or_expired_nip(oldpacket->chaddr); + packet.yiaddr = find_free_or_expired_nip(oldpacket->chaddr, arpping_ms); } if (!packet.yiaddr) { @@ -304,6 +306,8 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) unsigned opt; struct option_set *option; char *str_I = str_I; + const char *str_a = "2000"; + unsigned arpping_ms; IF_FEATURE_UDHCP_PORT(char *str_P;) #if ENABLE_FEATURE_UDHCP_PORT @@ -314,9 +318,10 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 opt_complementary = "vv"; #endif - opt = getopt32(argv, "fSI:v" + opt = getopt32(argv, "fSI:va:" IF_FEATURE_UDHCP_PORT("P:") , &str_I + , &str_a IF_FEATURE_UDHCP_PORT(, &str_P) IF_UDHCP_VERBOSE(, &dhcp_verbose) ); @@ -336,11 +341,13 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) free(lsa); } #if ENABLE_FEATURE_UDHCP_PORT - if (opt & 16) { /* -P */ + if (opt & 32) { /* -P */ SERVER_PORT = xatou16(str_P); CLIENT_PORT = SERVER_PORT + 1; } #endif + arpping_ms = xatou(str_a); + /* Would rather not do read_config before daemonization - * otherwise NOMMU machines will parse config twice */ read_config(argv[0] ? argv[0] : DHCPD_CONF_FILE); @@ -498,7 +505,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) case DHCPDISCOVER: log1("Received DISCOVER"); - send_offer(&packet, static_lease_nip, lease, requested_ip_opt); + send_offer(&packet, static_lease_nip, lease, requested_ip_opt, arpping_ms); break; 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( int is_expired_lease(struct dyn_lease *lease) FAST_FUNC; struct dyn_lease *find_lease_by_mac(const uint8_t *mac) FAST_FUNC; struct dyn_lease *find_lease_by_nip(uint32_t nip) FAST_FUNC; -uint32_t find_free_or_expired_nip(const uint8_t *safe_mac) FAST_FUNC; +uint32_t find_free_or_expired_nip(const uint8_t *safe_mac, unsigned arpping_ms) FAST_FUNC; /* Config file parser will pass static lease info to this function 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) } /* Check if the IP is taken; if it is, add it to the lease table */ -static int nobody_responds_to_arp(uint32_t nip, const uint8_t *safe_mac) +static int nobody_responds_to_arp(uint32_t nip, const uint8_t *safe_mac, unsigned arpping_ms) { struct in_addr temp; int r; @@ -120,7 +120,8 @@ static int nobody_responds_to_arp(uint32_t nip, const uint8_t *safe_mac) r = arpping(nip, safe_mac, server_config.server_nip, server_config.server_mac, - server_config.interface); + server_config.interface, + arpping_ms); if (r) return r; @@ -132,7 +133,7 @@ static int nobody_responds_to_arp(uint32_t nip, const uint8_t *safe_mac) } /* Find a new usable (we think) address */ -uint32_t FAST_FUNC find_free_or_expired_nip(const uint8_t *safe_mac) +uint32_t FAST_FUNC find_free_or_expired_nip(const uint8_t *safe_mac, unsigned arpping_ms) { uint32_t addr; struct dyn_lease *oldest_lease = NULL; @@ -177,7 +178,7 @@ uint32_t FAST_FUNC find_free_or_expired_nip(const uint8_t *safe_mac) lease = find_lease_by_nip(nip); if (!lease) { //TODO: DHCP servers do not always sit on the same subnet as clients: should *ping*, not arp-ping! - if (nobody_responds_to_arp(nip, safe_mac)) + if (nobody_responds_to_arp(nip, safe_mac, arpping_ms)) return nip; } else { 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) if (oldest_lease && is_expired_lease(oldest_lease) - && nobody_responds_to_arp(oldest_lease->lease_nip, safe_mac) + && nobody_responds_to_arp(oldest_lease->lease_nip, safe_mac, arpping_ms) ) { return oldest_lease->lease_nip; } -- cgit v1.2.3-55-g6feb From fdd957bdc9981cc2c1efb4452f55bb44a88cbfe0 Mon Sep 17 00:00:00 2001 From: Michel Stam Date: Thu, 30 Oct 2014 13:43:09 +0100 Subject: zcip: allow our own class B range to be used for ZeroConf 169.254 may already be used by a local network. This patch allows specifying your own IP range. Our particular use case is a mesh network, in which the nodes partaking were using an IP range specifically assigned for the meshing purpose. As the LAN side of the mesh node could use 169.254, this default range was not an option. function old new delta zcip_main 1342 1426 +84 pick_nip - 40 +40 packed_usage 29974 29969 -5 pick 34 - -34 ------------------------------------------------------------------------------ (add/remove: 1/1 grow/shrink: 1/1 up/down: 124/-39) Total: 85 bytes Signed-off-by: Michel Stam Signed-off-by: Denys Vlasenko --- networking/zcip.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/networking/zcip.c b/networking/zcip.c index 45d1f7c1c..635d660b3 100644 --- a/networking/zcip.c +++ b/networking/zcip.c @@ -30,6 +30,7 @@ //usage: "\n -f Run in foreground" //usage: "\n -q Quit after obtaining address" //usage: "\n -r 169.254.x.x Request this address first" +//usage: "\n -l x.x.0.0 Use this range instead of 169.254" //usage: "\n -v Verbose" //usage: "\n" //usage: "\nWith no -q, runs continuously monitoring for ARP conflicts," @@ -87,6 +88,7 @@ enum { struct globals { struct sockaddr saddr; struct ether_addr eth_addr; + uint32_t localnet_ip; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) #define saddr (G.saddr ) @@ -98,14 +100,14 @@ struct globals { * Pick a random link local IP address on 169.254/16, except that * the first and last 256 addresses are reserved. */ -static uint32_t pick(void) +static uint32_t pick_nip(void) { unsigned tmp; do { tmp = rand() & IN_CLASSB_HOST; } while (tmp > (IN_CLASSB_HOST - 0x0200)); - return htonl((LINKLOCAL_ADDR + 0x0100) + tmp); + return htonl((G.localnet_ip + 0x0100) + tmp); } /** @@ -197,6 +199,7 @@ int zcip_main(int argc UNUSED_PARAM, char **argv) { int state; char *r_opt; + const char *l_opt = "169.254.0.0"; unsigned opts; // ugly trick, but I want these zeroed in one go @@ -231,7 +234,7 @@ int zcip_main(int argc UNUSED_PARAM, char **argv) // parse commandline: prog [options] ifname script // exactly 2 args; -v accumulates and implies -f opt_complementary = "=2:vv:vf"; - opts = getopt32(argv, "fqr:v", &r_opt, &verbose); + opts = getopt32(argv, "fqr:l:v", &r_opt, &l_opt, &verbose); #if !BB_MMU // on NOMMU reexec early (or else we will rerun things twice) if (!FOREGROUND) @@ -246,9 +249,18 @@ int zcip_main(int argc UNUSED_PARAM, char **argv) openlog(applet_name, 0, LOG_DAEMON); logmode |= LOGMODE_SYSLOG; } + { // -l n.n.n.n + struct in_addr net; + if (inet_aton(l_opt, &net) == 0 + || (net.s_addr & htonl(IN_CLASSB_NET)) != net.s_addr + ) { + bb_error_msg_and_die("invalid network address"); + } + G.localnet_ip = ntohl(net.s_addr); + } if (opts & 4) { // -r n.n.n.n if (inet_aton(r_opt, &ip) == 0 - || (ntohl(ip.s_addr) & IN_CLASSB_NET) != LINKLOCAL_ADDR + || (ntohl(ip.s_addr) & IN_CLASSB_NET) != G.localnet_ip ) { bb_error_msg_and_die("invalid link address"); } @@ -295,7 +307,7 @@ int zcip_main(int argc UNUSED_PARAM, char **argv) srand(t); } if (ip.s_addr == 0) - ip.s_addr = pick(); + ip.s_addr = pick_nip(); // FIXME cases to handle: // - zcip already running! @@ -433,7 +445,7 @@ int zcip_main(int argc UNUSED_PARAM, char **argv) default: // Invalid, should never happen. Restart the whole protocol. state = PROBE; - ip.s_addr = pick(); + ip.s_addr = pick_nip(); timeout_ms = 0; nprobes = 0; nclaims = 0; @@ -535,7 +547,7 @@ int zcip_main(int argc UNUSED_PARAM, char **argv) } // restart the whole protocol - ip.s_addr = pick(); + ip.s_addr = pick_nip(); timeout_ms = 0; nprobes = 0; nclaims = 0; @@ -561,7 +573,7 @@ int zcip_main(int argc UNUSED_PARAM, char **argv) run(argv, "deconfig", &ip); // restart the whole protocol - ip.s_addr = pick(); + ip.s_addr = pick_nip(); timeout_ms = 0; nprobes = 0; nclaims = 0; @@ -571,7 +583,7 @@ int zcip_main(int argc UNUSED_PARAM, char **argv) // Invalid, should never happen. Restart the whole protocol. VDBG("invalid state -- starting over\n"); state = PROBE; - ip.s_addr = pick(); + ip.s_addr = pick_nip(); timeout_ms = 0; nprobes = 0; nclaims = 0; -- cgit v1.2.3-55-g6feb From d3fabf89d7d38a436672ac2deea7904351b1b12a Mon Sep 17 00:00:00 2001 From: Michel Stam Date: Tue, 4 Nov 2014 12:19:04 +0100 Subject: zcip: Add environment variable for overriding log functionality function old new delta bb_logenv_override - 70 +70 packed_usage 29969 30033 +64 zcip_main 1426 1431 +5 ------------------------------------------------------------------------------ (add/remove: 2/0 grow/shrink: 2/0 up/down: 139/0) Total: 139 bytes Signed-off-by: Michel Stam Signed-off-by: Denys Vlasenko --- docs/logging_and_backgrounding.txt | 2 ++ include/libbb.h | 1 + libbb/Kbuild.src | 3 +++ libbb/logenv.c | 24 ++++++++++++++++++++++++ networking/zcip.c | 5 +++++ 5 files changed, 35 insertions(+) create mode 100644 libbb/logenv.c 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, udhcpd - auto-backgrounds and do not log to stderr unless -f, otherwise logs to stderr, but option -S makes it log *also* to syslog zcip - auto-backgrounds and logs *also* to syslog unless -f + behaviour can be overridden with experimental LOGGING env.var + (can be set to either "none" or "syslog") Total: 13 applets (+1 obsolete), 4 log to syslog by default (crond fakeidentd inetd zcip), diff --git a/include/libbb.h b/include/libbb.h index d57f00e0e..cc2bea32d 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1104,6 +1104,7 @@ extern void bb_perror_nomsg_and_die(void) NORETURN FAST_FUNC; extern void bb_perror_nomsg(void) FAST_FUNC; extern void bb_info_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC; extern void bb_verror_msg(const char *s, va_list p, const char *strerr) FAST_FUNC; +extern void bb_logenv_override(void) FAST_FUNC; /* We need to export XXX_main from libbusybox * only if we build "individual" binaries diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src index 0a9e803d7..f204816c5 100644 --- a/libbb/Kbuild.src +++ b/libbb/Kbuild.src @@ -187,3 +187,6 @@ lib-$(CONFIG_PGREP) += xregcomp.o lib-$(CONFIG_PKILL) += xregcomp.o lib-$(CONFIG_DEVFSD) += xregcomp.o lib-$(CONFIG_FEATURE_FIND_REGEX) += xregcomp.o + +# Add the experimental logging functionality, only used by zcip +lib-$(CONFIG_ZCIP) += logenv.o 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 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 2014 by Fugro Intersite B.V. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" + +void FAST_FUNC bb_logenv_override(void) +{ + const char* mode = getenv("LOGGING"); + + if (!mode) + return; + + if (strcmp(mode, "none") == 0) + logmode = LOGMODE_NONE; +#if ENABLE_FEATURE_SYSLOG + else if (strcmp(mode, "syslog") == 0) + logmode = LOGMODE_SYSLOG; +#endif +} diff --git a/networking/zcip.c b/networking/zcip.c index 635d660b3..a3307c5c9 100644 --- a/networking/zcip.c +++ b/networking/zcip.c @@ -33,6 +33,9 @@ //usage: "\n -l x.x.0.0 Use this range instead of 169.254" //usage: "\n -v Verbose" //usage: "\n" +//usage: "\n$LOGGING=none Suppress logging" +//usage: "\n$LOGGING=syslog Log to syslog" +//usage: "\n" //usage: "\nWith no -q, runs continuously monitoring for ARP conflicts," //usage: "\nexits only on I/O errors (link down etc)" @@ -249,6 +252,8 @@ int zcip_main(int argc UNUSED_PARAM, char **argv) openlog(applet_name, 0, LOG_DAEMON); logmode |= LOGMODE_SYSLOG; } + bb_logenv_override(); + { // -l n.n.n.n struct in_addr net; if (inet_aton(l_opt, &net) == 0 -- cgit v1.2.3-55-g6feb From 628f134fe7f1f868c60f8bd18645a626e9c5487f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 17 Nov 2014 17:03:47 +0100 Subject: exit with 127 if appled name wasn't found - it's more POSIXy Signed-off-by: Denys Vlasenko --- libbb/appletlib.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libbb/appletlib.c b/libbb/appletlib.c index cb16e310f..54300bd87 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -733,7 +733,8 @@ static int busybox_main(char **argv) /*bb_error_msg_and_die("applet not found"); - sucks in printf */ full_write2_str(applet_name); full_write2_str(": applet not found\n"); - xfunc_die(); + /* POSIX: "If a command is not found, the exit status shall be 127" */ + exit(127); } void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv) @@ -838,6 +839,7 @@ int main(int argc UNUSED_PARAM, char **argv) /*bb_error_msg_and_die("applet not found"); - sucks in printf */ full_write2_str(applet_name); full_write2_str(": applet not found\n"); - xfunc_die(); + /* POSIX: "If a command is not found, the exit status shall be 127" */ + exit(127); #endif } -- cgit v1.2.3-55-g6feb From 1a1143907c84308781e23f07d0c6c597bfd13abb Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Mon, 28 Jul 2014 10:05:41 +0400 Subject: iproute: support onelink route option and print route flags function old new delta print_route 1797 1865 +68 do_iproute 2097 2112 +15 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 83/0) Total: 83 bytes Signed-off-by: Michael Tokarev Signed-off-by: Denys Vlasenko --- networking/libiproute/iproute.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) 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, if (tb[RTA_PRIORITY]) { printf(" metric %d ", *(uint32_t*)RTA_DATA(tb[RTA_PRIORITY])); } + if (r->rtm_flags & RTNH_F_DEAD) { + printf("dead "); + } + if (r->rtm_flags & RTNH_F_ONLINK) { + printf("onlink "); + } + if (r->rtm_flags & RTNH_F_PERVASIVE) { + printf("pervasive "); + } + if (r->rtm_flags & RTM_F_NOTIFY) { + printf("notify "); + } + if (r->rtm_family == AF_INET6) { struct rta_cacheinfo *ci = NULL; if (tb[RTA_CACHEINFO]) { @@ -330,7 +343,7 @@ static int iproute_modify(int cmd, unsigned flags, char **argv) { static const char keywords[] ALIGN1 = "src\0""via\0""mtu\0""lock\0""protocol\0"IF_FEATURE_IP_RULE("table\0") - "dev\0""oif\0""to\0""metric\0"; + "dev\0""oif\0""to\0""metric\0""onlink\0"; enum { ARG_src, ARG_via, @@ -341,6 +354,7 @@ IF_FEATURE_IP_RULE(ARG_table,) ARG_oif, ARG_to, ARG_metric, + ARG_onlink, }; enum { gw_ok = 1 << 0, @@ -431,6 +445,8 @@ IF_FEATURE_IP_RULE(ARG_table,) NEXT_ARG(); metric = get_u32(*argv, "metric"); addattr32(&req.n, sizeof(req), RTA_PRIORITY, metric); + } else if (arg == ARG_onlink) { + req.r.rtm_flags |= RTNH_F_ONLINK; } else { int type; inet_prefix dst; -- cgit v1.2.3-55-g6feb From 08a5dab181fa4c28b7636c35021308e1e12e7b59 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 17 Nov 2014 20:27:18 +0100 Subject: ash: fix handling of negative start value in ${v:start:len} function old new delta subevalvar 1140 1168 +28 Signed-off-by: Denys Vlasenko --- shell/ash.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/shell/ash.c b/shell/ash.c index 705fe9fa4..90fb00fbd 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -6411,7 +6411,15 @@ subevalvar(char *p, char *varname, int strloc, int subtype, len = number(loc); } } - if (pos >= orig_len) { + if (pos < 0) { + /* ${VAR:$((-n)):l} starts n chars from the end */ + pos = orig_len + pos; + } + if ((unsigned)pos >= orig_len) { + /* apart from obvious ${VAR:999999:l}, + * covers ${VAR:$((-9999999)):l} - result is "" + * (bash-compat) + */ pos = 0; len = 0; } -- cgit v1.2.3-55-g6feb From 8a475def9e3e21f780ebcf07dd607b26ceb00ea8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 18 Nov 2014 14:32:58 +0100 Subject: ash,hush: do not segfault on $((2**63 / -1)) Signed-off-by: Denys Vlasenko --- shell/math.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/shell/math.c b/shell/math.c index 3da151137..e7565ebf2 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_ } else if (right_side_val == 0) return "divide by zero"; - else if (op == TOK_DIV || op == TOK_DIV_ASSIGN) - rez /= right_side_val; - else if (op == TOK_REM || op == TOK_REM_ASSIGN) - rez %= right_side_val; + else if (op == TOK_DIV || op == TOK_DIV_ASSIGN + || op == TOK_REM || op == TOK_REM_ASSIGN) { + /* + * bash 4.2.45 x86 64bit: SEGV on 'echo $((2**63 / -1))' + * + * MAX_NEGATIVE_INT / -1 = MAX_POSITIVE_INT+1 + * and thus is not representable. + * Some CPUs segfault trying such op. + * Others overfolw MAX_POSITIVE_INT+1 to + * MAX_NEGATIVE_INT (0x7fff+1 = 0x8000). + * Make sure to at least not SEGV here: + */ + if (right_side_val == -1 + && rez << 1 == 0 /* MAX_NEGATIVE_INT or 0 */ + ) { + right_side_val = 1; + } + if (op == TOK_DIV || op == TOK_DIV_ASSIGN) + rez /= right_side_val; + else { + rez %= right_side_val; + } + } } if (is_assign_op(op)) { -- cgit v1.2.3-55-g6feb From f5add44981b43490376ea0dfed1420dba09a3a75 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 20 Nov 2014 01:43:30 +0100 Subject: typo fix in comment Signed-off-by: Denys Vlasenko --- shell/math.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/math.c b/shell/math.c index e7565ebf2..006221b6a 100644 --- a/shell/math.c +++ b/shell/math.c @@ -423,7 +423,7 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_ * MAX_NEGATIVE_INT / -1 = MAX_POSITIVE_INT+1 * and thus is not representable. * Some CPUs segfault trying such op. - * Others overfolw MAX_POSITIVE_INT+1 to + * Others overflow MAX_POSITIVE_INT+1 to * MAX_NEGATIVE_INT (0x7fff+1 = 0x8000). * Make sure to at least not SEGV here: */ -- cgit v1.2.3-55-g6feb From 4e314faa0aecb66717418e9a47a4451aec59262b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 20 Nov 2014 18:24:33 +0100 Subject: modprobe,rmmod: reject module names with slashes function old new delta add_probe 86 113 +27 Signed-off-by: Denys Vlasenko --- modutils/modprobe.c | 11 +++++++++++ 1 file changed, 11 insertions(+) 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) { struct module_entry *m; + /* + * get_or_add_modentry() strips path from name and works + * on remaining basename. + * This would make "rmmod dir/name" and "modprobe dir/name" + * to work like "rmmod name" and "modprobe name", + * which is wrong, and can be abused via implicit modprobing: + * "ifconfig /usbserial up" tries to modprobe netdev-/usbserial. + */ + if (strchr(name, '/')) + bb_error_msg_and_die("malformed module name '%s'", name); + m = get_or_add_modentry(name); if (!(option_mask32 & (OPT_REMOVE | OPT_SHOW_DEPS)) && (m->flags & MODULE_FLAG_LOADED) -- cgit v1.2.3-55-g6feb From 2bba9ad67a917de2624d427c8c107ce3e2d3d085 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 21 Nov 2014 20:10:57 +0100 Subject: init: do not run shutdown/reexec actions from signal handler this is racy wrt various libc functions such as syslog() function old new delta check_delayed_sigs 182 352 +170 init_main 772 728 -44 restart_handler 74 - -74 halt_reboot_pwoff 79 - -79 ------------------------------------------------------------------------------ (add/remove: 0/2 grow/shrink: 1/1 up/down: 170/-197) Total: -27 bytes Signed-off-by: Denys Vlasenko --- init/init.c | 50 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 20 deletions(-) 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) /* Handler for QUIT - exec "restart" action, * else (no such action defined) do nothing */ -static void restart_handler(int sig UNUSED_PARAM) +static void exec_restart_action(void) { struct init_action *a; @@ -975,6 +975,20 @@ static int check_delayed_sigs(void) #endif if (sig == SIGINT) run_actions(CTRLALTDEL); + if (sig == SIGQUIT) { + exec_restart_action(); + /* returns only if no restart action defined */ + } + if ((1 << sig) & (0 +#ifdef SIGPWR + + (1 << SIGPWR) +#endif + + (1 << SIGUSR1) + + (1 << SIGUSR2) + + (1 << SIGTERM) + )) { + halt_reboot_pwoff(sig); + } } } @@ -1070,7 +1084,7 @@ int init_main(int argc UNUSED_PARAM, char **argv) #if 0 /* It's 2013, does anyone really still depend on this? */ -/* If you do, consider adding swapon to sysinot actions then! */ +/* If you do, consider adding swapon to sysinit actions then! */ /* struct sysinfo is linux-specific */ # ifdef __linux__ /* Make sure there is enough memory to do something useful. */ @@ -1134,16 +1148,6 @@ int init_main(int argc UNUSED_PARAM, char **argv) if (!DEBUG_INIT) { struct sigaction sa; - bb_signals(0 -#ifdef SIGPWR - + (1 << SIGPWR) /* halt */ -#endif - + (1 << SIGUSR1) /* halt */ - + (1 << SIGTERM) /* reboot */ - + (1 << SIGUSR2) /* poweroff */ - , halt_reboot_pwoff); - signal(SIGQUIT, restart_handler); /* re-exec another init */ - /* Stop handler must allow only SIGCONT inside itself */ memset(&sa, 0, sizeof(sa)); sigfillset(&sa.sa_mask); @@ -1158,18 +1162,24 @@ int init_main(int argc UNUSED_PARAM, char **argv) */ sigaction_set(SIGSTOP, &sa); /* pause */ - /* SIGINT (Ctrl-Alt-Del) must interrupt wait(), + /* These signals must interrupt wait(), * setting handler without SA_RESTART flag. */ - bb_signals_recursive_norestart((1 << SIGINT), record_signo); + bb_signals_recursive_norestart(0 + + (1 << SIGINT) /* Ctrl-Alt-Del */ + + (1 << SIGQUIT) /* re-exec another init */ +#ifdef SIGPWR + + (1 << SIGPWR) /* halt */ +#endif + + (1 << SIGUSR1) /* halt */ + + (1 << SIGTERM) /* reboot */ + + (1 << SIGUSR2) /* poweroff */ +#if ENABLE_FEATURE_USE_INITTAB + + (1 << SIGHUP) /* reread /etc/inittab */ +#endif + , record_signo); } - /* Set up "reread /etc/inittab" handler. - * Handler is set up without SA_RESTART, it will interrupt syscalls. - */ - if (!DEBUG_INIT && ENABLE_FEATURE_USE_INITTAB) - bb_signals_recursive_norestart((1 << SIGHUP), record_signo); - /* Now run everything that needs to be run */ /* First run the sysinit command */ run_actions(SYSINIT); -- cgit v1.2.3-55-g6feb From 298fabaefcdb79037d0dd33ba331369586690202 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 25 Nov 2014 18:49:14 +0100 Subject: udhcpd: if a lease from lease file coincides with a static one, ignore it function old new delta read_leases 269 328 +59 Signed-off-by: Denys Vlasenko --- networking/udhcp/files.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) 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) goto ret; while (full_read(fd, &lease, sizeof(lease)) == sizeof(lease)) { -//FIXME: what if it matches some static lease? uint32_t y = ntohl(lease.lease_nip); if (y >= server_config.start_ip && y <= server_config.end_ip) { signed_leasetime_t expires = ntohl(lease.expires) - (signed_leasetime_t)time_passed; + uint32_t static_nip; + if (expires <= 0) continue; + + /* Check if there is a different static lease for this IP or MAC */ + static_nip = get_static_nip_by_mac(server_config.static_leases, lease.lease_mac); + if (static_nip) { + /* NB: we do not add lease even if static_nip == lease.lease_nip. + */ + continue; + } + if (is_nip_reserved(server_config.static_leases, lease.lease_nip)) + continue; + /* NB: add_lease takes "relative time", IOW, * lease duration, not lease deadline. */ if (add_lease(lease.lease_mac, lease.lease_nip, -- cgit v1.2.3-55-g6feb From eff58f15b05733eb10b8a579fd495cf4ca3b1493 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 26 Nov 2014 13:28:54 +0100 Subject: gitignore: add testsuite/echo-ne Signed-off-by: Bartosz Golaszewski Signed-off-by: Denys Vlasenko --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8d6d17601..73e88fb5b 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,4 @@ core # /busybox.links /runtest-tempdir-links +/testsuite/echo-ne -- cgit v1.2.3-55-g6feb From 2835a224cd603489ac08625265d383d4690cb58a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 26 Nov 2014 14:04:51 +0100 Subject: bbunit: fix WANT_TIMING compilation Signed-off-by: Denys Vlasenko --- libbb/bbunit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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) #if WANT_TIMING gettimeofday(&end, NULL); timeval_diff(&time_spent, &end, &begin); - bb_error_msg("Elapsed time %u.%06u seconds" + bb_error_msg("Elapsed time %u.%06u seconds", (int)time_spent.tv_sec, (int)time_spent.tv_usec); #endif -- cgit v1.2.3-55-g6feb From 04c14176023c65550fd46c2e44a1aa04d426d69a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 26 Nov 2014 15:17:59 +0100 Subject: libbb: use ARG_MAX for bb_arg_max() only if it's 60k+ Sometimes ARG_MAX is small (like 32k) yet sysconf(_SC_ARG_MAX) is big, and people prefer using the bigger value. OTOH, with sufficiently large ARG_MAX, further wins from sysconf(_SC_ARG_MAX) being bigger are exponentially smaller: you can see 4 times fewer fork+execs when you run find, but when each execed process already takes a thousand parameters it's likely execution time is dominated by what that process does with each parameter. Thus, with this change ARG_MAX is used if it's sufficiently big, otherwise sysconf(_SC_ARG_MAX) is used. Signed-off-by: Denys Vlasenko --- include/libbb.h | 7 +++++-- libbb/sysconf.c | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index cc2bea32d..17a0089d8 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -731,11 +731,14 @@ extern void *xmalloc_open_read_close(const char *filename, size_t *maxsz_p) FAST /* Never returns NULL */ extern void *xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; -#if defined ARG_MAX +#if defined(ARG_MAX) && (ARG_MAX >= 60*1024 || !defined(_SC_ARG_MAX)) +/* Use _constant_ maximum if: defined && (big enough || no variable one exists) */ # define bb_arg_max() ((unsigned)ARG_MAX) -#elif defined _SC_ARG_MAX +#elif defined(_SC_ARG_MAX) +/* Else use variable one (a bit more expensive) */ unsigned bb_arg_max(void) FAST_FUNC; #else +/* If all else fails */ # define bb_arg_max() ((unsigned)(32 * 1024)) #endif unsigned bb_clk_tck(void) FAST_FUNC; 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 @@ */ #include "libbb.h" -#if !defined(ARG_MAX) && defined(_SC_ARG_MAX) +#if !defined(bb_arg_max) unsigned FAST_FUNC bb_arg_max(void) { return sysconf(_SC_ARG_MAX); -- cgit v1.2.3-55-g6feb From ee41094b809452fdd23d25c1879a96acfcddde08 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 27 Nov 2014 00:40:08 +0100 Subject: man: accept a list of dirs in $MANPATH function old new delta add_MANPATH - 143 +143 man_main 852 731 -121 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 0/1 up/down: 143/-121) Total: 22 bytes Signed-off-by: Denys Vlasenko --- miscutils/man.c | 86 ++++++++++++++++++++++++++++++++------------------------- 1 file changed, 49 insertions(+), 37 deletions(-) diff --git a/miscutils/man.c b/miscutils/man.c index 5c1fa2c9d..ccb57a93f 100644 --- a/miscutils/man.c +++ b/miscutils/man.c @@ -147,15 +147,49 @@ static int show_manpage(const char *pager, char *man_filename, int man, int leve return run_pipe(pager, man_filename, man, level); } +static char **add_MANPATH(char **man_path_list, int *count_mp, char *path) +{ + if (path) while (*path) { + char *next_path; + char **path_element; + + next_path = strchr(path, ':'); + if (next_path) { + *next_path = '\0'; + if (next_path++ == path) /* "::"? */ + goto next; + } + /* Do we already have path? */ + path_element = man_path_list; + if (path_element) while (*path_element) { + if (strcmp(*path_element, path) == 0) + goto skip; + path_element++; + } + man_path_list = xrealloc_vector(man_path_list, 4, *count_mp); + man_path_list[*count_mp] = xstrdup(path); + (*count_mp)++; + /* man_path_list is NULL terminated */ + /* man_path_list[*count_mp] = NULL; - xrealloc_vector did it */ + skip: + if (!next_path) + break; + next: + path = next_path; + } + return man_path_list; +} + int man_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int man_main(int argc UNUSED_PARAM, char **argv) { parser_t *parser; const char *pager = ENABLE_LESS ? "less" : "more"; - char **man_path_list; char *sec_list; char *cur_path, *cur_sect; - int count_mp, cur_mp; + char **man_path_list; + int count_mp; + int cur_mp; int opt, not_found; char *token[2]; @@ -164,14 +198,20 @@ int man_main(int argc UNUSED_PARAM, char **argv) argv += optind; sec_list = xstrdup("0p:1:1p:2:3:3p:4:5:6:7:8:9"); - /* Last valid man_path_list[] is [0x10] */ + count_mp = 0; - man_path_list = xzalloc(0x11 * sizeof(man_path_list[0])); - man_path_list[0] = getenv("MANPATH"); - if (!man_path_list[0]) /* default, may be overridden by /etc/man.conf */ + man_path_list = add_MANPATH(NULL, &count_mp, + getenv("MANDATORY_MANPATH"+10) /* "MANPATH" */ + ); + if (!man_path_list) { + /* default, may be overridden by /etc/man.conf */ + man_path_list = xzalloc(2 * sizeof(man_path_list[0])); man_path_list[0] = (char*)"/usr/man"; - else - count_mp++; + /* count_mp stays 0. + * Thus, man.conf will overwrite man_path_list[0] + * if a path is defined there. + */ + } /* Parse man.conf[ig] or man_db.conf */ /* man version 1.6f uses man.config */ @@ -193,35 +233,7 @@ int man_main(int argc UNUSED_PARAM, char **argv) if (strcmp("MANDATORY_MANPATH"+10, token[0]) == 0 /* "MANPATH"? */ || strcmp("MANDATORY_MANPATH", token[0]) == 0 ) { - char *path = token[1]; - while (*path) { - char *next_path; - char **path_element; - - next_path = strchr(path, ':'); - if (next_path) { - *next_path = '\0'; - if (next_path++ == path) /* "::"? */ - goto next; - } - /* Do we already have path? */ - path_element = man_path_list; - while (*path_element) { - if (strcmp(*path_element, path) == 0) - goto skip; - path_element++; - } - man_path_list = xrealloc_vector(man_path_list, 4, count_mp); - man_path_list[count_mp] = xstrdup(path); - count_mp++; - /* man_path_list is NULL terminated */ - /*man_path_list[count_mp] = NULL; - xrealloc_vector did it */ - skip: - if (!next_path) - break; - next: - path = next_path; - } + man_path_list = add_MANPATH(man_path_list, &count_mp, token[1]); } if (strcmp("MANSECT", token[0]) == 0) { free(sec_list); -- cgit v1.2.3-55-g6feb From 8d75d794ea505003fddea8e757d43976db8d6861 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 27 Nov 2014 13:20:24 +0100 Subject: libbb: use sendfile() to copy data between file descriptors Busybox already uses sendfile in httpd. This patch proposes to use it globally to copy data between file descriptors. It speeds up the copying on slow systems a lot - below are the times needed to copy a 450Mb file with and without this option enabled on a BeagleBone Black: sendfile: user 0m0.000s sys 0m8.170s read/write 4k: user 0m0.470s sys 0m16.300s function old new delta bb_full_fd_action 394 474 +80 Signed-off-by: Bartosz Golaszewski Signed-off-by: Denys Vlasenko --- Config.in | 12 +++++++ libbb/copyfd.c | 87 +++++++++++++++++++++++++++++++++------------------ networking/Config.src | 8 ----- networking/httpd.c | 6 ++-- 4 files changed, 71 insertions(+), 42 deletions(-) diff --git a/Config.in b/Config.in index b83beb52d..285fe0a19 100644 --- a/Config.in +++ b/Config.in @@ -264,6 +264,18 @@ config PAM Use PAM in some busybox applets (currently login and httpd) instead of direct access to password database. +config FEATURE_USE_SENDFILE + bool "Use sendfile system call" + default y + help + When enabled, busybox will use the kernel sendfile() function + instead of read/write loops to copy data between file descriptors + (for example, cp command does this a lot). + If sendfile() doesn't work, copying code falls back to read/write + loop. sendfile() was originally implemented for faster I/O + from files to sockets, but since Linux 2.6.33 it was extended + to work for many more file types. + config LONG_OPTS bool "Support for --long-options" default y 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 @@ */ #include "libbb.h" +#if ENABLE_FEATURE_USE_SENDFILE +# include +#else +# define sendfile(a,b,c,d) (-1) +#endif + +/* + * We were using 0x7fff0000 as sendfile chunk size, but it + * was seen to cause largish delays when user tries to ^C a file copy. + * Let's use a saner size. + * Note: needs to be >= max(CONFIG_FEATURE_COPYBUF_KB), + * or else "copy to eof" code will use neddlesly short reads. + */ +#define SENDFILE_BIGBUF (16*1024*1024) /* Used by NOFORK applets (e.g. cat) - must not use xmalloc. * 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) int status = -1; off_t total = 0; bool continue_on_write_error = 0; -#if CONFIG_FEATURE_COPYBUF_KB <= 4 + ssize_t sendfile_sz; +#if CONFIG_FEATURE_COPYBUF_KB > 4 + char *buffer = buffer; /* for compiler */ + int buffer_size = 0; +#else char buffer[CONFIG_FEATURE_COPYBUF_KB * 1024]; enum { buffer_size = sizeof(buffer) }; -#else - char *buffer; - int buffer_size; #endif if (size < 0) { @@ -31,46 +46,58 @@ static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size) continue_on_write_error = 1; } -#if CONFIG_FEATURE_COPYBUF_KB > 4 - if (size > 0 && size <= 4 * 1024) - goto use_small_buf; - /* We want page-aligned buffer, just in case kernel is clever - * and can do page-aligned io more efficiently */ - buffer = mmap(NULL, CONFIG_FEATURE_COPYBUF_KB * 1024, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON, - /* ignored: */ -1, 0); - buffer_size = CONFIG_FEATURE_COPYBUF_KB * 1024; - if (buffer == MAP_FAILED) { - use_small_buf: - buffer = alloca(4 * 1024); - buffer_size = 4 * 1024; - } -#endif - if (src_fd < 0) goto out; + sendfile_sz = !ENABLE_FEATURE_USE_SENDFILE + ? 0 + : SENDFILE_BIGBUF; if (!size) { - size = buffer_size; + size = SENDFILE_BIGBUF; status = 1; /* copy until eof */ } while (1) { ssize_t rd; - rd = safe_read(src_fd, buffer, size > buffer_size ? buffer_size : size); - - if (!rd) { /* eof - all done */ - status = 0; - break; + if (sendfile_sz) { + rd = sendfile(dst_fd, src_fd, NULL, + size > sendfile_sz ? sendfile_sz : size); + if (rd >= 0) + goto read_ok; + sendfile_sz = 0; /* do not try sendfile anymore */ + } +#if CONFIG_FEATURE_COPYBUF_KB > 4 + if (buffer_size == 0) { + if (size > 0 && size <= 4 * 1024) + goto use_small_buf; + /* We want page-aligned buffer, just in case kernel is clever + * and can do page-aligned io more efficiently */ + buffer = mmap(NULL, CONFIG_FEATURE_COPYBUF_KB * 1024, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, + /* ignored: */ -1, 0); + buffer_size = CONFIG_FEATURE_COPYBUF_KB * 1024; + if (buffer == MAP_FAILED) { + use_small_buf: + buffer = alloca(4 * 1024); + buffer_size = 4 * 1024; + } } +#endif + rd = safe_read(src_fd, buffer, + size > buffer_size ? buffer_size : size); if (rd < 0) { bb_perror_msg(bb_msg_read_error); break; } + read_ok: + if (!rd) { /* eof - all done */ + status = 0; + break; + } /* dst_fd == -1 is a fake, else... */ - if (dst_fd >= 0) { + if (dst_fd >= 0 && !sendfile_sz) { ssize_t wr = full_write(dst_fd, buffer, rd); if (wr < rd) { 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) } out: -#if CONFIG_FEATURE_COPYBUF_KB > 4 - if (buffer_size != 4 * 1024) + if (buffer_size > 4 * 1024) munmap(buffer, buffer_size); -#endif return status ? -1 : total; } 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 "Range: bytes=NNN-[MMM]" header. Allows for resuming interrupted downloads, seeking in multimedia players etc. -config FEATURE_HTTPD_USE_SENDFILE - bool "Use sendfile system call" - default y - depends on HTTPD - help - When enabled, httpd will use the kernel sendfile() function - instead of read/write loop. - config FEATURE_HTTPD_SETUID bool "Enable -u option" 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 @@ # include # include #endif -#if ENABLE_FEATURE_HTTPD_USE_SENDFILE +#if ENABLE_FEATURE_USE_SENDFILE # include #endif /* amount of buffering in a pipe */ @@ -1624,7 +1624,7 @@ static NOINLINE void send_file_and_exit(const char *url, int what) #endif if (what & SEND_HEADERS) send_headers(HTTP_OK); -#if ENABLE_FEATURE_HTTPD_USE_SENDFILE +#if ENABLE_FEATURE_USE_SENDFILE { off_t offset = range_start; while (1) { @@ -1654,7 +1654,7 @@ static NOINLINE void send_file_and_exit(const char *url, int what) break; } if (count < 0) { - IF_FEATURE_HTTPD_USE_SENDFILE(fin:) + IF_FEATURE_USE_SENDFILE(fin:) if (verbose > 1) bb_perror_msg("error"); } -- cgit v1.2.3-55-g6feb From 476654cdbeb2923fc5d2485701587b42579e1635 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 30 Nov 2014 19:39:58 +0100 Subject: man: do not mangle $MANPATH in memory Signed-off-by: Denys Vlasenko --- miscutils/man.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/miscutils/man.c b/miscutils/man.c index ccb57a93f..c39870e67 100644 --- a/miscutils/man.c +++ b/miscutils/man.c @@ -155,9 +155,9 @@ static char **add_MANPATH(char **man_path_list, int *count_mp, char *path) next_path = strchr(path, ':'); if (next_path) { - *next_path = '\0'; - if (next_path++ == path) /* "::"? */ + if (next_path == path) /* "::"? */ goto next; + *next_path = '\0'; } /* Do we already have path? */ path_element = man_path_list; @@ -174,8 +174,10 @@ static char **add_MANPATH(char **man_path_list, int *count_mp, char *path) skip: if (!next_path) break; + /* "path" may be a result of getenv(), be nice and don't mangle it */ + *next_path = ':'; next: - path = next_path; + path = next_path + 1; } return man_path_list; } -- cgit v1.2.3-55-g6feb From e7800f351ad9eca012fe27a1c9234692a04419e7 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 7 Dec 2014 00:42:49 +0100 Subject: Rename transformer_aux_data_t -> transformer_state_t No code changes Signed-off-by: Denys Vlasenko --- archival/bbunzip.c | 34 ++++++++++++++--------------- archival/bzip2.c | 2 +- archival/gzip.c | 2 +- archival/libarchive/decompress_bunzip2.c | 4 ++-- archival/libarchive/decompress_gunzip.c | 26 +++++++++++----------- archival/libarchive/decompress_uncompress.c | 4 ++-- archival/libarchive/decompress_unlzma.c | 2 +- archival/libarchive/decompress_unxz.c | 4 ++-- archival/libarchive/open_transformer.c | 22 +++++++++---------- archival/lzop.c | 2 +- archival/tar.c | 2 +- archival/unzip.c | 12 +++++----- include/bb_archive.h | 24 ++++++++++---------- 13 files changed, 70 insertions(+), 70 deletions(-) diff --git a/archival/bbunzip.c b/archival/bbunzip.c index fce5ab9e1..84f58f138 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c @@ -39,7 +39,7 @@ char* FAST_FUNC append_ext(char *filename, const char *expected_ext) } int FAST_FUNC bbunpack(char **argv, - IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(transformer_aux_data_t *aux), + IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(transformer_state_t *xstate), char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext), const char *expected_ext ) @@ -48,7 +48,7 @@ int FAST_FUNC bbunpack(char **argv, IF_DESKTOP(long long) int status = 0; char *filename, *new_name; smallint exitcode = 0; - transformer_aux_data_t aux; + transformer_state_t xstate; do { /* NB: new_name is *maybe* malloc'ed! */ @@ -120,9 +120,9 @@ int FAST_FUNC bbunpack(char **argv, } if (!(option_mask32 & SEAMLESS_MAGIC)) { - init_transformer_aux_data(&aux); - aux.check_signature = 1; - status = unpacker(&aux); + init_transformer_state(&xstate); + xstate.check_signature = 1; + status = unpacker(&xstate); if (status < 0) exitcode = 1; } else { @@ -141,10 +141,10 @@ int FAST_FUNC bbunpack(char **argv, unsigned new_name_len; /* TODO: restore other things? */ - if (aux.mtime != 0) { + if (xstate.mtime != 0) { struct timeval times[2]; - times[1].tv_sec = times[0].tv_sec = aux.mtime; + times[1].tv_sec = times[0].tv_sec = xstate.mtime; times[1].tv_usec = times[0].tv_usec = 0; /* Note: we closed it first. * On some systems calling utimes @@ -227,9 +227,9 @@ char* FAST_FUNC make_new_name_generic(char *filename, const char *expected_ext) //kbuild:lib-$(CONFIG_UNCOMPRESS) += bbunzip.o #if ENABLE_UNCOMPRESS static -IF_DESKTOP(long long) int FAST_FUNC unpack_uncompress(transformer_aux_data_t *aux) +IF_DESKTOP(long long) int FAST_FUNC unpack_uncompress(transformer_state_t *xstate) { - return unpack_Z_stream(aux, STDIN_FILENO, STDOUT_FILENO); + return unpack_Z_stream(xstate, STDIN_FILENO, STDOUT_FILENO); } int uncompress_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int uncompress_main(int argc UNUSED_PARAM, char **argv) @@ -325,9 +325,9 @@ char* FAST_FUNC make_new_name_gunzip(char *filename, const char *expected_ext UN return filename; } static -IF_DESKTOP(long long) int FAST_FUNC unpack_gunzip(transformer_aux_data_t *aux) +IF_DESKTOP(long long) int FAST_FUNC unpack_gunzip(transformer_state_t *xstate) { - return unpack_gz_stream(aux, STDIN_FILENO, STDOUT_FILENO); + return unpack_gz_stream(xstate, STDIN_FILENO, STDOUT_FILENO); } /* * Linux kernel build uses gzip -d -n. We accept and ignore it. @@ -396,9 +396,9 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv) //kbuild:lib-$(CONFIG_BUNZIP2) += bbunzip.o #if ENABLE_BUNZIP2 static -IF_DESKTOP(long long) int FAST_FUNC unpack_bunzip2(transformer_aux_data_t *aux) +IF_DESKTOP(long long) int FAST_FUNC unpack_bunzip2(transformer_state_t *xstate) { - return unpack_bz2_stream(aux, STDIN_FILENO, STDOUT_FILENO); + return unpack_bz2_stream(xstate, STDIN_FILENO, STDOUT_FILENO); } int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int bunzip2_main(int argc UNUSED_PARAM, char **argv) @@ -495,9 +495,9 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv) //kbuild:lib-$(CONFIG_UNLZMA) += bbunzip.o #if ENABLE_UNLZMA static -IF_DESKTOP(long long) int FAST_FUNC unpack_unlzma(transformer_aux_data_t *aux) +IF_DESKTOP(long long) int FAST_FUNC unpack_unlzma(transformer_state_t *xstate) { - return unpack_lzma_stream(aux, STDIN_FILENO, STDOUT_FILENO); + return unpack_lzma_stream(xstate, STDIN_FILENO, STDOUT_FILENO); } int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int unlzma_main(int argc UNUSED_PARAM, char **argv) @@ -538,9 +538,9 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv) //kbuild:lib-$(CONFIG_UNXZ) += bbunzip.o #if ENABLE_UNXZ static -IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(transformer_aux_data_t *aux) +IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(transformer_state_t *xstate) { - return unpack_xz_stream(aux, STDIN_FILENO, STDOUT_FILENO); + return unpack_xz_stream(xstate, STDIN_FILENO, STDOUT_FILENO); } int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int unxz_main(int argc UNUSED_PARAM, char **argv) 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 } static -IF_DESKTOP(long long) int FAST_FUNC compressStream(transformer_aux_data_t *aux UNUSED_PARAM) +IF_DESKTOP(long long) int FAST_FUNC compressStream(transformer_state_t *xstate UNUSED_PARAM) { IF_DESKTOP(long long) int total; 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) /* ======================================================================== */ static -IF_DESKTOP(long long) int FAST_FUNC pack_gzip(transformer_aux_data_t *aux UNUSED_PARAM) +IF_DESKTOP(long long) int FAST_FUNC pack_gzip(transformer_state_t *xstate UNUSED_PARAM) { struct stat s; diff --git a/archival/libarchive/decompress_bunzip2.c b/archival/libarchive/decompress_bunzip2.c index 6396fe40d..36237e221 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) /* Decompress src_fd to dst_fd. Stops at end of bzip data, not end of file. */ IF_DESKTOP(long long) int FAST_FUNC -unpack_bz2_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) +unpack_bz2_stream(transformer_state_t *xstate, int src_fd, int dst_fd) { IF_DESKTOP(long long total_written = 0;) bunzip_data *bd; @@ -739,7 +739,7 @@ unpack_bz2_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) int i; unsigned len; - if (check_signature16(aux, src_fd, BZIP2_MAGIC)) + if (check_signature16(xstate, src_fd, BZIP2_MAGIC)) return -1; outbuf = xmalloc(IOBUF_SIZE); diff --git a/archival/libarchive/decompress_gunzip.c b/archival/libarchive/decompress_gunzip.c index 7c6f38ec3..62a3d78b6 100644 --- a/archival/libarchive/decompress_gunzip.c +++ b/archival/libarchive/decompress_gunzip.c @@ -1034,22 +1034,22 @@ inflate_unzip_internal(STATE_PARAM int in, int out) /* For unzip */ IF_DESKTOP(long long) int FAST_FUNC -inflate_unzip(transformer_aux_data_t *aux, int in, int out) +inflate_unzip(transformer_state_t *xstate, int in, int out) { IF_DESKTOP(long long) int n; DECLARE_STATE; ALLOC_STATE; - to_read = aux->bytes_in; + to_read = xstate->bytes_in; // bytebuffer_max = 0x8000; bytebuffer_offset = 4; bytebuffer = xmalloc(bytebuffer_max); n = inflate_unzip_internal(PASS_STATE in, out); free(bytebuffer); - aux->crc32 = gunzip_crc; - aux->bytes_out = gunzip_bytes_out; + xstate->crc32 = gunzip_crc; + xstate->bytes_out = gunzip_bytes_out; DEALLOC_STATE; return n; } @@ -1107,7 +1107,7 @@ static uint32_t buffer_read_le_u32(STATE_PARAM_ONLY) return res; } -static int check_header_gzip(STATE_PARAM transformer_aux_data_t *aux) +static int check_header_gzip(STATE_PARAM transformer_state_t *xstate) { union { unsigned char raw[8]; @@ -1169,8 +1169,8 @@ static int check_header_gzip(STATE_PARAM transformer_aux_data_t *aux) } } - if (aux) - aux->mtime = SWAP_LE32(header.formatted.mtime); + if (xstate) + xstate->mtime = SWAP_LE32(header.formatted.mtime); /* Read the header checksum */ if (header.formatted.flags & 0x02) { @@ -1182,17 +1182,17 @@ static int check_header_gzip(STATE_PARAM transformer_aux_data_t *aux) } IF_DESKTOP(long long) int FAST_FUNC -unpack_gz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) +unpack_gz_stream(transformer_state_t *xstate, int src_fd, int dst_fd) { uint32_t v32; IF_DESKTOP(long long) int total, n; DECLARE_STATE; #if !ENABLE_FEATURE_SEAMLESS_Z - if (check_signature16(aux, src_fd, GZIP_MAGIC)) + if (check_signature16(xstate, src_fd, GZIP_MAGIC)) return -1; #else - if (aux && aux->check_signature) { + if (xstate && xstate->check_signature) { uint16_t magic2; if (full_read(src_fd, &magic2, 2) != 2) { @@ -1201,8 +1201,8 @@ unpack_gz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) return -1; } if (magic2 == COMPRESS_MAGIC) { - aux->check_signature = 0; - return unpack_Z_stream(aux, src_fd, dst_fd); + xstate->check_signature = 0; + return unpack_Z_stream(xstate, src_fd, dst_fd); } if (magic2 != GZIP_MAGIC) goto bad_magic; @@ -1218,7 +1218,7 @@ unpack_gz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) gunzip_src_fd = src_fd; again: - if (!check_header_gzip(PASS_STATE aux)) { + if (!check_header_gzip(PASS_STATE xstate)) { bb_error_msg("corrupted data"); total = -1; goto ret; diff --git a/archival/libarchive/decompress_uncompress.c b/archival/libarchive/decompress_uncompress.c index 53c27080f..cb3d55a88 100644 --- a/archival/libarchive/decompress_uncompress.c +++ b/archival/libarchive/decompress_uncompress.c @@ -73,7 +73,7 @@ */ IF_DESKTOP(long long) int FAST_FUNC -unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) +unpack_Z_stream(transformer_state_t *xstate, int src_fd, int dst_fd) { IF_DESKTOP(long long total_written = 0;) 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) /* block compress mode -C compatible with 2.0 */ int block_mode; /* = BLOCK_MODE; */ - if (check_signature16(aux, src_fd, COMPRESS_MAGIC)) + if (check_signature16(xstate, src_fd, COMPRESS_MAGIC)) return -1; inbuf = xzalloc(IBUFSIZ + 64); diff --git a/archival/libarchive/decompress_unlzma.c b/archival/libarchive/decompress_unlzma.c index 3d99e1388..ccedac49d 100644 --- a/archival/libarchive/decompress_unlzma.c +++ b/archival/libarchive/decompress_unlzma.c @@ -206,7 +206,7 @@ enum { IF_DESKTOP(long long) int FAST_FUNC -unpack_lzma_stream(transformer_aux_data_t *aux UNUSED_PARAM, int src_fd, int dst_fd) +unpack_lzma_stream(transformer_state_t *xstate UNUSED_PARAM, int src_fd, int dst_fd) { IF_DESKTOP(long long total_written = 0;) lzma_header_t header; diff --git a/archival/libarchive/decompress_unxz.c b/archival/libarchive/decompress_unxz.c index 986b7b191..6df54e131 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) #include "unxz/xz_dec_stream.c" IF_DESKTOP(long long) int FAST_FUNC -unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) +unpack_xz_stream(transformer_state_t *xstate, int src_fd, int dst_fd) { enum xz_ret xz_result; struct xz_buf iobuf; @@ -55,7 +55,7 @@ unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) iobuf.out = membuf + BUFSIZ; iobuf.out_size = BUFSIZ; - if (!aux || aux->check_signature == 0) { + if (!xstate || xstate->check_signature == 0) { /* Preload XZ file signature */ strcpy((char*)membuf, HEADER_MAGIC); iobuf.in_size = HEADER_MAGIC_SIZE; diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c index 198663041..584b15de4 100644 --- a/archival/libarchive/open_transformer.c +++ b/archival/libarchive/open_transformer.c @@ -6,19 +6,19 @@ #include "libbb.h" #include "bb_archive.h" -void FAST_FUNC init_transformer_aux_data(transformer_aux_data_t *aux) +void FAST_FUNC init_transformer_state(transformer_state_t *xstate) { - memset(aux, 0, sizeof(*aux)); + memset(xstate, 0, sizeof(*xstate)); } -int FAST_FUNC check_signature16(transformer_aux_data_t *aux, int src_fd, unsigned magic16) +int FAST_FUNC check_signature16(transformer_state_t *xstate, int src_fd, unsigned magic16) { - if (aux && aux->check_signature) { + if (xstate && xstate->check_signature) { uint16_t magic2; if (full_read(src_fd, &magic2, 2) != 2 || magic2 != magic16) { bb_error_msg("invalid magic"); #if 0 /* possible future extension */ - if (aux->check_signature > 1) + if (xstate->check_signature > 1) xfunc_die(); #endif return -1; @@ -62,7 +62,7 @@ void check_errors_in_children(int signo) #if BB_MMU void FAST_FUNC open_transformer(int fd, int check_signature, - IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd) + IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_state_t *xstate, int src_fd, int dst_fd) ) #else void FAST_FUNC open_transformer(int fd, const char *transform_prog) @@ -80,10 +80,10 @@ void FAST_FUNC open_transformer(int fd, const char *transform_prog) #if BB_MMU { IF_DESKTOP(long long) int r; - transformer_aux_data_t aux; - init_transformer_aux_data(&aux); - aux.check_signature = check_signature; - r = transformer(&aux, fd, fd_pipe.wr); + transformer_state_t xstate; + init_transformer_state(&xstate); + xstate.check_signature = check_signature; + r = transformer(&xstate, fd, fd_pipe.wr); if (ENABLE_FEATURE_CLEAN_UP) { close(fd_pipe.wr); /* send EOF */ close(fd); @@ -126,7 +126,7 @@ int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed) uint32_t b32[1]; } magic; int offset = -2; - USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd);) + USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_state_t *xstate, int src_fd, int dst_fd);) USE_FOR_NOMMU(const char *xformer_prog;) /* .gz and .bz2 both have 2-byte signature, and their 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 return xasprintf("%s.lzo", filename); } -static IF_DESKTOP(long long) int FAST_FUNC pack_lzop(transformer_aux_data_t *aux UNUSED_PARAM) +static IF_DESKTOP(long long) int FAST_FUNC pack_lzop(transformer_state_t *xstate UNUSED_PARAM) { if (option_mask32 & OPT_DECOMPRESS) return do_lzo_decompress(); diff --git a/archival/tar.c b/archival/tar.c index aa02d3512..7897a4af6 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -1171,7 +1171,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) } if (opt & OPT_ANY_COMPRESS) { - USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd);) + USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_state_t *xstate, int src_fd, int dst_fd);) USE_FOR_NOMMU(const char *xformer_prog;) if (opt & OPT_COMPRESS) diff --git a/archival/unzip.c b/archival/unzip.c index fcfc9a448..c622bde57 100644 --- a/archival/unzip.c +++ b/archival/unzip.c @@ -280,17 +280,17 @@ static void unzip_extract(zip_header_t *zip_header, int dst_fd) bb_copyfd_exact_size(zip_fd, dst_fd, size); } else { /* Method 8 - inflate */ - transformer_aux_data_t aux; - init_transformer_aux_data(&aux); - aux.bytes_in = zip_header->formatted.cmpsize; - if (inflate_unzip(&aux, zip_fd, dst_fd) < 0) + transformer_state_t xstate; + init_transformer_state(&xstate); + xstate.bytes_in = zip_header->formatted.cmpsize; + if (inflate_unzip(&xstate, zip_fd, dst_fd) < 0) bb_error_msg_and_die("inflate error"); /* Validate decompression - crc */ - if (zip_header->formatted.crc32 != (aux.crc32 ^ 0xffffffffL)) { + if (zip_header->formatted.crc32 != (xstate.crc32 ^ 0xffffffffL)) { bb_error_msg_and_die("crc error"); } /* Validate decompression - size */ - if (zip_header->formatted.ucmpsize != aux.bytes_out) { + if (zip_header->formatted.ucmpsize != xstate.bytes_out) { /* Don't die. Who knows, maybe len calculation * was botched somewhere. After all, crc matched! */ bb_error_msg("bad length"); diff --git a/include/bb_archive.h b/include/bb_archive.h index b82cfd83c..8a2dd2735 100644 --- a/include/bb_archive.h +++ b/include/bb_archive.h @@ -203,27 +203,27 @@ int read_bunzip(bunzip_data *bd, char *outbuf, int len) FAST_FUNC; void dealloc_bunzip(bunzip_data *bd) FAST_FUNC; /* Meaning and direction (input/output) of the fields are transformer-specific */ -typedef struct transformer_aux_data_t { +typedef struct transformer_state_t { smallint check_signature; /* most often referenced member */ off_t bytes_out; off_t bytes_in; /* used in unzip code only: needs to know packed size */ uint32_t crc32; time_t mtime; /* gunzip code may set this on exit */ -} transformer_aux_data_t; +} transformer_state_t; -void init_transformer_aux_data(transformer_aux_data_t *aux) FAST_FUNC; -int FAST_FUNC check_signature16(transformer_aux_data_t *aux, int src_fd, unsigned magic16) FAST_FUNC; +void init_transformer_state(transformer_state_t *xstate) FAST_FUNC; +int FAST_FUNC check_signature16(transformer_state_t *xstate, int src_fd, unsigned magic16) FAST_FUNC; -IF_DESKTOP(long long) int inflate_unzip(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; -IF_DESKTOP(long long) int unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; -IF_DESKTOP(long long) int unpack_gz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; -IF_DESKTOP(long long) int unpack_bz2_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; -IF_DESKTOP(long long) int unpack_lzma_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; -IF_DESKTOP(long long) int unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; +IF_DESKTOP(long long) int inflate_unzip(transformer_state_t *xstate, int src_fd, int dst_fd) FAST_FUNC; +IF_DESKTOP(long long) int unpack_Z_stream(transformer_state_t *xstate, int src_fd, int dst_fd) FAST_FUNC; +IF_DESKTOP(long long) int unpack_gz_stream(transformer_state_t *xstate, int src_fd, int dst_fd) FAST_FUNC; +IF_DESKTOP(long long) int unpack_bz2_stream(transformer_state_t *xstate, int src_fd, int dst_fd) FAST_FUNC; +IF_DESKTOP(long long) int unpack_lzma_stream(transformer_state_t *xstate, int src_fd, int dst_fd) FAST_FUNC; +IF_DESKTOP(long long) int unpack_xz_stream(transformer_state_t *xstate, int src_fd, int dst_fd) FAST_FUNC; char* append_ext(char *filename, const char *expected_ext) FAST_FUNC; int bbunpack(char **argv, - IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(transformer_aux_data_t *aux), + IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(transformer_state_t *xstate), char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext), const char *expected_ext ) FAST_FUNC; @@ -232,7 +232,7 @@ void check_errors_in_children(int signo); #if BB_MMU void open_transformer(int fd, int check_signature, - IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd) + IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_state_t *xstate, int src_fd, int dst_fd) ) FAST_FUNC; #define open_transformer_with_sig(fd, transformer, transform_prog) open_transformer((fd), 1, (transformer)) #define open_transformer_with_no_sig(fd, transformer) open_transformer((fd), 0, (transformer)) -- cgit v1.2.3-55-g6feb From b4c11c139717729b8257ee9382d4e5ed713d4dde Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 7 Dec 2014 00:44:00 +0100 Subject: libarchive: add capability to unpack to mem.buffer The performance and number of processes for a "depmod -a" with gzipped modules was abysmal. This patch adds a code path without fork, benefiting all users of xmalloc_open_zipped_read_close. "modinfo radeon.ko.gz", a single-file reader, got 30% faster. "depmod -a", which used to fork over 800 times, got 20% faster. Heavily based on a patch by Lauri Kasanen function old new delta setup_transformer_on_fd - 159 +159 transformer_write - 122 +122 fork_transformer - 112 +112 xmalloc_open_zipped_read_close 63 118 +55 read_bunzip 1866 1896 +30 xtransformer_write - 19 +19 unzip_main 2449 2462 +13 bbunpack 755 766 +11 unpack_lzma_stream 2717 2723 +6 unpack_xz_stream 2393 2397 +4 unpack_Z_stream 1173 1175 +2 inflate_unzip 111 105 -6 check_signature16 70 63 -7 unpack_bz2_stream 359 349 -10 unpack_unxz 12 - -12 unpack_unlzma 12 - -12 unpack_uncompress 12 - -12 unpack_gunzip 12 - -12 unpack_bunzip2 12 - -12 open_transformer 106 92 -14 inflate_unzip_internal 1945 1916 -29 unpack_gz_stream 693 655 -38 open_zipped 89 47 -42 setup_unzip_on_fd 142 53 -89 ------------------------------------------------------------------------------ (add/remove: 4/5 grow/shrink: 7/8 up/down: 533/-295) Total: 238 bytes Signed-off-by: Denys Vlasenko --- archival/bbunzip.c | 37 +----- archival/libarchive/decompress_bunzip2.c | 11 +- archival/libarchive/decompress_gunzip.c | 30 ++--- archival/libarchive/decompress_uncompress.c | 12 +- archival/libarchive/decompress_unlzma.c | 12 +- archival/libarchive/decompress_unxz.c | 6 +- archival/libarchive/get_header_tar_bz2.c | 2 +- archival/libarchive/get_header_tar_gz.c | 2 +- archival/libarchive/get_header_tar_lzma.c | 2 +- archival/libarchive/open_transformer.c | 199 ++++++++++++++++++++++------ archival/tar.c | 4 +- archival/unzip.c | 4 +- include/bb_archive.h | 42 ++++-- include/libbb.h | 3 +- 14 files changed, 241 insertions(+), 125 deletions(-) diff --git a/archival/bbunzip.c b/archival/bbunzip.c index 84f58f138..90aac1427 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c @@ -122,6 +122,8 @@ int FAST_FUNC bbunpack(char **argv, if (!(option_mask32 & SEAMLESS_MAGIC)) { init_transformer_state(&xstate); xstate.check_signature = 1; + /*xstate.src_fd = STDIN_FILENO; - already is */ + xstate.dst_fd = STDOUT_FILENO; status = unpacker(&xstate); if (status < 0) exitcode = 1; @@ -226,18 +228,13 @@ char* FAST_FUNC make_new_name_generic(char *filename, const char *expected_ext) //applet:IF_UNCOMPRESS(APPLET(uncompress, BB_DIR_BIN, BB_SUID_DROP)) //kbuild:lib-$(CONFIG_UNCOMPRESS) += bbunzip.o #if ENABLE_UNCOMPRESS -static -IF_DESKTOP(long long) int FAST_FUNC unpack_uncompress(transformer_state_t *xstate) -{ - return unpack_Z_stream(xstate, STDIN_FILENO, STDOUT_FILENO); -} int uncompress_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int uncompress_main(int argc UNUSED_PARAM, char **argv) { getopt32(argv, "cf"); argv += optind; - return bbunpack(argv, unpack_uncompress, make_new_name_generic, "Z"); + return bbunpack(argv, unpack_Z_stream, make_new_name_generic, "Z"); } #endif @@ -324,11 +321,6 @@ char* FAST_FUNC make_new_name_gunzip(char *filename, const char *expected_ext UN } return filename; } -static -IF_DESKTOP(long long) int FAST_FUNC unpack_gunzip(transformer_state_t *xstate) -{ - return unpack_gz_stream(xstate, STDIN_FILENO, STDOUT_FILENO); -} /* * Linux kernel build uses gzip -d -n. We accept and ignore it. * Man page says: @@ -355,7 +347,7 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv) if (applet_name[1] == 'c') option_mask32 |= OPT_STDOUT | SEAMLESS_MAGIC; - return bbunpack(argv, unpack_gunzip, make_new_name_gunzip, /*unused:*/ NULL); + return bbunpack(argv, unpack_gz_stream, make_new_name_gunzip, /*unused:*/ NULL); } #endif @@ -395,11 +387,6 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv) //kbuild:lib-$(CONFIG_BZIP2) += bbunzip.o //kbuild:lib-$(CONFIG_BUNZIP2) += bbunzip.o #if ENABLE_BUNZIP2 -static -IF_DESKTOP(long long) int FAST_FUNC unpack_bunzip2(transformer_state_t *xstate) -{ - return unpack_bz2_stream(xstate, STDIN_FILENO, STDOUT_FILENO); -} int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int bunzip2_main(int argc UNUSED_PARAM, char **argv) { @@ -408,7 +395,7 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv) if (applet_name[2] == 'c') /* bzcat */ option_mask32 |= OPT_STDOUT; - return bbunpack(argv, unpack_bunzip2, make_new_name_generic, "bz2"); + return bbunpack(argv, unpack_bz2_stream, make_new_name_generic, "bz2"); } #endif @@ -494,11 +481,6 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv) //applet:IF_LZMA(APPLET_ODDNAME(lzma, unlzma, BB_DIR_USR_BIN, BB_SUID_DROP, lzma)) //kbuild:lib-$(CONFIG_UNLZMA) += bbunzip.o #if ENABLE_UNLZMA -static -IF_DESKTOP(long long) int FAST_FUNC unpack_unlzma(transformer_state_t *xstate) -{ - return unpack_lzma_stream(xstate, STDIN_FILENO, STDOUT_FILENO); -} int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int unlzma_main(int argc UNUSED_PARAM, char **argv) { @@ -513,7 +495,7 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv) option_mask32 |= OPT_STDOUT; argv += optind; - return bbunpack(argv, unpack_unlzma, make_new_name_generic, "lzma"); + return bbunpack(argv, unpack_lzma_stream, make_new_name_generic, "lzma"); } #endif @@ -537,11 +519,6 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv) //applet:IF_XZ(APPLET_ODDNAME(xz, unxz, BB_DIR_USR_BIN, BB_SUID_DROP, xz)) //kbuild:lib-$(CONFIG_UNXZ) += bbunzip.o #if ENABLE_UNXZ -static -IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(transformer_state_t *xstate) -{ - return unpack_xz_stream(xstate, STDIN_FILENO, STDOUT_FILENO); -} int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int unxz_main(int argc UNUSED_PARAM, char **argv) { @@ -556,6 +533,6 @@ int unxz_main(int argc UNUSED_PARAM, char **argv) option_mask32 |= OPT_STDOUT; argv += optind; - return bbunpack(argv, unpack_unxz, make_new_name_generic, "xz"); + return bbunpack(argv, unpack_xz_stream, make_new_name_generic, "xz"); } #endif diff --git a/archival/libarchive/decompress_bunzip2.c b/archival/libarchive/decompress_bunzip2.c index 36237e221..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) /* Decompress src_fd to dst_fd. Stops at end of bzip data, not end of file. */ IF_DESKTOP(long long) int FAST_FUNC -unpack_bz2_stream(transformer_state_t *xstate, int src_fd, int dst_fd) +unpack_bz2_stream(transformer_state_t *xstate) { IF_DESKTOP(long long total_written = 0;) bunzip_data *bd; @@ -739,14 +739,14 @@ unpack_bz2_stream(transformer_state_t *xstate, int src_fd, int dst_fd) int i; unsigned len; - if (check_signature16(xstate, src_fd, BZIP2_MAGIC)) + if (check_signature16(xstate, BZIP2_MAGIC)) return -1; outbuf = xmalloc(IOBUF_SIZE); len = 0; while (1) { /* "Process one BZ... stream" loop */ - i = start_bunzip(&bd, src_fd, outbuf + 2, len); + i = start_bunzip(&bd, xstate->src_fd, outbuf + 2, len); if (i == 0) { while (1) { /* "Produce some output bytes" loop */ @@ -756,8 +756,7 @@ unpack_bz2_stream(transformer_state_t *xstate, int src_fd, int dst_fd) i = IOBUF_SIZE - i; /* number of bytes produced */ if (i == 0) /* EOF? */ break; - if (i != full_write(dst_fd, outbuf, i)) { - bb_error_msg("short write"); + if (i != transformer_write(xstate, outbuf, i)) { i = RETVAL_SHORT_WRITE; goto release_mem; } @@ -790,7 +789,7 @@ unpack_bz2_stream(transformer_state_t *xstate, int src_fd, int dst_fd) len = bd->inbufCount - bd->inbufPos; memcpy(outbuf, &bd->inbuf[bd->inbufPos], len); if (len < 2) { - if (safe_read(src_fd, outbuf + len, 2 - len) != 2 - len) + if (safe_read(xstate->src_fd, outbuf + len, 2 - len) != 2 - len) break; len = 2; } diff --git a/archival/libarchive/decompress_gunzip.c b/archival/libarchive/decompress_gunzip.c index 62a3d78b6..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) /* Called from unpack_gz_stream() and inflate_unzip() */ static IF_DESKTOP(long long) int -inflate_unzip_internal(STATE_PARAM int in, int out) +inflate_unzip_internal(STATE_PARAM transformer_state_t *xstate) { IF_DESKTOP(long long) int n = 0; ssize_t nwrote; @@ -980,7 +980,7 @@ inflate_unzip_internal(STATE_PARAM int in, int out) gunzip_window = xmalloc(GUNZIP_WSIZE); gunzip_outbuf_count = 0; gunzip_bytes_out = 0; - gunzip_src_fd = in; + gunzip_src_fd = xstate->src_fd; /* (re) initialize state */ method = -1; @@ -1002,9 +1002,8 @@ inflate_unzip_internal(STATE_PARAM int in, int out) while (1) { int r = inflate_get_next_window(PASS_STATE_ONLY); - nwrote = full_write(out, gunzip_window, gunzip_outbuf_count); - if (nwrote != (ssize_t)gunzip_outbuf_count) { - bb_perror_msg("write"); + nwrote = transformer_write(xstate, gunzip_window, gunzip_outbuf_count); + if (nwrote == (ssize_t)-1) { n = -1; goto ret; } @@ -1034,7 +1033,7 @@ inflate_unzip_internal(STATE_PARAM int in, int out) /* For unzip */ IF_DESKTOP(long long) int FAST_FUNC -inflate_unzip(transformer_state_t *xstate, int in, int out) +inflate_unzip(transformer_state_t *xstate) { IF_DESKTOP(long long) int n; DECLARE_STATE; @@ -1045,7 +1044,7 @@ inflate_unzip(transformer_state_t *xstate, int in, int out) // bytebuffer_max = 0x8000; bytebuffer_offset = 4; bytebuffer = xmalloc(bytebuffer_max); - n = inflate_unzip_internal(PASS_STATE in, out); + n = inflate_unzip_internal(PASS_STATE xstate); free(bytebuffer); xstate->crc32 = gunzip_crc; @@ -1169,8 +1168,7 @@ static int check_header_gzip(STATE_PARAM transformer_state_t *xstate) } } - if (xstate) - xstate->mtime = SWAP_LE32(header.formatted.mtime); + xstate->mtime = SWAP_LE32(header.formatted.mtime); /* Read the header checksum */ if (header.formatted.flags & 0x02) { @@ -1182,27 +1180,27 @@ static int check_header_gzip(STATE_PARAM transformer_state_t *xstate) } IF_DESKTOP(long long) int FAST_FUNC -unpack_gz_stream(transformer_state_t *xstate, int src_fd, int dst_fd) +unpack_gz_stream(transformer_state_t *xstate) { uint32_t v32; IF_DESKTOP(long long) int total, n; DECLARE_STATE; #if !ENABLE_FEATURE_SEAMLESS_Z - if (check_signature16(xstate, src_fd, GZIP_MAGIC)) + if (check_signature16(xstate, GZIP_MAGIC)) return -1; #else - if (xstate && xstate->check_signature) { + if (xstate->check_signature) { uint16_t magic2; - if (full_read(src_fd, &magic2, 2) != 2) { + if (full_read(xstate->src_fd, &magic2, 2) != 2) { bad_magic: bb_error_msg("invalid magic"); return -1; } if (magic2 == COMPRESS_MAGIC) { xstate->check_signature = 0; - return unpack_Z_stream(xstate, src_fd, dst_fd); + return unpack_Z_stream(xstate); } if (magic2 != GZIP_MAGIC) goto bad_magic; @@ -1215,7 +1213,7 @@ unpack_gz_stream(transformer_state_t *xstate, int src_fd, int dst_fd) to_read = -1; // bytebuffer_max = 0x8000; bytebuffer = xmalloc(bytebuffer_max); - gunzip_src_fd = src_fd; + gunzip_src_fd = xstate->src_fd; again: if (!check_header_gzip(PASS_STATE xstate)) { @@ -1224,7 +1222,7 @@ unpack_gz_stream(transformer_state_t *xstate, int src_fd, int dst_fd) goto ret; } - n = inflate_unzip_internal(PASS_STATE src_fd, dst_fd); + n = inflate_unzip_internal(PASS_STATE xstate); if (n < 0) { total = -1; goto ret; diff --git a/archival/libarchive/decompress_uncompress.c b/archival/libarchive/decompress_uncompress.c index cb3d55a88..496d864a7 100644 --- a/archival/libarchive/decompress_uncompress.c +++ b/archival/libarchive/decompress_uncompress.c @@ -73,7 +73,7 @@ */ IF_DESKTOP(long long) int FAST_FUNC -unpack_Z_stream(transformer_state_t *xstate, int src_fd, int dst_fd) +unpack_Z_stream(transformer_state_t *xstate) { IF_DESKTOP(long long total_written = 0;) IF_DESKTOP(long long) int retval = -1; @@ -102,7 +102,7 @@ unpack_Z_stream(transformer_state_t *xstate, int src_fd, int dst_fd) /* block compress mode -C compatible with 2.0 */ int block_mode; /* = BLOCK_MODE; */ - if (check_signature16(xstate, src_fd, COMPRESS_MAGIC)) + if (check_signature16(xstate, COMPRESS_MAGIC)) return -1; inbuf = xzalloc(IBUFSIZ + 64); @@ -114,7 +114,7 @@ unpack_Z_stream(transformer_state_t *xstate, int src_fd, int dst_fd) /* xread isn't good here, we have to return - caller may want * to do some cleanup (e.g. delete incomplete unpacked file etc) */ - if (full_read(src_fd, inbuf, 1) != 1) { + if (full_read(xstate->src_fd, inbuf, 1) != 1) { bb_error_msg("short read"); goto err; } @@ -166,7 +166,7 @@ unpack_Z_stream(transformer_state_t *xstate, int src_fd, int dst_fd) } if (insize < (int) (IBUFSIZ + 64) - IBUFSIZ) { - rsize = safe_read(src_fd, inbuf + insize, IBUFSIZ); + rsize = safe_read(xstate->src_fd, inbuf + insize, IBUFSIZ); if (rsize < 0) bb_error_msg_and_die(bb_msg_read_error); insize += rsize; @@ -274,7 +274,7 @@ unpack_Z_stream(transformer_state_t *xstate, int src_fd, int dst_fd) } if (outpos >= OBUFSIZ) { - xwrite(dst_fd, outbuf, outpos); + xtransformer_write(xstate, outbuf, outpos); IF_DESKTOP(total_written += outpos;) outpos = 0; } @@ -301,7 +301,7 @@ unpack_Z_stream(transformer_state_t *xstate, int src_fd, int dst_fd) } while (rsize > 0); if (outpos > 0) { - xwrite(dst_fd, outbuf, outpos); + xtransformer_write(xstate, outbuf, outpos); IF_DESKTOP(total_written += outpos;) } diff --git a/archival/libarchive/decompress_unlzma.c b/archival/libarchive/decompress_unlzma.c index ccedac49d..c8622f97b 100644 --- a/archival/libarchive/decompress_unlzma.c +++ b/archival/libarchive/decompress_unlzma.c @@ -206,7 +206,7 @@ enum { IF_DESKTOP(long long) int FAST_FUNC -unpack_lzma_stream(transformer_state_t *xstate UNUSED_PARAM, int src_fd, int dst_fd) +unpack_lzma_stream(transformer_state_t *xstate) { IF_DESKTOP(long long total_written = 0;) lzma_header_t header; @@ -223,7 +223,7 @@ unpack_lzma_stream(transformer_state_t *xstate UNUSED_PARAM, int src_fd, int dst int state = 0; uint32_t rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1; - if (full_read(src_fd, &header, sizeof(header)) != sizeof(header) + if (full_read(xstate->src_fd, &header, sizeof(header)) != sizeof(header) || header.pos >= (9 * 5 * 5) ) { bb_error_msg("bad lzma header"); @@ -258,7 +258,7 @@ unpack_lzma_stream(transformer_state_t *xstate UNUSED_PARAM, int src_fd, int dst p[i] = (1 << RC_MODEL_TOTAL_BITS) >> 1; } - rc = rc_init(src_fd); /*, RC_BUFFER_SIZE); */ + rc = rc_init(xstate->src_fd); /*, RC_BUFFER_SIZE); */ while (global_pos + buffer_pos < header.dst_size) { int pos_state = (buffer_pos + global_pos) & pos_state_mask; @@ -306,7 +306,7 @@ unpack_lzma_stream(transformer_state_t *xstate UNUSED_PARAM, int src_fd, int dst if (buffer_pos == header.dict_size) { buffer_pos = 0; global_pos += header.dict_size; - if (full_write(dst_fd, buffer, header.dict_size) != (ssize_t)header.dict_size) + if (transformer_write(xstate, buffer, header.dict_size) != (ssize_t)header.dict_size) goto bad; IF_DESKTOP(total_written += header.dict_size;) } @@ -440,7 +440,7 @@ unpack_lzma_stream(transformer_state_t *xstate UNUSED_PARAM, int src_fd, int dst if (buffer_pos == header.dict_size) { buffer_pos = 0; global_pos += header.dict_size; - if (full_write(dst_fd, buffer, header.dict_size) != (ssize_t)header.dict_size) + if (transformer_write(xstate, buffer, header.dict_size) != (ssize_t)header.dict_size) goto bad; IF_DESKTOP(total_written += header.dict_size;) } @@ -455,7 +455,7 @@ unpack_lzma_stream(transformer_state_t *xstate UNUSED_PARAM, int src_fd, int dst { IF_NOT_DESKTOP(int total_written = 0; /* success */) IF_DESKTOP(total_written += buffer_pos;) - if (full_write(dst_fd, buffer, buffer_pos) != (ssize_t)buffer_pos) { + if (transformer_write(xstate, buffer, buffer_pos) != (ssize_t)buffer_pos) { bad: total_written = -1; /* failure */ } diff --git a/archival/libarchive/decompress_unxz.c b/archival/libarchive/decompress_unxz.c index 6df54e131..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) #include "unxz/xz_dec_stream.c" IF_DESKTOP(long long) int FAST_FUNC -unpack_xz_stream(transformer_state_t *xstate, int src_fd, int dst_fd) +unpack_xz_stream(transformer_state_t *xstate) { enum xz_ret xz_result; struct xz_buf iobuf; @@ -67,7 +67,7 @@ unpack_xz_stream(transformer_state_t *xstate, int src_fd, int dst_fd) xz_result = X_OK; while (1) { if (iobuf.in_pos == iobuf.in_size) { - int rd = safe_read(src_fd, membuf, BUFSIZ); + int rd = safe_read(xstate->src_fd, membuf, BUFSIZ); if (rd < 0) { bb_error_msg(bb_msg_read_error); total = -1; @@ -104,7 +104,7 @@ unpack_xz_stream(transformer_state_t *xstate, int src_fd, int dst_fd) // bb_error_msg("seek = seek_by_read; - open_transformer_with_sig(archive_handle->src_fd, unpack_bz2_stream, "bunzip2"); + fork_transformer_with_sig(archive_handle->src_fd, unpack_bz2_stream, "bunzip2"); archive_handle->offset = 0; while (get_header_tar(archive_handle) == EXIT_SUCCESS) 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) /* Can't lseek over pipes */ archive_handle->seek = seek_by_read; - open_transformer_with_sig(archive_handle->src_fd, unpack_gz_stream, "gunzip"); + fork_transformer_with_sig(archive_handle->src_fd, unpack_gz_stream, "gunzip"); archive_handle->offset = 0; while (get_header_tar(archive_handle) == EXIT_SUCCESS) 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) /* Can't lseek over pipes */ archive_handle->seek = seek_by_read; - open_transformer_with_sig(archive_handle->src_fd, unpack_lzma_stream, "unlzma"); + fork_transformer_with_sig(archive_handle->src_fd, unpack_lzma_stream, "unlzma"); archive_handle->offset = 0; while (get_header_tar(archive_handle) == EXIT_SUCCESS) continue; diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c index 584b15de4..9d762a859 100644 --- a/archival/libarchive/open_transformer.c +++ b/archival/libarchive/open_transformer.c @@ -11,11 +11,11 @@ void FAST_FUNC init_transformer_state(transformer_state_t *xstate) memset(xstate, 0, sizeof(*xstate)); } -int FAST_FUNC check_signature16(transformer_state_t *xstate, int src_fd, unsigned magic16) +int FAST_FUNC check_signature16(transformer_state_t *xstate, unsigned magic16) { - if (xstate && xstate->check_signature) { + if (xstate->check_signature) { uint16_t magic2; - if (full_read(src_fd, &magic2, 2) != 2 || magic2 != magic16) { + if (full_read(xstate->src_fd, &magic2, 2) != 2 || magic2 != magic16) { bb_error_msg("invalid magic"); #if 0 /* possible future extension */ if (xstate->check_signature > 1) @@ -27,6 +27,46 @@ int FAST_FUNC check_signature16(transformer_state_t *xstate, int src_fd, unsigne return 0; } +ssize_t FAST_FUNC transformer_write(transformer_state_t *xstate, const void *buf, size_t bufsize) +{ + ssize_t nwrote; + + if (xstate->mem_output_size_max != 0) { + size_t pos = xstate->mem_output_size; + size_t size; + + size = (xstate->mem_output_size += bufsize); + if (size > xstate->mem_output_size_max) { + free(xstate->mem_output_buf); + xstate->mem_output_buf = NULL; + bb_perror_msg("buffer %u too small", (unsigned)xstate->mem_output_size_max); + nwrote = -1; + goto ret; + } + xstate->mem_output_buf = xrealloc(xstate->mem_output_buf, size); + memcpy(xstate->mem_output_buf + pos, buf, bufsize); + nwrote = bufsize; + } else { + nwrote = full_write(xstate->dst_fd, buf, bufsize); + if (nwrote != (ssize_t)bufsize) { + bb_perror_msg("write"); + nwrote = -1; + goto ret; + } + } + ret: + return nwrote; +} + +ssize_t FAST_FUNC xtransformer_write(transformer_state_t *xstate, const void *buf, size_t bufsize) +{ + ssize_t nwrote = transformer_write(xstate, buf, bufsize); + if (nwrote != (ssize_t)bufsize) { + xfunc_die(); + } + return nwrote; +} + void check_errors_in_children(int signo) { int status; @@ -60,12 +100,12 @@ void check_errors_in_children(int signo) /* transformer(), more than meets the eye */ #if BB_MMU -void FAST_FUNC open_transformer(int fd, +void FAST_FUNC fork_transformer(int fd, int check_signature, - IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_state_t *xstate, int src_fd, int dst_fd) + IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_state_t *xstate) ) #else -void FAST_FUNC open_transformer(int fd, const char *transform_prog) +void FAST_FUNC fork_transformer(int fd, const char *transform_prog) #endif { struct fd_pair fd_pipe; @@ -83,7 +123,9 @@ void FAST_FUNC open_transformer(int fd, const char *transform_prog) transformer_state_t xstate; init_transformer_state(&xstate); xstate.check_signature = check_signature; - r = transformer(&xstate, fd, fd_pipe.wr); + xstate.src_fd = fd; + xstate.dst_fd = fd_pipe.wr; + r = transformer(&xstate); if (ENABLE_FEATURE_CLEAN_UP) { close(fd_pipe.wr); /* send EOF */ close(fd); @@ -118,16 +160,19 @@ void FAST_FUNC open_transformer(int fd, const char *transform_prog) /* Used by e.g. rpm which gives us a fd without filename, * thus we can't guess the format from filename's extension. */ -int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed) +static transformer_state_t *setup_transformer_on_fd(int fd, int fail_if_not_compressed) { union { uint8_t b[4]; uint16_t b16[2]; uint32_t b32[1]; } magic; - int offset = -2; - USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_state_t *xstate, int src_fd, int dst_fd);) - USE_FOR_NOMMU(const char *xformer_prog;) + int offset; + transformer_state_t *xstate; + + offset = -2; + xstate = xzalloc(sizeof(*xstate)); + xstate->src_fd = fd; /* .gz and .bz2 both have 2-byte signature, and their * unpack_XXX_stream wants this header skipped. */ @@ -135,15 +180,15 @@ int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed) if (ENABLE_FEATURE_SEAMLESS_GZ && magic.b16[0] == GZIP_MAGIC ) { - USE_FOR_MMU(xformer = unpack_gz_stream;) - USE_FOR_NOMMU(xformer_prog = "gunzip";) + xstate->xformer = unpack_gz_stream; + USE_FOR_NOMMU(xstate->xformer_prog = "gunzip";) goto found_magic; } if (ENABLE_FEATURE_SEAMLESS_BZ2 && magic.b16[0] == BZIP2_MAGIC ) { - USE_FOR_MMU(xformer = unpack_bz2_stream;) - USE_FOR_NOMMU(xformer_prog = "bunzip2";) + xstate->xformer = unpack_bz2_stream; + USE_FOR_NOMMU(xstate->xformer_prog = "bunzip2";) goto found_magic; } if (ENABLE_FEATURE_SEAMLESS_XZ @@ -152,8 +197,8 @@ int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed) offset = -6; xread(fd, magic.b32, sizeof(magic.b32[0])); if (magic.b32[0] == XZ_MAGIC2) { - USE_FOR_MMU(xformer = unpack_xz_stream;) - USE_FOR_NOMMU(xformer_prog = "unxz";) + xstate->xformer = unpack_xz_stream; + USE_FOR_NOMMU(xstate->xformer_prog = "unxz";) goto found_magic; } } @@ -164,52 +209,130 @@ int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed) IF_FEATURE_SEAMLESS_BZ2("/bzip2") IF_FEATURE_SEAMLESS_XZ("/xz") " magic"); + + /* Some callers expect this function to "consume" fd + * even if data is not compressed. In this case, + * we return a state with trivial transformer. + */ +// USE_FOR_MMU(xstate->xformer = copy_stream;) +// USE_FOR_NOMMU(xstate->xformer_prog = "cat";) + /* fall through to seeking bck over bytes we read earlier */ + + USE_FOR_NOMMU(found_magic:) + /* NOMMU version of fork_transformer execs + * an external unzipper that wants + * file position at the start of the file. + */ xlseek(fd, offset, SEEK_CUR); - return 1; - found_magic: + USE_FOR_MMU(found_magic:) + /* In MMU case, if magic was found, seeking back is not necessary */ + + return xstate; +} + +/* Used by e.g. rpm which gives us a fd without filename, + * thus we can't guess the format from filename's extension. + */ +int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed) +{ + transformer_state_t *xstate = setup_transformer_on_fd(fd, fail_if_not_compressed); + + if (!xstate || !xstate->xformer) { + free(xstate); + return 1; + } + # if BB_MMU - open_transformer_with_no_sig(fd, xformer); + fork_transformer_with_no_sig(xstate->src_fd, xstate->xformer); # else - /* NOMMU version of open_transformer execs - * an external unzipper that wants - * file position at the start of the file */ - xlseek(fd, offset, SEEK_CUR); - open_transformer_with_sig(fd, xformer, xformer_prog); + fork_transformer_with_sig(xstate->src_fd, xstate->xformer, xstate->xformer_prog); # endif + free(xstate); return 0; } -int FAST_FUNC open_zipped(const char *fname, int fail_if_not_compressed) +static transformer_state_t *open_transformer(const char *fname, int fail_if_not_compressed) { + transformer_state_t *xstate; int fd; fd = open(fname, O_RDONLY); if (fd < 0) - return fd; + return NULL; if (ENABLE_FEATURE_SEAMLESS_LZMA) { /* .lzma has no header/signature, can only detect it by extension */ char *sfx = strrchr(fname, '.'); if (sfx && strcmp(sfx+1, "lzma") == 0) { - open_transformer_with_sig(fd, unpack_lzma_stream, "unlzma"); - return fd; + xstate = xzalloc(sizeof(*xstate)); + xstate->src_fd = fd; + xstate->xformer = unpack_lzma_stream; + USE_FOR_NOMMU(xstate->xformer_prog = "unlzma";) + return xstate; } } - if ((ENABLE_FEATURE_SEAMLESS_GZ) - || (ENABLE_FEATURE_SEAMLESS_BZ2) - || (ENABLE_FEATURE_SEAMLESS_XZ) - ) { - setup_unzip_on_fd(fd, fail_if_not_compressed); + + xstate = setup_transformer_on_fd(fd, fail_if_not_compressed); + + return xstate; +} + +int FAST_FUNC open_zipped(const char *fname, int fail_if_not_compressed) +{ + int fd; + transformer_state_t *xstate; + + xstate = open_transformer(fname, fail_if_not_compressed); + if (!xstate) + return -1; + + fd = xstate->src_fd; + if (xstate->xformer) { +# if BB_MMU + fork_transformer_with_no_sig(xstate->src_fd, xstate->xformer); +# else + fork_transformer_with_sig(xstate->src_fd, xstate->xformer, xstate->xformer_prog); +# endif } + /* else: the file is not compressed */ + free(xstate); return fd; } -#endif /* SEAMLESS_COMPRESSION */ - void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) { +# if 1 + transformer_state_t *xstate; + char *image; + + xstate = open_transformer(fname, /*fail_if_not_compressed:*/ 0); + if (!xstate) /* file open error */ + return NULL; + + image = NULL; + if (xstate->xformer) { + /* In-memory decompression */ + xstate->mem_output_size_max = maxsz_p ? *maxsz_p : (size_t)(INT_MAX - 4095); + xstate->xformer(xstate); + if (xstate->mem_output_buf) { + image = xstate->mem_output_buf; + if (maxsz_p) + *maxsz_p = xstate->mem_output_size; + } + } else { + /* File is not compressed */ + image = xmalloc_read(xstate->src_fd, maxsz_p); + } + + if (!image) + bb_perror_msg("read error from '%s'", fname); + close(xstate->src_fd); + free(xstate); + return image; +# else + /* This version forks a subprocess - much more expensive */ int fd; char *image; @@ -221,6 +344,8 @@ void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_ if (!image) bb_perror_msg("read error from '%s'", fname); close(fd); - return image; +# endif } + +#endif /* SEAMLESS_COMPRESSION */ diff --git a/archival/tar.c b/archival/tar.c index 7897a4af6..5bd473aac 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -1171,7 +1171,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) } if (opt & OPT_ANY_COMPRESS) { - USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_state_t *xstate, int src_fd, int dst_fd);) + USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_state_t *xstate);) USE_FOR_NOMMU(const char *xformer_prog;) if (opt & OPT_COMPRESS) @@ -1190,7 +1190,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) USE_FOR_MMU(xformer = unpack_xz_stream;) USE_FOR_NOMMU(xformer_prog = "unxz";) - open_transformer_with_sig(tar_handle->src_fd, xformer, xformer_prog); + fork_transformer_with_sig(tar_handle->src_fd, xformer, xformer_prog); /* Can't lseek over pipes */ tar_handle->seek = seek_by_read; /*tar_handle->offset = 0; - already is */ diff --git a/archival/unzip.c b/archival/unzip.c index c622bde57..38a07e212 100644 --- a/archival/unzip.c +++ b/archival/unzip.c @@ -283,7 +283,9 @@ static void unzip_extract(zip_header_t *zip_header, int dst_fd) transformer_state_t xstate; init_transformer_state(&xstate); xstate.bytes_in = zip_header->formatted.cmpsize; - if (inflate_unzip(&xstate, zip_fd, dst_fd) < 0) + xstate.src_fd = zip_fd; + xstate.dst_fd = dst_fd; + if (inflate_unzip(&xstate) < 0) bb_error_msg_and_die("inflate error"); /* Validate decompression - crc */ if (zip_header->formatted.crc32 != (xstate.crc32 ^ 0xffffffffL)) { diff --git a/include/bb_archive.h b/include/bb_archive.h index 8a2dd2735..a6b166fe3 100644 --- a/include/bb_archive.h +++ b/include/bb_archive.h @@ -205,6 +205,18 @@ void dealloc_bunzip(bunzip_data *bd) FAST_FUNC; /* Meaning and direction (input/output) of the fields are transformer-specific */ typedef struct transformer_state_t { smallint check_signature; /* most often referenced member */ + + IF_DESKTOP(long long) int FAST_FUNC (*xformer)(struct transformer_state_t *xstate); + USE_FOR_NOMMU(const char *xformer_prog;) + + /* Source */ + int src_fd; + /* Output */ + int dst_fd; + size_t mem_output_size_max; /* if non-zero, decompress to RAM instead of fd */ + size_t mem_output_size; + char *mem_output_buf; + off_t bytes_out; off_t bytes_in; /* used in unzip code only: needs to know packed size */ uint32_t crc32; @@ -212,14 +224,16 @@ typedef struct transformer_state_t { } transformer_state_t; void init_transformer_state(transformer_state_t *xstate) FAST_FUNC; -int FAST_FUNC check_signature16(transformer_state_t *xstate, int src_fd, unsigned magic16) FAST_FUNC; +ssize_t transformer_write(transformer_state_t *xstate, const void *buf, size_t bufsize) FAST_FUNC; +ssize_t xtransformer_write(transformer_state_t *xstate, const void *buf, size_t bufsize) FAST_FUNC; +int check_signature16(transformer_state_t *xstate, unsigned magic16) FAST_FUNC; -IF_DESKTOP(long long) int inflate_unzip(transformer_state_t *xstate, int src_fd, int dst_fd) FAST_FUNC; -IF_DESKTOP(long long) int unpack_Z_stream(transformer_state_t *xstate, int src_fd, int dst_fd) FAST_FUNC; -IF_DESKTOP(long long) int unpack_gz_stream(transformer_state_t *xstate, int src_fd, int dst_fd) FAST_FUNC; -IF_DESKTOP(long long) int unpack_bz2_stream(transformer_state_t *xstate, int src_fd, int dst_fd) FAST_FUNC; -IF_DESKTOP(long long) int unpack_lzma_stream(transformer_state_t *xstate, int src_fd, int dst_fd) FAST_FUNC; -IF_DESKTOP(long long) int unpack_xz_stream(transformer_state_t *xstate, int src_fd, int dst_fd) FAST_FUNC; +IF_DESKTOP(long long) int inflate_unzip(transformer_state_t *xstate) FAST_FUNC; +IF_DESKTOP(long long) int unpack_Z_stream(transformer_state_t *xstate) FAST_FUNC; +IF_DESKTOP(long long) int unpack_gz_stream(transformer_state_t *xstate) FAST_FUNC; +IF_DESKTOP(long long) int unpack_bz2_stream(transformer_state_t *xstate) FAST_FUNC; +IF_DESKTOP(long long) int unpack_lzma_stream(transformer_state_t *xstate) FAST_FUNC; +IF_DESKTOP(long long) int unpack_xz_stream(transformer_state_t *xstate) FAST_FUNC; char* append_ext(char *filename, const char *expected_ext) FAST_FUNC; int bbunpack(char **argv, @@ -230,16 +244,16 @@ int bbunpack(char **argv, void check_errors_in_children(int signo); #if BB_MMU -void open_transformer(int fd, +void fork_transformer(int fd, int check_signature, - IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_state_t *xstate, int src_fd, int dst_fd) + IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_state_t *xstate) ) FAST_FUNC; -#define open_transformer_with_sig(fd, transformer, transform_prog) open_transformer((fd), 1, (transformer)) -#define open_transformer_with_no_sig(fd, transformer) open_transformer((fd), 0, (transformer)) +#define fork_transformer_with_sig(fd, transformer, transform_prog) fork_transformer((fd), 1, (transformer)) +#define fork_transformer_with_no_sig(fd, transformer) fork_transformer((fd), 0, (transformer)) #else -void open_transformer(int fd, const char *transform_prog) FAST_FUNC; -#define open_transformer_with_sig(fd, transformer, transform_prog) open_transformer((fd), (transform_prog)) -/* open_transformer_with_no_sig() does not exist on NOMMU */ +void fork_transformer(int fd, const char *transform_prog) FAST_FUNC; +#define fork_transformer_with_sig(fd, transformer, transform_prog) fork_transformer((fd), (transform_prog)) +/* fork_transformer_with_no_sig() does not exist on NOMMU */ #endif diff --git a/include/libbb.h b/include/libbb.h index 17a0089d8..8e8b9ca0e 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -755,11 +755,12 @@ unsigned bb_clk_tck(void) FAST_FUNC; extern int setup_unzip_on_fd(int fd, int fail_if_not_compressed) FAST_FUNC; /* Autodetects .gz etc */ extern int open_zipped(const char *fname, int fail_if_not_compressed) FAST_FUNC; +extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; #else # define setup_unzip_on_fd(...) (0) # define open_zipped(fname, fail_if_not_compressed) open((fname), O_RDONLY); +# define xmalloc_open_zipped_read_close(fname, maxsz_p) xmalloc_open_read_close((fname), (maxsz_p)) #endif -extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; extern ssize_t safe_write(int fd, const void *buf, size_t count) FAST_FUNC; // NB: will return short write on error, not -1, -- cgit v1.2.3-55-g6feb From cfcd2399b20998a374ad52a5fac353f77e6ec0f6 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 7 Dec 2014 00:49:55 +0100 Subject: make xmalloc_open_zipped_read_close result NUL terminated Compat with xmalloc_open_read_close Signed-off-by: Denys Vlasenko --- archival/libarchive/open_transformer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c index 9d762a859..ab6aa3afc 100644 --- a/archival/libarchive/open_transformer.c +++ b/archival/libarchive/open_transformer.c @@ -43,8 +43,9 @@ ssize_t FAST_FUNC transformer_write(transformer_state_t *xstate, const void *buf nwrote = -1; goto ret; } - xstate->mem_output_buf = xrealloc(xstate->mem_output_buf, size); + xstate->mem_output_buf = xrealloc(xstate->mem_output_buf, size + 1); memcpy(xstate->mem_output_buf + pos, buf, bufsize); + xstate->mem_output_buf[size] = '\0'; nwrote = bufsize; } else { nwrote = full_write(xstate->dst_fd, buf, bufsize); -- cgit v1.2.3-55-g6feb From bd7c1f2d13cd1f7927ec081e4f23ee0f0b079e9a Mon Sep 17 00:00:00 2001 From: Jacob Kjaergaard Date: Wed, 10 Dec 2014 13:44:27 +0100 Subject: flashcp: change BUFSIZE to 4k some flash partitions can be smaller than the existing BUFSIZE thus write BUFSIZE will fail with "no space left on device" Signed-off-by: Jacob Kjaergaard Signed-off-by: Denys Vlasenko --- miscutils/flashcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 @@ #define OPT_v (1 << 0) -#define BUFSIZE (8 * 1024) +#define BUFSIZE (4 * 1024) static void progress(int mode, uoff_t count, uoff_t total) { -- cgit v1.2.3-55-g6feb From 202d9a646489ed3f15c0460d76776b3dfb1d4e72 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 10 Dec 2014 13:34:42 +0100 Subject: Config: select PLATFORM_LINUX if using sendfile() Man entry for sendfile: Not specified in POSIX.1-2001, or other standards. Other UNIX systems implement sendfile() with different semantics and prototypes. It should not be used in portable programs. Select PLATFORM_LINUX if enabling FEATURE_USE_SENDFILE. Signed-off-by: Bartosz Golaszewski Signed-off-by: Denys Vlasenko --- Config.in | 1 + 1 file changed, 1 insertion(+) diff --git a/Config.in b/Config.in index 285fe0a19..07b4bf36b 100644 --- a/Config.in +++ b/Config.in @@ -267,6 +267,7 @@ config PAM config FEATURE_USE_SENDFILE bool "Use sendfile system call" default y + select PLATFORM_LINUX help When enabled, busybox will use the kernel sendfile() function instead of read/write loops to copy data between file descriptors -- cgit v1.2.3-55-g6feb From d598a8d4e655b095c741f0cf73e139b3c9524da1 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 10 Dec 2014 17:22:13 +0100 Subject: lineedit: don't fall back to simple line input if tty is in raw mode Testcase: shell command input after python ^Z should still work Signed-off-by: Denys Vlasenko --- libbb/lineedit.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 85643079b..3961b1de3 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -2256,9 +2256,13 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman INIT_S(); if (tcgetattr(STDIN_FILENO, &initial_settings) < 0 - || !(initial_settings.c_lflag & ECHO) + || (initial_settings.c_lflag & (ECHO|ICANON)) == ICANON ) { - /* Happens when e.g. stty -echo was run before */ + /* Happens when e.g. stty -echo was run before. + * But if ICANON is not set, we don't come here. + * (example: interactive python ^Z-backgrounded, + * tty is still in "raw mode"). + */ parse_and_put_prompt(prompt); /* fflush_all(); - done by parse_and_put_prompt */ if (fgets(command, maxsize, stdin) == NULL) -- cgit v1.2.3-55-g6feb From acb8be721768b54075a51d1859d390904a0f1f6c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 11 Dec 2014 15:33:07 +0100 Subject: tar: fix "tar -cJ" ignoring -J option. closes 7706 function old new delta tar_main 895 938 +43 vfork_compressor 206 191 -15 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/1 up/down: 43/-15) Total: 28 bytes Signed-off-by: Denys Vlasenko --- archival/tar.c | 66 +++++++++++++++++++++++++--------------------------------- 1 file changed, 28 insertions(+), 38 deletions(-) diff --git a/archival/tar.c b/archival/tar.c index 5bd473aac..e116bd287 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -160,13 +160,6 @@ #define block_buf bb_common_bufsiz1 -#if !ENABLE_FEATURE_SEAMLESS_GZ && !ENABLE_FEATURE_SEAMLESS_BZ2 -/* Do not pass gzip flag to writeTarFile() */ -#define writeTarFile(tar_fd, verboseFlag, recurseFlags, include, exclude, gzip) \ - writeTarFile(tar_fd, verboseFlag, recurseFlags, include, exclude) -#endif - - #if ENABLE_FEATURE_TAR_CREATE /* @@ -621,21 +614,12 @@ static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statb return TRUE; } -#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 -# if !(ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2) -# define vfork_compressor(tar_fd, gzip) vfork_compressor(tar_fd) -# endif +#if SEAMLESS_COMPRESSION /* Don't inline: vfork scares gcc and pessimizes code */ -static void NOINLINE vfork_compressor(int tar_fd, int gzip) +static void NOINLINE vfork_compressor(int tar_fd, const char *gzip) { pid_t gzipPid; -# if ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2 - const char *zip_exec = (gzip == 1) ? "gzip" : "bzip2"; -# elif ENABLE_FEATURE_SEAMLESS_GZ - const char *zip_exec = "gzip"; -# else /* only ENABLE_FEATURE_SEAMLESS_BZ2 */ - const char *zip_exec = "bzip2"; -# endif + // On Linux, vfork never unpauses parent early, although standard // allows for that. Do we want to waste bytes checking for it? # define WAIT_FOR_CHILD 0 @@ -649,11 +633,6 @@ static void NOINLINE vfork_compressor(int tar_fd, int gzip) signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ -# if defined(__GNUC__) && __GNUC__ - /* Avoid vfork clobbering */ - (void) &zip_exec; -# endif - gzipPid = xvfork(); if (gzipPid == 0) { @@ -669,7 +648,7 @@ static void NOINLINE vfork_compressor(int tar_fd, int gzip) xmove_fd(gzipDataPipe.rd, 0); xmove_fd(tar_fd, 1); /* exec gzip/bzip2 program/applet */ - BB_EXECLP(zip_exec, zip_exec, "-f", (char *)0); + BB_EXECLP(gzip, gzip, "-f", (char *)0); vfork_exec_errno = errno; _exit(EXIT_FAILURE); } @@ -692,16 +671,21 @@ static void NOINLINE vfork_compressor(int tar_fd, int gzip) # endif if (vfork_exec_errno) { errno = vfork_exec_errno; - bb_perror_msg_and_die("can't execute '%s'", zip_exec); + bb_perror_msg_and_die("can't execute '%s'", gzip); } } -#endif /* ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 */ +#endif /* SEAMLESS_COMPRESSION */ +#if !SEAMLESS_COMPRESSION +/* Do not pass gzip flag to writeTarFile() */ +#define writeTarFile(tar_fd, verboseFlag, recurseFlags, include, exclude, gzip) \ + writeTarFile(tar_fd, verboseFlag, recurseFlags, include, exclude) +#endif /* gcc 4.2.1 inlines it, making code bigger */ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag, int recurseFlags, const llist_t *include, - const llist_t *exclude, int gzip) + const llist_t *exclude, const char *gzip) { int errorFlag = FALSE; struct TarBallInfo tbInfo; @@ -714,7 +698,7 @@ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag, * can avoid including the tarball into itself.... */ xfstat(tbInfo.tarFd, &tbInfo.tarFileStatBuf, "can't stat tar file"); -#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 +#if SEAMLESS_COMPRESSION if (gzip) vfork_compressor(tbInfo.tarFd, gzip); #endif @@ -749,7 +733,7 @@ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag, if (errorFlag) bb_error_msg("error exit delayed from previous errors"); -#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 +#if SEAMLESS_COMPRESSION if (gzip) { int status; if (safe_waitpid(-1, &status, 0) == -1) @@ -764,7 +748,7 @@ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag, #else int writeTarFile(int tar_fd, int verboseFlag, int recurseFlags, const llist_t *include, - const llist_t *exclude, int gzip); + const llist_t *exclude, const char *gzip); #endif /* FEATURE_TAR_CREATE */ #if ENABLE_FEATURE_TAR_FROM @@ -1149,18 +1133,24 @@ int tar_main(int argc UNUSED_PARAM, char **argv) if (base_dir) xchdir(base_dir); - //if (SEAMLESS_COMPRESSION || OPT_COMPRESS) + //if (SEAMLESS_COMPRESSION) // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ // signal(SIGCHLD, check_errors_in_children); /* Create an archive */ if (opt & OPT_CREATE) { -#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 - int zipMode = 0; - if (ENABLE_FEATURE_SEAMLESS_GZ && (opt & OPT_GZIP)) - zipMode = 1; - if (ENABLE_FEATURE_SEAMLESS_BZ2 && (opt & OPT_BZIP2)) - zipMode = 2; +#if SEAMLESS_COMPRESSION + const char *zipMode = NULL; + if (opt & OPT_COMPRESS) + zipMode = "compress"; + if (opt & OPT_GZIP) + zipMode = "gzip"; + if (opt & OPT_BZIP2) + zipMode = "bzip2"; + if (opt & OPT_LZMA) + zipMode = "lzma"; + if (opt & OPT_XZ) + zipMode = "xz"; #endif /* NB: writeTarFile() closes tar_handle->src_fd */ return writeTarFile(tar_handle->src_fd, verboseFlag, -- cgit v1.2.3-55-g6feb