From 2017d48c0d70bef8768efb42909e605ea8eb5a21 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 5 Nov 2011 01:24:14 +0100 Subject: udhcpc: deprecate --hostname NAME Signed-off-by: Denys Vlasenko --- networking/udhcp/dhcpc.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index 3d4c397ff..d0fe94a48 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -29,7 +29,7 @@ #include #include -/* struct client_config_t client_config is in bb_common_bufsiz1 */ +/* "struct client_config_t client_config" is in bb_common_bufsiz1 */ #if ENABLE_LONG_OPTS @@ -598,6 +598,12 @@ static void add_client_options(struct dhcp_packet *packet) // if (client_config.boot_file) // strncpy((char*)packet->file, client_config.boot_file, sizeof(packet->file) - 1); } + + // This will be needed if we remove -V VENDOR_STR in favor of + // -x vendor:VENDOR_STR + //if (!udhcp_find_option(packet.options, DHCP_VENDOR)) + // /* not set, set the default vendor ID */ + // ...add (DHCP_VENDOR, "udhcp "BB_VER) opt... } /* RFC 2131 @@ -1086,7 +1092,6 @@ static void client_background(void) //usage: "\n -x lease:3600 - option 51 (lease time)" //usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)" //usage: "\n -F,--fqdn NAME Ask server to update DNS mapping for NAME" -//usage: "\n -H,-h,--hostname NAME Send NAME as client hostname (default none)" //usage: "\n -V,--vendorclass VENDOR Vendor identifier (default 'udhcp VERSION')" //usage: "\n -C,--clientid-none Don't send MAC as client identifier" //usage: IF_UDHCP_VERBOSE( @@ -1124,7 +1129,6 @@ static void client_background(void) //usage: "\n -x lease:3600 - option 51 (lease time)" //usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)" //usage: "\n -F NAME Ask server to update DNS mapping for NAME" -//usage: "\n -H,-h NAME Send NAME as client hostname (default none)" //usage: "\n -V VENDOR Vendor identifier (default 'udhcp VERSION')" //usage: "\n -C Don't send MAC as client identifier" //usage: IF_UDHCP_VERBOSE( @@ -1187,8 +1191,11 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) IF_FEATURE_UDHCP_PORT(, &str_P) IF_UDHCP_VERBOSE(, &dhcp_verbose) ); - if (opt & (OPT_h|OPT_H)) + if (opt & (OPT_h|OPT_H)) { + //msg added 2011-11 + bb_error_msg("option -h NAME is deprecated, use -x hostname:NAME"); client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0); + } if (opt & OPT_F) { /* FQDN option format: [0x51][len][flags][0][0] */ client_config.fqdn = alloc_dhcp_option(DHCP_FQDN, str_F, 3); @@ -1249,8 +1256,16 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) clientid_mac_ptr = client_config.clientid + OPT_DATA+1; memcpy(clientid_mac_ptr, client_config.client_mac, 6); } - if (str_V[0] != '\0') + if (str_V[0] != '\0') { + // can drop -V, str_V, client_config.vendorclass, + // but need to add "vendor" to the list of recognized + // string opts for this to work; + // and need to tweak add_client_options() too... + // ...so the question is, should we? + //bb_error_msg("option -V VENDOR is deprecated, use -x vendor:VENDOR"); client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0); + } + #if !BB_MMU /* on NOMMU reexec (i.e., background) early */ if (!(opt & OPT_f)) { -- cgit v1.2.3-55-g6feb From d38ca03946000f0837e9a0e04937499509db54c4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 5 Nov 2011 01:25:03 +0100 Subject: udhcpc: reuse string constant; remove unneeded memset(0) Signed-off-by: Denys Vlasenko --- networking/udhcp/dhcpc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index d0fe94a48..ea798a3f4 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -800,7 +800,6 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) struct ip_udp_dhcp_packet packet; uint16_t check; - memset(&packet, 0, sizeof(packet)); bytes = safe_read(fd, &packet, sizeof(packet)); if (bytes < 0) { log1("Packet read error, ignoring"); @@ -858,7 +857,7 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) return -2; } - log1("Got valid DHCP packet"); + log1("Received a packet"); udhcp_dump_packet(&packet.data); bytes -= sizeof(packet.ip) + sizeof(packet.udp); -- cgit v1.2.3-55-g6feb From 3b46fcb95d1276c538f4c84b63eec33cc27ac760 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 5 Nov 2011 01:26:18 +0100 Subject: udhcpc: remove workaround for bugs in Win98 dhcp server ("MSFT 98" vendor string) Stats for last three commits: function old new delta udhcpc_main 2635 2646 +11 udhcp_recv_raw_packet 425 414 -11 udhcp_recv_kernel_packet 210 134 -76 packed_usage 28940 28857 -83 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/3 up/down: 11/-170) Total: -159 bytes text data bss dec hex filename 879524 493 7584 887601 d8b31 busybox_old 879340 493 7584 887417 d8a79 busybox_unstripped Signed-off-by: Denys Vlasenko --- networking/udhcp/packet.c | 34 +++------------------------------- 1 file changed, 3 insertions(+), 31 deletions(-) diff --git a/networking/udhcp/packet.c b/networking/udhcp/packet.c index 4d5ff0676..bd754f766 100644 --- a/networking/udhcp/packet.c +++ b/networking/udhcp/packet.c @@ -81,7 +81,6 @@ void FAST_FUNC udhcp_dump_packet(struct dhcp_packet *packet) int FAST_FUNC udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) { int bytes; - unsigned char *vendor; memset(packet, 0, sizeof(*packet)); bytes = safe_read(fd, packet, sizeof(*packet)); @@ -90,42 +89,15 @@ int FAST_FUNC udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) return bytes; /* returns -1 */ } - if (packet->cookie != htonl(DHCP_MAGIC)) { + if (bytes < offsetof(struct dhcp_packet, options) + || packet->cookie != htonl(DHCP_MAGIC) + ) { bb_info_msg("Packet with bad magic, ignoring"); return -2; } log1("Received a packet"); udhcp_dump_packet(packet); - if (packet->op == BOOTREQUEST) { - vendor = udhcp_get_option(packet, DHCP_VENDOR); - if (vendor) { -#if 0 - static const char broken_vendors[][8] = { - "MSFT 98", - "" - }; - int i; - for (i = 0; broken_vendors[i][0]; i++) { - if (vendor[OPT_LEN - OPT_DATA] == (uint8_t)strlen(broken_vendors[i]) - && strncmp((char*)vendor, broken_vendors[i], vendor[OPT_LEN - OPT_DATA]) == 0 - ) { - log1("Broken client (%s), forcing broadcast replies", - broken_vendors[i]); - packet->flags |= htons(BROADCAST_FLAG); - } - } -#else - if (vendor[OPT_LEN - OPT_DATA] == (uint8_t)(sizeof("MSFT 98")-1) - && memcmp(vendor, "MSFT 98", sizeof("MSFT 98")-1) == 0 - ) { - log1("Broken client (%s), forcing broadcast replies", "MSFT 98"); - packet->flags |= htons(BROADCAST_FLAG); - } -#endif - } - } - return bytes; } -- cgit v1.2.3-55-g6feb From 0fd4347cedd1d32341e827c04dd36aaaf2e8040d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Nov 2011 00:54:27 +0100 Subject: udhcpc: code shrink function old new delta udhcpc_main 2646 2649 +3 udhcp_run_script 816 802 -14 Signed-off-by: Denys Vlasenko --- networking/udhcp/dhcpc.c | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index ea798a3f4..f202ecf74 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -499,9 +499,6 @@ static void udhcp_run_script(struct dhcp_packet *packet, const char *name) char **envp, **curr; char *argv[3]; - if (client_config.script == NULL) - return; - envp = fill_envp(packet); /* call script */ @@ -1009,7 +1006,7 @@ static void perform_renew(void) } } -static void perform_release(uint32_t requested_ip, uint32_t server_addr) +static void perform_release(uint32_t server_addr, uint32_t requested_ip) { char buffer[sizeof("255.255.255.255")]; struct in_addr temp_addr; @@ -1154,15 +1151,12 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) uint32_t server_addr = server_addr; /* for compiler */ uint32_t requested_ip = 0; uint32_t xid = 0; - uint32_t lease_seconds = 0; /* can be given as 32-bit quantity */ int packet_num; int timeout; /* must be signed */ unsigned already_waited_sec; unsigned opt; int max_fd; int retval; - struct timeval tv; - struct dhcp_packet packet; fd_set rfds; /* Default options */ @@ -1302,6 +1296,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) * "continue" statements in code below jump to the top of the loop. */ for (;;) { + struct timeval tv; + struct dhcp_packet packet; /* silence "uninitialized!" warning */ unsigned timestamp_before_wait = timestamp_before_wait; @@ -1349,7 +1345,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) NULL, client_config.client_mac) ) { - return 1; /* iface is gone? */ + goto ret0; /* iface is gone? */ } if (clientid_mac_ptr) memcpy(clientid_mac_ptr, client_config.client_mac, 6); @@ -1486,13 +1482,11 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) timeout = 0; continue; case SIGUSR2: - perform_release(requested_ip, server_addr); + perform_release(server_addr, requested_ip); timeout = INT_MAX; continue; case SIGTERM: bb_info_msg("Received SIGTERM"); - if (opt & OPT_R) /* release on quit */ - perform_release(requested_ip, server_addr); goto ret0; } @@ -1589,6 +1583,9 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) case RENEW_REQUESTED: case REBINDING: if (*message == DHCPACK) { + uint32_t lease_seconds; + struct in_addr temp_addr; + temp = udhcp_get_option(&packet, DHCP_LEASE_TIME); if (!temp) { bb_error_msg("no lease time with ACK, using 1 hour lease"); @@ -1597,9 +1594,11 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) /* it IS unaligned sometimes, don't "optimize" */ move_from_unaligned32(lease_seconds, temp); lease_seconds = ntohl(lease_seconds); - lease_seconds &= 0x0fffffff; /* paranoia: must not be prone to overflows */ - if (lease_seconds < 10) /* and not too small */ - lease_seconds = 10; + /* paranoia: must not be too small and not prone to overflows */ + if (lease_seconds < 0x10) + lease_seconds = 0x10; + if (lease_seconds >= 0x10000000) + lease_seconds = 0x0fffffff; } #if ENABLE_FEATURE_UDHCPC_ARPING if (opt & OPT_a) { @@ -1637,20 +1636,15 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) #endif /* enter bound state */ timeout = lease_seconds / 2; - { - struct in_addr temp_addr; - temp_addr.s_addr = packet.yiaddr; - bb_info_msg("Lease of %s obtained, lease time %u", - inet_ntoa(temp_addr), (unsigned)lease_seconds); - } + temp_addr.s_addr = packet.yiaddr; + bb_info_msg("Lease of %s obtained, lease time %u", + inet_ntoa(temp_addr), (unsigned)lease_seconds); requested_ip = packet.yiaddr; udhcp_run_script(&packet, state == REQUESTING ? "bound" : "renew"); state = BOUND; change_listen_mode(LISTEN_NONE); if (opt & OPT_q) { /* quit after lease */ - if (opt & OPT_R) /* release on quit */ - perform_release(requested_ip, server_addr); goto ret0; } /* future renew failures should not exit (JM) */ @@ -1688,6 +1682,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) } /* for (;;) - main loop ends */ ret0: + if (opt & OPT_R) /* release on quit */ + perform_release(server_addr, requested_ip); retval = 0; ret: /*if (client_config.pidfile) - remove_pidfile has its own check */ -- cgit v1.2.3-55-g6feb From 50089fc61c1dbb3d09c4bee21ab6d2aa44361ff9 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Nov 2011 15:44:46 +0100 Subject: udhcpc: trim help text, rename badly-named variable Signed-off-by: Denys Vlasenko --- networking/udhcp/dhcpc.c | 6 +++--- networking/udhcp/packet.c | 23 +++++++++++------------ 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index f202ecf74..3a4ef9e64 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -1055,7 +1055,7 @@ static void client_background(void) //usage:#endif //usage:#define udhcpc_trivial_usage //usage: "[-fbnq"IF_UDHCP_VERBOSE("v")"oCRB] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n" -//usage: " [-H HOSTNAME] [-V VENDOR] [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]") +//usage: " [-V VENDOR] [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]") //usage:#define udhcpc_full_usage "\n" //usage: IF_LONG_OPTS( //usage: "\n -i,--interface IFACE Interface to use (default eth0)" @@ -1132,8 +1132,8 @@ static void client_background(void) //usage: ) //usage: ) //usage: "\nSignals:" -//usage: "\n USR1 Renew current lease" -//usage: "\n USR2 Release current lease" +//usage: "\n USR1 Renew lease" +//usage: "\n USR2 Release lease" int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/networking/udhcp/packet.c b/networking/udhcp/packet.c index bd754f766..33c9585cf 100644 --- a/networking/udhcp/packet.c +++ b/networking/udhcp/packet.c @@ -182,7 +182,7 @@ int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, uint32_t source_nip, int source_port, uint32_t dest_nip, int dest_port) { - struct sockaddr_in client; + struct sockaddr_in sa; unsigned padding; int fd; int result = -1; @@ -195,26 +195,25 @@ int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, } setsockopt_reuseaddr(fd); - memset(&client, 0, sizeof(client)); - client.sin_family = AF_INET; - client.sin_port = htons(source_port); - client.sin_addr.s_addr = source_nip; - if (bind(fd, (struct sockaddr *)&client, sizeof(client)) == -1) { + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons(source_port); + sa.sin_addr.s_addr = source_nip; + if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { msg = "bind(%s)"; goto ret_close; } - memset(&client, 0, sizeof(client)); - client.sin_family = AF_INET; - client.sin_port = htons(dest_port); - client.sin_addr.s_addr = dest_nip; - if (connect(fd, (struct sockaddr *)&client, sizeof(client)) == -1) { + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons(dest_port); + sa.sin_addr.s_addr = dest_nip; + if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { msg = "connect"; goto ret_close; } udhcp_dump_packet(dhcp_pkt); - padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(dhcp_pkt->options); result = safe_write(fd, dhcp_pkt, DHCP_SIZE - padding); msg = "write"; -- cgit v1.2.3-55-g6feb From 9ba75048c0099ed90b9a64cb7bb57bf12be93528 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Nov 2011 15:55:39 +0100 Subject: udhcpc6: new applet. Not yet functional. It builds. It sends Solicit packets. Not sure these packets are well-formed. I have no server to test it against. function old new delta udhcpc6_main - 2426 +2426 d6_send_raw_packet - 428 +428 d6_send_kernel_packet - 274 +274 d6_recv_raw_packet - 248 +248 send_d6_discover - 177 +177 packed_usage 28795 28966 +171 d6_run_script - 156 +156 send_d6_renew - 140 +140 send_d6_release - 126 +126 d6_recv_kernel_packet - 116 +116 send_d6_select - 95 +95 perform_d6_release - 78 +78 d6_find_option - 74 +74 init_d6_packet - 54 +54 d6_copy_option - 48 +48 d6_mcast_from_client_config_ifindex - 42 +42 d6_dump_packet - 24 +24 static.FF02__1_2 - 16 +16 d6_store_blob - 13 +13 applet_names 2432 2440 +8 applet_main 1412 1416 +4 applet_nameofs 706 708 +2 add_d6_client_options - 1 +1 ------------------------------------------------------------------------------ (add/remove: 21/0 grow/shrink: 4/0 up/down: 4721/0) Total: 4721 bytes text data bss dec hex filename 879080 493 7584 887157 d8975 busybox_old 884585 497 7584 892666 d9efa busybox_unstripped Signed-off-by: Denys Vlasenko --- networking/udhcp/d6_common.h | 118 ++++ networking/udhcp/d6_dhcpc.c | 1404 ++++++++++++++++++++++++++++++++++++++++++ networking/udhcp/d6_packet.c | 168 +++++ networking/udhcp/d6_socket.c | 34 + 4 files changed, 1724 insertions(+) create mode 100644 networking/udhcp/d6_common.h create mode 100644 networking/udhcp/d6_dhcpc.c create mode 100644 networking/udhcp/d6_packet.c create mode 100644 networking/udhcp/d6_socket.c diff --git a/networking/udhcp/d6_common.h b/networking/udhcp/d6_common.h new file mode 100644 index 000000000..88afaf8af --- /dev/null +++ b/networking/udhcp/d6_common.h @@ -0,0 +1,118 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2011 Denys Vlasenko. + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +#ifndef UDHCP_D6_COMMON_H +#define UDHCP_D6_COMMON_H 1 + +#include + +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN + + +/*** DHCPv6 packet ***/ + +/* DHCPv6 protocol. See RFC 3315 */ +#define D6_MSG_SOLICIT 1 +#define D6_MSG_ADVERTISE 2 +#define D6_MSG_REQUEST 3 +#define D6_MSG_CONFIRM 4 +#define D6_MSG_RENEW 5 +#define D6_MSG_REBIND 6 +#define D6_MSG_REPLY 7 +#define D6_MSG_RELEASE 8 +#define D6_MSG_DECLINE 9 +#define D6_MSG_RECONFIGURE 10 +#define D6_MSG_INFORMATION_REQUEST 11 +#define D6_MSG_RELAY_FORW 12 +#define D6_MSG_RELAY_REPL 13 + +struct d6_packet { + union { + uint8_t d6_msg_type; + uint32_t d6_xid32; + } d6_u; + uint8_t d6_options[576 - sizeof(struct iphdr) - sizeof(struct udphdr) - 4 + + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS]; +} PACKED; +#define d6_msg_type d6_u.d6_msg_type +#define d6_xid32 d6_u.d6_xid32 + +struct ip6_udp_d6_packet { + struct ip6_hdr ip6; + struct udphdr udp; + struct d6_packet data; +} PACKED; + +struct udp_d6_packet { + struct udphdr udp; + struct d6_packet data; +} PACKED; + +/*** Options ***/ + +struct d6_option { + uint8_t code; + uint8_t code_hi; + uint8_t len; + uint8_t len_hi; + uint8_t data[1]; +} PACKED; + +#define D6_OPT_CLIENTID 1 +#define D6_OPT_SERVERID 2 +#define D6_OPT_IA_NA 3 +#define D6_OPT_IA_TA 4 +#define D6_OPT_IAADDR 5 +#define D6_OPT_ORO 6 +#define D6_OPT_PREFERENCE 7 +#define D6_OPT_ELAPSED_TIME 8 +#define D6_OPT_RELAY_MSG 9 +#define D6_OPT_AUTH 11 +#define D6_OPT_UNICAST 12 +#define D6_OPT_STATUS_CODE 13 +#define D6_OPT_RAPID_COMMIT 14 +#define D6_OPT_USER_CLASS 15 +#define D6_OPT_VENDOR_CLASS 16 +#define D6_OPT_VENDOR_OPTS 17 +#define D6_OPT_INTERFACE_ID 18 +#define D6_OPT_RECONF_MSG 19 +#define D6_OPT_RECONF_ACCEPT 20 + +/*** Other shared functions ***/ + +struct client6_data_t { + struct d6_option *server_id; + struct d6_option *ia_na; +}; + +#define client6_data (*(struct client6_data_t*)(&bb_common_bufsiz1[COMMON_BUFSIZE - sizeof(struct client6_data_t)])) + +int FAST_FUNC d6_listen_socket(int port, const char *inf); + +int FAST_FUNC d6_recv_kernel_packet( + struct in6_addr *peer_ipv6, + struct d6_packet *packet, int fd +); + +int FAST_FUNC d6_send_raw_packet( + struct d6_packet *d6_pkt, unsigned d6_pkt_size, + struct in6_addr *src_ipv6, int source_port, + struct in6_addr *dst_ipv6, int dest_port, const uint8_t *dest_arp, + int ifindex +); + +int FAST_FUNC d6_send_kernel_packet( + struct d6_packet *d6_pkt, unsigned d6_pkt_size, + struct in6_addr *src_ipv6, int source_port, + struct in6_addr *dst_ipv6, int dest_port +); + +void FAST_FUNC d6_dump_packet(struct d6_packet *packet); + + +POP_SAVED_FUNCTION_VISIBILITY + +#endif diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c new file mode 100644 index 000000000..d1baaae9b --- /dev/null +++ b/networking/udhcp/d6_dhcpc.c @@ -0,0 +1,1404 @@ +/* vi: set sw=4 ts=4: */ +/* + * DHCPv6 client. + * + * 2011-11. + * WARNING: THIS CODE IS INCOMPLETE. IT IS NOWHERE NEAR + * TO BE READY FOR PRODUCTION USE. + * + * Copyright (C) 2011 Denys Vlasenko. + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//config:config UDHCPC6 +//config: bool "udhcp client for DHCPv6 (udhcpc6)" +//config: default n # not yet ready +//config: help +//config: udhcpc6 is a DHCPv6 client + +//applet:IF_UDHCPC6(APPLET(udhcpc6, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_UDHCPC6) += d6_dhcpc.o d6_packet.o d6_socket.o common.o + + +#include +/* Override ENABLE_FEATURE_PIDFILE - ifupdown needs our pidfile to always exist */ +#define WANT_PIDFILE 1 +#include "common.h" +#include "dhcpd.h" +#include "dhcpc.h" +#include "d6_common.h" + +#include +#include +#include + +/* "struct client_config_t client_config" is in bb_common_bufsiz1 */ + + +#if ENABLE_LONG_OPTS +static const char udhcpc_longopts[] ALIGN1 = + "interface\0" Required_argument "i" + "now\0" No_argument "n" + "pidfile\0" Required_argument "p" + "quit\0" No_argument "q" + "release\0" No_argument "R" + "request\0" Required_argument "r" + "script\0" Required_argument "s" + "timeout\0" Required_argument "T" + "version\0" No_argument "v" + "retries\0" Required_argument "t" + "tryagain\0" Required_argument "A" + "syslog\0" No_argument "S" + "request-option\0" Required_argument "O" + "no-default-options\0" No_argument "o" + "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_UDHCP_PORT("client-port\0" Required_argument "P") + ; +#endif +/* Must match getopt32 option string order */ +enum { + OPT_i = 1 << 0, + OPT_n = 1 << 1, + OPT_p = 1 << 2, + OPT_q = 1 << 3, + OPT_R = 1 << 4, + OPT_r = 1 << 5, + OPT_s = 1 << 6, + OPT_T = 1 << 7, + OPT_t = 1 << 8, + OPT_S = 1 << 9, + OPT_A = 1 << 10, + OPT_O = 1 << 11, + OPT_o = 1 << 12, + OPT_x = 1 << 13, + OPT_f = 1 << 14, + OPT_B = 1 << 15, +/* The rest has variable bit positions, need to be clever */ + OPTBIT_B = 15, + USE_FOR_MMU( OPTBIT_b,) + ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) + IF_FEATURE_UDHCP_PORT( OPTBIT_P,) + USE_FOR_MMU( OPT_b = 1 << OPTBIT_b,) + ///IF_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,) + IF_FEATURE_UDHCP_PORT( OPT_P = 1 << OPTBIT_P,) +}; + + +/*** Utility functions ***/ + +static void *d6_find_option(uint8_t *option, uint8_t *option_end, unsigned code) +{ + /* "length minus 4" */ + int len_m4 = option_end - option - 4; + while (len_m4 >= 0) { + /* Next option's len is too big? */ + if (option[2] > len_m4) + return NULL; /* yes. bogus packet! */ + /* So far we treat any opts with code >255 + * or len >255 as bogus, and stop at once. + * This simplifies big-endian handling. + */ + if (option[1] != 0 || option[3] != 0) + return NULL; + /* Option seems to be valid */ + /* Does its code match? */ + if (option[0] == code) + return option; /* yes! */ + option += option[2] + 4; + len_m4 -= option[2] + 4; + } + return NULL; +} + +static void *d6_copy_option(uint8_t *option, uint8_t *option_end, unsigned code) +{ + uint8_t *opt = d6_find_option(option, option_end, code); + if (!opt) + return opt; + return memcpy(xmalloc(opt[2] + 4), opt, opt[2] + 4); +} + +static void *d6_store_blob(void *dst, const void *src, unsigned len) +{ + memcpy(dst, src, len); + return dst + len; +} + + +/*** Script execution code ***/ + +/* put all the parameters into the environment */ +static char **fill_envp(struct d6_packet *packet + UNUSED_PARAM +) +{ + int envc; + char **envp, **curr; + +#define BITMAP unsigned +#define BBITS (sizeof(BITMAP) * 8) +#define BMASK(i) (1 << (i & (sizeof(BITMAP) * 8 - 1))) +#define FOUND_OPTS(i) (found_opts[(unsigned)i / BBITS]) + ///BITMAP found_opts[256 / BBITS]; + + ///memset(found_opts, 0, sizeof(found_opts)); + + /* We need 2 elements for: + * "interface=IFACE" + * terminating NULL + */ + envc = 2; + + curr = envp = xzalloc(sizeof(envp[0]) * envc); + + *curr = xasprintf("interface=%s", client_config.interface); + putenv(*curr++); + + return envp; +} + +/* Call a script with a par file and env vars */ +static void d6_run_script(struct d6_packet *packet, const char *name) +{ + char **envp, **curr; + char *argv[3]; + + envp = fill_envp(packet); + + /* call script */ + log1("Executing %s %s", client_config.script, name); + argv[0] = (char*) client_config.script; + argv[1] = (char*) name; + argv[2] = NULL; + spawn_and_wait(argv); + + for (curr = envp; *curr; curr++) { + log2(" %s", *curr); + bb_unsetenv_and_free(*curr); + } + free(envp); +} + + +/*** Sending/receiving packets ***/ + +static ALWAYS_INLINE uint32_t random_xid(void) +{ + uint32_t t = rand() & htonl(0x00ffffff); + return t; +} + +/* Initialize the packet with the proper defaults */ +static uint8_t *init_d6_packet(struct d6_packet *packet, char type, uint32_t xid) +{ + struct d6_option *clientid; + + memset(packet, 0, sizeof(*packet)); + + packet->d6_xid32 = xid; + packet->d6_msg_type = type; + + clientid = (void*)client_config.clientid; + return d6_store_blob(packet->d6_options, clientid, clientid->len + 2+2); +} + +static uint8_t *add_d6_client_options(uint8_t *ptr) +{ + return ptr; + //uint8_t c; + //int i, end, len; + + /* Add a "param req" option with the list of options we'd like to have + * from stubborn DHCP servers. Pull the data from the struct in common.c. + * No bounds checking because it goes towards the head of the packet. */ + //... + + /* Add -x options if any */ + //... +} + +static int d6_mcast_from_client_config_ifindex(struct d6_packet *packet, uint8_t *end) +{ + static const uint8_t FF02__1_2[16] = { + 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, + }; + + return d6_send_raw_packet( + packet, (end - (uint8_t*) packet), + /*src*/ NULL, CLIENT_PORT, + /*dst*/ (struct in6_addr*)FF02__1_2, SERVER_PORT, MAC_BCAST_ADDR, + client_config.ifindex + ); +} + +/* Milticast a DHCPv6 Solicit packet to the network, with an optionally requested IP. + * + * RFC 3315 17.1.1. Creation of Solicit Messages + * + * The client MUST include a Client Identifier option to identify itself + * to the server. The client includes IA options for any IAs to which + * it wants the server to assign addresses. The client MAY include + * addresses in the IAs as a hint to the server about addresses for + * which the client has a preference. ... + * + * The client uses IA_NA options to request the assignment of non- + * temporary addresses and uses IA_TA options to request the assignment + * of temporary addresses. Either IA_NA or IA_TA options, or a + * combination of both, can be included in DHCP messages. + * + * The client SHOULD include an Option Request option (see section 22.7) + * to indicate the options the client is interested in receiving. The + * client MAY additionally include instances of those options that are + * identified in the Option Request option, with data values as hints to + * the server about parameter values the client would like to have + * returned. + * + * The client includes a Reconfigure Accept option (see section 22.20) + * if the client is willing to accept Reconfigure messages from the + * server. + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | OPTION_CLIENTID | option-len | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + . . + . DUID . + . (variable length) . + . . + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | OPTION_IA_NA | option-len | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | IAID (4 octets) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | T1 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | T2 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + . IA_NA-options . + . . + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | OPTION_IAADDR | option-len | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + | IPv6 address | + | | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | preferred-lifetime | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | valid-lifetime | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + . . + . IAaddr-options . + . . + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | OPTION_ORO | option-len | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | requested-option-code-1 | requested-option-code-2 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | OPTION_RECONF_ACCEPT | 0 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +/* NOINLINE: limit stack usage in caller */ +static NOINLINE int send_d6_discover(uint32_t xid, struct in6_addr *requested_ipv6) +{ + struct d6_packet packet; + uint8_t *opt_ptr; + unsigned len; + + /* Fill in: msg type, client id */ + opt_ptr = init_d6_packet(&packet, D6_MSG_SOLICIT, xid); + + /* Create new IA_NA, optionally with included IAADDR with requested IP */ + free(client6_data.ia_na); + len = requested_ipv6 ? 2+2+4+4+4 + 2+2+16+4+4 : 2+2+4+4+4; + client6_data.ia_na = xzalloc(len); + client6_data.ia_na->code = D6_OPT_IA_NA; + client6_data.ia_na->len = len - 4; + *(uint32_t*)client6_data.ia_na->data = rand(); /* IAID */ + if (requested_ipv6) { + struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4); + iaaddr->code = D6_OPT_IAADDR; + iaaddr->len = 16+4+4; + memcpy(iaaddr->data, requested_ipv6, 16); + } + opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, len); + + /* Add options: + * "param req" option according to -O, options specified with -x + */ + opt_ptr = add_d6_client_options(opt_ptr); + + bb_info_msg("Sending discover..."); + return d6_mcast_from_client_config_ifindex(&packet, opt_ptr); +} + +/* Multicast a DHCPv6 request message + * + * RFC 3315 18.1.1. Creation and Transmission of Request Messages + * + * The client uses a Request message to populate IAs with addresses and + * obtain other configuration information. The client includes one or + * more IA options in the Request message. The server then returns + * addresses and other information about the IAs to the client in IA + * options in a Reply message. + * + * The client generates a transaction ID and inserts this value in the + * "transaction-id" field. + * + * The client places the identifier of the destination server in a + * Server Identifier option. + * + * The client MUST include a Client Identifier option to identify itself + * to the server. The client adds any other appropriate options, + * including one or more IA options (if the client is requesting that + * the server assign it some network addresses). + * + * The client MUST include an Option Request option (see section 22.7) + * to indicate the options the client is interested in receiving. The + * client MAY include options with data values as hints to the server + * about parameter values the client would like to have returned. + * + * The client includes a Reconfigure Accept option (see section 22.20) + * indicating whether or not the client is willing to accept Reconfigure + * messages from the server. + */ +/* NOINLINE: limit stack usage in caller */ +static NOINLINE int send_d6_select(uint32_t xid) +{ + struct d6_packet packet; + uint8_t *opt_ptr; + + /* Fill in: msg type, client id */ + opt_ptr = init_d6_packet(&packet, D6_MSG_REQUEST, xid); + + /* server id */ + opt_ptr = d6_store_blob(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); + /* IA NA (contains requested IP) */ + opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); + + /* Add options: + * "param req" option according to -O, options specified with -x + */ + opt_ptr = add_d6_client_options(opt_ptr); + + bb_info_msg("Sending select..."); + return d6_mcast_from_client_config_ifindex(&packet, opt_ptr); +} + +/* Unicast or broadcast a DHCP renew message + * + * RFC 3315 18.1.3. Creation and Transmission of Renew Messages + * + * To extend the valid and preferred lifetimes for the addresses + * associated with an IA, the client sends a Renew message to the server + * from which the client obtained the addresses in the IA containing an + * IA option for the IA. The client includes IA Address options in the + * IA option for the addresses associated with the IA. The server + * determines new lifetimes for the addresses in the IA according to the + * administrative configuration of the server. The server may also add + * new addresses to the IA. The server may remove addresses from the IA + * by setting the preferred and valid lifetimes of those addresses to + * zero. + * + * The server controls the time at which the client contacts the server + * to extend the lifetimes on assigned addresses through the T1 and T2 + * parameters assigned to an IA. + * + * At time T1 for an IA, the client initiates a Renew/Reply message + * exchange to extend the lifetimes on any addresses in the IA. The + * client includes an IA option with all addresses currently assigned to + * the IA in its Renew message. + * + * If T1 or T2 is set to 0 by the server (for an IA_NA) or there are no + * T1 or T2 times (for an IA_TA), the client may send a Renew or Rebind + * message, respectively, at the client's discretion. + * + * The client sets the "msg-type" field to RENEW. The client generates + * a transaction ID and inserts this value in the "transaction-id" + * field. + * + * The client places the identifier of the destination server in a + * Server Identifier option. + * + * The client MUST include a Client Identifier option to identify itself + * to the server. The client adds any appropriate options, including + * one or more IA options. The client MUST include the list of + * addresses the client currently has associated with the IAs in the + * Renew message. + * + * The client MUST include an Option Request option (see section 22.7) + * to indicate the options the client is interested in receiving. The + * client MAY include options with data values as hints to the server + * about parameter values the client would like to have returned. + */ +/* NOINLINE: limit stack usage in caller */ +static NOINLINE int send_d6_renew(uint32_t xid, struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6) +{ + struct d6_packet packet; + uint8_t *opt_ptr; + + /* Fill in: msg type, client id */ + opt_ptr = init_d6_packet(&packet, DHCPREQUEST, xid); + + /* server id */ + opt_ptr = d6_store_blob(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); + /* IA NA (contains requested IP) */ + opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); + + /* Add options: + * "param req" option according to -O, options specified with -x + */ + opt_ptr = add_d6_client_options(opt_ptr); + + bb_info_msg("Sending renew..."); + if (server_ipv6) + return d6_send_kernel_packet( + &packet, (opt_ptr - (uint8_t*) &packet), + our_cur_ipv6, CLIENT_PORT, + server_ipv6, SERVER_PORT + ); + return d6_mcast_from_client_config_ifindex(&packet, opt_ptr); +} + +/* Unicast a DHCP release message */ +static int send_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6) +{ + struct d6_packet packet; + uint8_t *opt_ptr; + + /* Fill in: msg type, client id */ + opt_ptr = init_d6_packet(&packet, D6_MSG_RELEASE, random_xid()); + /* server id */ + opt_ptr = d6_store_blob(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); + /* IA NA (contains our current IP) */ + opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); + + bb_info_msg("Sending release..."); + return d6_send_kernel_packet( + &packet, (opt_ptr - (uint8_t*) &packet), + our_cur_ipv6, CLIENT_PORT, + server_ipv6, SERVER_PORT + ); +} + +/* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */ +/* NOINLINE: limit stack usage in caller */ +static NOINLINE int d6_recv_raw_packet(struct in6_addr *peer_ipv6 + UNUSED_PARAM + , struct d6_packet *d6_pkt, int fd) +{ + int bytes; + struct ip6_udp_d6_packet packet; + + bytes = safe_read(fd, &packet, sizeof(packet)); + if (bytes < 0) { + log1("Packet read error, ignoring"); + /* NB: possible down interface, etc. Caller should pause. */ + return bytes; /* returns -1 */ + } + + if (bytes < (int) (sizeof(packet.ip6) + sizeof(packet.udp))) { + log1("Packet is too short, ignoring"); + return -2; + } + + if (bytes < sizeof(packet.ip6) + ntohs(packet.ip6.ip6_plen)) { + /* packet is bigger than sizeof(packet), we did partial read */ + log1("Oversized packet, ignoring"); + return -2; + } + + /* ignore any extra garbage bytes */ + bytes = sizeof(packet.ip6) + ntohs(packet.ip6.ip6_plen); + + /* make sure its the right packet for us, and that it passes sanity checks */ + if (packet.ip6.ip6_nxt != IPPROTO_UDP + || (packet.ip6.ip6_vfc >> 4) != 6 + || packet.udp.dest != htons(CLIENT_PORT) + /* || bytes > (int) sizeof(packet) - can't happen */ + || packet.udp.len != packet.ip6.ip6_plen + ) { + log1("Unrelated/bogus packet, ignoring"); + return -2; + } + +//How to do this for ipv6? +// /* verify UDP checksum. IP header has to be modified for this */ +// memset(&packet.ip, 0, offsetof(struct iphdr, protocol)); +// /* ip.xx fields which are not memset: protocol, check, saddr, daddr */ +// packet.ip.tot_len = packet.udp.len; /* yes, this is needed */ +// check = packet.udp.check; +// packet.udp.check = 0; +// if (check && check != inet_cksum((uint16_t *)&packet, bytes)) { +// log1("Packet with bad UDP checksum received, ignoring"); +// return -2; +// } + + log1("Received a packet"); + d6_dump_packet(&packet.data); + + bytes -= sizeof(packet.ip6) + sizeof(packet.udp); + memcpy(d6_pkt, &packet.data, bytes); + return bytes; +} + + +/*** Main ***/ + +static int sockfd = -1; + +#define LISTEN_NONE 0 +#define LISTEN_KERNEL 1 +#define LISTEN_RAW 2 +static smallint listen_mode; + +/* initial state: (re)start DHCP negotiation */ +#define INIT_SELECTING 0 +/* discover was sent, DHCPOFFER reply received */ +#define REQUESTING 1 +/* select/renew was sent, DHCPACK reply received */ +#define BOUND 2 +/* half of lease passed, want to renew it by sending unicast renew requests */ +#define RENEWING 3 +/* renew requests were not answered, lease is almost over, send broadcast renew */ +#define REBINDING 4 +/* manually requested renew (SIGUSR1) */ +#define RENEW_REQUESTED 5 +/* release, possibly manually requested (SIGUSR2) */ +#define RELEASED 6 +static smallint state; + +static int d6_raw_socket(int ifindex) +{ + int fd; + struct sockaddr_ll sock; + + /* + * Comment: + * + * I've selected not to see LL header, so BPF doesn't see it, too. + * The filter may also pass non-IP and non-ARP packets, but we do + * a more complete check when receiving the message in userspace. + * + * and filter shamelessly stolen from: + * + * http://www.flamewarmaster.de/software/dhcpclient/ + * + * There are a few other interesting ideas on that page (look under + * "Motivation"). Use of netlink events is most interesting. Think + * of various network servers listening for events and reconfiguring. + * That would obsolete sending HUP signals and/or make use of restarts. + * + * Copyright: 2006, 2007 Stefan Rompf . + * License: GPL v2. + * + * TODO: make conditional? + */ +#if 0 + static const struct sock_filter filter_instr[] = { + /* load 9th byte (protocol) */ + BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9), + /* jump to L1 if it is IPPROTO_UDP, else to L4 */ + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 6), + /* L1: load halfword from offset 6 (flags and frag offset) */ + BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6), + /* jump to L4 if any bits in frag offset field are set, else to L2 */ + BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x1fff, 4, 0), + /* L2: skip IP header (load index reg with header len) */ + BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), + /* load udp destination port from halfword[header_len + 2] */ + BPF_STMT(BPF_LD|BPF_H|BPF_IND, 2), + /* jump to L3 if udp dport is CLIENT_PORT, else to L4 */ + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1), + /* L3: accept packet */ + BPF_STMT(BPF_RET|BPF_K, 0xffffffff), + /* L4: discard packet */ + BPF_STMT(BPF_RET|BPF_K, 0), + }; + static const struct sock_fprog filter_prog = { + .len = sizeof(filter_instr) / sizeof(filter_instr[0]), + /* casting const away: */ + .filter = (struct sock_filter *) filter_instr, + }; +#endif + + log1("Opening raw socket on ifindex %d", ifindex); //log2? + + fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6)); + log1("Got raw socket fd %d", fd); //log2? + + sock.sll_family = AF_PACKET; + sock.sll_protocol = htons(ETH_P_IPV6); + sock.sll_ifindex = ifindex; + xbind(fd, (struct sockaddr *) &sock, sizeof(sock)); + +#if 0 + if (CLIENT_PORT == 68) { + /* Use only if standard port is in use */ + /* Ignoring error (kernel may lack support for this) */ + if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, + sizeof(filter_prog)) >= 0) + log1("Attached filter to raw socket fd %d", fd); // log? + } +#endif + + log1("Created raw socket"); + + return fd; +} + +static void change_listen_mode(int new_mode) +{ + log1("Entering listen mode: %s", + new_mode != LISTEN_NONE + ? (new_mode == LISTEN_KERNEL ? "kernel" : "raw") + : "none" + ); + + listen_mode = new_mode; + if (sockfd >= 0) { + close(sockfd); + sockfd = -1; + } + if (new_mode == LISTEN_KERNEL) + sockfd = udhcp_listen_socket(/*INADDR_ANY,*/ CLIENT_PORT, client_config.interface); + else if (new_mode != LISTEN_NONE) + sockfd = d6_raw_socket(client_config.ifindex); + /* else LISTEN_NONE: sockfd stays closed */ +} + +/* Called only on SIGUSR1 */ +static void perform_renew(void) +{ + bb_info_msg("Performing a DHCP renew"); + switch (state) { + case BOUND: + change_listen_mode(LISTEN_KERNEL); + case RENEWING: + case REBINDING: + state = RENEW_REQUESTED; + break; + case RENEW_REQUESTED: /* impatient are we? fine, square 1 */ + d6_run_script(NULL, "deconfig"); + case REQUESTING: + case RELEASED: + change_listen_mode(LISTEN_RAW); + state = INIT_SELECTING; + break; + case INIT_SELECTING: + break; + } +} + +static void perform_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6) +{ + /* send release packet */ + if (state == BOUND || state == RENEWING || state == REBINDING) { + bb_info_msg("Unicasting a release"); + send_d6_release(server_ipv6, our_cur_ipv6); /* unicast */ + d6_run_script(NULL, "deconfig"); + } + bb_info_msg("Entering released state"); + + change_listen_mode(LISTEN_NONE); + state = RELEASED; +} + +///static uint8_t* alloc_dhcp_option(int code, const char *str, int extra) +///{ +/// uint8_t *storage; +/// int len = strnlen(str, 255); +/// storage = xzalloc(len + extra + OPT_DATA); +/// storage[OPT_CODE] = code; +/// storage[OPT_LEN] = len + extra; +/// memcpy(storage + extra + OPT_DATA, str, len); +/// return storage; +///} + +#if BB_MMU +static void client_background(void) +{ + bb_daemonize(0); + logmode &= ~LOGMODE_STDIO; + /* rewrite pidfile, as our pid is different now */ + write_pidfile(client_config.pidfile); +} +#endif + +//usage:#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 +//usage:# define IF_UDHCP_VERBOSE(...) __VA_ARGS__ +//usage:#else +//usage:# define IF_UDHCP_VERBOSE(...) +//usage:#endif +//usage:#define udhcpc6_trivial_usage +//usage: "[-fbnq"IF_UDHCP_VERBOSE("v")"oRB] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n" +//usage: " [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]") +//usage:#define udhcpc6_full_usage "\n" +//usage: IF_LONG_OPTS( +//usage: "\n -i,--interface IFACE Interface to use (default eth0)" +//usage: "\n -p,--pidfile FILE Create pidfile" +//usage: "\n -s,--script PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" +//usage: "\n -B,--broadcast Request broadcast replies" +//usage: "\n -t,--retries N Send up to N discover packets" +//usage: "\n -T,--timeout N Pause between packets (default 3 seconds)" +//usage: "\n -A,--tryagain N Wait N seconds after failure (default 20)" +//usage: "\n -f,--foreground Run in foreground" +//usage: USE_FOR_MMU( +//usage: "\n -b,--background Background if lease is not obtained" +//usage: ) +//usage: "\n -n,--now Exit if lease is not obtained" +//usage: "\n -q,--quit Exit after obtaining lease" +//usage: "\n -R,--release Release IP on exit" +//usage: "\n -S,--syslog Log to syslog too" +//usage: IF_FEATURE_UDHCP_PORT( +//usage: "\n -P,--client-port N Use port N (default 68)" +//usage: ) +////usage: IF_FEATURE_UDHCPC_ARPING( +////usage: "\n -a,--arping Use arping to validate offered address" +////usage: ) +//usage: "\n -O,--request-option OPT Request option OPT from server (cumulative)" +//usage: "\n -o,--no-default-options Don't request any options (unless -O is given)" +//usage: "\n -r,--request IP Request this IP address" +//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" +//usage: "\n Examples of string, numeric, and hex byte opts:" +//usage: "\n -x hostname:bbox - option 12" +//usage: "\n -x lease:3600 - option 51 (lease time)" +//usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)" +//usage: IF_UDHCP_VERBOSE( +//usage: "\n -v Verbose" +//usage: ) +//usage: ) +//usage: IF_NOT_LONG_OPTS( +//usage: "\n -i IFACE Interface to use (default eth0)" +//usage: "\n -p FILE Create pidfile" +//usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" +//usage: "\n -B Request broadcast replies" +//usage: "\n -t N Send up to N discover packets" +//usage: "\n -T N Pause between packets (default 3 seconds)" +//usage: "\n -A N Wait N seconds (default 20) after failure" +//usage: "\n -f Run in foreground" +//usage: USE_FOR_MMU( +//usage: "\n -b Background if lease is not obtained" +//usage: ) +//usage: "\n -n Exit if lease is not obtained" +//usage: "\n -q Exit after obtaining lease" +//usage: "\n -R Release IP on exit" +//usage: "\n -S Log to syslog too" +//usage: IF_FEATURE_UDHCP_PORT( +//usage: "\n -P N Use port N (default 68)" +//usage: ) +////usage: IF_FEATURE_UDHCPC_ARPING( +////usage: "\n -a Use arping to validate offered address" +////usage: ) +//usage: "\n -O OPT Request option OPT from server (cumulative)" +//usage: "\n -o Don't request any options (unless -O is given)" +//usage: "\n -r IP Request this IP address" +//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" +//usage: "\n Examples of string, numeric, and hex byte opts:" +//usage: "\n -x hostname:bbox - option 12" +//usage: "\n -x lease:3600 - option 51 (lease time)" +//usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)" +//usage: IF_UDHCP_VERBOSE( +//usage: "\n -v Verbose" +//usage: ) +//usage: ) +//usage: "\nSignals:" +//usage: "\n USR1 Renew lease" +//usage: "\n USR2 Release lease" + + +int udhcpc6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int udhcpc6_main(int argc UNUSED_PARAM, char **argv) +{ + const char *str_r; + IF_FEATURE_UDHCP_PORT(char *str_P;) + void *clientid_mac_ptr; + llist_t *list_O = NULL; + llist_t *list_x = NULL; + int tryagain_timeout = 20; + int discover_timeout = 3; + int discover_retries = 3; + struct in6_addr srv6_buf; + struct in6_addr ipv6_buf; + struct in6_addr *requested_ipv6; + uint32_t xid = 0; + int packet_num; + int timeout; /* must be signed */ + unsigned already_waited_sec; + unsigned opt; + int max_fd; + int retval; + fd_set rfds; + + /* Default options */ + IF_FEATURE_UDHCP_PORT(SERVER_PORT = 547;) + IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 546;) + client_config.interface = "eth0"; + client_config.script = CONFIG_UDHCPC_DEFAULT_SCRIPT; + + /* Parse command line */ + /* O,x: list; -T,-t,-A take numeric param */ + opt_complementary = "O::x::T+:t+:A+" IF_UDHCP_VERBOSE(":vv") ; + IF_LONG_OPTS(applet_long_options = udhcpc_longopts;) + opt = getopt32(argv, "i:np:qRr:s:T:t:SA:O:ox:fB" + USE_FOR_MMU("b") + ///IF_FEATURE_UDHCPC_ARPING("a") + IF_FEATURE_UDHCP_PORT("P:") + "v" + , &client_config.interface, &client_config.pidfile, &str_r /* i,p */ + , &client_config.script /* s */ + , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */ + , &list_O + , &list_x + IF_FEATURE_UDHCP_PORT(, &str_P) + IF_UDHCP_VERBOSE(, &dhcp_verbose) + ); + requested_ipv6 = NULL; + if (opt & OPT_r) { + if (inet_pton(AF_INET6, str_r, &ipv6_buf) <= 0) + bb_error_msg_and_die("bad IPv6 address '%s'", str_r); + requested_ipv6 = &ipv6_buf; + } +#if ENABLE_FEATURE_UDHCP_PORT + if (opt & OPT_P) { + CLIENT_PORT = xatou16(str_P); + SERVER_PORT = CLIENT_PORT - 1; + } +#endif + if (opt & OPT_o) + client_config.no_default_options = 1; + while (list_O) { + char *optstr = llist_pop(&list_O); + unsigned n = bb_strtou(optstr, NULL, 0); + if (errno || n > 254) { + n = udhcp_option_idx(optstr); + n = dhcp_optflags[n].code; + } + client_config.opt_mask[n >> 3] |= 1 << (n & 7); + } + while (list_x) { + char *optstr = llist_pop(&list_x); + char *colon = strchr(optstr, ':'); + if (colon) + *colon = ' '; + /* now it looks similar to udhcpd's config file line: + * "optname optval", using the common routine: */ + udhcp_str2optset(optstr, &client_config.options); + } + + if (udhcp_read_interface(client_config.interface, + &client_config.ifindex, + NULL, + client_config.client_mac) + ) { + return 1; + } + + /* Create client ID based on mac, set clientid_mac_ptr */ + { + struct d6_option *clientid; + clientid = xzalloc(2+2+2+2+6); + clientid->code = D6_OPT_CLIENTID; + clientid->len = 2+2+6; + clientid->data[0] = 3; /* DUID-LL */ + clientid->data[2] = 1; /* ethernet */ + clientid_mac_ptr = clientid->data + 2+2; + memcpy(clientid_mac_ptr, client_config.client_mac, 6); + client_config.clientid = (void*)clientid; + } + +#if !BB_MMU + /* on NOMMU reexec (i.e., background) early */ + if (!(opt & OPT_f)) { + bb_daemonize_or_rexec(0 /* flags */, argv); + logmode = LOGMODE_NONE; + } +#endif + if (opt & OPT_S) { + openlog(applet_name, LOG_PID, LOG_DAEMON); + logmode |= LOGMODE_SYSLOG; + } + + /* Make sure fd 0,1,2 are open */ + bb_sanitize_stdio(); + /* Equivalent of doing a fflush after every \n */ + setlinebuf(stdout); + /* Create pidfile */ + write_pidfile(client_config.pidfile); + /* Goes to stdout (unless NOMMU) and possibly syslog */ + bb_info_msg("%s (v"BB_VER") started", applet_name); + /* Set up the signal pipe */ + udhcp_sp_setup(); + /* We want random_xid to be random... */ + srand(monotonic_us()); + + state = INIT_SELECTING; + d6_run_script(NULL, "deconfig"); + change_listen_mode(LISTEN_RAW); + packet_num = 0; + timeout = 0; + already_waited_sec = 0; + + /* Main event loop. select() waits on signal pipe and possibly + * on sockfd. + * "continue" statements in code below jump to the top of the loop. + */ + for (;;) { + struct timeval tv; + struct d6_packet packet; + uint8_t *packet_end; + /* silence "uninitialized!" warning */ + unsigned timestamp_before_wait = timestamp_before_wait; + + //bb_error_msg("sockfd:%d, listen_mode:%d", sockfd, listen_mode); + + /* Was opening raw or udp socket here + * if (listen_mode != LISTEN_NONE && sockfd < 0), + * but on fast network renew responses return faster + * than we open sockets. Thus this code is moved + * to change_listen_mode(). Thus we open listen socket + * BEFORE we send renew request (see "case BOUND:"). */ + + max_fd = udhcp_sp_fd_set(&rfds, sockfd); + + tv.tv_sec = timeout - already_waited_sec; + tv.tv_usec = 0; + retval = 0; + /* If we already timed out, fall through with retval = 0, else... */ + if ((int)tv.tv_sec > 0) { + timestamp_before_wait = (unsigned)monotonic_sec(); + log1("Waiting on select..."); + retval = select(max_fd + 1, &rfds, NULL, NULL, &tv); + if (retval < 0) { + /* EINTR? A signal was caught, don't panic */ + if (errno == EINTR) { + already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait; + continue; + } + /* Else: an error occured, panic! */ + bb_perror_msg_and_die("select"); + } + } + + /* If timeout dropped to zero, time to become active: + * resend discover/renew/whatever + */ + if (retval == 0) { + /* When running on a bridge, the ifindex may have changed + * (e.g. if member interfaces were added/removed + * or if the status of the bridge changed). + * Refresh ifindex and client_mac: + */ + if (udhcp_read_interface(client_config.interface, + &client_config.ifindex, + NULL, + client_config.client_mac) + ) { + goto ret0; /* iface is gone? */ + } + memcpy(clientid_mac_ptr, client_config.client_mac, 6); + + /* We will restart the wait in any case */ + already_waited_sec = 0; + + switch (state) { + case INIT_SELECTING: + if (packet_num < discover_retries) { + if (packet_num == 0) + xid = random_xid(); + /* multicast */ + send_d6_discover(xid, requested_ipv6); + timeout = discover_timeout; + packet_num++; + continue; + } + leasefail: + d6_run_script(NULL, "leasefail"); +#if BB_MMU /* -b is not supported on NOMMU */ + if (opt & OPT_b) { /* background if no lease */ + bb_info_msg("No lease, forking to background"); + client_background(); + /* do not background again! */ + opt = ((opt & ~OPT_b) | OPT_f); + } else +#endif + if (opt & OPT_n) { /* abort if no lease */ + bb_info_msg("No lease, failing"); + retval = 1; + goto ret; + } + /* wait before trying again */ + timeout = tryagain_timeout; + packet_num = 0; + continue; + case REQUESTING: + if (packet_num < discover_retries) { + /* send multicast select packet */ + send_d6_select(xid); + timeout = discover_timeout; + packet_num++; + continue; + } + /* Timed out, go back to init state. + * "discover...select...discover..." loops + * were seen in the wild. Treat them similarly + * to "no response to discover" case */ + change_listen_mode(LISTEN_RAW); + state = INIT_SELECTING; + goto leasefail; + case BOUND: + /* 1/2 lease passed, enter renewing state */ + state = RENEWING; + client_config.first_secs = 0; /* make secs field count from 0 */ + change_listen_mode(LISTEN_KERNEL); + log1("Entering renew state"); + /* fall right through */ + case RENEW_REQUESTED: /* manual (SIGUSR1) renew */ + case_RENEW_REQUESTED: + case RENEWING: + if (timeout > 60) { + /* send an unicast renew request */ + /* Sometimes observed to fail (EADDRNOTAVAIL) to bind + * a new UDP socket for sending inside send_renew. + * I hazard to guess existing listening socket + * is somehow conflicting with it, but why is it + * not deterministic then?! Strange. + * Anyway, it does recover by eventually failing through + * into INIT_SELECTING state. + */ + send_d6_renew(xid, &srv6_buf, requested_ipv6); + timeout >>= 1; + continue; + } + /* Timed out, enter rebinding state */ + log1("Entering rebinding state"); + state = REBINDING; + /* fall right through */ + case REBINDING: + /* Switch to bcast receive */ + change_listen_mode(LISTEN_RAW); + /* Lease is *really* about to run out, + * try to find DHCP server using broadcast */ + if (timeout > 0) { + /* send a broadcast renew request */ + send_d6_renew(xid, /*server_ipv6:*/ NULL, requested_ipv6); + timeout >>= 1; + continue; + } + /* Timed out, enter init state */ + bb_info_msg("Lease lost, entering init state"); + d6_run_script(NULL, "deconfig"); + state = INIT_SELECTING; + client_config.first_secs = 0; /* make secs field count from 0 */ + /*timeout = 0; - already is */ + packet_num = 0; + continue; + /* case RELEASED: */ + } + /* yah, I know, *you* say it would never happen */ + timeout = INT_MAX; + continue; /* back to main loop */ + } /* if select timed out */ + + /* select() didn't timeout, something happened */ + + /* Is it a signal? */ + /* note: udhcp_sp_read checks FD_ISSET before reading */ + switch (udhcp_sp_read(&rfds)) { + case SIGUSR1: + client_config.first_secs = 0; /* make secs field count from 0 */ + already_waited_sec = 0; + perform_renew(); + if (state == RENEW_REQUESTED) { + /* We might be either on the same network + * (in which case renew might work), + * or we might be on a completely different one + * (in which case renew won't ever succeed). + * For the second case, must make sure timeout + * is not too big, or else we can send + * futile renew requests for hours. + * (Ab)use -A TIMEOUT value (usually 20 sec) + * as a cap on the timeout. + */ + if (timeout > tryagain_timeout) + timeout = tryagain_timeout; + goto case_RENEW_REQUESTED; + } + /* Start things over */ + packet_num = 0; + /* Kill any timeouts, user wants this to hurry along */ + timeout = 0; + continue; + case SIGUSR2: + perform_d6_release(&srv6_buf, requested_ipv6); + timeout = INT_MAX; + continue; + case SIGTERM: + bb_info_msg("Received SIGTERM"); + goto ret0; + } + + /* Is it a packet? */ + if (listen_mode == LISTEN_NONE || !FD_ISSET(sockfd, &rfds)) + continue; /* no */ + + { + int len; + + /* A packet is ready, read it */ + if (listen_mode == LISTEN_KERNEL) + len = d6_recv_kernel_packet(&srv6_buf, &packet, sockfd); + else + len = d6_recv_raw_packet(&srv6_buf, &packet, sockfd); + if (len == -1) { + /* Error is severe, reopen socket */ + bb_info_msg("Read error: %s, reopening socket", strerror(errno)); + sleep(discover_timeout); /* 3 seconds by default */ + change_listen_mode(listen_mode); /* just close and reopen */ + } + /* If this packet will turn out to be unrelated/bogus, + * we will go back and wait for next one. + * Be sure timeout is properly decreased. */ + already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait; + if (len < 0) + continue; + packet_end = (uint8_t*)&packet + len; + } + + if ((packet.d6_xid32 & htonl(0x00ffffff)) != xid) { + log1("xid %x (our is %x), ignoring packet", + (unsigned)(packet.d6_xid32 & htonl(0x00ffffff)), (unsigned)xid); + continue; + } + + switch (state) { + case INIT_SELECTING: + if (packet.d6_msg_type == D6_MSG_ADVERTISE) + goto type_is_ok; + /* DHCPv6 has "Rapid Commit", when instead of Advertise, + * server sends Reply right away. + * Fall through to check for this case. + */ + case REQUESTING: + case RENEWING: + case RENEW_REQUESTED: + case REBINDING: + if (packet.d6_msg_type == D6_MSG_REPLY) { + uint32_t lease_seconds; + struct d6_option *option, *iaaddr; + type_is_ok: + option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE); + if (option && option->data[4] != 0) { + /* return to init state */ + bb_info_msg("Received DHCP NAK (%u)", option->data[4]); + d6_run_script(&packet, "nak"); + if (state != REQUESTING) + d6_run_script(NULL, "deconfig"); + change_listen_mode(LISTEN_RAW); + sleep(3); /* avoid excessive network traffic */ + state = INIT_SELECTING; + client_config.first_secs = 0; /* make secs field count from 0 */ + requested_ipv6 = NULL; + timeout = 0; + packet_num = 0; + already_waited_sec = 0; + continue; + } + option = d6_copy_option(packet.d6_options, packet_end, D6_OPT_SERVERID); + if (!option) { + bb_error_msg("no server ID, ignoring packet"); + continue; + /* still selecting - this server looks bad */ + } +//Note: we do not bother comparing server IDs in Advertise and Reply msgs. +//server_id variable is used solely for creation of proper server_id option +//in outgoing packets. (why DHCPv6 even introduced it is a mystery). + free(client6_data.server_id); + client6_data.server_id = option; + if (packet.d6_msg_type == D6_MSG_ADVERTISE) { + /* enter requesting state */ + state = REQUESTING; + timeout = 0; + packet_num = 0; + already_waited_sec = 0; + continue; + } + /* It's a D6_MSG_REPLY */ +/* + * RFC 3315 18.1.8. Receipt of Reply Messages + * + * Upon the receipt of a valid Reply message in response to a Solicit + * (with a Rapid Commit option), Request, Confirm, Renew, Rebind or + * Information-request message, the client extracts the configuration + * information contained in the Reply. The client MAY choose to report + * any status code or message from the status code option in the Reply + * message. + * + * The client SHOULD perform duplicate address detection [17] on each of + * the addresses in any IAs it receives in the Reply message before + * using that address for traffic. If any of the addresses are found to + * be in use on the link, the client sends a Decline message to the + * server as described in section 18.1.7. + * + * If the Reply was received in response to a Solicit (with a Rapid + * Commit option), Request, Renew or Rebind message, the client updates + * the information it has recorded about IAs from the IA options + * contained in the Reply message: + * + * - Record T1 and T2 times. + * + * - Add any new addresses in the IA option to the IA as recorded by + * the client. + * + * - Update lifetimes for any addresses in the IA option that the + * client already has recorded in the IA. + * + * - Discard any addresses from the IA, as recorded by the client, that + * have a valid lifetime of 0 in the IA Address option. + * + * - Leave unchanged any information about addresses the client has + * recorded in the IA but that were not included in the IA from the + * server. + * + * Management of the specific configuration information is detailed in + * the definition of each option in section 22. + * + * If the client receives a Reply message with a Status Code containing + * UnspecFail, the server is indicating that it was unable to process + * the message due to an unspecified failure condition. If the client + * retransmits the original message to the same server to retry the + * desired operation, the client MUST limit the rate at which it + * retransmits the message and limit the duration of the time during + * which it retransmits the message. + * + * When the client receives a Reply message with a Status Code option + * with the value UseMulticast, the client records the receipt of the + * message and sends subsequent messages to the server through the + * interface on which the message was received using multicast. The + * client resends the original message using multicast. + * + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | OPTION_IA_NA | option-len | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | IAID (4 octets) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | T1 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | T2 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * . IA_NA-options . + * . . + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | OPTION_IAADDR | option-len | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * | IPv6 address | + * | | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | preferred-lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | valid-lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * . . + * . IAaddr-options . + * . . + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + free(client6_data.ia_na); + client6_data.ia_na = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_NA); + if (!client6_data.ia_na) { + bb_error_msg("no lease time, ignoring packet"); + continue; + } + if (client6_data.ia_na->len < (4 + 4 + 4) + (2 + 2 + 16 + 4 + 4)) { + bb_error_msg("IA_NA option is too short:%d bytes", client6_data.ia_na->len); + continue; + } + iaaddr = d6_find_option(client6_data.ia_na->data, + client6_data.ia_na->data + client6_data.ia_na->len, + D6_OPT_IAADDR + ); + if (!iaaddr) { + bb_error_msg("no lease time, ignoring packet"); + continue; + } + if (iaaddr->len < (16 + 4 + 4)) { + bb_error_msg("IAADDR option is too short:%d bytes", iaaddr->len); + continue; + } + /* Note: the address is sufficiently aligned for cast: + * we _copied_ IA-NA, and copy is always well-aligned. + */ + requested_ipv6 = (struct in6_addr*) iaaddr->data; + move_from_unaligned32(lease_seconds, iaaddr->data + 16 + 4); + lease_seconds = ntohl(lease_seconds); + /* paranoia: must not be too small and not prone to overflows */ + if (lease_seconds < 0x10) + lease_seconds = 0x10; +/// TODO: check for 0 lease time? + if (lease_seconds >= 0x10000000) + lease_seconds = 0x0fffffff; + /* enter bound state */ + timeout = lease_seconds / 2; + bb_info_msg("Lease obtained, lease time %u", + /*inet_ntoa(temp_addr),*/ (unsigned)lease_seconds); + d6_run_script(&packet, state == REQUESTING ? "bound" : "renew"); + + state = BOUND; + change_listen_mode(LISTEN_NONE); + if (opt & OPT_q) { /* quit after lease */ + goto ret0; + } + /* future renew failures should not exit (JM) */ + opt &= ~OPT_n; +#if BB_MMU /* NOMMU case backgrounded earlier */ + if (!(opt & OPT_f)) { + client_background(); + /* do not background again! */ + opt = ((opt & ~OPT_b) | OPT_f); + } +#endif + already_waited_sec = 0; + continue; /* back to main loop */ + } + continue; + /* case BOUND: - ignore all packets */ + /* case RELEASED: - ignore all packets */ + } + /* back to main loop */ + } /* for (;;) - main loop ends */ + + ret0: + if (opt & OPT_R) /* release on quit */ + perform_d6_release(&srv6_buf, requested_ipv6); + retval = 0; + ret: + /*if (client_config.pidfile) - remove_pidfile has its own check */ + remove_pidfile(client_config.pidfile); + return retval; +} diff --git a/networking/udhcp/d6_packet.c b/networking/udhcp/d6_packet.c new file mode 100644 index 000000000..3a1bb3df1 --- /dev/null +++ b/networking/udhcp/d6_packet.c @@ -0,0 +1,168 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2011 Denys Vlasenko. + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +#include "common.h" +#include "d6_common.h" +#include "dhcpd.h" +#include +#include +#include + +#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2 +void FAST_FUNC d6_dump_packet(struct d6_packet *packet) +{ + if (dhcp_verbose < 2) + return; + + bb_info_msg( + " xid %x" + , packet->d6_xid32 + ); + //*bin2hex(buf, (void *) packet->chaddr, sizeof(packet->chaddr)) = '\0'; + //bb_info_msg(" chaddr %s", buf); +} +#endif + +int FAST_FUNC d6_recv_kernel_packet(struct in6_addr *peer_ipv6 + UNUSED_PARAM + , struct d6_packet *packet, int fd) +{ + int bytes; + + memset(packet, 0, sizeof(*packet)); + bytes = safe_read(fd, packet, sizeof(*packet)); + if (bytes < 0) { + log1("Packet read error, ignoring"); + return bytes; /* returns -1 */ + } + + if (bytes < offsetof(struct d6_packet, d6_options)) { + bb_info_msg("Packet with bad magic, ignoring"); + return -2; + } + log1("Received a packet"); + d6_dump_packet(packet); + + return bytes; +} + +/* Construct a ipv6+udp header for a packet, send packet */ +int FAST_FUNC d6_send_raw_packet( + struct d6_packet *d6_pkt, unsigned d6_pkt_size, + struct in6_addr *src_ipv6, int source_port, + struct in6_addr *dst_ipv6, int dest_port, const uint8_t *dest_arp, + int ifindex) +{ + struct sockaddr_ll dest_sll; + struct ip6_udp_d6_packet packet; + int fd; + int result = -1; + const char *msg; + + fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6)); + if (fd < 0) { + msg = "socket(%s)"; + goto ret_msg; + } + + memset(&dest_sll, 0, sizeof(dest_sll)); + memset(&packet, 0, offsetof(struct ip6_udp_d6_packet, data)); + packet.data = *d6_pkt; /* struct copy */ + + dest_sll.sll_family = AF_PACKET; + dest_sll.sll_protocol = htons(ETH_P_IPV6); + dest_sll.sll_ifindex = ifindex; + dest_sll.sll_halen = 6; + memcpy(dest_sll.sll_addr, dest_arp, 6); + + if (bind(fd, (struct sockaddr *)&dest_sll, sizeof(dest_sll)) < 0) { + msg = "bind(%s)"; + goto ret_close; + } + + packet.ip6.ip6_vfc = (6 << 4); /* 4 bits version, top 4 bits of tclass */ + if (src_ipv6) + packet.ip6.ip6_src = *src_ipv6; /* struct copy */ + packet.ip6.ip6_dst = *dst_ipv6; /* struct copy */ + packet.udp.source = htons(source_port); + packet.udp.dest = htons(dest_port); + /* size, excluding IP header: */ + packet.udp.len = htons(sizeof(struct udphdr) + d6_pkt_size); + packet.ip6.ip6_plen = packet.udp.len; + /* UDP checksum skips first four bytes of IP header. + * IPv6 'hop limit' field should be 0. + * 'next header' field should be summed as if it is in a different + * position, therefore we write its value into ip6_hlim: + */ + packet.ip6.ip6_hlim = IPPROTO_UDP; + packet.udp.check = inet_cksum((uint16_t *)&packet + 2, + offsetof(struct ip6_udp_d6_packet, data) - 4 + d6_pkt_size); + /* fix 'hop limit' and 'next header' after UDP checksumming */ + packet.ip6.ip6_hlim = 8; + packet.ip6.ip6_nxt = IPPROTO_UDP; + + d6_dump_packet(d6_pkt); + result = sendto(fd, &packet, offsetof(struct ip6_udp_d6_packet, data) + d6_pkt_size, + /*flags:*/ 0, + (struct sockaddr *) &dest_sll, sizeof(dest_sll) + ); + msg = "sendto"; + ret_close: + close(fd); + if (result < 0) { + ret_msg: + bb_perror_msg(msg, "PACKET"); + } + return result; +} + +/* Let the kernel do all the work for packet generation */ +int FAST_FUNC d6_send_kernel_packet( + struct d6_packet *d6_pkt, unsigned d6_pkt_size, + struct in6_addr *src_ipv6, int source_port, + struct in6_addr *dst_ipv6, int dest_port) +{ + struct sockaddr_in6 sa; + int fd; + int result = -1; + const char *msg; + + fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (fd < 0) { + msg = "socket(%s)"; + goto ret_msg; + } + setsockopt_reuseaddr(fd); + + memset(&sa, 0, sizeof(sa)); + sa.sin6_family = AF_INET6; + sa.sin6_port = htons(source_port); + sa.sin6_addr = *src_ipv6; /* struct copy */ + if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { + msg = "bind(%s)"; + goto ret_close; + } + + memset(&sa, 0, sizeof(sa)); + sa.sin6_family = AF_INET6; + sa.sin6_port = htons(dest_port); + sa.sin6_addr = *dst_ipv6; /* struct copy */ + if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { + msg = "connect"; + goto ret_close; + } + + d6_dump_packet(d6_pkt); + result = safe_write(fd, d6_pkt, d6_pkt_size); + msg = "write"; + ret_close: + close(fd); + if (result < 0) { + ret_msg: + bb_perror_msg(msg, "UDP"); + } + return result; +} diff --git a/networking/udhcp/d6_socket.c b/networking/udhcp/d6_socket.c new file mode 100644 index 000000000..56f69f6a1 --- /dev/null +++ b/networking/udhcp/d6_socket.c @@ -0,0 +1,34 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2011 Denys Vlasenko. + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +#include "common.h" +#include "d6_common.h" +#include + +int FAST_FUNC d6_listen_socket(int port, const char *inf) +{ + int fd; + struct sockaddr_in6 addr; + + log1("Opening listen socket on *:%d %s", port, inf); + fd = xsocket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); + + setsockopt_reuseaddr(fd); + if (setsockopt_broadcast(fd) == -1) + bb_perror_msg_and_die("SO_BROADCAST"); + + /* NB: bug 1032 says this doesn't work on ethernet aliases (ethN:M) */ + if (setsockopt_bindtodevice(fd, inf)) + xfunc_die(); /* warning is already printed */ + + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(port); + /* addr.sin6_addr is all-zeros */ + xbind(fd, (struct sockaddr *)&addr, sizeof(addr)); + + return fd; +} -- cgit v1.2.3-55-g6feb From 68c5b28156450d686605bd4715980037cabf1286 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Nov 2011 16:21:24 +0100 Subject: udhcpc6: fix endianness Signed-off-by: Denys Vlasenko --- networking/udhcp/d6_common.h | 4 ++-- networking/udhcp/d6_dhcpc.c | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/networking/udhcp/d6_common.h b/networking/udhcp/d6_common.h index 88afaf8af..36d822f7e 100644 --- a/networking/udhcp/d6_common.h +++ b/networking/udhcp/d6_common.h @@ -54,10 +54,10 @@ struct udp_d6_packet { /*** Options ***/ struct d6_option { - uint8_t code; uint8_t code_hi; - uint8_t len; + uint8_t code; uint8_t len_hi; + uint8_t len; uint8_t data[1]; } PACKED; diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c index d1baaae9b..62d79b363 100644 --- a/networking/udhcp/d6_dhcpc.c +++ b/networking/udhcp/d6_dhcpc.c @@ -97,20 +97,20 @@ static void *d6_find_option(uint8_t *option, uint8_t *option_end, unsigned code) int len_m4 = option_end - option - 4; while (len_m4 >= 0) { /* Next option's len is too big? */ - if (option[2] > len_m4) + if (option[3] > len_m4) return NULL; /* yes. bogus packet! */ /* So far we treat any opts with code >255 * or len >255 as bogus, and stop at once. * This simplifies big-endian handling. */ - if (option[1] != 0 || option[3] != 0) + if (option[0] != 0 || option[2] != 0) return NULL; /* Option seems to be valid */ /* Does its code match? */ - if (option[0] == code) + if (option[1] == code) return option; /* yes! */ - option += option[2] + 4; - len_m4 -= option[2] + 4; + option += option[3] + 4; + len_m4 -= option[3] + 4; } return NULL; } @@ -120,7 +120,7 @@ static void *d6_copy_option(uint8_t *option, uint8_t *option_end, unsigned code) uint8_t *opt = d6_find_option(option, option_end, code); if (!opt) return opt; - return memcpy(xmalloc(opt[2] + 4), opt, opt[2] + 4); + return memcpy(xmalloc(opt[3] + 4), opt, opt[3] + 4); } static void *d6_store_blob(void *dst, const void *src, unsigned len) @@ -920,8 +920,8 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) clientid = xzalloc(2+2+2+2+6); clientid->code = D6_OPT_CLIENTID; clientid->len = 2+2+6; - clientid->data[0] = 3; /* DUID-LL */ - clientid->data[2] = 1; /* ethernet */ + clientid->data[1] = 3; /* DUID-LL */ + clientid->data[3] = 1; /* ethernet */ clientid_mac_ptr = clientid->data + 2+2; memcpy(clientid_mac_ptr, client_config.client_mac, 6); client_config.clientid = (void*)clientid; -- cgit v1.2.3-55-g6feb From 2b6a6b90cc7cebe777ce5d6eec10ecfc8f7a54b7 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Nov 2011 18:22:06 +0100 Subject: udhcpc6: set hop limit to 1 in emitted raw packets Signed-off-by: Denys Vlasenko --- networking/udhcp/d6_packet.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/networking/udhcp/d6_packet.c b/networking/udhcp/d6_packet.c index 3a1bb3df1..79b2946ef 100644 --- a/networking/udhcp/d6_packet.c +++ b/networking/udhcp/d6_packet.c @@ -92,16 +92,20 @@ int FAST_FUNC d6_send_raw_packet( /* size, excluding IP header: */ packet.udp.len = htons(sizeof(struct udphdr) + d6_pkt_size); packet.ip6.ip6_plen = packet.udp.len; - /* UDP checksum skips first four bytes of IP header. - * IPv6 'hop limit' field should be 0. - * 'next header' field should be summed as if it is in a different - * position, therefore we write its value into ip6_hlim: + /* + * Someone was smoking weed (at least) while inventing UDP checksumming: + * UDP checksum skips first four bytes of IPv6 header. + * 'next header' field should be summed as if it is one more byte + * to the right, therefore we write its value (IPPROTO_UDP) + * into ip6_hlim, and its 'real' location remains zero-filled for now. */ packet.ip6.ip6_hlim = IPPROTO_UDP; - packet.udp.check = inet_cksum((uint16_t *)&packet + 2, - offsetof(struct ip6_udp_d6_packet, data) - 4 + d6_pkt_size); + packet.udp.check = inet_cksum( + (uint16_t *)&packet + 2, + offsetof(struct ip6_udp_d6_packet, data) - 4 + d6_pkt_size + ); /* fix 'hop limit' and 'next header' after UDP checksumming */ - packet.ip6.ip6_hlim = 8; + packet.ip6.ip6_hlim = 1; /* observed Windows machines to use hlim=1 */ packet.ip6.ip6_nxt = IPPROTO_UDP; d6_dump_packet(d6_pkt); -- cgit v1.2.3-55-g6feb From 7e21f0491cf3e72835cd9b515734caec56d41e70 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 8 Nov 2011 11:39:41 +0100 Subject: udhcpc[6]: tweak help text, remove -B from udhcpc6 and "--version" from both Signed-off-by: Denys Vlasenko --- networking/udhcp/d6_dhcpc.c | 19 ++++++++----------- networking/udhcp/dhcpc.c | 3 +-- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c index 62d79b363..5c98e82f1 100644 --- a/networking/udhcp/d6_dhcpc.c +++ b/networking/udhcp/d6_dhcpc.c @@ -38,7 +38,7 @@ #if ENABLE_LONG_OPTS -static const char udhcpc_longopts[] ALIGN1 = +static const char udhcpc6_longopts[] ALIGN1 = "interface\0" Required_argument "i" "now\0" No_argument "n" "pidfile\0" Required_argument "p" @@ -47,7 +47,6 @@ static const char udhcpc_longopts[] ALIGN1 = "request\0" Required_argument "r" "script\0" Required_argument "s" "timeout\0" Required_argument "T" - "version\0" No_argument "v" "retries\0" Required_argument "t" "tryagain\0" Required_argument "A" "syslog\0" No_argument "S" @@ -55,7 +54,6 @@ static const char udhcpc_longopts[] ALIGN1 = "no-default-options\0" No_argument "o" "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_UDHCP_PORT("client-port\0" Required_argument "P") ; @@ -77,9 +75,8 @@ enum { OPT_o = 1 << 12, OPT_x = 1 << 13, OPT_f = 1 << 14, - OPT_B = 1 << 15, /* The rest has variable bit positions, need to be clever */ - OPTBIT_B = 15, + OPTBIT_f = 14, USE_FOR_MMU( OPTBIT_b,) ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) IF_FEATURE_UDHCP_PORT( OPTBIT_P,) @@ -751,7 +748,7 @@ static void client_background(void) //usage:# define IF_UDHCP_VERBOSE(...) //usage:#endif //usage:#define udhcpc6_trivial_usage -//usage: "[-fbnq"IF_UDHCP_VERBOSE("v")"oRB] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n" +//usage: "[-fbnq"IF_UDHCP_VERBOSE("v")"oR] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n" //usage: " [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]") //usage:#define udhcpc6_full_usage "\n" //usage: IF_LONG_OPTS( @@ -771,7 +768,7 @@ static void client_background(void) //usage: "\n -R,--release Release IP on exit" //usage: "\n -S,--syslog Log to syslog too" //usage: IF_FEATURE_UDHCP_PORT( -//usage: "\n -P,--client-port N Use port N (default 68)" +//usage: "\n -P,--client-port N Use port N (default 546)" //usage: ) ////usage: IF_FEATURE_UDHCPC_ARPING( ////usage: "\n -a,--arping Use arping to validate offered address" @@ -805,7 +802,7 @@ static void client_background(void) //usage: "\n -R Release IP on exit" //usage: "\n -S Log to syslog too" //usage: IF_FEATURE_UDHCP_PORT( -//usage: "\n -P N Use port N (default 68)" +//usage: "\n -P N Use port N (default 546)" //usage: ) ////usage: IF_FEATURE_UDHCPC_ARPING( ////usage: "\n -a Use arping to validate offered address" @@ -859,8 +856,8 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) /* Parse command line */ /* O,x: list; -T,-t,-A take numeric param */ opt_complementary = "O::x::T+:t+:A+" IF_UDHCP_VERBOSE(":vv") ; - IF_LONG_OPTS(applet_long_options = udhcpc_longopts;) - opt = getopt32(argv, "i:np:qRr:s:T:t:SA:O:ox:fB" + IF_LONG_OPTS(applet_long_options = udhcpc6_longopts;) + opt = getopt32(argv, "i:np:qRr:s:T:t:SA:O:ox:f" USE_FOR_MMU("b") ///IF_FEATURE_UDHCPC_ARPING("a") IF_FEATURE_UDHCP_PORT("P:") @@ -872,7 +869,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) , &list_x IF_FEATURE_UDHCP_PORT(, &str_P) IF_UDHCP_VERBOSE(, &dhcp_verbose) - ); + ); requested_ipv6 = NULL; if (opt & OPT_r) { if (inet_pton(AF_INET6, str_r, &ipv6_buf) <= 0) diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index 3a4ef9e64..3c4e8dee1 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -46,7 +46,6 @@ static const char udhcpc_longopts[] ALIGN1 = "request\0" Required_argument "r" "script\0" Required_argument "s" "timeout\0" Required_argument "T" - "version\0" No_argument "v" "retries\0" Required_argument "t" "tryagain\0" Required_argument "A" "syslog\0" No_argument "S" @@ -1183,7 +1182,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) , &list_x IF_FEATURE_UDHCP_PORT(, &str_P) IF_UDHCP_VERBOSE(, &dhcp_verbose) - ); + ); if (opt & (OPT_h|OPT_H)) { //msg added 2011-11 bb_error_msg("option -h NAME is deprecated, use -x hostname:NAME"); -- cgit v1.2.3-55-g6feb From 743edac6c84ac207d0bb4c3124b0e8fe450a38b4 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Wed, 9 Nov 2011 19:44:37 +0100 Subject: bb_daemonize_or_rexec(): add flag to double-fork; use it in start-stop-daemon Add a DAEMON_DOUBLE_FORK flag to make bb_daemonize double-fork so it isn't a session leader, and hence doesn't get a controlling tty on Linux if a tty is ever opened, similar to how libdaemon's daemon_fork or the big start-stop-daemon does it - And use it in start-stop-daemon. For details, see http://www.win.tue.nl/~aeb/linux/lk/lk-10.html#ss10.3 Signed-off-by: Peter Korsgaard Signed-off-by: Denys Vlasenko --- debianutils/start_stop_daemon.c | 2 +- include/libbb.h | 1 + libbb/vfork_daemon_rexec.c | 10 +++++++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c index 02609c04f..495ed0a09 100644 --- a/debianutils/start_stop_daemon.c +++ b/debianutils/start_stop_daemon.c @@ -474,7 +474,7 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) *--argv = startas; if (opt & OPT_BACKGROUND) { #if BB_MMU - bb_daemonize(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS); + bb_daemonize(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS + DAEMON_DOUBLE_FORK); /* DAEMON_DEVNULL_STDIO is superfluous - * it's always done by bb_daemonize() */ #else diff --git a/include/libbb.h b/include/libbb.h index 53224fa35..09e8d28e7 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -966,6 +966,7 @@ enum { DAEMON_DEVNULL_STDIO = 2, DAEMON_CLOSE_EXTRA_FDS = 4, DAEMON_ONLY_SANITIZE = 8, /* internal use */ + DAEMON_DOUBLE_FORK = 16, /* double fork to avoid controlling tty */ }; #if BB_MMU enum { re_execed = 0 }; diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index a75eafbd3..ed1f86f0c 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -253,11 +253,19 @@ void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv) if (!(flags & DAEMON_ONLY_SANITIZE)) { if (fork_or_rexec(argv)) exit(EXIT_SUCCESS); /* parent */ - /* if daemonizing, make sure we detach from stdio & ctty */ + /* if daemonizing, detach from stdio & ctty */ setsid(); dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); + if (flags & DAEMON_DOUBLE_FORK) { + /* On Linux, session leader can acquire ctty + * unknowingly, by opening a tty. + * Prevent this: stop being a session leader. + */ + if (fork_or_rexec(argv)) + exit(EXIT_SUCCESS); /* parent */ + } } while (fd > 2) { close(fd--); -- cgit v1.2.3-55-g6feb From b9f4cd85f0e9c62aba2d6f1be67eb8369fdcedce Mon Sep 17 00:00:00 2001 From: Bernhard Reutner-Fischer Date: Wed, 9 Nov 2011 20:23:38 +0100 Subject: Config: clarify {SHOW,VERBOSE,COMPRESS}_USAGE Signed-off-by: Bernhard Reutner-Fischer --- Config.in | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Config.in b/Config.in index 1e7181261..79fe8ff9a 100644 --- a/Config.in +++ b/Config.in @@ -83,20 +83,21 @@ config FEATURE_BUFFERS_GO_IN_BSS endchoice config SHOW_USAGE - bool "Show terse applet usage messages" + bool "Show applet usage messages" default y help - All BusyBox applets will show help messages when invoked with - wrong arguments. You can turn off printing these terse usage - messages if you say no here. - This will save you up to 7k. + Enabling this option, BusyBox applets will show terse help messages + when invoked with wrong arguments. + If you do not want to show any (helpful) usage message when + issuing wrong command syntax, you can say 'N' here, + saving approximately 7k. config FEATURE_VERBOSE_USAGE bool "Show verbose applet usage messages" default y depends on SHOW_USAGE help - All BusyBox applets will show more verbose help messages when + All BusyBox applets will show verbose help messages when busybox is invoked with --help. This will add a lot of text to the busybox binary. In the default configuration, this will add about 13k, but it can add much more depending on your configuration. @@ -106,8 +107,8 @@ config FEATURE_COMPRESS_USAGE default y depends on SHOW_USAGE help - Store usage messages in compressed form, uncompress them on-the-fly - when --help is called. + Store usage messages in .bz compressed form, uncompress them + on-the-fly when --help is called. If you have a really tiny busybox with few applets enabled (and bunzip2 isn't one of them), the overhead of the decompressor might -- cgit v1.2.3-55-g6feb From fae473c81b98a1b2290b7efcd4ee9a8ebbb3b1e6 Mon Sep 17 00:00:00 2001 From: Dave Love Date: Thu, 10 Nov 2011 15:19:25 +0100 Subject: mount: support -o noacl Signed-off-by: Dave Love Signed-off-by: Denys Vlasenko --- util-linux/mount.c | 52 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/util-linux/mount.c b/util-linux/mount.c index f94b6e643..1dd4c0c43 100644 --- a/util-linux/mount.c +++ b/util-linux/mount.c @@ -820,31 +820,31 @@ enum { */ struct nfs2_fh { - char data[32]; + char data[32]; }; struct nfs3_fh { - unsigned short size; - unsigned char data[64]; + unsigned short size; + unsigned char data[64]; }; struct nfs_mount_data { - int version; /* 1 */ - int fd; /* 1 */ - struct nfs2_fh old_root; /* 1 */ - int flags; /* 1 */ - int rsize; /* 1 */ - int wsize; /* 1 */ - int timeo; /* 1 */ - int retrans; /* 1 */ - int acregmin; /* 1 */ - int acregmax; /* 1 */ - int acdirmin; /* 1 */ - int acdirmax; /* 1 */ - struct sockaddr_in addr; /* 1 */ - char hostname[256]; /* 1 */ - int namlen; /* 2 */ - unsigned int bsize; /* 3 */ - struct nfs3_fh root; /* 4 */ + int version; /* 1 */ + int fd; /* 1 */ + struct nfs2_fh old_root; /* 1 */ + int flags; /* 1 */ + int rsize; /* 1 */ + int wsize; /* 1 */ + int timeo; /* 1 */ + int retrans; /* 1 */ + int acregmin; /* 1 */ + int acregmax; /* 1 */ + int acdirmin; /* 1 */ + int acdirmax; /* 1 */ + struct sockaddr_in addr; /* 1 */ + char hostname[256]; /* 1 */ + int namlen; /* 2 */ + unsigned int bsize; /* 3 */ + struct nfs3_fh root; /* 4 */ }; /* bits in the flags field */ @@ -859,6 +859,7 @@ enum { NFS_MOUNT_VER3 = 0x0080, /* 3 */ NFS_MOUNT_KERBEROS = 0x0100, /* 3 */ NFS_MOUNT_NONLM = 0x0200, /* 3 */ + NFS_MOUNT_NOACL = 0x0800, /* 4 */ NFS_MOUNT_NORDIRPLUS = 0x4000 }; @@ -1123,6 +1124,7 @@ static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts) int noac; int nordirplus; int nolock; + int noacl; find_kernel_nfs_mount_version(); @@ -1195,6 +1197,7 @@ static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts) nolock = 0; noac = 0; nordirplus = 0; + noacl = 0; retry = 10000; /* 10000 minutes ~ 1 week */ tcp = 1; /* nfs-utils uses tcp per default */ @@ -1333,7 +1336,8 @@ static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts) "tcp\0" "udp\0" "lock\0" - "rdirplus\0"; + "rdirplus\0" + "acl\0"; int val = 1; if (!strncmp(opt, "no", 2)) { val = 0; @@ -1383,6 +1387,9 @@ static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts) case 11: //rdirplus nordirplus = !val; break; + case 12: // acl + noacl = !val; + break; default: bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt); goto fail; @@ -1396,7 +1403,8 @@ static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts) | (posix ? NFS_MOUNT_POSIX : 0) | (nocto ? NFS_MOUNT_NOCTO : 0) | (noac ? NFS_MOUNT_NOAC : 0) - | (nordirplus ? NFS_MOUNT_NORDIRPLUS : 0); + | (nordirplus ? NFS_MOUNT_NORDIRPLUS : 0) + | (noacl ? NFS_MOUNT_NOACL : 0); if (nfs_mount_version >= 2) data.flags |= (tcp ? NFS_MOUNT_TCP : 0); if (nfs_mount_version >= 3) -- cgit v1.2.3-55-g6feb From a86e02492d7700ce8cb4108f53646dfb025c2dff Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 10 Nov 2011 16:53:35 +0100 Subject: mount: make FEATURE_MOUNT_NFS not needed for Linux 2.6.23+ Signed-off-by: Denys Vlasenko --- util-linux/Config.src | 11 ++++++++--- util-linux/mount.c | 47 +++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/util-linux/Config.src b/util-linux/Config.src index 888bc8f3b..57a52cefb 100644 --- a/util-linux/Config.src +++ b/util-linux/Config.src @@ -485,13 +485,18 @@ config FEATURE_MOUNT_LABEL This also enables label or uuid support for swapon. config FEATURE_MOUNT_NFS - bool "Support mounting NFS file systems" - default y + bool "Support mounting NFS file systems on Linux < 2.6.23" + default n depends on MOUNT select FEATURE_HAVE_RPC select FEATURE_SYSLOG help - Enable mounting of NFS file systems. + Enable mounting of NFS file systems on Linux kernels prior + to version 2.6.23. Note that in this case mounting of NFS + over IPv6 will not be possible. + + Note that this option links in RPC support from libc, + which is rather large (~10 kbytes on uclibc). config FEATURE_MOUNT_CIFS bool "Support mounting CIFS/SMB file systems" diff --git a/util-linux/mount.c b/util-linux/mount.c index 1dd4c0c43..7ae1981c8 100644 --- a/util-linux/mount.c +++ b/util-linux/mount.c @@ -1144,7 +1144,7 @@ static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts) pathname = s + 1; *s = '\0'; /* Ignore all but first hostname in replicated mounts - until they can be fully supported. (mack@sgi.com) */ + * until they can be fully supported. (mack@sgi.com) */ s = strchr(hostname, ','); if (s) { *s = '\0'; @@ -1683,7 +1683,6 @@ static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts) /* Perform actual mount */ do_mount: - mp->mnt_type = (char*)"nfs"; retval = mount_it_now(mp, vfsflags, (char*)&data); goto ret; @@ -1708,8 +1707,43 @@ static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts) #else // !ENABLE_FEATURE_MOUNT_NFS -// Never called. Call should be optimized out. -int nfsmount(struct mntent *mp, long vfsflags, char *filteropts); +/* Linux 2.6.23+ supports nfs mounts with options passed as a string. + * For older kernels, you must build busybox with ENABLE_FEATURE_MOUNT_NFS. + * (However, note that then you lose any chances that NFS over IPv6 would work). + */ +static int nfsmount(struct mntent *mp, long vfsflags, char *filteropts) +{ + len_and_sockaddr *lsa; + char *opts; + char *end; + char *dotted; + int ret; + +# if ENABLE_FEATURE_IPV6 + end = strchr(mp->mnt_fsname, ']'); + if (end && end[1] == ':') + end++; + else +# endif + /* mount_main() guarantees that ':' is there */ + end = strchr(mp->mnt_fsname, ':'); + + *end = '\0'; + lsa = xdotted2sockaddr(mp->mnt_fsname, /*port:*/ 0); + *end = ':'; + dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa); + if (ENABLE_FEATURE_CLEAN_UP) free(lsa); + opts = xasprintf("%s%saddr=%s", + filteropts ? filteropts : "", + filteropts ? "," : "", + dotted + ); + if (ENABLE_FEATURE_CLEAN_UP) free(dotted); + ret = mount_it_now(mp, vfsflags, opts); + if (ENABLE_FEATURE_CLEAN_UP) free(opts); + + return ret; +} #endif // !ENABLE_FEATURE_MOUNT_NFS @@ -1800,10 +1834,11 @@ static int singlemount(struct mntent *mp, int ignore_busy) } // Might this be an NFS filesystem? - if (ENABLE_FEATURE_MOUNT_NFS - && (!mp->mnt_type || strcmp(mp->mnt_type, "nfs") == 0) + if ((!mp->mnt_type || strncmp(mp->mnt_type, "nfs", 3) == 0) && strchr(mp->mnt_fsname, ':') != NULL ) { + if (!mp->mnt_type) + mp->mnt_type = (char*)"nfs"; rc = nfsmount(mp, vfsflags, filteropts); goto report_error; } -- cgit v1.2.3-55-g6feb From 39b233182c0a13200be051b993da181a1db80a87 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 10 Nov 2011 17:01:39 +0100 Subject: mount: resolve hosts to IPs in nfs mounts Signed-off-by: Denys Vlasenko --- util-linux/mount.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util-linux/mount.c b/util-linux/mount.c index 7ae1981c8..807e89747 100644 --- a/util-linux/mount.c +++ b/util-linux/mount.c @@ -1729,7 +1729,7 @@ static int nfsmount(struct mntent *mp, long vfsflags, char *filteropts) end = strchr(mp->mnt_fsname, ':'); *end = '\0'; - lsa = xdotted2sockaddr(mp->mnt_fsname, /*port:*/ 0); + lsa = xhost2sockaddr(mp->mnt_fsname, /*port:*/ 0); *end = ':'; dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa); if (ENABLE_FEATURE_CLEAN_UP) free(lsa); -- cgit v1.2.3-55-g6feb From 2951add2bf240e47b1d2e7bc384f138428391366 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 10 Nov 2011 18:00:28 +0100 Subject: applets_sh/nologin: an applet implemented as shell script Signed-off-by: Denys Vlasenko --- applets_sh/nologin | 4 ++++ 1 file changed, 4 insertions(+) create mode 100755 applets_sh/nologin diff --git a/applets_sh/nologin b/applets_sh/nologin new file mode 100755 index 000000000..3768eaaa7 --- /dev/null +++ b/applets_sh/nologin @@ -0,0 +1,4 @@ +#!/bin/sh +cat /etc/nologin.txt 2>/dev/null || echo "This account is not available" +sleep 5 +exit 1 -- cgit v1.2.3-55-g6feb From a092a89d8f052072e562861f2968573d89e10dd5 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 16 Nov 2011 20:17:12 +0100 Subject: udhcpc6: rudimentary code to export data to script; fix IAADDR parsing Signed-off-by: Denys Vlasenko --- networking/udhcp/common.c | 19 +++++++ networking/udhcp/common.h | 3 ++ networking/udhcp/d6_common.h | 5 ++ networking/udhcp/d6_dhcpc.c | 126 +++++++++++++++++++++++++++++++++++-------- networking/udhcp/dhcpc.c | 18 ------- 5 files changed, 131 insertions(+), 40 deletions(-) diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c index 2e6113627..a89dce3ae 100644 --- a/networking/udhcp/common.c +++ b/networking/udhcp/common.c @@ -539,3 +539,22 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg) return retval; } + +/* note: ip is a pointer to an IPv6 in network order, possibly misaliged */ +int FAST_FUNC sprint_nip6(char *dest, /*const char *pre,*/ const uint8_t *ip) +{ + char hexstrbuf[16 * 2]; + bin2hex(hexstrbuf, (void*)ip, 16); + return sprintf(dest, /* "%s" */ + "%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s", + /* pre, */ + hexstrbuf + 0 * 4, + hexstrbuf + 1 * 4, + hexstrbuf + 2 * 4, + hexstrbuf + 3 * 4, + hexstrbuf + 4 * 4, + hexstrbuf + 5 * 4, + hexstrbuf + 6 * 4, + hexstrbuf + 7 * 4 + ); +} diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h index a7f9395b8..479ae49f3 100644 --- a/networking/udhcp/common.h +++ b/networking/udhcp/common.h @@ -308,6 +308,9 @@ int arpping(uint32_t test_nip, uint8_t *from_mac, const char *interface) 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; + POP_SAVED_FUNCTION_VISIBILITY #endif diff --git a/networking/udhcp/d6_common.h b/networking/udhcp/d6_common.h index 36d822f7e..4dd7e621e 100644 --- a/networking/udhcp/d6_common.h +++ b/networking/udhcp/d6_common.h @@ -81,11 +81,16 @@ struct d6_option { #define D6_OPT_RECONF_MSG 19 #define D6_OPT_RECONF_ACCEPT 20 +#define D6_OPT_IA_PD 25 +#define D6_OPT_IAPREFIX 26 + /*** Other shared functions ***/ struct client6_data_t { struct d6_option *server_id; struct d6_option *ia_na; + char **env_ptr; + unsigned env_idx; }; #define client6_data (*(struct client6_data_t*)(&bb_common_bufsiz1[COMMON_BUFSIZE - sizeof(struct client6_data_t)])) diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c index 5c98e82f1..23e6862dc 100644 --- a/networking/udhcp/d6_dhcpc.c +++ b/networking/udhcp/d6_dhcpc.c @@ -129,32 +129,114 @@ static void *d6_store_blob(void *dst, const void *src, unsigned len) /*** Script execution code ***/ +static char** new_env(void) +{ + client6_data.env_ptr = xrealloc_vector(client6_data.env_ptr, 3, client6_data.env_idx); + return &client6_data.env_ptr[client6_data.env_idx++]; +} + /* put all the parameters into the environment */ -static char **fill_envp(struct d6_packet *packet - UNUSED_PARAM -) +static void option_to_env(uint8_t *option, uint8_t *option_end) { - int envc; - char **envp, **curr; + /* "length minus 4" */ + int len_m4 = option_end - option - 4; + while (len_m4 >= 0) { + uint32_t v32; + char ipv6str[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")]; -#define BITMAP unsigned -#define BBITS (sizeof(BITMAP) * 8) -#define BMASK(i) (1 << (i & (sizeof(BITMAP) * 8 - 1))) -#define FOUND_OPTS(i) (found_opts[(unsigned)i / BBITS]) - ///BITMAP found_opts[256 / BBITS]; + if (option[0] != 0 || option[2] != 0) + break; + + switch (option[1]) { + //case D6_OPT_CLIENTID: + //case D6_OPT_SERVERID: + case D6_OPT_IA_NA: + case D6_OPT_IA_PD: + option_to_env(option + 16, option + 4 + option[3]); + break; + //case D6_OPT_IA_TA: + case D6_OPT_IAADDR: +/* 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | OPTION_IAADDR | option-len | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * | IPv6 address | + * | | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | preferred-lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | valid-lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + sprint_nip6(ipv6str, option + 4); + *new_env() = xasprintf("ipv6=%s", ipv6str); + + move_from_unaligned32(v32, option + 4 + 16 + 4); + *new_env() = xasprintf("lease=%u", (unsigned)v32); + break; + + //case D6_OPT_ORO: + //case D6_OPT_PREFERENCE: + //case D6_OPT_ELAPSED_TIME: + //case D6_OPT_RELAY_MSG: + //case D6_OPT_AUTH: + //case D6_OPT_UNICAST: + //case D6_OPT_STATUS_CODE: + //case D6_OPT_RAPID_COMMIT: + //case D6_OPT_USER_CLASS: + //case D6_OPT_VENDOR_CLASS: + //case D6_OPT_VENDOR_OPTS: + //case D6_OPT_INTERFACE_ID: + //case D6_OPT_RECONF_MSG: + //case D6_OPT_RECONF_ACCEPT: + + case D6_OPT_IAPREFIX: +/* 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | OPTION_IAPREFIX | option-length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | preferred-lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | valid-lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | prefix-length | | + * +-+-+-+-+-+-+-+-+ IPv6 prefix | + * | (16 octets) | + * | | + * | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * +-+-+-+-+-+-+-+-+ + */ + //move_from_unaligned32(v32, option + 4 + 4); + //*new_env() = xasprintf("lease=%u", (unsigned)v32); - ///memset(found_opts, 0, sizeof(found_opts)); + sprint_nip6(ipv6str, option + 4 + 4 + 1); + *new_env() = xasprintf("ipv6prefix=%s/%u", ipv6str, (unsigned)(option[4 + 4])); + } + option += 4 + option[3]; + len_m4 -= 4 + option[3]; + } +} - /* We need 2 elements for: - * "interface=IFACE" - * terminating NULL - */ - envc = 2; +static char **fill_envp(struct d6_packet *packet) +{ + char **envp, **curr; + + client6_data.env_ptr = NULL; + client6_data.env_idx = 0; + + *new_env() = xasprintf("interface=%s", client_config.interface); - curr = envp = xzalloc(sizeof(envp[0]) * envc); + if (packet) + option_to_env(packet->d6_options, packet->d6_options + sizeof(packet->d6_options)); - *curr = xasprintf("interface=%s", client_config.interface); - putenv(*curr++); + envp = curr = client6_data.env_ptr; + while (*curr) + putenv(*curr++); return envp; } @@ -1329,19 +1411,19 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) free(client6_data.ia_na); client6_data.ia_na = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_NA); if (!client6_data.ia_na) { - bb_error_msg("no lease time, ignoring packet"); + bb_error_msg("no %s option, ignoring packet", "IA_NA"); continue; } if (client6_data.ia_na->len < (4 + 4 + 4) + (2 + 2 + 16 + 4 + 4)) { bb_error_msg("IA_NA option is too short:%d bytes", client6_data.ia_na->len); continue; } - iaaddr = d6_find_option(client6_data.ia_na->data, + iaaddr = d6_find_option(client6_data.ia_na->data + 4 + 4 + 4, client6_data.ia_na->data + client6_data.ia_na->len, D6_OPT_IAADDR ); if (!iaaddr) { - bb_error_msg("no lease time, ignoring packet"); + bb_error_msg("no %s option, ignoring packet", "IAADDR"); continue; } if (iaaddr->len < (16 + 4 + 4)) { diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index 3c4e8dee1..43d682341 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -123,24 +123,6 @@ static int sprint_nip(char *dest, const char *pre, const uint8_t *ip) return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]); } -static int sprint_nip6(char *dest, /*const char *pre,*/ const uint8_t *ip) -{ - char hexstrbuf[16 * 2]; - bin2hex(hexstrbuf, (void*)ip, 16); - return sprintf(dest, /* "%s" */ - "%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s", - /* pre, */ - hexstrbuf + 0 * 4, - hexstrbuf + 1 * 4, - hexstrbuf + 2 * 4, - hexstrbuf + 3 * 4, - hexstrbuf + 4 * 4, - hexstrbuf + 5 * 4, - hexstrbuf + 6 * 4, - hexstrbuf + 7 * 4 - ); -} - /* really simple implementation, just count the bits */ static int mton(uint32_t mask) { -- cgit v1.2.3-55-g6feb From f59a50ee3031c520fdb4183b98fd7b13b94be4f7 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 16 Nov 2011 21:30:19 +0100 Subject: libbb.h: tighten up macro code Signed-off-by: Denys Vlasenko --- include/libbb.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index 09e8d28e7..796351865 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -211,7 +211,7 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN # if ULONG_MAX > 0xffffffff /* "long" is long enough on this system */ typedef unsigned long uoff_t; -# define XATOOFF(a) xatoul_range(a, 0, LONG_MAX) +# define XATOOFF(a) xatoul_range((a), 0, LONG_MAX) /* usage: sz = BB_STRTOOFF(s, NULL, 10); if (errno || sz < 0) die(); */ # define BB_STRTOOFF bb_strtoul # define STRTOOFF strtoul @@ -220,7 +220,7 @@ typedef unsigned long uoff_t; # else /* "long" is too short, need "long long" */ typedef unsigned long long uoff_t; -# define XATOOFF(a) xatoull_range(a, 0, LLONG_MAX) +# define XATOOFF(a) xatoull_range((a), 0, LLONG_MAX) # define BB_STRTOOFF bb_strtoull # define STRTOOFF strtoull # define OFF_FMT "ll" @@ -237,7 +237,7 @@ typedef unsigned long uoff_t; # define OFF_FMT "l" # else typedef unsigned long uoff_t; -# define XATOOFF(a) xatoul_range(a, 0, LONG_MAX) +# define XATOOFF(a) xatoul_range((a), 0, LONG_MAX) # define BB_STRTOOFF bb_strtoul # define STRTOOFF strtol # define OFF_FMT "l" -- cgit v1.2.3-55-g6feb From 1dc80bae0b4c339553b8ee9fd8309c13f8c1f1d8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 17 Nov 2011 21:51:32 +0100 Subject: libbb.h: add check for bad off_t size detection Signed-off-by: Denys Vlasenko --- include/libbb.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/libbb.h b/include/libbb.h index 796351865..3f6fe47ed 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -245,6 +245,12 @@ typedef unsigned long uoff_t; #endif /* scary. better ideas? (but do *test* them first!) */ #define OFF_T_MAX ((off_t)~((off_t)1 << (sizeof(off_t)*8-1))) +/* Users report bionic to use 32-bit off_t even if LARGEFILE support is requested. + * We misdetected that. Don't let it build: + */ +struct BUG_off_t_size_is_misdetected { + char BUG_off_t_size_is_misdetected[sizeof(off_t) == sizeof(uoff_t) ? 1 : -1]; +}; /* Some useful definitions */ #undef FALSE -- cgit v1.2.3-55-g6feb From 860491c5251886c40d6dfb89723f392db3a397a9 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 18 Nov 2011 02:09:13 +0100 Subject: udhcpc: shrink code by setting xid more economically function old new delta send_decline 90 82 -8 udhcpc_main 2649 2640 -9 Signed-off-by: Denys Vlasenko --- networking/udhcp/dhcpc.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index 43d682341..945600c6b 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -726,7 +726,7 @@ static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) #if ENABLE_FEATURE_UDHCPC_ARPING /* Broadcast a DHCP decline message */ /* NOINLINE: limit stack usage in caller */ -static NOINLINE int send_decline(uint32_t xid, uint32_t server, uint32_t requested) +static NOINLINE int send_decline(/*uint32_t xid,*/ uint32_t server, uint32_t requested) { struct dhcp_packet packet; @@ -735,12 +735,14 @@ static NOINLINE int send_decline(uint32_t xid, uint32_t server, uint32_t request */ init_packet(&packet, DHCPDECLINE); +#if 0 /* RFC 2131 says DHCPDECLINE's xid is randomly selected by client, * but in case the server is buggy and wants DHCPDECLINE's xid * to match the xid which started entire handshake, * we use the same xid we used in initial DHCPDISCOVER: */ packet.xid = xid; +#endif /* DHCPDECLINE uses "requested ip", not ciaddr, to store offered IP */ udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); @@ -1131,7 +1133,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) int discover_retries = 3; uint32_t server_addr = server_addr; /* for compiler */ uint32_t requested_ip = 0; - uint32_t xid = 0; + uint32_t xid = xid; /* for compiler */ int packet_num; int timeout; /* must be signed */ unsigned already_waited_sec; @@ -1520,7 +1522,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) switch (state) { case INIT_SELECTING: - /* Must be a DHCPOFFER to one of our xid's */ + /* Must be a DHCPOFFER */ if (*message == DHCPOFFER) { /* What exactly is server's IP? There are several values. * Example DHCP offer captured with tchdump: @@ -1600,7 +1602,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) ) { bb_info_msg("Offered address is in use " "(got ARP reply), declining"); - send_decline(xid, server_addr, packet.yiaddr); + send_decline(/*xid,*/ server_addr, packet.yiaddr); if (state != REQUESTING) udhcp_run_script(NULL, "deconfig"); @@ -1637,6 +1639,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) opt = ((opt & ~OPT_b) | OPT_f); } #endif + /* make future renew packets use different xid */ + /* xid = random_xid(); ...but why bother? */ already_waited_sec = 0; continue; /* back to main loop */ } -- cgit v1.2.3-55-g6feb From a0bef7cc276476e69e2496e728bf97b32d3b561d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 18 Nov 2011 02:47:35 +0100 Subject: hexdump: fix hexdump -n1 -ve '8/2 ""' SEGV. Closes 4478 Signed-off-by: Denys Vlasenko --- libbb/dump.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/libbb/dump.c b/libbb/dump.c index 919fe135c..7e435643b 100644 --- a/libbb/dump.c +++ b/libbb/dump.c @@ -71,7 +71,8 @@ static NOINLINE int bb_dump_size(FS *fs) * skip any special chars -- save precision in * case it's a %s format. */ - while (strchr(index_str + 1, *++fmt)); + while (strchr(index_str + 1, *++fmt)) + continue; if (*fmt == '.' && isdigit(*++fmt)) { prec = atoi(fmt); while (isdigit(*++fmt)) @@ -99,8 +100,8 @@ static NOINLINE int bb_dump_size(FS *fs) static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) { enum { NOTOKAY, USEBCNT, USEPREC } sokay; - PR *pr; FU *fu; + PR *pr; char *p1, *p2, *p3; char savech, *fmtp; const char *byte_count_str; @@ -292,16 +293,18 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) * interprets any data at all, and has no iteration count, * repeat it as necessary. * - * if, rep count is greater than 1, no trailing whitespace + * if rep count is greater than 1, no trailing whitespace * gets output from the last iteration of the format unit. */ for (fu = fs->nextfu; fu; fu = fu->nextfu) { - if (!fu->nextfu && fs->bcnt < dumper->blocksize - && !(fu->flags & F_SETREP) && fu->bcnt + if (!fu->nextfu + && fs->bcnt < dumper->blocksize + && !(fu->flags & F_SETREP) + && fu->bcnt ) { fu->reps += (dumper->blocksize - fs->bcnt) / fu->bcnt; } - if (fu->reps > 1) { + if (fu->reps > 1 && fu->nextpr) { for (pr = fu->nextpr;; pr = pr->nextpr) if (!pr->nextpr) break; @@ -721,7 +724,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) p = fmt; for (;;) { p = skip_whitespace(p); - if (!*p) { + if (*p == '\0') { break; } @@ -749,7 +752,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) /* skip slash and trailing white space */ if (*p == '/') { - p = skip_whitespace(++p); + p = skip_whitespace(p + 1); } /* byte count */ @@ -763,7 +766,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) } tfu->bcnt = atoi(savep); /* skip trailing white space */ - p = skip_whitespace(++p); + p = skip_whitespace(p + 1); } /* format */ @@ -771,7 +774,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) bb_error_msg_and_die("bad format {%s}", fmt); } for (savep = ++p; *p != '"';) { - if (*p++ == 0) { + if (*p++ == '\0') { bb_error_msg_and_die("bad format {%s}", fmt); } } @@ -782,7 +785,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) /* alphabetic escape sequences have to be done in place */ for (p2 = p1;; ++p1, ++p2) { - if (!*p1) { + if (*p1 == '\0') { *p2 = *p1; break; } -- cgit v1.2.3-55-g6feb From 41fea01066539ed8e958c21591a5fe7155565ceb Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 18 Nov 2011 22:25:35 +0100 Subject: sendmail: stop doing -t unconditionally; makemime: generate 76 char base64 lines Signed-off-by: Denys Vlasenko --- mailutils/mail.c | 2 +- mailutils/sendmail.c | 22 ++++++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/mailutils/mail.c b/mailutils/mail.c index f5260d9db..199f64407 100644 --- a/mailutils/mail.c +++ b/mailutils/mail.c @@ -119,7 +119,7 @@ static char* FAST_FUNC parse_url(char *url, char **user, char **pass) void FAST_FUNC encode_base64(char *fname, const char *text, const char *eol) { enum { - SRC_BUF_SIZE = 45, /* This *MUST* be a multiple of 3 */ + SRC_BUF_SIZE = 57, /* This *MUST* be a multiple of 3 */ DST_BUF_SIZE = 4 * ((SRC_BUF_SIZE + 2) / 3), }; #define src_buf text diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c index dbd491002..f96ca3291 100644 --- a/mailutils/sendmail.c +++ b/mailutils/sendmail.c @@ -281,17 +281,19 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) // analyze headers // To: or Cc: headers add recipients - if (0 == strncasecmp("To:", s, 3) || 0 == strncasecmp("Bcc:" + 1, s, 3)) { - rcptto(sane_address(s+3)); - goto addheader; + if (opts & OPT_t) { + if (0 == strncasecmp("To:", s, 3) || 0 == strncasecmp("Bcc:" + 1, s, 3)) { + rcptto(sane_address(s+3)); + goto addheader; + } + // Bcc: header adds blind copy (hidden) recipient + if (0 == strncasecmp("Bcc:", s, 4)) { + rcptto(sane_address(s+4)); + free(s); + continue; // N.B. Bcc: vanishes from headers! + } } - // Bcc: header adds blind copy (hidden) recipient - if (0 == strncasecmp("Bcc:", s, 4)) { - rcptto(sane_address(s+4)); - free(s); - // N.B. Bcc: vanishes from headers! - } else - if (strchr(s, ':') || (list && skip_whitespace(s) != s)) { + if (strchr(s, ':') || (list && isspace(s))) { // other headers go verbatim // N.B. RFC2822 2.2.3 "Long Header Fields" allows for headers to occupy several lines. // Continuation is denoted by prefixing additional lines with whitespace(s). -- cgit v1.2.3-55-g6feb From 578b8171511f67a9c2afc5c6ae9745de9f9b5e42 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 19 Nov 2011 13:54:50 +0100 Subject: sendmail: fix a mistake in previous commit Signed-off-by: Denys Vlasenko --- mailutils/sendmail.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c index f96ca3291..aa381c60f 100644 --- a/mailutils/sendmail.c +++ b/mailutils/sendmail.c @@ -293,7 +293,7 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) continue; // N.B. Bcc: vanishes from headers! } } - if (strchr(s, ':') || (list && isspace(s))) { + if (strchr(s, ':') || (list && isspace(s[0]))) { // other headers go verbatim // N.B. RFC2822 2.2.3 "Long Header Fields" allows for headers to occupy several lines. // Continuation is denoted by prefixing additional lines with whitespace(s). -- cgit v1.2.3-55-g6feb From 3bc4fc5857e2daba601442f95771a590bce915bc Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 19 Nov 2011 13:55:46 +0100 Subject: makemime: content-type should default to application/octet-stream Signed-off-by: Denys Vlasenko --- mailutils/mail.h | 7 ------- mailutils/makemime.c | 5 +++-- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/mailutils/mail.h b/mailutils/mail.h index d1d783055..fa0c5b378 100644 --- a/mailutils/mail.h +++ b/mailutils/mail.h @@ -16,22 +16,15 @@ struct globals { char *pass; FILE *fp0; // initial stdin char *opt_charset; - char *content_type; }; #define G (*ptr_to_globals) #define timeout (G.timeout ) #define verbose (G.verbose ) #define opts (G.opts ) -//#define user (G.user ) -//#define pass (G.pass ) -//#define fp0 (G.fp0 ) -//#define opt_charset (G.opt_charset) -//#define content_type (G.content_type) #define INIT_G() do { \ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ G.opt_charset = (char *)CONFIG_FEATURE_MIME_CHARSET; \ - G.content_type = (char *)"text/plain"; \ } while (0) //char FAST_FUNC *parse_url(char *url, char **user, char **pass); diff --git a/mailutils/makemime.c b/mailutils/makemime.c index a9ff03d03..f1ef602a4 100644 --- a/mailutils/makemime.c +++ b/mailutils/makemime.c @@ -146,6 +146,7 @@ int makemime_main(int argc UNUSED_PARAM, char **argv) { llist_t *opt_headers = NULL, *l; const char *opt_output; + const char *content_type = "application/octet-stream"; #define boundary opt_output enum { @@ -165,7 +166,7 @@ int makemime_main(int argc UNUSED_PARAM, char **argv) opt_complementary = "a::"; opts = getopt32(argv, "c:e:o:C:N:a:", //:m:j:", - &G.content_type, NULL, &opt_output, &G.opt_charset, NULL, &opt_headers //, NULL, NULL + &content_type, NULL, &opt_output, &G.opt_charset, NULL, &opt_headers //, NULL, NULL ); //argc -= optind; argv += optind; @@ -202,7 +203,7 @@ int makemime_main(int argc UNUSED_PARAM, char **argv) "Content-Disposition: inline; filename=\"%s\"\n" "Content-Transfer-Encoding: base64\n" , boundary - , G.content_type + , content_type , G.opt_charset , bb_get_last_path_component_strip(*argv) ); -- cgit v1.2.3-55-g6feb From fc186711fe75cfc4abda9a7ff29050bc7a56313b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 19 Nov 2011 14:43:02 +0100 Subject: makemime: document our current behavior. Tweak help text Signed-off-by: Denys Vlasenko --- mailutils/makemime.c | 29 +++++++++++++++++++++++++---- mailutils/reformime.c | 1 - 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/mailutils/makemime.c b/mailutils/makemime.c index f1ef602a4..4b07e54de 100644 --- a/mailutils/makemime.c +++ b/mailutils/makemime.c @@ -1,7 +1,6 @@ /* vi: set sw=4 ts=4: */ /* * makemime: create MIME-encoded message - * reformime: parse MIME-encoded message * * Copyright (C) 2008 by Vladimir Dronnikov * @@ -135,12 +134,35 @@ Content-Transfer-Encoding: 7bit //usage: "\n -o FILE Output. Default: stdout" //usage: "\n -a HDR Add header. Examples:" //usage: "\n \"From: user@host.org\", \"Date: `date -R`\"" -//usage: "\n -c CT Content type. Default: text/plain" +//usage: "\n -c CT Content type. Default: application/octet-stream" //usage: "\n -C CS Charset. Default: " CONFIG_FEATURE_MIME_CHARSET /* //usage: "\n -e ENC Transfer encoding. Ignored. base64 is assumed" */ //usage: "\n" //usage: "\nOther options are silently ignored" +/* + * -c [Content-Type] should create just one MIME section + * with "Content-Type:", "Content-Transfer-Encoding:", and HDR from "-a HDR". + * NB: without "Content-Disposition:" auto-added, unlike we do now + * NB2: -c has *optional* param which nevertheless _can_ be specified after a space :( + * + * -m [multipart/mixed] should create multipart MIME section + * with "Content-Type:", "Content-Transfer-Encoding:", and HDR from "-a HDR", + * and add FILE to it _verbatim_: + * HEADERS + * + * --=_1_1321709112_1605 + * FILE_CONTENTS + * --=_1_1321709112_1605 + * without any encoding of FILE_CONTENTS. (Basically, it expects that FILE + * is the result of "makemime -c"). + * + * -j MULTIPART_FILE1 SINGLE_FILE2 should output MULTIPART_FILE1 + SINGLE_FILE2 + * + * Our current behavior is a mutant "-m + -c + -j" one: we create multipart MIME + * and we put "-c" encoded FILEs into many multipart sections. + */ + int makemime_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int makemime_main(int argc UNUSED_PARAM, char **argv) { @@ -148,7 +170,6 @@ int makemime_main(int argc UNUSED_PARAM, char **argv) const char *opt_output; const char *content_type = "application/octet-stream"; #define boundary opt_output - enum { OPT_c = 1 << 0, // create (non-multipart) section OPT_e = 1 << 1, // Content-Transfer-Encoding. Ignored. Assumed base64 @@ -165,7 +186,7 @@ int makemime_main(int argc UNUSED_PARAM, char **argv) // parse options opt_complementary = "a::"; opts = getopt32(argv, - "c:e:o:C:N:a:", //:m:j:", + "c:e:o:C:N:a:", // "m:j:", &content_type, NULL, &opt_output, &G.opt_charset, NULL, &opt_headers //, NULL, NULL ); //argc -= optind; diff --git a/mailutils/reformime.c b/mailutils/reformime.c index 5e28ef729..8e7d455f6 100644 --- a/mailutils/reformime.c +++ b/mailutils/reformime.c @@ -1,6 +1,5 @@ /* vi: set sw=4 ts=4: */ /* - * makemime: create MIME-encoded message * reformime: parse MIME-encoded message * * Copyright (C) 2008 by Vladimir Dronnikov -- cgit v1.2.3-55-g6feb From fcb9e07eca65b98093dd0b2b80451934a8719914 Mon Sep 17 00:00:00 2001 From: Daniel Fandrich Date: Sun, 6 Nov 2011 15:06:16 -0800 Subject: Added a few more features to android_defconfig Signed-off-by: Daniel Fandrich Signed-off-by: Denys Vlasenko --- configs/android_defconfig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/configs/android_defconfig b/configs/android_defconfig index b9df0ea02..f1263b964 100644 --- a/configs/android_defconfig +++ b/configs/android_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Busybox version: 1.20.0.git -# Wed Nov 2 17:54:00 2011 +# Sun Nov 6 07:51:38 2011 # CONFIG_HAVE_DOT_CONFIG=y @@ -790,7 +790,7 @@ CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN=y CONFIG_FEATURE_IFUPDOWN_IPV4=y # CONFIG_FEATURE_IFUPDOWN_IPV6 is not set CONFIG_FEATURE_IFUPDOWN_MAPPING=y -# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set +CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP=y # CONFIG_INETD is not set # CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set # CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set @@ -841,9 +841,9 @@ CONFIG_FEATURE_TFTP_PUT=y CONFIG_FEATURE_TFTP_BLOCKSIZE=y CONFIG_FEATURE_TFTP_PROGRESS_BAR=y # CONFIG_TFTP_DEBUG is not set -# CONFIG_TRACEROUTE is not set +CONFIG_TRACEROUTE=y # CONFIG_TRACEROUTE6 is not set -# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set +CONFIG_FEATURE_TRACEROUTE_VERBOSE=y # CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE is not set # CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set CONFIG_TUNCTL=y @@ -856,7 +856,7 @@ CONFIG_FEATURE_TUNCTL_UG=y CONFIG_DHCPD_LEASES_FILE="" CONFIG_UDHCPC=y CONFIG_FEATURE_UDHCPC_ARPING=y -# CONFIG_FEATURE_UDHCP_PORT is not set +CONFIG_FEATURE_UDHCP_PORT=y CONFIG_UDHCP_DEBUG=9 CONFIG_FEATURE_UDHCP_RFC3397=y CONFIG_FEATURE_UDHCP_8021Q=y -- cgit v1.2.3-55-g6feb From d2277e262ff7dd2dd946ea16b93462f3dcdf0447 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 22 Nov 2011 17:19:26 +0100 Subject: nommu: fix cases where we mangle argv[0][0] Signed-off-by: Denys Vlasenko --- archival/cpio.c | 1 + include/libbb.h | 3 +++ init/bootchartd.c | 2 ++ networking/httpd.c | 1 + 4 files changed, 7 insertions(+) diff --git a/archival/cpio.c b/archival/cpio.c index c2a5b8ab9..98cc18fa0 100644 --- a/archival/cpio.c +++ b/archival/cpio.c @@ -384,6 +384,7 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) goto dump; } /* parent */ + USE_FOR_NOMMU(argv[-optind][0] &= 0x7f); /* undo fork_or_rexec() damage */ xchdir(*argv++); close(pp.wr); xmove_fd(pp.rd, STDIN_FILENO); diff --git a/include/libbb.h b/include/libbb.h index 3f6fe47ed..bc9b7b06d 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -981,6 +981,9 @@ enum { # define bb_daemonize(flags) bb_daemonize_or_rexec(flags, bogus) #else extern bool re_execed; + /* Note: re_exec() and fork_or_rexec() do argv[0][0] |= 0x80 on NOMMU! + * _Parent_ needs to undo it if it doesn't want to have argv[0] mangled. + */ void re_exec(char **argv) NORETURN FAST_FUNC; pid_t fork_or_rexec(char **argv) FAST_FUNC; int BUG_fork_is_unavailable_on_nommu(void) FAST_FUNC; diff --git a/init/bootchartd.c b/init/bootchartd.c index 5f6121fa4..cc23e6073 100644 --- a/init/bootchartd.c +++ b/init/bootchartd.c @@ -418,6 +418,8 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) /* parent */ + USE_FOR_NOMMU(argv[0][0] &= 0x7f); /* undo fork_or_rexec() damage */ + if (DO_SIGNAL_SYNC) { /* Wait for logger child to set handlers, then unpause it. * Otherwise with short-lived PROG (e.g. "bootchartd start true") diff --git a/networking/httpd.c b/networking/httpd.c index 24482fe52..ecdf5b572 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -2243,6 +2243,7 @@ static void mini_httpd_nommu(int server_socket, int argc, char **argv) /* Run a copy of ourself in inetd mode */ re_exec(argv_copy); } + argv_copy[0][0] &= 0x7f; /* parent, or vfork failed */ close(n); } /* while (1) */ -- cgit v1.2.3-55-g6feb From 65a1ee956f0721ad3cebf79c0a6b3266a0676524 Mon Sep 17 00:00:00 2001 From: Daniel Fandrich Date: Wed, 23 Nov 2011 12:07:31 +0100 Subject: rx: fix file corruption on block checksum failure Rather than dropping the bad block, rx was appending it to the file. Signed-off-by: Daniel Fandrich Signed-off-by: Denys Vlasenko --- miscutils/rx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/miscutils/rx.c b/miscutils/rx.c index c48a61fd0..af597320c 100644 --- a/miscutils/rx.c +++ b/miscutils/rx.c @@ -207,6 +207,7 @@ static int receive(/*int read_fd, */int file_fd) continue; error: timeout: + blockLength = 0; errors++; if (errors == MAXERRORS) { /* Abort */ -- cgit v1.2.3-55-g6feb From 1fd7129bc6b3792f2dc5ff08a77f167c7e628093 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 28 Nov 2011 04:55:48 +0100 Subject: vi: fix [end] key handling Signed-off-by: Denys Vlasenko --- editors/vi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editors/vi.c b/editors/vi.c index 71d600834..6070c48d2 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -3319,7 +3319,7 @@ static void do_cmd(int c) case KEYCODE_END: // Cursor Key End for (;;) { dot = end_line(dot); - if (--cmdcnt > 0) + if (--cmdcnt <= 0) break; dot_next(); } -- cgit v1.2.3-55-g6feb From 901365fcffbc318395d24a05b6951288562da6af Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 28 Nov 2011 18:57:04 +0100 Subject: old_e2fsprogs/blkid: close the fd after we are done with it Some people have HUGE /dev/*... Signed-off-by: Denys Vlasenko --- e2fsprogs/old_e2fsprogs/blkid/probe.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/e2fsprogs/old_e2fsprogs/blkid/probe.c b/e2fsprogs/old_e2fsprogs/blkid/probe.c index 77bfc737d..651193b42 100644 --- a/e2fsprogs/old_e2fsprogs/blkid/probe.c +++ b/e2fsprogs/old_e2fsprogs/blkid/probe.c @@ -575,8 +575,12 @@ blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev) printf("need to revalidate %s (time since last check %lu)\n", dev->bid_name, diff)); - if (((fd = open(dev->bid_name, O_RDONLY)) < 0) || - (fstat(fd, &st) < 0)) { + fd = open(dev->bid_name, O_RDONLY); + if (fd < 0 + || fstat(fd, &st) < 0 + ) { + if (fd >= 0) + close(fd); if (errno == ENXIO || errno == ENODEV || errno == ENOENT) { blkid_free_dev(dev); return NULL; @@ -653,6 +657,7 @@ try_again: if (!dev->bid_type) { blkid_free_dev(dev); + close(fd); return NULL; } -- cgit v1.2.3-55-g6feb From 7291755439ad2f400df51a74b4e9a31a48f484b1 Mon Sep 17 00:00:00 2001 From: Pascal Bellard Date: Tue, 29 Nov 2011 13:51:11 +0100 Subject: httpd: make it possible to use system passwords for auth function old new delta check_user_passwd 320 467 +147 httpd_main 760 757 -3 Signed-off-by: Pascal Bellard Signed-off-by: Denys Vlasenko --- networking/httpd.c | 175 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 147 insertions(+), 28 deletions(-) diff --git a/networking/httpd.c b/networking/httpd.c index ecdf5b572..c66e0f66b 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -54,6 +54,8 @@ * /cgi-bin:foo:bar # Require user foo, pwd bar on urls starting with /cgi-bin/ * /adm:admin:setup # Require user admin, pwd setup on urls starting with /adm/ * /adm:toor:PaSsWd # or user toor, pwd PaSsWd on urls starting with /adm/ + * /adm:root:* # or user root, pwd from /etc/passwd on urls starting with /adm/ + * /wiki:*:* # or any user from /etc/passwd with according pwd on urls starting with /wiki/ * .au:audio/basic # additional mime type for audio.au files * *.php:/path/php # run xxx.php through an interpreter * @@ -123,6 +125,14 @@ //usage: "\n -d STRING URL decode STRING" #include "libbb.h" +#if ENABLE_PAM +/* PAM may include . We may need to undefine bbox's stub define: */ +# undef setlocale +/* For some obscure reason, PAM is not in pam/xxx, but in security/xxx. + * Apparently they like to confuse people. */ +# include +# include +#endif #if ENABLE_FEATURE_HTTPD_USE_SENDFILE # include #endif @@ -1658,6 +1668,56 @@ static int checkPermIP(void) } #if ENABLE_FEATURE_HTTPD_BASIC_AUTH + +# if ENABLE_FEATURE_HTTPD_AUTH_MD5 && ENABLE_PAM +struct pam_userinfo { + const char *name; + const char *pw; +}; + +static int pam_talker(int num_msg, + const struct pam_message **msg, + struct pam_response **resp, + void *appdata_ptr) +{ + int i; + struct pam_userinfo *userinfo = (struct pam_userinfo *) appdata_ptr; + struct pam_response *response; + + if (!resp || !msg || !userinfo) + return PAM_CONV_ERR; + + /* allocate memory to store response */ + response = xzalloc(num_msg * sizeof(*response)); + + /* copy values */ + for (i = 0; i < num_msg; i++) { + const char *s; + + switch (msg[i]->msg_style) { + case PAM_PROMPT_ECHO_ON: + s = userinfo->name; + break; + case PAM_PROMPT_ECHO_OFF: + s = userinfo->pw; + break; + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: + s = ""; + break; + default: + free(response); + return PAM_CONV_ERR; + } + response[i].resp = xstrdup(s); + if (PAM_SUCCESS != 0) + response[i].resp_retcode = PAM_SUCCESS; + } + *resp = response; + return PAM_SUCCESS; +} +# endif + /* * Config file entries are of the form "/::". * If config file has no prefix match for path, access is allowed. @@ -1667,7 +1727,7 @@ static int checkPermIP(void) * * Returns 1 if user_and_passwd is OK. */ -static int check_user_passwd(const char *path, const char *user_and_passwd) +static int check_user_passwd(const char *path, char *user_and_passwd) { Htaccess *cur; const char *prev = NULL; @@ -1675,6 +1735,7 @@ static int check_user_passwd(const char *path, const char *user_and_passwd) for (cur = g_auth; cur; cur = cur->next) { const char *dir_prefix; size_t len; + int r; dir_prefix = cur->before_colon; @@ -1690,7 +1751,8 @@ static int check_user_passwd(const char *path, const char *user_and_passwd) len = strlen(dir_prefix); if (len != 1 /* dir_prefix "/" matches all, don't need to check */ && (strncmp(dir_prefix, path, len) != 0 - || (path[len] != '/' && path[len] != '\0')) + || (path[len] != '/' && path[len] != '\0') + ) ) { continue; } @@ -1699,38 +1761,95 @@ static int check_user_passwd(const char *path, const char *user_and_passwd) prev = dir_prefix; if (ENABLE_FEATURE_HTTPD_AUTH_MD5) { - char *md5_passwd; - - md5_passwd = strchr(cur->after_colon, ':'); - if (md5_passwd && md5_passwd[1] == '$' && md5_passwd[2] == '1' - && md5_passwd[3] == '$' && md5_passwd[4] - ) { - char *encrypted; - int r, user_len_p1; - - md5_passwd++; - user_len_p1 = md5_passwd - cur->after_colon; - /* comparing "user:" */ - if (strncmp(cur->after_colon, user_and_passwd, user_len_p1) != 0) { + char *colon_after_user; + const char *passwd; + + colon_after_user = strchr(user_and_passwd, ':'); + if (!colon_after_user) + goto bad_input; + passwd = strchr(cur->after_colon, ':'); + if (!passwd) + goto bad_input; + passwd++; + if (passwd[0] == '*') { +# if ENABLE_PAM + struct pam_userinfo userinfo; + struct pam_conv conv_info = { &pam_talker, (void *) &userinfo }; + pam_handle_t *pamh; + + /* compare "user:" */ + if (cur->after_colon[0] != '*' + && strncmp(cur->after_colon, user_and_passwd, colon_after_user - user_and_passwd + 1) != 0 + ) { + continue; + } + /* this cfg entry is '*' or matches username from peer */ + *colon_after_user = '\0'; + userinfo.name = user_and_passwd; + userinfo.pw = colon_after_user + 1; + r = pam_start("httpd", user_and_passwd, &conv_info, &pamh) != PAM_SUCCESS + || pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK) != PAM_SUCCESS + || pam_acct_mgmt(pamh, PAM_DISALLOW_NULL_AUTHTOK) != PAM_SUCCESS + ; + pam_end(pamh, PAM_SUCCESS); + *colon_after_user = ':'; + goto end_check_passwd; +# else +# if ENABLE_FEATURE_SHADOWPASSWDS + /* Using _r function to avoid pulling in static buffers */ + struct spwd spw; + char buffer[256]; +# endif + struct passwd *pw; + + *colon_after_user = '\0'; + pw = getpwnam(user_and_passwd); + *colon_after_user = ':'; + if (!pw || !pw->pw_passwd) continue; + passwd = pw->pw_passwd; +# if ENABLE_FEATURE_SHADOWPASSWDS + if ((passwd[0] == 'x' || passwd[0] == '*') && !passwd[1]) { + /* getspnam_r may return 0 yet set result to NULL. + * At least glibc 2.4 does this. Be extra paranoid here. */ + struct spwd *result = NULL; + r = getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result); + if (r == 0 && result) + passwd = result->sp_pwdp; } +# endif +# endif /* ENABLE_PAM */ + } - encrypted = pw_encrypt( - user_and_passwd + user_len_p1 /* cleartext pwd from user */, - md5_passwd /*salt */, 1 /* cleanup */); - r = strcmp(encrypted, md5_passwd); - free(encrypted); - if (r == 0) - goto set_remoteuser_var; /* Ok */ + /* compare "user:" */ + if (cur->after_colon[0] != '*' + && strncmp(cur->after_colon, user_and_passwd, colon_after_user - user_and_passwd + 1) != 0 + ) { continue; } + /* this cfg entry is '*' or matches username from peer */ + + /* encrypt pwd from peer and check match with local one */ + { + char *encrypted = pw_encrypt( + /* pwd: */ colon_after_user + 1, + /* salt: */ passwd, + /* cleanup: */ 0 + ); + r = strcmp(encrypted, passwd); + free(encrypted); + goto end_check_passwd; + } + bad_input: ; } /* Comparing plaintext "user:pass" in one go */ - if (strcmp(cur->after_colon, user_and_passwd) == 0) { - set_remoteuser_var: + r = strcmp(cur->after_colon, user_and_passwd); + end_check_passwd: + if (r == 0) { remoteuser = xstrndup(user_and_passwd, - strchrnul(user_and_passwd, ':') - user_and_passwd); + strchrnul(user_and_passwd, ':') - user_and_passwd + ); return 1; /* Ok */ } } /* for */ @@ -2067,10 +2186,10 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) } #if ENABLE_FEATURE_HTTPD_BASIC_AUTH - /* Case: no "Authorization:" was seen, but page does require passwd. + /* Case: no "Authorization:" was seen, but page might require passwd. * Check that with dummy user:pass */ if (authorized < 0) - authorized = check_user_passwd(urlcopy, ":"); + authorized = check_user_passwd(urlcopy, (char *) ""); if (!authorized) send_headers_and_exit(HTTP_UNAUTHORIZED); #endif @@ -2353,7 +2472,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) salt[1] = '1'; salt[2] = '$'; crypt_make_salt(salt + 3, 4); - puts(pw_encrypt(pass, salt, 1)); + puts(pw_encrypt(pass, salt, /*cleanup:*/ 0)); return 0; } #endif -- cgit v1.2.3-55-g6feb From 0fa3e5f6f9ad55871d52bd10988fec66398f3d65 Mon Sep 17 00:00:00 2001 From: Pascal Bellard Date: Tue, 29 Nov 2011 20:54:30 +0100 Subject: httpd: small fixes to previous change Signed-off-by: Pascal Bellard Signed-off-by: Denys Vlasenko --- networking/httpd.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/networking/httpd.c b/networking/httpd.c index c66e0f66b..0356e4c1b 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -1763,6 +1763,9 @@ static int check_user_passwd(const char *path, char *user_and_passwd) if (ENABLE_FEATURE_HTTPD_AUTH_MD5) { char *colon_after_user; const char *passwd; +# if ENABLE_FEATURE_SHADOWPASSWDS && !ENABLE_PAM + char sp_buf[256]; +# endif colon_after_user = strchr(user_and_passwd, ':'); if (!colon_after_user) @@ -1787,18 +1790,19 @@ static int check_user_passwd(const char *path, char *user_and_passwd) *colon_after_user = '\0'; userinfo.name = user_and_passwd; userinfo.pw = colon_after_user + 1; - r = pam_start("httpd", user_and_passwd, &conv_info, &pamh) != PAM_SUCCESS - || pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK) != PAM_SUCCESS - || pam_acct_mgmt(pamh, PAM_DISALLOW_NULL_AUTHTOK) != PAM_SUCCESS - ; - pam_end(pamh, PAM_SUCCESS); + r = pam_start("httpd", user_and_passwd, &conv_info, &pamh) != PAM_SUCCESS; + if (r == 0) { + r = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK) != PAM_SUCCESS + || pam_acct_mgmt(pamh, PAM_DISALLOW_NULL_AUTHTOK) != PAM_SUCCESS + ; + pam_end(pamh, PAM_SUCCESS); + } *colon_after_user = ':'; goto end_check_passwd; # else # if ENABLE_FEATURE_SHADOWPASSWDS /* Using _r function to avoid pulling in static buffers */ struct spwd spw; - char buffer[256]; # endif struct passwd *pw; @@ -1813,7 +1817,7 @@ static int check_user_passwd(const char *path, char *user_and_passwd) /* getspnam_r may return 0 yet set result to NULL. * At least glibc 2.4 does this. Be extra paranoid here. */ struct spwd *result = NULL; - r = getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result); + r = getspnam_r(pw->pw_name, &spw, sp_buf, sizeof(sp_buf), &result); if (r == 0 && result) passwd = result->sp_pwdp; } -- cgit v1.2.3-55-g6feb From beb860ac758a5b08f4270da03a5f894f95816109 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 5 Dec 2011 03:31:05 +0100 Subject: init: utmp update of DEAD_PROCESS was misplaced, and could be skipped. Fixing. Signed-off-by: Denys Vlasenko --- init/init.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/init/init.c b/init/init.c index 645f694c0..864ee6ab8 100644 --- a/init/init.c +++ b/init/init.c @@ -523,15 +523,17 @@ static struct init_action *mark_terminated(pid_t pid) struct init_action *a; if (pid > 0) { + update_utmp(pid, DEAD_PROCESS, + /*tty_name:*/ NULL, + /*username:*/ NULL, + /*hostname:*/ NULL + ); for (a = init_action_list; a; a = a->next) { if (a->pid == pid) { a->pid = 0; return a; } } - update_utmp(pid, DEAD_PROCESS, /*tty_name:*/ NULL, - /*username:*/ NULL, - /*hostname:*/ NULL); } return NULL; } -- cgit v1.2.3-55-g6feb From ef7aa46bc4caa05e39458a47de02d0411e15f8d5 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 5 Dec 2011 03:54:28 +0100 Subject: init: code shrink -4 bytes Signed-off-by: Denys Vlasenko --- init/init.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/init/init.c b/init/init.c index 864ee6ab8..c540faa70 100644 --- a/init/init.c +++ b/init/init.c @@ -598,7 +598,7 @@ static void new_init_action(uint8_t action_type, const char *command, const char */ nextp = &init_action_list; while ((a = *nextp) != NULL) { - /* Don't enter action if it's already in the list, + /* Don't enter action if it's already in the list. * This prevents losing running RESPAWNs. */ if (strcmp(a->command, command) == 0 @@ -610,14 +610,15 @@ static void new_init_action(uint8_t action_type, const char *command, const char while (*nextp != NULL) nextp = &(*nextp)->next; a->next = NULL; - break; + goto append; } nextp = &a->next; } - if (!a) - a = xzalloc(sizeof(*a)); + a = xzalloc(sizeof(*a)); + /* Append to the end of the list */ + append: *nextp = a; a->action_type = action_type; safe_strncpy(a->command, command, sizeof(a->command)); -- cgit v1.2.3-55-g6feb From 5560e1af0ada7eb75e8bd4945e2c05ab5d31b415 Mon Sep 17 00:00:00 2001 From: Tristan Schmelcher Date: Mon, 5 Dec 2011 04:38:58 +0100 Subject: Fix link failure on some platforms when PAM is enabled Signed-off-by: Tristan Schmelcher Signed-off-by: Denys Vlasenko --- Makefile.flags | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Makefile.flags b/Makefile.flags index 7e1c6030c..ee4c518d8 100644 --- a/Makefile.flags +++ b/Makefile.flags @@ -105,7 +105,14 @@ LDLIBS += m endif ifeq ($(CONFIG_PAM),y) -LDLIBS += pam pam_misc +# libpam uses libpthread, so for static builds busybox must be linked to +# libpthread. On some platforms that requires an explicit -lpthread, so +# it should be in LDLIBS. For non-static builds, scripts/trylink will +# take care of removing -lpthread if possible. (Not bothering to check +# CONFIG_STATIC because even in a non-static build it could be that the +# only libpam available is libpam.a, so -lpthread could still be +# needed.) +LDLIBS += pam pam_misc pthread endif ifeq ($(CONFIG_SELINUX),y) -- cgit v1.2.3-55-g6feb From b8ff9357d579913a5c699d89b4126d859590eea3 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 5 Dec 2011 04:54:14 +0100 Subject: suppress a "integer overflow in expression" waring on big endian. Closes 4405 Signed-off-by: Denys Vlasenko --- include/bb_archive.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/bb_archive.h b/include/bb_archive.h index 9e176d335..d1a9a34ec 100644 --- a/include/bb_archive.h +++ b/include/bb_archive.h @@ -12,9 +12,10 @@ enum { /* .xz signature: 0xfd, '7', 'z', 'X', 'Z', 0x00 */ /* More info at: http://tukaani.org/xz/xz-file-format.txt */ XZ_MAGIC1 = 256 * 0xfd + '7', - XZ_MAGIC2 = 256 * (256 * (256 * 'z' + 'X') + 'Z') + 0, + XZ_MAGIC2 = 256 * (unsigned)(256 * (256 * 'z' + 'X') + 'Z') + 0, /* Different form: 32 bits, then 16 bits: */ - XZ_MAGIC1a = 256 * (256 * (256 * 0xfd + '7') + 'z') + 'X', + /* (unsigned) cast suppresses "integer overflow in expression" warning */ + XZ_MAGIC1a = 256 * (unsigned)(256 * (256 * 0xfd + '7') + 'z') + 'X', XZ_MAGIC2a = 256 * 'Z' + 0, #else COMPRESS_MAGIC = 0x9d1f, -- cgit v1.2.3-55-g6feb From c3375f0389469f596b93cdb34a6005382bc19a36 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 6 Dec 2011 15:06:59 +0100 Subject: volume_id/get_devname: trivial code shrink function old new delta uuidcache_init 36 41 +5 get_devname_from_uuid 55 51 -4 get_devname_from_label 61 57 -4 display_uuid_cache 109 105 -4 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/3 up/down: 5/-12) Total: -7 bytes Signed-off-by: Denys Vlasenko --- util-linux/volume_id/get_devname.c | 41 ++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/util-linux/volume_id/get_devname.c b/util-linux/volume_id/get_devname.c index 7c9930543..d81e24438 100644 --- a/util-linux/volume_id/get_devname.c +++ b/util-linux/volume_id/get_devname.c @@ -114,12 +114,12 @@ uuidcache_check_device(const char *device, return TRUE; } -static void +static struct uuidCache_s* uuidcache_init(void) { dbg("DBG: uuidCache=%x, uuidCache"); if (uuidCache) - return; + return uuidCache; /* We were scanning /proc/partitions * and /proc/sys/dev/cdrom/info here. @@ -137,6 +137,8 @@ uuidcache_init(void) NULL, /* dir_action */ NULL, /* userData */ 0 /* depth */); + + return uuidCache; } #define UUID 1 @@ -148,9 +150,7 @@ get_spec_by_x(int n, const char *t, int *majorPtr, int *minorPtr) { struct uuidCache_s *uc; - uuidcache_init(); - uc = uuidCache; - + uc = uuidcache_init(); while (uc) { switch (n) { case UUID: @@ -217,22 +217,21 @@ get_spec_by_volume_label(const char *s, int *major, int *minor) /* Used by blkid */ void display_uuid_cache(void) { - struct uuidCache_s *u; - - uuidcache_init(); - u = uuidCache; - while (u) { - printf("%s:", u->device); - if (u->label[0]) - printf(" LABEL=\"%s\"", u->label); - if (u->uc_uuid[0]) - printf(" UUID=\"%s\"", u->uc_uuid); + struct uuidCache_s *uc; + + uc = uuidcache_init(); + while (uc) { + printf("%s:", uc->device); + if (uc->label[0]) + printf(" LABEL=\"%s\"", uc->label); + if (uc->uc_uuid[0]) + printf(" UUID=\"%s\"", uc->uc_uuid); #if ENABLE_FEATURE_BLKID_TYPE - if (u->type) - printf(" TYPE=\"%s\"", u->type); + if (uc->type) + printf(" TYPE=\"%s\"", uc->type); #endif bb_putchar('\n'); - u = u->next; + uc = uc->next; } } @@ -265,8 +264,7 @@ char *get_devname_from_label(const char *spec) { struct uuidCache_s *uc; - uuidcache_init(); - uc = uuidCache; + uc = uuidcache_init(); while (uc) { if (uc->label[0] && strcmp(spec, uc->label) == 0) { return xstrdup(uc->device); @@ -280,8 +278,7 @@ char *get_devname_from_uuid(const char *spec) { struct uuidCache_s *uc; - uuidcache_init(); - uc = uuidCache; + uc = uuidcache_init(); while (uc) { /* case of hex numbers doesn't matter */ if (strcasecmp(spec, uc->uc_uuid) == 0) { -- cgit v1.2.3-55-g6feb From 2f8ccc14f73fc062dae74ad59476da9ec0a6dedf Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 6 Dec 2011 15:09:27 +0100 Subject: blkid: make help text show [BLOCKDEV]... Signed-off-by: Denys Vlasenko --- util-linux/blkid.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/util-linux/blkid.c b/util-linux/blkid.c index c30360c65..a9fd9f361 100644 --- a/util-linux/blkid.c +++ b/util-linux/blkid.c @@ -8,15 +8,13 @@ */ //usage:#define blkid_trivial_usage -//usage: "" +//usage: "[BLOCKDEV]..." //usage:#define blkid_full_usage "\n\n" //usage: "Print UUIDs of all filesystems" #include "libbb.h" #include "volume_id.h" -//TODO: extend to take BLOCKDEV args, and show TYPE="fstype" - int blkid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int blkid_main(int argc UNUSED_PARAM, char **argv) { -- cgit v1.2.3-55-g6feb From 53782d9221c854be057edfc4e847ea13717dfece Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 6 Dec 2011 18:59:55 +0100 Subject: iproute: fix help text Signed-off-by: Denys Vlasenko --- networking/ip.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/networking/ip.c b/networking/ip.c index fb2f5e2da..98fe621b1 100644 --- a/networking/ip.c +++ b/networking/ip.c @@ -50,16 +50,15 @@ //usage: "iplink show [DEVICE]" //usage: //usage:#define iproute_trivial_usage -//usage: "{ list | flush | { add | del | change | append |\n" -//usage: " replace | monitor } ROUTE }" +//usage: "{ list | flush | add | del | change | append |\n" +//usage: " replace | test } ROUTE" //usage:#define iproute_full_usage "\n\n" //usage: "iproute { list | flush } SELECTOR\n" //usage: "iproute get ADDRESS [from ADDRESS iif STRING]\n" -//usage: " [oif STRING] [tos TOS]\n" -//usage: "iproute { add | del | change | append | replace | monitor } ROUTE\n" -//usage: " SELECTOR := [root PREFIX] [match PREFIX] [proto RTPROTO]\n" -//usage: " ROUTE := [TYPE] PREFIX [tos TOS] [proto RTPROTO]\n" -//usage: " [metric METRIC]" +//usage: " [oif STRING] [tos TOS]\n" +//usage: "iproute { add | del | change | append | replace | test } ROUTE\n" +//usage: " SELECTOR := [root PREFIX] [match PREFIX] [proto RTPROTO]\n" +//usage: " ROUTE := [TYPE] PREFIX [tos TOS] [proto RTPROTO] [metric METRIC]" //usage: //usage:#define iprule_trivial_usage //usage: "{[list | add | del] RULE}" -- cgit v1.2.3-55-g6feb From 7280d2017d8075267a12e469983e38277dcf0374 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 8 Dec 2011 16:41:05 +0100 Subject: udhcpc: sanitize hostnames in incoming packets. Closes 3979. The following options are replaced with string "bad" if they contain malformed hostname: HOST_NAME, DOMAIN_NAME, NIS_DOMAIN, TFTP_SERVER_NAME function old new delta xmalloc_optname_optval 850 888 +38 attach_option 440 443 +3 len_of_option_as_string 13 14 +1 dhcp_option_lengths 13 14 +1 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 4/0 up/down: 43/0) Total: 43 bytes Signed-off-by: Denys Vlasenko --- networking/udhcp/common.c | 14 +++++++---- networking/udhcp/common.h | 3 +++ networking/udhcp/dhcpc.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 5 deletions(-) diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c index a89dce3ae..cf6b1ca91 100644 --- a/networking/udhcp/common.c +++ b/networking/udhcp/common.c @@ -29,9 +29,9 @@ const struct dhcp_optflag dhcp_optflags[] = { // { OPTION_IP | OPTION_LIST , 0x07 }, /* DHCP_LOG_SERVER */ // { OPTION_IP | OPTION_LIST , 0x08 }, /* DHCP_COOKIE_SERVER */ { OPTION_IP | OPTION_LIST , 0x09 }, /* DHCP_LPR_SERVER */ - { OPTION_STRING | OPTION_REQ, 0x0c }, /* DHCP_HOST_NAME */ + { OPTION_STRING_HOST | OPTION_REQ, 0x0c }, /* DHCP_HOST_NAME */ { OPTION_U16 , 0x0d }, /* DHCP_BOOT_SIZE */ - { OPTION_STRING | OPTION_REQ, 0x0f }, /* DHCP_DOMAIN_NAME */ + { OPTION_STRING_HOST | OPTION_REQ, 0x0f }, /* DHCP_DOMAIN_NAME */ { OPTION_IP , 0x10 }, /* DHCP_SWAP_SERVER */ { OPTION_STRING , 0x11 }, /* DHCP_ROOT_PATH */ { OPTION_U8 , 0x17 }, /* DHCP_IP_TTL */ @@ -41,7 +41,7 @@ const struct dhcp_optflag dhcp_optflags[] = { //server would let us know anyway? { OPTION_IP | OPTION_REQ, 0x1c }, /* DHCP_BROADCAST */ { OPTION_IP_PAIR | OPTION_LIST , 0x21 }, /* DHCP_ROUTES */ - { OPTION_STRING , 0x28 }, /* DHCP_NIS_DOMAIN */ + { OPTION_STRING_HOST , 0x28 }, /* DHCP_NIS_DOMAIN */ { OPTION_IP | OPTION_LIST , 0x29 }, /* DHCP_NIS_SERVER */ { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x2a }, /* DHCP_NTP_SERVER */ { OPTION_IP | OPTION_LIST , 0x2c }, /* DHCP_WINS_SERVER */ @@ -49,7 +49,7 @@ const struct dhcp_optflag dhcp_optflags[] = { { OPTION_IP , 0x36 }, /* DHCP_SERVER_ID */ { OPTION_STRING , 0x38 }, /* DHCP_ERR_MESSAGE */ //TODO: must be combined with 'sname' and 'file' handling: - { OPTION_STRING , 0x42 }, /* DHCP_TFTP_SERVER_NAME */ + { OPTION_STRING_HOST , 0x42 }, /* DHCP_TFTP_SERVER_NAME */ { OPTION_STRING , 0x43 }, /* DHCP_BOOT_FILE */ //TODO: not a string, but a set of LASCII strings: // { OPTION_STRING , 0x4D }, /* DHCP_USER_CLASS */ @@ -148,6 +148,7 @@ const uint8_t dhcp_option_lengths[] ALIGN1 = { [OPTION_IP_PAIR] = 8, // [OPTION_BOOLEAN] = 1, [OPTION_STRING] = 1, /* ignored by udhcp_str2optset */ + [OPTION_STRING_HOST] = 1, /* ignored by udhcp_str2optset */ #if ENABLE_FEATURE_UDHCP_RFC3397 [OPTION_DNS_STRING] = 1, /* ignored by both udhcp_str2optset and xmalloc_optname_optval */ [OPTION_SIP_SERVERS] = 1, @@ -417,7 +418,9 @@ static NOINLINE void attach_option( /* actually 255 is ok too, but adding a space can overlow it */ existing->data = xrealloc(existing->data, OPT_DATA + 1 + old_len + length); - if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_STRING) { + if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_STRING + || (optflag->flags & OPTION_TYPE_MASK) == OPTION_STRING_HOST + ) { /* add space separator between STRING options in a list */ existing->data[OPT_DATA + old_len] = ' '; old_len++; @@ -481,6 +484,7 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg) retval = udhcp_str2nip(val, buffer + 4); break; case OPTION_STRING: + case OPTION_STRING_HOST: #if ENABLE_FEATURE_UDHCP_RFC3397 case OPTION_DNS_STRING: #endif diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h index 479ae49f3..cfd58679a 100644 --- a/networking/udhcp/common.h +++ b/networking/udhcp/common.h @@ -80,6 +80,9 @@ enum { OPTION_IP = 1, OPTION_IP_PAIR, OPTION_STRING, + /* Opts of STRING_HOST type will be sanitized before they are passed + * to udhcpc script's environment: */ + OPTION_STRING_HOST, // OPTION_BOOLEAN, OPTION_U8, OPTION_U16, diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index 945600c6b..2f2016cd5 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -135,6 +135,63 @@ static int mton(uint32_t mask) return i; } +/* Check if a given label represents a valid DNS label + * Return pointer to the first character after the label upon success, + * NULL otherwise. + * See RFC1035, 2.3.1 + */ +/* We don't need to be particularly anal. For example, allowing _, hyphen + * at the end, or leading and trailing dots would be ok, since it + * can't be used for attacks. (Leading hyphen can be, if someone uses + * cmd "$hostname" + * in the script: then hostname may be treated as an option) + */ +static const char *valid_domain_label(const char *label) +{ + unsigned char ch; + unsigned pos = 0; + + for (;;) { + ch = *label; + if ((ch|0x20) < 'a' || (ch|0x20) > 'z') { + if (pos == 0) { + /* label must begin with letter */ + return NULL; + } + if (ch < '0' || ch > '9') { + if (ch == '\0' || ch == '.') + return label; + /* DNS allows only '-', but we are more permissive */ + if (ch != '-' && ch != '_') + return NULL; + } + } + label++; + pos++; + //Do we want this? + //if (pos > 63) /* NS_MAXLABEL; labels must be 63 chars or less */ + // return NULL; + } +} + +/* Check if a given name represents a valid DNS name */ +/* See RFC1035, 2.3.1 */ +static int good_hostname(const char *name) +{ + //const char *start = name; + + for (;;) { + name = valid_domain_label(name); + if (!name) + return 0; + if (!name[0]) + return 1; + //Do we want this? + //return ((name - start) < 1025); /* NS_MAXDNAME */ + name++; + } +} + /* Create "opt_name=opt_value" string */ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_optflag *optflag, const char *opt_name) { @@ -187,8 +244,11 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ * the case of list of options. */ case OPTION_STRING: + case OPTION_STRING_HOST: memcpy(dest, option, len); dest[len] = '\0'; + if (type == OPTION_STRING_HOST && !good_hostname(dest)) + safe_strncpy(dest, "bad", len); return ret; case OPTION_STATIC_ROUTES: { /* Option binary format: @@ -368,6 +428,7 @@ static char **fill_envp(struct dhcp_packet *packet) /* +1 element for each option, +2 for subnet option: */ if (packet) { /* note: do not search for "pad" (0) and "end" (255) options */ +//TODO: change logic to scan packet _once_ for (i = 1; i < 255; i++) { temp = udhcp_get_option(packet, i); if (temp) { -- cgit v1.2.3-55-g6feb From 3ef3cc59493aef4464458ddc47035815f4d13635 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 13 Dec 2011 16:56:47 +0100 Subject: touch: document -t DT option in help text Signed-off-by: Denys Vlasenko --- coreutils/touch.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/coreutils/touch.c b/coreutils/touch.c index 0f980fd7b..dc95edf1f 100644 --- a/coreutils/touch.c +++ b/coreutils/touch.c @@ -7,7 +7,7 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ -/* BB_AUDIT SUSv3 _NOT_ compliant -- options -a, -m, -r, -t not supported. */ +/* BB_AUDIT SUSv3 _NOT_ compliant -- options -a, -m not supported. */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/touch.html */ /* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) @@ -31,12 +31,13 @@ //kbuild:lib-$(CONFIG_TOUCH) += touch.o //usage:#define touch_trivial_usage -//usage: "[-c]" IF_DESKTOP(" [-d DATE] [-r FILE]") " FILE [FILE]..." +//usage: "[-c]" IF_DESKTOP(" [-d DATE] [-t DATE] [-r FILE]") " FILE [FILE]..." //usage:#define touch_full_usage "\n\n" //usage: "Update the last-modified date on the given FILE[s]\n" //usage: "\n -c Don't create files" //usage: IF_DESKTOP( //usage: "\n -d DT Date/time to use" +//usage: "\n -t DT Date/time to use" //usage: "\n -r FILE Use FILE's date/time" //usage: ) //usage: -- cgit v1.2.3-55-g6feb From fdf514f3433de6de30b01ca355fa1146729a3307 Mon Sep 17 00:00:00 2001 From: walter harms Date: Wed, 14 Dec 2011 08:48:59 +0100 Subject: touch: add new option FEATURE_TOUCH_SUSV3 This options -d -t -r where hidden under DESKTOP. This option allows the user to enable these options for (only) touch. The patch only changes DESKTOP to FEATURE_TOUCH_SUSV3. Signed-off-by: walter harms Signed-off-by: Denys Vlasenko --- coreutils/touch.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/coreutils/touch.c b/coreutils/touch.c index dc95edf1f..1216ca202 100644 --- a/coreutils/touch.c +++ b/coreutils/touch.c @@ -25,17 +25,24 @@ //config: help //config: touch is used to create or change the access and/or //config: modification timestamp of specified files. +//config: +//config:config FEATURE_TOUCH_SUSV3 +//config: bool "Add support for SUSV3 features (-d -t -r)" +//config: default y +//config: depends on TOUCH +//config: help +//config: Enable touch to use a reference file or a given date/time argument. //applet:IF_TOUCH(APPLET_NOFORK(touch, touch, BB_DIR_BIN, BB_SUID_DROP, touch)) //kbuild:lib-$(CONFIG_TOUCH) += touch.o //usage:#define touch_trivial_usage -//usage: "[-c]" IF_DESKTOP(" [-d DATE] [-t DATE] [-r FILE]") " FILE [FILE]..." +//usage: "[-c]" IF_FEATURE_TOUCH_SUSV3(" [-d DATE] [-t DATE] [-r FILE]") " FILE..." //usage:#define touch_full_usage "\n\n" //usage: "Update the last-modified date on the given FILE[s]\n" //usage: "\n -c Don't create files" -//usage: IF_DESKTOP( +//usage: IF_FEATURE_TOUCH_SUSV3( //usage: "\n -d DT Date/time to use" //usage: "\n -t DT Date/time to use" //usage: "\n -r FILE Use FILE's date/time" @@ -72,7 +79,7 @@ int touch_main(int argc UNUSED_PARAM, char **argv) int fd; int status = EXIT_SUCCESS; int opts; -#if ENABLE_DESKTOP +#if ENABLE_FEATURE_TOUCH_SUSV3 # if ENABLE_LONG_OPTS static const char touch_longopts[] ALIGN1 = /* name, has_arg, val */ @@ -91,17 +98,17 @@ int touch_main(int argc UNUSED_PARAM, char **argv) # define timebuf ((struct timeval*)NULL) #endif -#if ENABLE_DESKTOP && ENABLE_LONG_OPTS +#if ENABLE_FEATURE_TOUCH_SUSV3 && ENABLE_LONG_OPTS applet_long_options = touch_longopts; #endif /* -d and -t both set time. In coreutils, * accepted data format differs a bit between -d and -t. * We accept the same formats for both */ - opts = getopt32(argv, "c" IF_DESKTOP("r:d:t:") + opts = getopt32(argv, "c" IF_FEATURE_TOUCH_SUSV3("r:d:t:") /*ignored:*/ "fma" - IF_DESKTOP(, &reference_file) - IF_DESKTOP(, &date_str) - IF_DESKTOP(, &date_str) + IF_FEATURE_TOUCH_SUSV3(, &reference_file) + IF_FEATURE_TOUCH_SUSV3(, &date_str) + IF_FEATURE_TOUCH_SUSV3(, &date_str) ); opts &= 1; /* only -c bit is left */ -- cgit v1.2.3-55-g6feb From 1b41b33be34305e75eb8998f408f79193d7241e5 Mon Sep 17 00:00:00 2001 From: Daniel Fandrich Date: Thu, 15 Dec 2011 10:14:51 +0100 Subject: configs/android_defconfig: update Signed-off-by: Daniel Fandrich Signed-off-by: Denys Vlasenko --- configs/android_defconfig | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/configs/android_defconfig b/configs/android_defconfig index f1263b964..a9a8d5e1f 100644 --- a/configs/android_defconfig +++ b/configs/android_defconfig @@ -60,7 +60,7 @@ CONFIG_FEATURE_SYSLOG=y # CONFIG_BUILD_LIBBUSYBOX is not set # CONFIG_FEATURE_INDIVIDUAL is not set # CONFIG_FEATURE_SHARED_BUSYBOX is not set -CONFIG_LFS=y +# CONFIG_LFS is not set CONFIG_CROSS_COMPILER_PREFIX="arm-eabi-" # # Removed: @@ -199,6 +199,7 @@ CONFIG_CAT=y CONFIG_TEST=y CONFIG_FEATURE_TEST_64=y CONFIG_TOUCH=y +CONFIG_FEATURE_TOUCH_SUSV3=y CONFIG_TR=y CONFIG_FEATURE_TR_CLASSES=y CONFIG_FEATURE_TR_EQUIV=y @@ -554,7 +555,7 @@ CONFIG_FEATURE_FBSET_READMODE=y CONFIG_FDFLUSH=y CONFIG_FDFORMAT=y CONFIG_FDISK=y -# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set +CONFIG_FDISK_SUPPORT_LARGE_DISKS=y CONFIG_FEATURE_FDISK_WRITABLE=y # CONFIG_FEATURE_AIX_LABEL is not set # CONFIG_FEATURE_SGI_LABEL is not set @@ -848,6 +849,7 @@ CONFIG_FEATURE_TRACEROUTE_VERBOSE=y # CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set CONFIG_TUNCTL=y CONFIG_FEATURE_TUNCTL_UG=y +# CONFIG_UDHCPC6 is not set # CONFIG_UDHCPD is not set # CONFIG_DHCPRELAY is not set # CONFIG_DUMPLEASES is not set -- cgit v1.2.3-55-g6feb From 454fe29a802f5f32b802df1a54324946d0b87669 Mon Sep 17 00:00:00 2001 From: Lauri Hintsala Date: Wed, 14 Dec 2011 16:49:58 +0200 Subject: ifupdown: remove interface from state_list if iface_up fails Fix the issue where interface is set to the configured state even if configuration has failed. Add error check to state setting logic. Signed-off-by: Lauri Hintsala Signed-off-by: Denys Vlasenko --- networking/ifupdown.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/ifupdown.c b/networking/ifupdown.c index 5946323d0..9c2cad231 100644 --- a/networking/ifupdown.c +++ b/networking/ifupdown.c @@ -1311,7 +1311,7 @@ int ifupdown_main(int argc UNUSED_PARAM, char **argv) llist_t *state_list = read_iface_state(); llist_t *iface_state = find_iface_state(state_list, iface); - if (cmds == iface_up) { + if (cmds == iface_up && !any_failures) { char * const newiface = xasprintf("%s=%s", iface, liface); if (iface_state == NULL) { llist_add_to_end(&state_list, newiface); -- cgit v1.2.3-55-g6feb From d6f5000c1303ca7c31759d380fe154a46bd7126b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 15 Dec 2011 12:39:25 +0100 Subject: *: style fixes. no code changes Signed-off-by: Denys Vlasenko --- archival/lzop.c | 11 ++++++----- networking/ifupdown.c | 4 ++-- util-linux/rdev.c | 4 ++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/archival/lzop.c b/archival/lzop.c index 7e30091d9..67baeff7e 100644 --- a/archival/lzop.c +++ b/archival/lzop.c @@ -201,7 +201,7 @@ static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len, /* remove short run */ *litp &= ~3; /* copy over the 2 literals that replace the match */ - copy2(ip-3+1,m_pos,pd(op,m_pos)); + copy2(ip-3+1, m_pos, pd(op, m_pos)); /* move literals 1 byte ahead */ litp += 2; if (lit > 0) @@ -211,7 +211,8 @@ static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len, *litp = (unsigned char)(lit - 3); o_m1_b++; - *op++ = *m_pos++; *op++ = *m_pos++; + *op++ = *m_pos++; + *op++ = *m_pos++; goto copy_literal_run; } copy_m1: @@ -240,7 +241,7 @@ static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len, ) { t = *ip++; /* copy over the 3 literals that replace the match */ - copy3(ip-1-2,m_pos,pd(op,m_pos)); + copy3(ip-1-2, m_pos, pd(op, m_pos)); /* set new length of previous literal run */ lit += 3 + t + 3; *litp = (unsigned char)(lit - 3); @@ -289,7 +290,7 @@ static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len, lit += 3; *litp = (unsigned char)((*litp & ~3) | lit); /* copy over the 3 literals that replace the match */ - copy3(ip-3,m_pos,pd(op,m_pos)); + copy3(ip-3, m_pos, pd(op, m_pos)); o_m3_a++; } /* test if a literal run follows */ @@ -300,7 +301,7 @@ static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len, /* remove short run */ *litp &= ~3; /* copy over the 3 literals that replace the match */ - copy3(ip-4+1,m_pos,pd(op,m_pos)); + copy3(ip-4+1, m_pos, pd(op, m_pos)); /* move literals 1 byte ahead */ litp += 2; if (lit > 0) diff --git a/networking/ifupdown.c b/networking/ifupdown.c index 9c2cad231..73da26085 100644 --- a/networking/ifupdown.c +++ b/networking/ifupdown.c @@ -1312,8 +1312,8 @@ int ifupdown_main(int argc UNUSED_PARAM, char **argv) llist_t *iface_state = find_iface_state(state_list, iface); if (cmds == iface_up && !any_failures) { - char * const newiface = xasprintf("%s=%s", iface, liface); - if (iface_state == NULL) { + char *newiface = xasprintf("%s=%s", iface, liface); + if (!iface_state) { llist_add_to_end(&state_list, newiface); } else { free(iface_state->data); diff --git a/util-linux/rdev.c b/util-linux/rdev.c index 1212f841e..465281756 100644 --- a/util-linux/rdev.c +++ b/util-linux/rdev.c @@ -23,9 +23,9 @@ int rdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int rdev_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) { - char const * const root_device = find_block_device("/"); + const char *root_device = find_block_device("/"); - if (root_device != NULL) { + if (root_device) { printf("%s /\n", root_device); return EXIT_SUCCESS; } -- cgit v1.2.3-55-g6feb From 2bef526331a194da199993ec747598f625a5a9a8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 16 Dec 2011 00:25:17 +0100 Subject: ash: add comment about bash's ENOEXEC handling. No code changes Signed-off-by: Denys Vlasenko --- shell/ash.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/shell/ash.c b/shell/ash.c index 14472cb61..d02b74a4c 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -7435,6 +7435,12 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char ** * * That is, do not use $SHELL, user's shell, or /bin/sh; * just call ourselves. + * + * Note that bash reads ~80 chars of the file, and if it sees + * a zero byte before it sees newline, it doesn't try to + * interpret it, but fails with "cannot execute binary file" + * message. For one, it prevents atempts to interpret + * foreign ELF binaries as shell scripts. */ char **ap; char **new; -- cgit v1.2.3-55-g6feb From cda6ea905d448e2a2058b5eb44db50b256659b50 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 16 Dec 2011 00:44:36 +0100 Subject: ash: document bash's exit code too. No code changes Signed-off-by: Denys Vlasenko --- shell/ash.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shell/ash.c b/shell/ash.c index d02b74a4c..b4ed8e578 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -7439,8 +7439,8 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char ** * Note that bash reads ~80 chars of the file, and if it sees * a zero byte before it sees newline, it doesn't try to * interpret it, but fails with "cannot execute binary file" - * message. For one, it prevents atempts to interpret - * foreign ELF binaries as shell scripts. + * message and exit code 126. For one, this prevents attempts + * to interpret foreign ELF binaries as shell scripts. */ char **ap; char **new; -- cgit v1.2.3-55-g6feb From b05cd6b7a768039fa799f62634bdc83cb5803ed7 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 16 Dec 2011 01:37:02 +0100 Subject: httpd: fix /../ sanitization (had one extra semicolon). rewrote it Signed-off-by: Denys Vlasenko --- networking/httpd.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/networking/httpd.c b/networking/httpd.c index 0356e4c1b..f52785bf4 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -2012,30 +2012,36 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) /* Algorithm stolen from libbb bb_simplify_path(), * but don't strdup, retain trailing slash, protect root */ urlp = tptr = urlcopy; - do { + for (;;) { if (*urlp == '/') { /* skip duplicate (or initial) slash */ if (*tptr == '/') { - continue; + goto next_char; } if (*tptr == '.') { - /* skip extra "/./" */ - if (tptr[1] == '/' || !tptr[1]) { - continue; - } - /* "..": be careful */ - if (tptr[1] == '.' && (tptr[2] == '/' || !tptr[2])) { - ++tptr; - if (urlp == urlcopy) /* protect root */ + if (tptr[1] == '.' && (tptr[2] == '/' || tptr[2] == '\0')) { + /* "..": be careful */ + /* protect root */ + if (urlp == urlcopy) send_headers_and_exit(HTTP_BAD_REQUEST); - while (*--urlp != '/') /* omit previous dir */; + /* omit previous dir */ + while (*--urlp != '/') continue; + /* skip to "./" or "." */ + tptr++; + } + if (tptr[1] == '/' || tptr[1] == '\0') { + /* skip extra "/./" */ + goto next_char; } } } *++urlp = *tptr; - } while (*++tptr); - *++urlp = '\0'; /* terminate after last character */ + if (*urlp == '\0') + break; + next_char: + tptr++; + } /* If URL is a directory, add '/' */ if (urlp[-1] != '/') { -- cgit v1.2.3-55-g6feb From be2a557918af86cc55b3426f97664503fe7e265f Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Fri, 16 Dec 2011 01:42:55 +0100 Subject: vconfig: remove /proc/net/vlan/config check In original implementation /proc/net/vlan/config check only prints warning and does not exit. Busybox version exits if this file is not found and this prevents kernel module autoloading to work. I think it is safe to remove this check since ioctl() call will fail (with proper error code) anyway if 802.1q module is not loaded (or autoloading is off). Signed-off-by: Paulius Zaleckas Signed-off-by: Denys Vlasenko --- networking/vconfig.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/networking/vconfig.c b/networking/vconfig.c index 48b45d9af..ac8b96d8c 100644 --- a/networking/vconfig.c +++ b/networking/vconfig.c @@ -116,8 +116,6 @@ static const char name_types[] ALIGN1 = { '_', 'N', 'O', '_', 'P', 'A', 'D', 0, }; -static const char conf_file_name[] ALIGN1 = "/proc/net/vlan/config"; - int vconfig_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int vconfig_main(int argc, char **argv) { @@ -129,10 +127,6 @@ int vconfig_main(int argc, char **argv) bb_show_usage(); } - /* Don't bother closing the filedes. It will be closed on cleanup. */ - /* Will die if 802.1q is not present */ - xopen(conf_file_name, O_RDONLY); - memset(&ifr, 0, sizeof(ifr)); ++argv; -- cgit v1.2.3-55-g6feb From 7b57ff4436f3e672076e6f5440954a958ba04ab3 Mon Sep 17 00:00:00 2001 From: Michael McTernan Date: Fri, 16 Dec 2011 17:05:52 +0100 Subject: udhcp: finish support of classless static routes function old new delta udhcp_str2optset 415 532 +117 Signed-off-by: Michael McTernan Signed-off-by: Denys Vlasenko --- examples/udhcp/udhcpd.conf | 6 ++++-- include/xatonum.h | 9 +++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/examples/udhcp/udhcpd.conf b/examples/udhcp/udhcpd.conf index cd2957ccc..eca44c0ab 100644 --- a/examples/udhcp/udhcpd.conf +++ b/examples/udhcp/udhcpd.conf @@ -68,6 +68,8 @@ opt wins 192.168.10.10 option dns 129.219.13.81 # appended to above DNS servers for a total of 3 option domain local option lease 864000 # default: 10 days +option msstaticroutes 10.0.0.0/8 10.127.0.1 # single static route +option staticroutes 10.0.0.0/8 10.127.0.1, 10.11.12.0/24 10.11.12.1 # Arbitrary option in hex form: option 0x08 01020304 # option 8: "cookie server IP addr: 1.2.3.4" @@ -101,6 +103,8 @@ option 0x08 01020304 # option 8: "cookie server IP addr: 1.2.3.4" #opt swapsrv IP # Options specifying routes #opt routes IP_PAIR_LIST +#opt staticroutes STATIC_ROUTES # RFC 3442 classless static route option +#opt msstaticroutes STATIC_ROUTES # same, using MS option number # Obsolete options, no longer supported #opt logsrv IP_LIST # 704/UDP log server (not syslog!) #opt namesrv IP_LIST # IEN 116 name server, obsolete (August 1979!!!) @@ -109,5 +113,3 @@ option 0x08 01020304 # option 8: "cookie server IP addr: 1.2.3.4" # TODO: in development #opt userclass STRING # RFC 3004. set of LASCII strings. "I am a printer" etc #opt sipserv STRING LIST # RFC 3361. flag byte, then: 0: domain names, 1: IP addrs -#opt staticroutes STATIC_ROUTES -#opt msstaticroutes STATIC_ROUTES diff --git a/include/xatonum.h b/include/xatonum.h index 6f76a3c96..45ebbfc00 100644 --- a/include/xatonum.h +++ b/include/xatonum.h @@ -168,6 +168,15 @@ uint32_t bb_strtou32(const char *arg, char **endp, int base) return bb_strtoul(arg, endp, base); return BUG_bb_strtou32_unimplemented(); } +static ALWAYS_INLINE +int32_t bb_strtoi32(const char *arg, char **endp, int base) +{ + if (sizeof(int32_t) == sizeof(int)) + return bb_strtoi(arg, endp, base); + if (sizeof(int32_t) == sizeof(long)) + return bb_strtol(arg, endp, base); + return BUG_bb_strtou32_unimplemented(); +} /* Floating point */ -- cgit v1.2.3-55-g6feb From ee0f444f11504e47fc0f3ab6bc2bf95defb6e6ae Mon Sep 17 00:00:00 2001 From: Michael McTernan Date: Fri, 16 Dec 2011 17:10:09 +0100 Subject: udhcp: finish support of classless static routes (now the correct patch!) Signed-off-by: Michael McTernan Signed-off-by: Denys Vlasenko --- networking/udhcp/common.c | 55 +++++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c index cf6b1ca91..ae0e0d306 100644 --- a/networking/udhcp/common.c +++ b/networking/udhcp/common.c @@ -57,13 +57,13 @@ const struct dhcp_optflag dhcp_optflags[] = { { OPTION_DNS_STRING | OPTION_LIST , 0x77 }, /* DHCP_DOMAIN_SEARCH */ { OPTION_SIP_SERVERS , 0x78 }, /* DHCP_SIP_SERVERS */ #endif - { OPTION_STATIC_ROUTES , 0x79 }, /* DHCP_STATIC_ROUTES */ + { OPTION_STATIC_ROUTES | OPTION_LIST , 0x79 }, /* DHCP_STATIC_ROUTES */ #if ENABLE_FEATURE_UDHCP_8021Q { OPTION_U16 , 0x84 }, /* DHCP_VLAN_ID */ { OPTION_U8 , 0x85 }, /* DHCP_VLAN_PRIORITY */ #endif { OPTION_6RD , 0xd4 }, /* DHCP_6RD */ - { OPTION_STATIC_ROUTES , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */ + { OPTION_STATIC_ROUTES | OPTION_LIST , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */ { OPTION_STRING , 0xfc }, /* DHCP_WPAD */ /* Options below have no match in dhcp_option_strings[], @@ -123,8 +123,6 @@ const char dhcp_option_strings[] ALIGN1 = // is not handled yet by "string->option" conversion code: "sipsrv" "\0" /* DHCP_SIP_SERVERS */ #endif -// doesn't work in udhcpd.conf since OPTION_STATIC_ROUTES -// is not handled yet by "string->option" conversion code: "staticroutes" "\0"/* DHCP_STATIC_ROUTES */ #if ENABLE_FEATURE_UDHCP_8021Q "vlanid" "\0" /* DHCP_VLAN_ID */ @@ -338,7 +336,8 @@ int FAST_FUNC udhcp_str2nip(const char *str, void *arg) lsa = host_and_af2sockaddr(str, 0, AF_INET); if (!lsa) return 0; - *(uint32_t*)arg = lsa->u.sin.sin_addr.s_addr; + /* arg maybe unaligned */ + move_to_unaligned32((uint32_t*)arg, lsa->u.sin.sin_addr.s_addr); free(lsa); return 1; } @@ -437,13 +436,14 @@ static NOINLINE void attach_option( int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg) { struct option_set **opt_list = arg; - char *opt, *val, *endptr; + char *opt, *val; char *str; const struct dhcp_optflag *optflag; struct dhcp_optflag bin_optflag; unsigned optcode; int retval, length; - char buffer[8] ALIGNED(4); + /* IP_PAIR needs 8 bytes, STATIC_ROUTES needs 9 max */ + char buffer[9] ALIGNED(4); uint16_t *result_u16 = (uint16_t *) buffer; uint32_t *result_u32 = (uint32_t *) buffer; @@ -501,34 +501,53 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg) // break; // } case OPTION_U8: - buffer[0] = strtoul(val, &endptr, 0); - retval = (endptr[0] == '\0'); + buffer[0] = bb_strtou32(val, NULL, 0); + retval = (errno == 0); break; /* htonX are macros in older libc's, using temp var * in code below for safety */ /* TODO: use bb_strtoX? */ case OPTION_U16: { - unsigned long tmp = strtoul(val, &endptr, 0); + uint32_t tmp = bb_strtou32(val, NULL, 0); *result_u16 = htons(tmp); - retval = (endptr[0] == '\0' /*&& tmp < 0x10000*/); + retval = (errno == 0 /*&& tmp < 0x10000*/); break; } // case OPTION_S16: { -// long tmp = strtol(val, &endptr, 0); +// long tmp = bb_strtoi32(val, NULL, 0); // *result_u16 = htons(tmp); -// retval = (endptr[0] == '\0'); +// retval = (errno == 0); // break; // } case OPTION_U32: { - unsigned long tmp = strtoul(val, &endptr, 0); + uint32_t tmp = bb_strtou32(val, NULL, 0); *result_u32 = htonl(tmp); - retval = (endptr[0] == '\0'); + retval = (errno == 0); break; } case OPTION_S32: { - long tmp = strtol(val, &endptr, 0); + int32_t tmp = bb_strtoi32(val, NULL, 0); *result_u32 = htonl(tmp); - retval = (endptr[0] == '\0'); + retval = (errno == 0); + break; + } + case OPTION_STATIC_ROUTES: { + /* Input: "a.b.c.d/m" */ + /* Output: mask(1 byte),pfx(0-4 bytes),gw(4 bytes) */ + unsigned mask; + char *slash = strchr(val, '/'); + if (slash) { + *slash = '\0'; + retval = udhcp_str2nip(val, buffer + 1); + buffer[0] = mask = bb_strtou(slash + 1, NULL, 10); + val = strtok(NULL, ", \t/-"); + if (!val || mask > 32 || errno) + retval = 0; + if (retval) { + length = ((mask + 7) >> 3) + 5; + retval = udhcp_str2nip(val, buffer + (length - 4)); + } + } break; } case OPTION_BIN: /* handled in attach_option() */ @@ -539,7 +558,7 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg) } if (retval) attach_option(opt_list, optflag, opt, length); - } while (retval && optflag->flags & OPTION_LIST); + } while (retval && (optflag->flags & OPTION_LIST)); return retval; } -- cgit v1.2.3-55-g6feb From f85bd1a7a7e712c4dd2dfd86daa9ab01a708b7b4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 18 Dec 2011 03:22:36 +0100 Subject: httpd: remove redundant NULL assignment and save one strrchr. -8 bytes Signed-off-by: Denys Vlasenko --- networking/httpd.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/networking/httpd.c b/networking/httpd.c index f52785bf4..cda7cc7af 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -1284,7 +1284,7 @@ static void send_cgi_and_exit( { struct fd_pair fromCgi; /* CGI -> httpd pipe */ struct fd_pair toCgi; /* httpd -> CGI pipe */ - char *script; + char *script, *last_slash; int pid; /* Make a copy. NB: caller guarantees: @@ -1298,15 +1298,18 @@ static void send_cgi_and_exit( */ /* Check for [dirs/]script.cgi/PATH_INFO */ - script = (char*)url; + last_slash = script = (char*)url; while ((script = strchr(script + 1, '/')) != NULL) { + int dir; *script = '\0'; - if (!is_directory(url + 1, 1, NULL)) { + dir = is_directory(url + 1, /*followlinks:*/ 1, NULL); + *script = '/'; + if (!dir) { /* not directory, found script.cgi/PATH_INFO */ - *script = '/'; break; } - *script = '/'; /* is directory, find next '/' */ + /* is directory, find next '/' */ + last_slash = script; } setenv1("PATH_INFO", script); /* set to /PATH_INFO or "" */ setenv1("REQUEST_METHOD", request); @@ -1387,7 +1390,7 @@ static void send_cgi_and_exit( log_and_exit(); } - if (!pid) { + if (pid == 0) { /* Child process */ char *argv[3]; @@ -1403,7 +1406,7 @@ static void send_cgi_and_exit( /* dup2(1, 2); */ /* Chdiring to script's dir */ - script = strrchr(url, '/'); + script = last_slash; if (script != url) { /* paranoia */ *script = '\0'; if (chdir(url + 1) != 0) { @@ -1992,7 +1995,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) /* NB: urlcopy ptr is never changed after this */ /* Extract url args if present */ - g_query = NULL; + /* g_query = NULL; - already is */ tptr = strchr(urlcopy, '?'); if (tptr) { *tptr++ = '\0'; -- cgit v1.2.3-55-g6feb From f282c6b65775d3dff03de6fd3585722a1638f734 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 18 Dec 2011 03:27:46 +0100 Subject: libbb: remove is_directory's argument which is always NULL function old new delta send_cgi_and_exit 892 890 -2 ln_main 447 445 -2 handle_incoming_and_exit 2784 2780 -4 is_directory 66 59 -7 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/6 up/down: 2/-19) Total: -15 bytes Signed-off-by: Denys Vlasenko --- coreutils/ln.c | 4 ++-- include/libbb.h | 2 +- libbb/isdirectory.c | 15 +++++---------- networking/httpd.c | 6 +++--- 4 files changed, 11 insertions(+), 16 deletions(-) diff --git a/coreutils/ln.c b/coreutils/ln.c index 88a9a8f91..0eb3e6579 100644 --- a/coreutils/ln.c +++ b/coreutils/ln.c @@ -69,8 +69,8 @@ int ln_main(int argc, char **argv) src = last; if (is_directory(src, - (opts & LN_NODEREFERENCE) ^ LN_NODEREFERENCE, - NULL) + (opts & LN_NODEREFERENCE) ^ LN_NODEREFERENCE + ) ) { src_name = xstrdup(*argv); src = concat_path_file(src, bb_get_last_path_component_strip(src_name)); diff --git a/include/libbb.h b/include/libbb.h index bc9b7b06d..22d2a5b20 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -314,7 +314,7 @@ extern char *strrstr(const char *haystack, const char *needle) FAST_FUNC; //TODO: supply a pointer to char[11] buffer (avoid statics)? extern const char *bb_mode_string(mode_t mode) FAST_FUNC; -extern int is_directory(const char *name, int followLinks, struct stat *statBuf) FAST_FUNC; +extern int is_directory(const char *name, int followLinks) FAST_FUNC; enum { /* DO NOT CHANGE THESE VALUES! cp.c, mv.c, install.c depend on them. */ FILEUTILS_PRESERVE_STATUS = 1 << 0, /* -p */ FILEUTILS_DEREFERENCE = 1 << 1, /* !-d */ diff --git a/libbb/isdirectory.c b/libbb/isdirectory.c index 9861be6f8..ba6c52ce8 100644 --- a/libbb/isdirectory.c +++ b/libbb/isdirectory.c @@ -15,22 +15,17 @@ * Return TRUE if fileName is a directory. * Nonexistent files return FALSE. */ -int FAST_FUNC is_directory(const char *fileName, int followLinks, struct stat *statBuf) +int FAST_FUNC is_directory(const char *fileName, int followLinks) { int status; - struct stat astatBuf; - - if (statBuf == NULL) { - /* use auto stack buffer */ - statBuf = &astatBuf; - } + struct stat statBuf; if (followLinks) - status = stat(fileName, statBuf); + status = stat(fileName, &statBuf); else - status = lstat(fileName, statBuf); + status = lstat(fileName, &statBuf); - status = (status == 0 && S_ISDIR(statBuf->st_mode)); + status = (status == 0 && S_ISDIR(statBuf.st_mode)); return status; } diff --git a/networking/httpd.c b/networking/httpd.c index cda7cc7af..e9cd213f1 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -1302,7 +1302,7 @@ static void send_cgi_and_exit( while ((script = strchr(script + 1, '/')) != NULL) { int dir; *script = '\0'; - dir = is_directory(url + 1, /*followlinks:*/ 1, NULL); + dir = is_directory(url + 1, /*followlinks:*/ 1); *script = '/'; if (!dir) { /* not directory, found script.cgi/PATH_INFO */ @@ -2048,7 +2048,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) /* If URL is a directory, add '/' */ if (urlp[-1] != '/') { - if (is_directory(urlcopy + 1, 1, NULL)) { + if (is_directory(urlcopy + 1, /*followlinks:*/ 1)) { found_moved_temporarily = urlcopy; } } @@ -2062,7 +2062,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) while (ip_allowed && (tptr = strchr(tptr + 1, '/')) != NULL) { /* have path1/path2 */ *tptr = '\0'; - if (is_directory(urlcopy + 1, 1, NULL)) { + if (is_directory(urlcopy + 1, /*followlinks:*/ 1)) { /* may have subdir config */ parse_conf(urlcopy + 1, SUBDIR_PARSE); ip_allowed = checkPermIP(); -- cgit v1.2.3-55-g6feb From 93b4a605263612cf32ad9de746a4fafaf4515115 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 18 Dec 2011 05:11:56 +0100 Subject: wget: fix use-after-free on redirect function old new delta wget_main 2153 2168 +15 Signed-off-by: Denys Vlasenko --- networking/wget.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/networking/wget.c b/networking/wget.c index 94a2f7c3d..1991a1072 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -557,6 +557,7 @@ static void download_one_url(const char *url) FILE *dfp; /* socket to ftp server (data) */ char *proxy = NULL; char *fname_out_alloc; + char *redirected_path = NULL; struct host_info server; struct host_info target; @@ -793,8 +794,8 @@ However, in real world it was observed that some web servers bb_error_msg_and_die("too many redirections"); fclose(sfp); if (str[0] == '/') { - free(target.allocated); - target.path = target.allocated = xstrdup(str+1); + free(redirected_path); + target.path = redirected_path = xstrdup(str+1); /* lsa stays the same: it's on the same server */ } else { parse_url(str, &target); @@ -849,6 +850,7 @@ However, in real world it was observed that some web servers free(server.allocated); free(target.allocated); free(fname_out_alloc); + free(redirected_path); } int wget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -- cgit v1.2.3-55-g6feb From 03419aa037ce37d1c3accb0df52fdc456b360541 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 19 Dec 2011 12:30:34 +0100 Subject: httpd: don't drop/abuse QUERY_STRING when /cgi-bin/index.cgi is used Signed-off-by: Peter Korsgaard Signed-off-by: Denys Vlasenko --- networking/httpd.c | 26 ++++++++++++++++++-------- networking/httpd_indexcgi.c | 27 ++++++++++++++++----------- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/networking/httpd.c b/networking/httpd.c index e9cd213f1..3f4e6aab7 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -1265,18 +1265,21 @@ static void setenv1(const char *name, const char *value) * * Parameters: * const char *url The requested URL (with leading /). + * const char *orig_uri The original URI before rewriting (if any) * int post_len Length of the POST body. * const char *cookie For set HTTP_COOKIE. * const char *content_type For set CONTENT_TYPE. */ static void send_cgi_and_exit( const char *url, + const char *orig_uri, const char *request, int post_len, const char *cookie, const char *content_type) NORETURN; static void send_cgi_and_exit( const char *url, + const char *orig_uri, const char *request, int post_len, const char *cookie, @@ -1314,9 +1317,9 @@ static void send_cgi_and_exit( setenv1("PATH_INFO", script); /* set to /PATH_INFO or "" */ setenv1("REQUEST_METHOD", request); if (g_query) { - putenv(xasprintf("%s=%s?%s", "REQUEST_URI", url, g_query)); + putenv(xasprintf("%s=%s?%s", "REQUEST_URI", orig_uri, g_query)); } else { - setenv1("REQUEST_URI", url); + setenv1("REQUEST_URI", orig_uri); } if (script != NULL) *script = '\0'; /* cut off /PATH_INFO */ @@ -2248,12 +2251,20 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) /* protect listing "cgi-bin/" */ send_headers_and_exit(HTTP_FORBIDDEN); } - send_cgi_and_exit(urlcopy, prequest, length, cookie, content_type); + send_cgi_and_exit(urlcopy, urlcopy, prequest, length, cookie, content_type); } #endif - if (urlp[-1] == '/') + if (urlp[-1] == '/') { + /* When index_page string is appended to / URL, it overwrites + * the query string. If we fall back to call /cgi-bin/index.cgi, + * query string would be lost and not available to the CGI. + * Work around it by making a deep copy. + */ + if (ENABLE_FEATURE_HTTPD_CGI) + g_query = xstrdup(g_query); /* ok for NULL too */ strcpy(urlp, index_page); + } if (stat(tptr, &sb) == 0) { #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR char *suffix = strrchr(tptr, '.'); @@ -2261,7 +2272,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) Htaccess *cur; for (cur = script_i; cur; cur = cur->next) { if (strcmp(cur->before_colon + 1, suffix) == 0) { - send_cgi_and_exit(urlcopy, prequest, length, cookie, content_type); + send_cgi_and_exit(urlcopy, urlcopy, prequest, length, cookie, content_type); } } } @@ -2274,9 +2285,8 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) /* It's a dir URL and there is no index.html * Try cgi-bin/index.cgi */ if (access("/cgi-bin/index.cgi"+1, X_OK) == 0) { - urlp[0] = '\0'; - g_query = urlcopy; - send_cgi_and_exit("/cgi-bin/index.cgi", prequest, length, cookie, content_type); + urlp[0] = '\0'; /* remove index_page */ + send_cgi_and_exit("/cgi-bin/index.cgi", urlcopy, prequest, length, cookie, content_type); } } /* else fall through to send_file, it errors out if open fails: */ diff --git a/networking/httpd_indexcgi.c b/networking/httpd_indexcgi.c index 7e0225e19..d732cd4f8 100644 --- a/networking/httpd_indexcgi.c +++ b/networking/httpd_indexcgi.c @@ -221,20 +221,25 @@ int main(int argc, char *argv[]) unsigned long long size_total; int odd; DIR *dirp; - char *QUERY_STRING; - - QUERY_STRING = getenv("QUERY_STRING"); - if (!QUERY_STRING - || QUERY_STRING[0] != '/' - || strstr(QUERY_STRING, "//") - || strstr(QUERY_STRING, "/../") - || strcmp(strrchr(QUERY_STRING, '/'), "/..") == 0 + char *location; + + location = getenv("REQUEST_URI"); + if (!location) + return 1; + + /* drop URL arguments if any */ + strchrnul(location, '?')[0] = '\0'; + + if (location[0] != '/' + || strstr(location, "//") + || strstr(location, "/../") + || strcmp(strrchr(location, '/'), "/..") == 0 ) { return 1; } if (chdir("..") - || (QUERY_STRING[1] && chdir(QUERY_STRING + 1)) + || (location[1] && chdir(location + 1)) ) { return 1; } @@ -271,14 +276,14 @@ int main(int argc, char *argv[]) "\r\n" /* Mandatory empty line after headers */ "Index of "); /* Guard against directories with &, > etc */ - fmt_html(QUERY_STRING); + fmt_html(location); fmt_str( "\n" STYLE_STR "" "\n" "" "\n" "

Index of "); - fmt_html(QUERY_STRING); + fmt_html(location); fmt_str( "

" "\n" "" "\n" -- cgit v1.2.3-55-g6feb From 3365e9f3cc1859e8c427533e13676740d8038719 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 20 Dec 2011 02:15:19 +0100 Subject: makemime: tweak help text: -a HDR can be repeated Signed-off-by: Denys Vlasenko --- mailutils/makemime.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mailutils/makemime.c b/mailutils/makemime.c index 4b07e54de..1dadd715f 100644 --- a/mailutils/makemime.c +++ b/mailutils/makemime.c @@ -132,7 +132,7 @@ Content-Transfer-Encoding: 7bit //usage: "Create multipart MIME-encoded message from FILEs\n" /* //usage: "Transfer encoding is base64, disposition is inline (not attachment)\n" */ //usage: "\n -o FILE Output. Default: stdout" -//usage: "\n -a HDR Add header. Examples:" +//usage: "\n -a HDR Add header(s). Examples:" //usage: "\n \"From: user@host.org\", \"Date: `date -R`\"" //usage: "\n -c CT Content type. Default: application/octet-stream" //usage: "\n -C CS Charset. Default: " CONFIG_FEATURE_MIME_CHARSET @@ -142,12 +142,12 @@ Content-Transfer-Encoding: 7bit /* * -c [Content-Type] should create just one MIME section - * with "Content-Type:", "Content-Transfer-Encoding:", and HDR from "-a HDR". + * with "Content-Type:", "Content-Transfer-Encoding:", and HDRs from "-a HDR". * NB: without "Content-Disposition:" auto-added, unlike we do now * NB2: -c has *optional* param which nevertheless _can_ be specified after a space :( * * -m [multipart/mixed] should create multipart MIME section - * with "Content-Type:", "Content-Transfer-Encoding:", and HDR from "-a HDR", + * with "Content-Type:", "Content-Transfer-Encoding:", and HDRs from "-a HDR", * and add FILE to it _verbatim_: * HEADERS * -- cgit v1.2.3-55-g6feb From 83f103b30e41ab038e45661df97625f655abe491 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 20 Dec 2011 06:10:35 +0100 Subject: ash: in standalone mode, search in $PATH if /proc/self/exe doesn't exist Signed-off-by: Denys Vlasenko --- shell/ash.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/shell/ash.c b/shell/ash.c index b4ed8e578..d197fa19a 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -7471,9 +7471,7 @@ shellexec(char **argv, const char *path, int idx) int e; char **envp; int exerrno; -#if ENABLE_FEATURE_SH_STANDALONE - int applet_no = -1; -#endif + int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ clearredir(/*drop:*/ 1); envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); @@ -7483,8 +7481,16 @@ shellexec(char **argv, const char *path, int idx) #endif ) { tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp); + if (applet_no >= 0) { + /* We tried execing ourself, but it didn't work. + * Maybe /proc/self/exe doesn't exist? + * Try $PATH search. + */ + goto try_PATH; + } e = errno; } else { + try_PATH: e = ENOENT; while ((cmdname = path_advance(&path, argv[0])) != NULL) { if (--idx < 0 && pathopt == NULL) { -- cgit v1.2.3-55-g6feb From 6a93212b54327c77383d88efd581475105f3b72a Mon Sep 17 00:00:00 2001 From: Alexey Fomenko Date: Thu, 22 Dec 2011 11:38:57 +0100 Subject: kill: fix segfault in arguments parsing Signed-off-by: Alexey Fomenko Signed-off-by: Denys Vlasenko --- procps/kill.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/procps/kill.c b/procps/kill.c index 224e5ad1a..b267a7aaf 100644 --- a/procps/kill.c +++ b/procps/kill.c @@ -165,13 +165,15 @@ int kill_main(int argc, char **argv) /* Stop all processes */ kill(-1, SIGSTOP); /* Signal all processes except those in our session */ - while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_SID))) { + while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_SID)) != NULL) { int i; if (p->sid == (unsigned)sid || p->pid == (unsigned)pid - || p->pid == 1) + || p->pid == 1 + ) { continue; + } /* All remaining args must be -o PID options. * Check p->pid against them. */ @@ -255,9 +257,10 @@ int kill_main(int argc, char **argv) pid = bb_strtoi(arg, &end, 10); if (errno && (errno != EINVAL || *end != ' ')) { bb_error_msg("invalid number '%s'", arg); - *end = '\0'; errors++; - } else if (kill(pid, signo) != 0) { + break; + } + if (kill(pid, signo) != 0) { bb_perror_msg("can't kill pid %d", (int)pid); errors++; } -- cgit v1.2.3-55-g6feb From ba6587295053f369d6e2e9b788f42b49e1baced5 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 22 Dec 2011 13:00:32 +0100 Subject: libbb/bb_strtonum: always set end ptr, even on error return function old new delta handle_errors 69 61 -8 Signed-off-by: Denys Vlasenko --- libbb/bb_strtonum.c | 59 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/libbb/bb_strtonum.c b/libbb/bb_strtonum.c index c66c774f4..949f26bee 100644 --- a/libbb/bb_strtonum.c +++ b/libbb/bb_strtonum.c @@ -36,14 +36,14 @@ static unsigned long long ret_ERANGE(void) return ULLONG_MAX; } -static unsigned long long handle_errors(unsigned long long v, char **endp, char *endptr) +static unsigned long long handle_errors(unsigned long long v, char **endp) { - if (endp) *endp = endptr; + char next_ch = **endp; /* errno is already set to ERANGE by strtoXXX if value overflowed */ - if (endptr[0]) { + if (next_ch) { /* "1234abcg" or out-of-range? */ - if (isalnum(endptr[0]) || errno) + if (isalnum(next_ch) || errno) return ret_ERANGE(); /* good number, just suspicious terminator */ errno = EINVAL; @@ -57,30 +57,37 @@ unsigned long long FAST_FUNC bb_strtoull(const char *arg, char **endp, int base) unsigned long long v; char *endptr; + if (!endp) endp = &endptr; + *endp = (char*) arg; + /* strtoul(" -4200000000") returns 94967296, errno 0 (!) */ /* I don't think that this is right. Preventing this... */ if (!isalnum(arg[0])) return ret_ERANGE(); /* not 100% correct for lib func, but convenient for the caller */ errno = 0; - v = strtoull(arg, &endptr, base); - return handle_errors(v, endp, endptr); + v = strtoull(arg, endp, base); + return handle_errors(v, endp); } long long FAST_FUNC bb_strtoll(const char *arg, char **endp, int base) { unsigned long long v; char *endptr; + char first; + + if (!endp) endp = &endptr; + *endp = (char*) arg; /* Check for the weird "feature": * a "-" string is apparently a valid "number" for strto[u]l[l]! * It returns zero and errno is 0! :( */ - char first = (arg[0] != '-' ? arg[0] : arg[1]); + first = (arg[0] != '-' ? arg[0] : arg[1]); if (!isalnum(first)) return ret_ERANGE(); errno = 0; - v = strtoll(arg, &endptr, base); - return handle_errors(v, endp, endptr); + v = strtoll(arg, endp, base); + return handle_errors(v, endp); } #if ULONG_MAX != ULLONG_MAX @@ -89,23 +96,30 @@ unsigned long FAST_FUNC bb_strtoul(const char *arg, char **endp, int base) unsigned long v; char *endptr; + if (!endp) endp = &endptr; + *endp = (char*) arg; + if (!isalnum(arg[0])) return ret_ERANGE(); errno = 0; - v = strtoul(arg, &endptr, base); - return handle_errors(v, endp, endptr); + v = strtoul(arg, endp, base); + return handle_errors(v, endp); } long FAST_FUNC bb_strtol(const char *arg, char **endp, int base) { long v; char *endptr; + char first; - char first = (arg[0] != '-' ? arg[0] : arg[1]); + if (!endp) endp = &endptr; + *endp = (char*) arg; + + first = (arg[0] != '-' ? arg[0] : arg[1]); if (!isalnum(first)) return ret_ERANGE(); errno = 0; - v = strtol(arg, &endptr, base); - return handle_errors(v, endp, endptr); + v = strtol(arg, endp, base); + return handle_errors(v, endp); } #endif @@ -115,25 +129,32 @@ unsigned FAST_FUNC bb_strtou(const char *arg, char **endp, int base) unsigned long v; char *endptr; + if (!endp) endp = &endptr; + *endp = (char*) arg; + if (!isalnum(arg[0])) return ret_ERANGE(); errno = 0; - v = strtoul(arg, &endptr, base); + v = strtoul(arg, endp, base); if (v > UINT_MAX) return ret_ERANGE(); - return handle_errors(v, endp, endptr); + return handle_errors(v, endp); } int FAST_FUNC bb_strtoi(const char *arg, char **endp, int base) { long v; char *endptr; + char first; + + if (!endp) endp = &endptr; + *endp = (char*) arg; - char first = (arg[0] != '-' ? arg[0] : arg[1]); + first = (arg[0] != '-' ? arg[0] : arg[1]); if (!isalnum(first)) return ret_ERANGE(); errno = 0; - v = strtol(arg, &endptr, base); + v = strtol(arg, endp, base); if (v > INT_MAX) return ret_ERANGE(); if (v < INT_MIN) return ret_ERANGE(); - return handle_errors(v, endp, endptr); + return handle_errors(v, endp); } #endif -- cgit v1.2.3-55-g6feb From 6b64a269766ace40c56826738de446537add37de Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 6 Jan 2012 16:23:18 +0100 Subject: platform.h: define endgrent() and endpwent() as no-ops on Android Surprisingly, bionic libc seems to lack these functions. Signed-off-by: Denys Vlasenko --- include/grp_.h | 2 +- include/platform.h | 5 +++++ include/pwd_.h | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/grp_.h b/include/grp_.h index 5c24d558a..82ad90492 100644 --- a/include/grp_.h +++ b/include/grp_.h @@ -29,7 +29,7 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN * We will use libc-defined structures, but will #define function names * so that function calls are directed to bb_internal_XXX replacements */ - +#undef endgrent #define setgrent bb_internal_setgrent #define endgrent bb_internal_endgrent #define getgrent bb_internal_getgrent diff --git a/include/platform.h b/include/platform.h index d79cc97e5..7451fb757 100644 --- a/include/platform.h +++ b/include/platform.h @@ -334,6 +334,11 @@ typedef unsigned smalluint; # define MAXSYMLINKS SYMLOOP_MAX #endif +#if defined(ANDROID) || defined(__ANDROID__) +# define endpwent() ((void)0) +# define endgrent() ((void)0) +#endif + /* ---- Who misses what? ------------------------------------ */ diff --git a/include/pwd_.h b/include/pwd_.h index e40b71dab..ea158da45 100644 --- a/include/pwd_.h +++ b/include/pwd_.h @@ -30,7 +30,7 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN * We will use libc-defined structures, but will #define function names * so that function calls are directed to bb_internal_XXX replacements */ - +#undef endpwent #define setpwent bb_internal_setpwent #define endpwent bb_internal_endpwent #define getpwent bb_internal_getpwent -- cgit v1.2.3-55-g6feb From 2e55404bcf76f05193803b3d35359c6024f2a5f8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 6 Jan 2012 16:23:42 +0100 Subject: libpwdgrp/pwd_grp.c: set opened /etc/{passwd,group,shadow} fds CLOEXEC Signed-off-by: Denys Vlasenko --- libpwdgrp/pwd_grp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libpwdgrp/pwd_grp.c b/libpwdgrp/pwd_grp.c index 2eb9d9dd1..23abdbec0 100644 --- a/libpwdgrp/pwd_grp.c +++ b/libpwdgrp/pwd_grp.c @@ -441,6 +441,7 @@ int getpwent_r(struct passwd *__restrict resultbuf, rv = errno; goto ERR; } + close_on_exec_on(fileno(pwf)); } rv = bb__pgsreader(bb__parsepwent, resultbuf, buffer, buflen, pwf); @@ -488,6 +489,7 @@ int getgrent_r(struct group *__restrict resultbuf, rv = errno; goto ERR; } + close_on_exec_on(fileno(grf)); } rv = bb__pgsreader(bb__parsegrent, resultbuf, buffer, buflen, grf); @@ -536,6 +538,7 @@ int getspent_r(struct spwd *resultbuf, char *buffer, rv = errno; goto ERR; } + close_on_exec_on(fileno(spf)); } rv = bb__pgsreader(bb__parsespent, resultbuf, buffer, buflen, spf); -- cgit v1.2.3-55-g6feb From acdb0041b35e27cd03c43b25410eda5151acd2c1 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 6 Jan 2012 16:24:56 +0100 Subject: libpwdgrp/pwd_grp.c: use same static buffer for all getpwXX functions This should save more than 0.5k of malloced memory in applets which use those functions. Signed-off-by: Denys Vlasenko --- libpwdgrp/pwd_grp.c | 100 ++++++++++++++++++++-------------------------------- 1 file changed, 38 insertions(+), 62 deletions(-) diff --git a/libpwdgrp/pwd_grp.c b/libpwdgrp/pwd_grp.c index 23abdbec0..edf53f350 100644 --- a/libpwdgrp/pwd_grp.c +++ b/libpwdgrp/pwd_grp.c @@ -23,8 +23,6 @@ /**********************************************************************/ /* Sizes for statically allocated buffers. */ -/* If you change these values, also change _SC_GETPW_R_SIZE_MAX and - * _SC_GETGR_R_SIZE_MAX in libc/unistd/sysconf.c to match */ #define PWD_BUFFER_SIZE 256 #define GRP_BUFFER_SIZE 256 @@ -49,46 +47,24 @@ static int FAST_FUNC bb__parsespent(void *sp, char *line); struct statics { /* Smaller things first */ - struct passwd getpwuid_resultbuf; - struct group getgrgid_resultbuf; - struct passwd getpwnam_resultbuf; - struct group getgrnam_resultbuf; - - char getpwuid_buffer[PWD_BUFFER_SIZE]; - char getgrgid_buffer[GRP_BUFFER_SIZE]; - char getpwnam_buffer[PWD_BUFFER_SIZE]; - char getgrnam_buffer[GRP_BUFFER_SIZE]; -#if 0 - struct passwd fgetpwent_resultbuf; - struct group fgetgrent_resultbuf; - struct spwd fgetspent_resultbuf; - char fgetpwent_buffer[PWD_BUFFER_SIZE]; - char fgetgrent_buffer[GRP_BUFFER_SIZE]; - char fgetspent_buffer[PWD_BUFFER_SIZE]; -#endif + /* It's ok to use one buffer for getpwuid and getpwnam. Manpage says: + * "The return value may point to a static area, and may be overwritten + * by subsequent calls to getpwent(), getpwnam(), or getpwuid()." + */ + struct passwd getpw_resultbuf; + struct group getgr_resultbuf; + + char getpw_buffer[PWD_BUFFER_SIZE]; + char getgr_buffer[GRP_BUFFER_SIZE]; #if 0 //ENABLE_USE_BB_SHADOW - struct spwd getspuid_resultbuf; - struct spwd getspnam_resultbuf; - char getspuid_buffer[PWD_BUFFER_SIZE]; - char getspnam_buffer[PWD_BUFFER_SIZE]; + struct spwd getsp_resultbuf; + char getsp_buffer[PWD_BUFFER_SIZE]; #endif // Not converted - too small to bother //pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER; //FILE *pwf /*= NULL*/; //FILE *grf /*= NULL*/; //FILE *spf /*= NULL*/; -#if 0 - struct passwd getpwent_pwd; - struct group getgrent_gr; - char getpwent_line_buff[PWD_BUFFER_SIZE]; - char getgrent_line_buff[GRP_BUFFER_SIZE]; -#endif -#if 0 //ENABLE_USE_BB_SHADOW - struct spwd getspent_spwd; - struct spwd sgetspent_spwd; - char getspent_line_buff[PWD_BUFFER_SIZE]; - char sgetspent_line_buff[PWD_BUFFER_SIZE]; -#endif }; static struct statics *ptr_to_statics; @@ -182,22 +158,22 @@ int fgetspent_r(FILE *__restrict stream, struct spwd *__restrict resultbuf, struct passwd *fgetpwent(FILE *stream) { struct statics *S; - struct passwd *resultbuf = RESULTBUF(fgetpwent); - char *buffer = BUFFER(fgetpwent); + struct passwd *resultbuf = RESULTBUF(getpw); + char *buffer = BUFFER(getpw); struct passwd *result; - fgetpwent_r(stream, resultbuf, buffer, sizeof(BUFFER(fgetpwent)), &result); + fgetpwent_r(stream, resultbuf, buffer, sizeof(BUFFER(getpw)), &result); return result; } struct group *fgetgrent(FILE *stream) { struct statics *S; - struct group *resultbuf = RESULTBUF(fgetgrent); - char *buffer = BUFFER(fgetgrent); + struct group *resultbuf = RESULTBUF(getgr); + char *buffer = BUFFER(getgr); struct group *result; - fgetgrent_r(stream, resultbuf, buffer, sizeof(BUFFER(fgetgrent)), &result); + fgetgrent_r(stream, resultbuf, buffer, sizeof(BUFFER(getgr)), &result); return result; } #endif @@ -207,11 +183,11 @@ struct group *fgetgrent(FILE *stream) struct spwd *fgetspent(FILE *stream) { struct statics *S; - struct spwd *resultbuf = RESULTBUF(fgetspent); - char *buffer = BUFFER(fgetspent); + struct spwd *resultbuf = RESULTBUF(getsp); + char *buffer = BUFFER(getsp); struct spwd *result; - fgetspent_r(stream, resultbuf, buffer, sizeof(BUFFER(fgetspent)), &result); + fgetspent_r(stream, resultbuf, buffer, sizeof(BUFFER(getsp)), &result); return result; } #endif @@ -299,11 +275,11 @@ int sgetspent_r(const char *string, struct spwd *result_buf, struct passwd *getpwuid(uid_t uid) { struct statics *S; - struct passwd *resultbuf = RESULTBUF(getpwuid); - char *buffer = BUFFER(getpwuid); + struct passwd *resultbuf = RESULTBUF(getpw); + char *buffer = BUFFER(getpw); struct passwd *result; - getpwuid_r(uid, resultbuf, buffer, sizeof(BUFFER(getpwuid)), &result); + getpwuid_r(uid, resultbuf, buffer, sizeof(BUFFER(getpw)), &result); return result; } @@ -311,11 +287,11 @@ struct passwd *getpwuid(uid_t uid) struct group *getgrgid(gid_t gid) { struct statics *S; - struct group *resultbuf = RESULTBUF(getgrgid); - char *buffer = BUFFER(getgrgid); + struct group *resultbuf = RESULTBUF(getgr); + char *buffer = BUFFER(getgr); struct group *result; - getgrgid_r(gid, resultbuf, buffer, sizeof(BUFFER(getgrgid)), &result); + getgrgid_r(gid, resultbuf, buffer, sizeof(BUFFER(getgr)), &result); return result; } @@ -346,11 +322,11 @@ int getspuid_r(uid_t uid, struct spwd *__restrict resultbuf, struct spwd *getspuid(uid_t uid) { struct statics *S; - struct spwd *resultbuf = RESULTBUF(getspuid); - char *buffer = BUFFER(getspuid); + struct spwd *resultbuf = RESULTBUF(getsp); + char *buffer = BUFFER(getsp); struct spwd *result; - getspuid_r(uid, resultbuf, buffer, sizeof(BUFFER(getspuid)), &result); + getspuid_r(uid, resultbuf, buffer, sizeof(BUFFER(getsp)), &result); return result; } #endif @@ -359,11 +335,11 @@ struct spwd *getspuid(uid_t uid) struct passwd *getpwnam(const char *name) { struct statics *S; - struct passwd *resultbuf = RESULTBUF(getpwnam); - char *buffer = BUFFER(getpwnam); + struct passwd *resultbuf = RESULTBUF(getpw); + char *buffer = BUFFER(getpw); struct passwd *result; - getpwnam_r(name, resultbuf, buffer, sizeof(BUFFER(getpwnam)), &result); + getpwnam_r(name, resultbuf, buffer, sizeof(BUFFER(getpw)), &result); return result; } @@ -371,11 +347,11 @@ struct passwd *getpwnam(const char *name) struct group *getgrnam(const char *name) { struct statics *S; - struct group *resultbuf = RESULTBUF(getgrnam); - char *buffer = BUFFER(getgrnam); + struct group *resultbuf = RESULTBUF(getgr); + char *buffer = BUFFER(getgr); struct group *result; - getgrnam_r(name, resultbuf, buffer, sizeof(BUFFER(getgrnam)), &result); + getgrnam_r(name, resultbuf, buffer, sizeof(BUFFER(getgr)), &result); return result; } @@ -383,11 +359,11 @@ struct group *getgrnam(const char *name) struct spwd *getspnam(const char *name) { struct statics *S; - struct spwd *resultbuf = RESULTBUF(getspnam); - char *buffer = BUFFER(getspnam); + struct spwd *resultbuf = RESULTBUF(getsp); + char *buffer = BUFFER(getsp); struct spwd *result; - getspnam_r(name, resultbuf, buffer, sizeof(BUFFER(getspnam)), &result); + getspnam_r(name, resultbuf, buffer, sizeof(BUFFER(getsp)), &result); return result; } #endif -- cgit v1.2.3-55-g6feb From a76dd50ce11eda47f5f5cba1cf189833f7126e12 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 8 Jan 2012 16:11:38 +0100 Subject: Move Adroid endgrent() and endpwent() NOPS to libbb.h They should be after includes of pwd.h and grp.h Signed-off-by: Denys Vlasenko --- include/libbb.h | 8 ++++++-- include/platform.h | 5 ----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index 22d2a5b20..5e957fbf8 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -51,6 +51,12 @@ #include #include #include +#include +#include +#if defined(ANDROID) || defined(__ANDROID__) +# define endpwent() ((void)0) +# define endgrent() ((void)0) +#endif #ifdef HAVE_MNTENT_H # include #endif @@ -80,8 +86,6 @@ #ifdef DMALLOC # include #endif -#include -#include #if ENABLE_FEATURE_SHADOWPASSWDS # if !ENABLE_USE_BB_SHADOW /* If using busybox's shadow implementation, do not include the shadow.h diff --git a/include/platform.h b/include/platform.h index 7451fb757..d79cc97e5 100644 --- a/include/platform.h +++ b/include/platform.h @@ -334,11 +334,6 @@ typedef unsigned smalluint; # define MAXSYMLINKS SYMLOOP_MAX #endif -#if defined(ANDROID) || defined(__ANDROID__) -# define endpwent() ((void)0) -# define endgrent() ((void)0) -#endif - /* ---- Who misses what? ------------------------------------ */ -- cgit v1.2.3-55-g6feb From 3e0c428c45fdb7ec51bd3c8ee1f072385d2e62ac Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 8 Jan 2012 16:13:55 +0100 Subject: Move include close to pwd.h and grp.h includes Signed-off-by: Denys Vlasenko --- include/libbb.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index 5e957fbf8..0c266dc53 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -53,6 +53,14 @@ #include #include #include +#if ENABLE_FEATURE_SHADOWPASSWDS +# if !ENABLE_USE_BB_SHADOW +/* If using busybox's shadow implementation, do not include the shadow.h + * header as the toolchain may not provide it at all. + */ +# include +# endif +#endif #if defined(ANDROID) || defined(__ANDROID__) # define endpwent() ((void)0) # define endgrent() ((void)0) @@ -86,14 +94,6 @@ #ifdef DMALLOC # include #endif -#if ENABLE_FEATURE_SHADOWPASSWDS -# if !ENABLE_USE_BB_SHADOW -/* If using busybox's shadow implementation, do not include the shadow.h - * header as the toolchain may not provide it at all. - */ -# include -# endif -#endif /* Just in case libc doesn't define some of these... */ #ifndef _PATH_PASSWD #define _PATH_PASSWD "/etc/passwd" -- cgit v1.2.3-55-g6feb From d45efd3a9f6854ab662afe272aeae5779300b126 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 8 Jan 2012 16:44:37 +0100 Subject: passwd,cryptpw: make default encryption algorithm configurable Signed-off-by: Denys Vlasenko --- loginutils/Config.src | 7 +++++++ loginutils/chpasswd.c | 2 ++ loginutils/cryptpw.c | 2 +- loginutils/passwd.c | 2 +- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/loginutils/Config.src b/loginutils/Config.src index 14ce53434..9bf79afee 100644 --- a/loginutils/Config.src +++ b/loginutils/Config.src @@ -283,6 +283,13 @@ config CHPASSWD Reads a file of user name and password pairs from standard input and uses this information to update a group of existing users. +config FEATURE_DEFAULT_PASSWD_ALGO + string "Default password encryption method (passwd -a, cryptpw -m parameter)" + default "des" + depends on PASSWD || CRYPTPW + help + Possible choices are "d[es]", "m[d5]", "s[ha256]" or "sha512". + config SU bool "su" default y diff --git a/loginutils/chpasswd.c b/loginutils/chpasswd.c index b7df57e5d..54ed73795 100644 --- a/loginutils/chpasswd.c +++ b/loginutils/chpasswd.c @@ -20,6 +20,8 @@ //usage: "\n -m Use MD5 encryption instead of DES" //usage: ) +//TODO: implement -c ALGO + #if ENABLE_LONG_OPTS static const char chpasswd_longopts[] ALIGN1 = "encrypted\0" No_argument "e" diff --git a/loginutils/cryptpw.c b/loginutils/cryptpw.c index b244f55e3..a36f920f4 100644 --- a/loginutils/cryptpw.c +++ b/loginutils/cryptpw.c @@ -105,7 +105,7 @@ int cryptpw_main(int argc UNUSED_PARAM, char **argv) applet_long_options = mkpasswd_longopts; #endif fd = STDIN_FILENO; - opt_m = "d"; + opt_m = CONFIG_FEATURE_DEFAULT_PASSWD_ALGO; opt_S = NULL; /* at most two non-option arguments; -P NUM */ opt_complementary = "?2:P+"; diff --git a/loginutils/passwd.c b/loginutils/passwd.c index 1cfafaec3..b83db0083 100644 --- a/loginutils/passwd.c +++ b/loginutils/passwd.c @@ -94,7 +94,7 @@ int passwd_main(int argc UNUSED_PARAM, char **argv) }; unsigned opt; int rc; - const char *opt_a = "d"; /* des */ + const char *opt_a = CONFIG_FEATURE_DEFAULT_PASSWD_ALGO; const char *filename; char *myname; char *name; -- cgit v1.2.3-55-g6feb From 982fdaf4b2f335506e570a06d5eab09068da3f61 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 9 Jan 2012 05:01:25 +0100 Subject: acpid: close fds which are reported as dead (POLLERR/POLLHUP/POLLNVAL) by poll. function old new delta acpid_main 1159 1229 +70 packed_usage 28977 28980 +3 Signed-off-by: Denys Vlasenko --- util-linux/acpid.c | 54 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/util-linux/acpid.c b/util-linux/acpid.c index 6e7321b02..361a2b206 100644 --- a/util-linux/acpid.c +++ b/util-linux/acpid.c @@ -8,13 +8,13 @@ */ //usage:#define acpid_trivial_usage -//usage: "[-d] [-c CONFDIR] [-l LOGFILE] [-a ACTIONFILE] [-M MAPFILE] [-e PROC_EVENT_FILE] [-p PIDFILE]" +//usage: "[-df] [-c CONFDIR] [-l LOGFILE] [-a ACTIONFILE] [-M MAPFILE] [-e PROC_EVENT_FILE] [-p PIDFILE]" //usage:#define acpid_full_usage "\n\n" //usage: "Listen to ACPI events and spawn specific helpers on event arrival\n" +//usage: "\n -d Log to stderr, not log file (implies -f)" +//usage: "\n -f Run in foreground" //usage: "\n -c DIR Config directory [/etc/acpi]" -//usage: "\n -d Don't daemonize, (implies -f)" //usage: "\n -e FILE /proc event file [/proc/acpi/event]" -//usage: "\n -f Run in foreground" //usage: "\n -l FILE Log file [/var/log/acpid.log]" //usage: "\n -p FILE Pid file [/var/run/acpid.pid]" //usage: "\n -a FILE Action file [/etc/acpid.conf]" @@ -225,7 +225,6 @@ static void parse_map_file(const char *filename) int acpid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int acpid_main(int argc UNUSED_PARAM, char **argv) { - struct input_event ev; int nfd; int opts; struct pollfd *pfd; @@ -248,15 +247,21 @@ int acpid_main(int argc UNUSED_PARAM, char **argv) ); if (!(opts & OPT_f)) { + /* No -f "Foreground", we go to background */ bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv); } if (!(opts & OPT_d)) { + /* No -d "Debug", we log to log file. + * This includes any output from children. + */ + xmove_fd(xopen(opt_logfile, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO); + xdup2(STDOUT_FILENO, STDERR_FILENO); + /* Also, acpid's messages (but not children) will go to syslog too */ openlog(applet_name, LOG_PID, LOG_DAEMON); logmode = LOGMODE_SYSLOG | LOGMODE_STDIO; - } else { - xmove_fd(xopen(opt_logfile, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO); } + /* else: -d "Debug", log is not redirected */ parse_conf_file(opt_action); parse_map_file(opt_map); @@ -272,13 +277,14 @@ int acpid_main(int argc UNUSED_PARAM, char **argv) int fd; char *dev_event; - dev_event = xasprintf((option_mask32 & OPT_e) ? "%s" : "%s%u", opt_input, nfd); + dev_event = xasprintf((opts & OPT_e) ? "%s" : "%s%u", opt_input, nfd); fd = open(dev_event, O_RDONLY | O_NONBLOCK); if (fd < 0) { if (nfd == 0) bb_simple_perror_msg_and_die(dev_event); break; } + free(dev_event); pfd = xrealloc_vector(pfd, 1, nfd); pfd[nfd].fd = fd; pfd[nfd].events = POLLIN; @@ -287,16 +293,26 @@ int acpid_main(int argc UNUSED_PARAM, char **argv) write_pidfile(opt_pidfile); - while (poll(pfd, nfd, -1) > 0) { + while (safe_poll(pfd, nfd, -1) > 0) { int i; for (i = 0; i < nfd; i++) { - const char *event = NULL; - - memset(&ev, 0, sizeof(ev)); - - if (!(pfd[i].revents & POLLIN)) - continue; + const char *event; + + if (!(pfd[i].revents & POLLIN)) { + if (pfd[i].revents == 0) + continue; /* this fd has nothing */ + + /* Likely POLLERR, POLLHUP, POLLNVAL. + * Do not listen on this fd anymore. + */ + close(pfd[i].fd); + nfd--; + for (; i < nfd; i++) + pfd[i].fd = pfd[i + 1].fd; + break; /* do poll() again */ + } + event = NULL; if (option_mask32 & OPT_e) { char *buf; int len; @@ -307,7 +323,10 @@ int acpid_main(int argc UNUSED_PARAM, char **argv) if (len >= 0) buf[len] = '\0'; event = find_action(NULL, buf); + free(buf); } else { + struct input_event ev; + if (sizeof(ev) != full_read(pfd[i].fd, &ev, sizeof(ev))) continue; @@ -324,11 +343,8 @@ int acpid_main(int argc UNUSED_PARAM, char **argv) } if (ENABLE_FEATURE_CLEAN_UP) { - while (nfd--) { - if (pfd[nfd].fd) { - close(pfd[nfd].fd); - } - } + while (nfd--) + close(pfd[nfd].fd); free(pfd); } remove_pidfile(opt_pidfile); -- cgit v1.2.3-55-g6feb From 499597d6efb0de5bb6d6f52bda1f348478d7f5a9 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 11 Jan 2012 00:37:17 +0100 Subject: mdev: do not treat non-leading '#' chars as start of comment. Closes 4676 Signed-off-by: Denys Vlasenko --- include/libbb.h | 5 +++-- libbb/parse_config.c | 2 +- util-linux/mdev.c | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index 0c266dc53..4975b97fe 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1195,13 +1195,14 @@ enum { PARSE_MIN_DIE = 0x00100000, // die if < min tokens found // keep a copy of current line PARSE_KEEP_COPY = 0x00200000 * ENABLE_FEATURE_CROND_D, -// PARSE_ESCAPE = 0x00400000, // process escape sequences in tokens + PARSE_EOL_COMMENTS = 0x00400000, // comments are recognized even if they aren't the first char // NORMAL is: // * remove leading and trailing delimiters and collapse // multiple delimiters into one // * warn and continue if less than mintokens delimiters found // * grab everything into last token - PARSE_NORMAL = PARSE_COLLAPSE | PARSE_TRIM | PARSE_GREEDY, + // * comments are recognized even if they aren't the first char + PARSE_NORMAL = PARSE_COLLAPSE | PARSE_TRIM | PARSE_GREEDY | PARSE_EOL_COMMENTS, }; typedef struct parser_t { FILE *fp; diff --git a/libbb/parse_config.c b/libbb/parse_config.c index cf5ba4deb..1590d9a4c 100644 --- a/libbb/parse_config.c +++ b/libbb/parse_config.c @@ -204,7 +204,7 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const line += strcspn(line, delims[0] ? delims : delims + 1); } else { /* Combining, find comment char if any */ - line = strchrnul(line, delims[0]); + line = strchrnul(line, PARSE_EOL_COMMENTS ? delims[0] : '\0'); /* Trim any extra delimiters from the end */ if (flags & PARSE_TRIM) { diff --git a/util-linux/mdev.c b/util-linux/mdev.c index c6be1b872..e5f0c2deb 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c @@ -206,7 +206,8 @@ static void parse_next_rule(void) char *tokens[4]; char *val; - if (!config_read(G.parser, tokens, 4, 3, "# \t", PARSE_NORMAL)) + /* No PARSE_EOL_COMMENTS, because command may contain '#' chars */ + if (!config_read(G.parser, tokens, 4, 3, "# \t", PARSE_NORMAL & ~PARSE_EOL_COMMENTS)) break; /* Fields: [-]regex uid:gid mode [alias] [cmd] */ -- cgit v1.2.3-55-g6feb From 7550201e9ac93e885e98feca1739921f73efcabd Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 11 Jan 2012 01:02:31 +0100 Subject: mke2fs: do not zero out first kilobyte. Closes 3247 Signed-off-by: Denys Vlasenko --- util-linux/mkfs_ext2.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/util-linux/mkfs_ext2.c b/util-linux/mkfs_ext2.c index f6ccc9c9e..6cbbe0e07 100644 --- a/util-linux/mkfs_ext2.c +++ b/util-linux/mkfs_ext2.c @@ -615,7 +615,11 @@ int mkfs_ext2_main(int argc UNUSED_PARAM, char **argv) // zero boot sectors memset(buf, 0, blocksize); - PUT(0, buf, 1024); // N.B. 1024 <= blocksize, so buf[0..1023] contains zeros + // Disabled: standard mke2fs doesn't do this, and + // on SPARC this destroys Sun disklabel. + // Users who need/want zeroing can easily do it with dd. + //PUT(0, buf, 1024); // N.B. 1024 <= blocksize, so buf[0..1023] contains zeros + // zero inode tables for (i = 0; i < ngroups; ++i) for (n = 0; n < inode_table_blocks; ++n) -- cgit v1.2.3-55-g6feb From d29ae7e071a11c51436922654c2de73a8ac36333 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 15 Jan 2012 20:06:03 +0100 Subject: sed: fix possible case of signed char bug; expand debugging printouts Signed-off-by: Denys Vlasenko --- editors/sed.c | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/editors/sed.c b/editors/sed.c index c8bb503ea..4e9babb9d 100644 --- a/editors/sed.c +++ b/editors/sed.c @@ -282,7 +282,7 @@ static int index_of_next_unescaped_regexp_delim(int delimiter, const char *str) static int parse_regex_delim(const char *cmdstr, char **match, char **replace) { const char *cmdstr_ptr = cmdstr; - char delimiter; + unsigned char delimiter; int idx = 0; /* verify that the 's' or 'y' is followed by something. That something @@ -297,7 +297,7 @@ static int parse_regex_delim(const char *cmdstr, char **match, char **replace) /* save the replacement string */ cmdstr_ptr += idx + 1; - idx = index_of_next_unescaped_regexp_delim(-delimiter, cmdstr_ptr); + idx = index_of_next_unescaped_regexp_delim(- (int)delimiter, cmdstr_ptr); *replace = copy_parsing_escapes(cmdstr_ptr, idx); return ((cmdstr_ptr - cmdstr) + idx); @@ -322,10 +322,11 @@ static int get_address(const char *my_str, int *linenum, regex_t ** regex) char *temp; delimiter = '/'; - if (*my_str == '\\') delimiter = *++pos; + if (*my_str == '\\') + delimiter = *++pos; next = index_of_next_unescaped_regexp_delim(delimiter, ++pos); temp = copy_parsing_escapes(pos, next); - *regex = xmalloc(sizeof(regex_t)); + *regex = xzalloc(sizeof(regex_t)); xregcomp(*regex, temp, G.regex_type|REG_NEWLINE); free(temp); /* Move position to next character after last delimiter */ @@ -434,8 +435,10 @@ static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr) /* compile the match string into a regex */ if (*match != '\0') { /* If match is empty, we use last regex used at runtime */ - sed_cmd->sub_match = xmalloc(sizeof(regex_t)); + sed_cmd->sub_match = xzalloc(sizeof(regex_t)); + dbg("xregcomp('%s',%x)", match, cflags); xregcomp(sed_cmd->sub_match, match, cflags); + dbg("regcomp ok"); } free(match); @@ -717,8 +720,12 @@ static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p) G.previous_regex_ptr = current_regex; /* Find the first match */ - if (REG_NOMATCH == regexec(current_regex, line, 10, G.regmatch, 0)) + dbg("matching '%s'", line); + if (REG_NOMATCH == regexec(current_regex, line, 10, G.regmatch, 0)) { + dbg("no match"); return 0; + } + dbg("match"); /* Initialize temporary output buffer. */ G.pipeline.buf = xmalloc(PIPE_GROW); @@ -730,9 +737,10 @@ static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p) int i; /* Work around bug in glibc regexec, demonstrated by: - echo " a.b" | busybox sed 's [^ .]* x g' - The match_count check is so not to break - echo "hi" | busybox sed 's/^/!/g' */ + * echo " a.b" | busybox sed 's [^ .]* x g' + * The match_count check is so not to break + * echo "hi" | busybox sed 's/^/!/g' + */ if (!G.regmatch[0].rm_so && !G.regmatch[0].rm_eo && match_count) { pipe_putc(*line++); continue; @@ -763,11 +771,14 @@ static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p) altered++; /* if we're not doing this globally, get out now */ - if (sed_cmd->which_match) + if (sed_cmd->which_match != 0) + break; + + if (*line == '\0') break; //maybe (G.regmatch[0].rm_eo ? REG_NOTBOL : 0) instead of unconditional REG_NOTBOL? - } while (*line && regexec(current_regex, line, 10, G.regmatch, REG_NOTBOL) != REG_NOMATCH); + } while (regexec(current_regex, line, 10, G.regmatch, REG_NOTBOL) != REG_NOMATCH); /* Copy rest of string into output pipeline */ while (1) { @@ -1067,8 +1078,8 @@ static void process_files(void) } /* actual sedding */ - //bb_error_msg("pattern_space:'%s' next_line:'%s' cmd:%c", - //pattern_space, next_line, sed_cmd->cmd); + dbg("pattern_space:'%s' next_line:'%s' cmd:%c", + pattern_space, next_line, sed_cmd->cmd); switch (sed_cmd->cmd) { /* Print line number */ @@ -1115,6 +1126,7 @@ static void process_files(void) case 's': if (!do_subst_command(sed_cmd, &pattern_space)) break; + dbg("do_subst_command succeeeded:'%s'", pattern_space); substituted |= 1; /* handle p option */ -- cgit v1.2.3-55-g6feb From 7ce209b9d4f6053b7e6d07dec66e382bc3614c35 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 15 Jan 2012 22:58:06 +0100 Subject: shell_builtin_read: set cc[VMIN] to 1; lineedit: don't clear c_cc[VINTR] First change fixes "read -n NUM". Apparently poll() won't report data availability if cc[VMIN] > 1 until there are at least cc[VMIN] bytes. function old new delta read_line_input 3885 3877 -8 shell_builtin_read 1097 1087 -10 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-18) Total: -18 bytes Signed-off-by: Denys Vlasenko --- libbb/lineedit.c | 15 +++++++++------ shell/shell_common.c | 8 +++++++- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 1390ed62d..460e27fed 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -2206,14 +2206,17 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman #define command command_must_not_be_used new_settings = initial_settings; - new_settings.c_lflag &= ~ICANON; /* unbuffered input */ - /* Turn off echoing and CTRL-C, so we can trap it */ - new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG); - /* Hmm, in linux c_cc[] is not parsed if ICANON is off */ + /* ~ICANON: unbuffered input (most c_cc[] are disabled, VMIN/VTIME are enabled) */ + /* ~ECHO, ~ECHONL: turn off echoing, including newline echoing */ + /* ~ISIG: turn off INTR (ctrl-C), QUIT, SUSP */ + new_settings.c_lflag &= ~(ICANON | ECHO | ECHONL | ISIG); + /* reads would block only if < 1 char is available */ new_settings.c_cc[VMIN] = 1; + /* no timeout (reads block forever) */ new_settings.c_cc[VTIME] = 0; - /* Turn off CTRL-C, so we can trap it */ - new_settings.c_cc[VINTR] = _POSIX_VDISABLE; + /* Should be not needed if ISIG is off: */ + /* Turn off CTRL-C */ + /* new_settings.c_cc[VINTR] = _POSIX_VDISABLE; */ tcsetattr_stdin_TCSANOW(&new_settings); #if ENABLE_USERNAME_OR_HOMEDIR diff --git a/shell/shell_common.c b/shell/shell_common.c index bbc22ed34..51c92d60e 100644 --- a/shell/shell_common.c +++ b/shell/shell_common.c @@ -138,7 +138,13 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), old_tty = tty; if (nchars) { tty.c_lflag &= ~ICANON; - tty.c_cc[VMIN] = nchars < 256 ? nchars : 255; + // Setting it to more than 1 breaks poll(): + // it blocks even if there's data. !?? + //tty.c_cc[VMIN] = nchars < 256 ? nchars : 255; + /* reads would block only if < 1 char is available */ + tty.c_cc[VMIN] = 1; + /* no timeout (reads block forever) */ + tty.c_cc[VTIME] = 0; } if (read_flags & BUILTIN_READ_SILENT) { tty.c_lflag &= ~(ECHO | ECHOK | ECHONL); -- cgit v1.2.3-55-g6feb From 6e8861b5f139cde297a95e785e7c616cf129df80 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 15 Jan 2012 23:00:13 +0100 Subject: *: better comments on termios manipulations. No code changes. Signed-off-by: Denys Vlasenko --- editors/vi.c | 2 +- loginutils/getty.c | 6 ++++-- util-linux/more.c | 3 +-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 6070c48d2..4a2d5d4f1 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -2304,7 +2304,7 @@ static void rawmode(void) { tcgetattr(0, &term_orig); term_vi = term_orig; - term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG ON- allow intr's + term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG on - allow intr's term_vi.c_iflag &= (~IXON & ~ICRNL); term_vi.c_oflag &= (~ONLCR); term_vi.c_cc[VMIN] = 1; diff --git a/loginutils/getty.c b/loginutils/getty.c index 1f417591b..afb411b98 100644 --- a/loginutils/getty.c +++ b/loginutils/getty.c @@ -294,8 +294,10 @@ static void init_tty_attrs(int speed) /* non-raw output; add CR to each NL */ G.tty_attrs.c_oflag = OPOST | ONLCR; - G.tty_attrs.c_cc[VMIN] = 1; /* block reads if < 1 char is available */ - G.tty_attrs.c_cc[VTIME] = 0; /* no timeout (reads block forever) */ + /* reads would block only if < 1 char is available */ + G.tty_attrs.c_cc[VMIN] = 1; + /* no timeout (reads block forever) */ + G.tty_attrs.c_cc[VTIME] = 0; #ifdef __linux__ G.tty_attrs.c_line = 0; #endif diff --git a/util-linux/more.c b/util-linux/more.c index efceb71ec..359571397 100644 --- a/util-linux/more.c +++ b/util-linux/more.c @@ -85,8 +85,7 @@ int more_main(int argc UNUSED_PARAM, char **argv) cin_fileno = fileno(cin); getTermSettings(cin_fileno, &initial_settings); new_settings = initial_settings; - new_settings.c_lflag &= ~ICANON; - new_settings.c_lflag &= ~ECHO; + new_settings.c_lflag &= ~(ICANON | ECHO); new_settings.c_cc[VMIN] = 1; new_settings.c_cc[VTIME] = 0; setTermSettings(cin_fileno, &new_settings); -- cgit v1.2.3-55-g6feb From fdd0b3b398d3ea859d758992ed24eac343a6ee12 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 16 Jan 2012 04:00:37 +0100 Subject: vconfig: fix help text; small code shrink. Closes 4658 function old new delta xfind_str 45 46 +1 vconfig_main 228 223 -5 packed_usage 28980 28954 -26 Signed-off-by: Denys Vlasenko --- networking/vconfig.c | 96 ++++++++++++++++++++++------------------------------ 1 file changed, 41 insertions(+), 55 deletions(-) diff --git a/networking/vconfig.c b/networking/vconfig.c index ac8b96d8c..924b2f009 100644 --- a/networking/vconfig.c +++ b/networking/vconfig.c @@ -13,12 +13,12 @@ //usage: "COMMAND [OPTIONS]" //usage:#define vconfig_full_usage "\n\n" //usage: "Create and remove virtual ethernet devices\n" -//usage: "\n add [interface-name] [vlan_id]" -//usage: "\n rem [vlan-name]" -//usage: "\n set_flag [interface-name] [flag-num] [0 | 1]" -//usage: "\n set_egress_map [vlan-name] [skb_priority] [vlan_qos]" -//usage: "\n set_ingress_map [vlan-name] [skb_priority] [vlan_qos]" -//usage: "\n set_name_type [name-type]" +//usage: "\n add IFACE VLAN_ID" +//usage: "\n rem VLAN_NAME" +//usage: "\n set_flag IFACE 0|1 VLAN_QOS" +//usage: "\n set_egress_map VLAN_NAME SKB_PRIO VLAN_QOS" +//usage: "\n set_ingress_map VLAN_NAME SKB_PRIO VLAN_QOS" +//usage: "\n set_name_type NAME_TYPE" #include "libbb.h" #include @@ -66,54 +66,38 @@ struct vlan_ioctl_args { * The return value is the last data entry for the matching string. */ static const char *xfind_str(const char *table, const char *str) { - while (strcasecmp(str, table+1) != 0) { - table += table[0]; - if (!*table) { + while (strcasecmp(str, table + 1) != 0) { + if (!table[0]) bb_show_usage(); - } + table += table[0]; } return table - 1; } static const char cmds[] ALIGN1 = { 4, ADD_VLAN_CMD, 7, - 'a', 'd', 'd', 0, + 'a','d','d',0, 3, DEL_VLAN_CMD, 7, - 'r', 'e', 'm', 0, + 'r','e','m',0, 3, SET_VLAN_NAME_TYPE_CMD, 17, - 's', 'e', 't', '_', - 'n', 'a', 'm', 'e', '_', - 't', 'y', 'p', 'e', 0, + 's','e','t','_','n','a','m','e','_','t','y','p','e',0, 5, SET_VLAN_FLAG_CMD, 12, - 's', 'e', 't', '_', - 'f', 'l', 'a', 'g', 0, + 's','e','t','_','f','l','a','g',0, 5, SET_VLAN_EGRESS_PRIORITY_CMD, 18, - 's', 'e', 't', '_', - 'e', 'g', 'r', 'e', 's', 's', '_', - 'm', 'a', 'p', 0, - 5, SET_VLAN_INGRESS_PRIORITY_CMD, 16, - 's', 'e', 't', '_', - 'i', 'n', 'g', 'r', 'e', 's', 's', '_', - 'm', 'a', 'p', 0, + 's','e','t','_','e','g','r','e','s','s','_','m','a','p',0, + 5, SET_VLAN_INGRESS_PRIORITY_CMD, 0, + 's','e','t','_','i','n','g','r','e','s','s','_','m','a','p',0, }; static const char name_types[] ALIGN1 = { VLAN_NAME_TYPE_PLUS_VID, 16, - 'V', 'L', 'A', 'N', - '_', 'P', 'L', 'U', 'S', '_', 'V', 'I', 'D', - 0, + 'V','L','A','N','_','P','L','U','S','_','V','I','D',0, VLAN_NAME_TYPE_PLUS_VID_NO_PAD, 22, - 'V', 'L', 'A', 'N', - '_', 'P', 'L', 'U', 'S', '_', 'V', 'I', 'D', - '_', 'N', 'O', '_', 'P', 'A', 'D', 0, + 'V','L','A','N','_','P','L','U','S','_','V','I','D','_','N','O','_','P','A','D',0, VLAN_NAME_TYPE_RAW_PLUS_VID, 15, - 'D', 'E', 'V', - '_', 'P', 'L', 'U', 'S', '_', 'V', 'I', 'D', - 0, - VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD, 20, - 'D', 'E', 'V', - '_', 'P', 'L', 'U', 'S', '_', 'V', 'I', 'D', - '_', 'N', 'O', '_', 'P', 'A', 'D', 0, + 'D','E','V','_','P','L','U','S','_','V','I','D',0, + VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD, 0, + 'D','E','V','_','P','L','U','S','_','V','I','D','_','N','O','_','P','A','D',0, }; int vconfig_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -123,21 +107,19 @@ int vconfig_main(int argc, char **argv) const char *p; int fd; - if (argc < 3) { - bb_show_usage(); - } - memset(&ifr, 0, sizeof(ifr)); ++argv; - p = xfind_str(cmds+2, *argv); + if (!argv[0]) + bb_show_usage(); + p = xfind_str(cmds + 2, argv[0]); ifr.cmd = *p; - if (argc != p[-1]) { + if (argc != p[-1]) bb_show_usage(); - } - if (ifr.cmd == SET_VLAN_NAME_TYPE_CMD) { /* set_name_type */ - ifr.u.name_type = *xfind_str(name_types+1, argv[1]); + if (ifr.cmd == SET_VLAN_NAME_TYPE_CMD) { + /* set_name_type */ + ifr.u.name_type = *xfind_str(name_types + 1, argv[1]); } else { strncpy_IFNAMSIZ(ifr.device1, argv[1]); p = argv[2]; @@ -146,22 +128,26 @@ int vconfig_main(int argc, char **argv) * since ifr.u.flag, ifr.u.VID, and ifr.u.skb_priority are all same-sized * (unsigned) int members of a unions. But because of the range checking, * doing so wouldn't save that much space and would also make maintainence - * more of a pain. */ - if (ifr.cmd == SET_VLAN_FLAG_CMD) { /* set_flag */ - ifr.u.flag = xatoul_range(p, 0, 1); + * more of a pain. + */ + if (ifr.cmd == SET_VLAN_FLAG_CMD) { + /* set_flag */ + ifr.u.flag = xatou_range(p, 0, 1); /* DM: in order to set reorder header, qos must be set */ - ifr.vlan_qos = xatoul_range(argv[3], 0, 7); - } else if (ifr.cmd == ADD_VLAN_CMD) { /* add */ - ifr.u.VID = xatoul_range(p, 0, VLAN_GROUP_ARRAY_LEN-1); - } else if (ifr.cmd != DEL_VLAN_CMD) { /* set_{egress|ingress}_map */ + ifr.vlan_qos = xatou_range(argv[3], 0, 7); + } else if (ifr.cmd == ADD_VLAN_CMD) { + /* add */ + ifr.u.VID = xatou_range(p, 0, VLAN_GROUP_ARRAY_LEN - 1); + } else if (ifr.cmd != DEL_VLAN_CMD) { + /* set_{egress|ingress}_map */ ifr.u.skb_priority = xatou(p); - ifr.vlan_qos = xatoul_range(argv[3], 0, 7); + ifr.vlan_qos = xatou_range(argv[3], 0, 7); } } fd = xsocket(AF_INET, SOCK_STREAM, 0); ioctl_or_perror_and_die(fd, SIOCSIFVLAN, &ifr, - "ioctl error for %s", *argv); + "ioctl error for %s", argv[0]); return 0; } -- cgit v1.2.3-55-g6feb From ce4f39ac7c6c30e94f7ff392058928bd98347113 Mon Sep 17 00:00:00 2001 From: Javier Viguera Date: Wed, 18 Jan 2012 01:49:11 +0100 Subject: find_mount_point: fix find_mount_point for char devices This allows to find mount points of 'char' devices such as UBI volumes which otherwise fail for example with 'df' command: / # df Filesystem 1K-blocks Used Available Use% Mounted on /dev/root 72091984 12360980 56068924 18% / devtmpfs 115236 4 115232 0% /dev tmpfs 28672 32 28640 0% /tmp /dev/ubi0_0 360268 18348 341920 5% /tmp/mnt/userfs / # df /dev/ubi0_0 Filesystem 1K-blocks Used Available Use% Mounted on devtmpfs 115236 4 115232 0% /dev Signed-off-by: Javier Viguera Signed-off-by: Denys Vlasenko --- libbb/find_mount_point.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libbb/find_mount_point.c b/libbb/find_mount_point.c index 56637ad92..9676b5f52 100644 --- a/libbb/find_mount_point.c +++ b/libbb/find_mount_point.c @@ -30,7 +30,8 @@ struct mntent* FAST_FUNC find_mount_point(const char *name, int subdir_too) devno_of_name = s.st_dev; block_dev = 0; - if (S_ISBLK(s.st_mode)) { + /* Why S_ISCHR? - UBI volumes use char devices, not block */ + if (S_ISBLK(s.st_mode) || S_ISCHR(s.st_mode)) { devno_of_name = s.st_rdev; block_dev = 1; } -- cgit v1.2.3-55-g6feb From c158601d50c2fab56ed0043989ba83fa9cd7f96a Mon Sep 17 00:00:00 2001 From: Quentin Casasnovas Date: Wed, 18 Jan 2012 02:12:13 +0100 Subject: bootchartd: add process accounting feature function old new delta bootchartd_main 962 1088 +126 finalize 294 357 +63 acct - 33 +33 ------------------------------------------------------------------------------ (add/remove: 2/0 grow/shrink: 2/0 up/down: 222/0) Total: 222 bytes Signed-off-by: Quentin Casasnovas Signed-off-by: Denys Vlasenko --- init/bootchartd.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/init/bootchartd.c b/init/bootchartd.c index cc23e6073..9fd623357 100644 --- a/init/bootchartd.c +++ b/init/bootchartd.c @@ -208,14 +208,8 @@ static char *make_tempdir(void) return tempdir; } -static void do_logging(unsigned sample_period_us) +static void do_logging(unsigned sample_period_us, int process_accounting) { - //# Enable process accounting if configured - //if [ "$PROCESS_ACCOUNTING" = "yes" ]; then - // [ -e kernel_pacct ] || : > kernel_pacct - // accton kernel_pacct - //fi - FILE *proc_stat = xfopen("proc_stat.log", "w"); FILE *proc_diskstats = xfopen("proc_diskstats.log", "w"); //FILE *proc_netdev = xfopen("proc_netdev.log", "w"); @@ -223,6 +217,11 @@ static void do_logging(unsigned sample_period_us) int look_for_login_process = (getppid() == 1); unsigned count = 60*1000*1000 / sample_period_us; /* ~1 minute */ + if (process_accounting) { + close(xopen("kernel_pacct", O_WRONLY | O_CREAT | O_TRUNC)); + acct("kernel_pacct"); + } + while (--count && !bb_got_signal) { char *p; int len = open_read_close("/proc/uptime", G.jiffy_line, sizeof(G.jiffy_line)-2); @@ -253,11 +252,9 @@ static void do_logging(unsigned sample_period_us) wait_more: usleep(sample_period_us); } - - // [ -e kernel_pacct ] && accton off } -static void finalize(char *tempdir, const char *prog) +static void finalize(char *tempdir, const char *prog, int process_accounting) { //# Stop process accounting if configured //local pacct= @@ -265,6 +262,9 @@ static void finalize(char *tempdir, const char *prog) FILE *header_fp = xfopen("header", "w"); + if (process_accounting) + acct(NULL); + if (prog) fprintf(header_fp, "profile.process = %s\n", prog); @@ -307,7 +307,7 @@ static void finalize(char *tempdir, const char *prog) fclose(header_fp); /* Package log files */ - system("tar -zcf /var/log/bootchart.tgz header *.log"); // + $pacct + system(xasprintf("tar -zcf /var/log/bootlog.tgz header %s *.log", process_accounting ? "kernel_pacct" : "")); /* Clean up (if we are not in detached tmpfs) */ if (tempdir) { unlink("header"); @@ -315,6 +315,8 @@ static void finalize(char *tempdir, const char *prog) unlink("proc_diskstats.log"); //unlink("proc_netdev.log"); unlink("proc_ps.log"); + if (process_accounting) + unlink("kernel_pacct"); rmdir(tempdir); } @@ -338,6 +340,7 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) unsigned sample_period_us; pid_t parent_pid, logger_pid; smallint cmd; + int process_accounting; enum { CMD_STOP = 0, CMD_START, @@ -371,6 +374,7 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) /* Read config file: */ sample_period_us = 200 * 1000; + process_accounting = 0; if (ENABLE_FEATURE_BOOTCHARTD_CONFIG_FILE) { char* token[2]; parser_t *parser = config_open2("/etc/bootchartd.conf" + 5, fopen_for_read); @@ -379,11 +383,16 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) while (config_read(parser, token, 2, 0, "#=", PARSE_NORMAL & ~PARSE_COLLAPSE)) { if (strcmp(token[0], "SAMPLE_PERIOD") == 0 && token[1]) sample_period_us = atof(token[1]) * 1000000; + if (strcmp(token[0], "PROCESS_ACCOUNTING") == 0 && token[1] + && (strcmp(token[1], "on") == 0 || strcmp(token[1], "yes") == 0) + ) { + process_accounting = 1; + } } config_close(parser); + if ((int)sample_period_us <= 0) + sample_period_us = 1; /* prevent division by 0 */ } - if ((int)sample_period_us <= 0) - sample_period_us = 1; /* prevent division by 0 */ /* Create logger child: */ logger_pid = fork_or_rexec(argv); @@ -411,8 +420,8 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) putenv((char*)bb_PATH_root_path); tempdir = make_tempdir(); - do_logging(sample_period_us); - finalize(tempdir, cmd == CMD_START ? argv[2] : NULL); + do_logging(sample_period_us, process_accounting); + finalize(tempdir, cmd == CMD_START ? argv[2] : NULL, process_accounting); return EXIT_SUCCESS; } -- cgit v1.2.3-55-g6feb From e8758eaf4f994f679142563623713f62d87a74a3 Mon Sep 17 00:00:00 2001 From: Javier Viguera Date: Fri, 27 Jan 2012 18:30:20 +0100 Subject: mdev: fix wrong sizeof Signed-off-by: Javier Viguera Signed-off-by: Denys Vlasenko --- util-linux/mdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util-linux/mdev.c b/util-linux/mdev.c index e5f0c2deb..976568814 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c @@ -783,7 +783,7 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) int seqlen; char seqbuf[sizeof(int)*3 + 2]; - seqlen = open_read_close("mdev.seq", seqbuf, sizeof(seqbuf-1)); + seqlen = open_read_close("mdev.seq", seqbuf, sizeof(seqbuf) - 1); if (seqlen < 0) { seq = NULL; break; -- cgit v1.2.3-55-g6feb From 1c7724bf2acb6ebe28b24bd6da3b740e716b46cf Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Mon, 30 Jan 2012 02:34:56 +0100 Subject: gen_build_files.sh: exclude hidden directories I am using quilt to manage patches internally. Quilt creates dir .pc and stores unmodified files there. Since I made change in one of Config.src quilt made a copy in .pc/xxx.patch/xxx/Config.src. When I run make it calls gen_build_files.sh and it generates .pc/xxx.patch/xxx/Config.in. Now when I want to pop patch quilt thinks I have made changes to original xxx/Config.in. IMO the best solution is just to ignore hidden directories in gen_build_files.sh. This also results in shorter build time in case busybox is under git/svn versioning, since it avoids searching many directories for Config.src. Signed-off-by: Paulius Zaleckas Signed-off-by: Denys Vlasenko --- scripts/gen_build_files.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/gen_build_files.sh b/scripts/gen_build_files.sh index c42fe9fbb..0989b2fe5 100755 --- a/scripts/gen_build_files.sh +++ b/scripts/gen_build_files.sh @@ -52,14 +52,17 @@ sed -n 's@^//applet:@@p' "$srctree"/*/*.c "$srctree"/*/*/*.c \ # We add line continuation backslash after each line, # and insert empty line before each line which doesn't start # with space or tab -sed -n -e 's@^//usage:\([ \t].*\)$@\1 \\@p' -e 's@^//usage:\([^ \t].*\)$@\n\1 \\@p' "$srctree"/*/*.c "$srctree"/*/*/*.c \ +sed -n -e 's@^//usage:\([ \t].*\)$@\1 \\@p' -e 's@^//usage:\([^ \t].*\)$@\n\1 \\@p' \ + "$srctree"/*/*.c "$srctree"/*/*/*.c \ | generate \ "$srctree/include/usage.src.h" \ "include/usage.h" \ "/* DO NOT EDIT. This file is generated from usage.src.h */" # (Re)generate */Kbuild and */Config.in -{ cd -- "$srctree" && find . -type d; } | while read -r d; do +# We skip .dotdirs - makes git/svn/etc users happier +{ cd -- "$srctree" && find . -type d -not '(' -name '.?*' -prune ')'; } \ +| while read -r d; do d="${d#./}" src="$srctree/$d/Kbuild.src" -- cgit v1.2.3-55-g6feb From da2b2da6a708edffcc3b405ab5fd7f3f11af5d33 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 30 Jan 2012 12:15:22 +0100 Subject: init: add a segv debugging aid, disabled by default Signed-off-by: Denys Vlasenko --- init/init.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/init/init.c b/init/init.c index c540faa70..724894698 100644 --- a/init/init.c +++ b/init/init.c @@ -108,6 +108,8 @@ //config: Note that on Linux, init attempts to detect serial terminal and //config: sets TERM to "vt102" if one is found. +#define DEBUG_SEGV_HANDLER 0 + #include "libbb.h" #include #include @@ -118,6 +120,15 @@ #endif #include "reboot.h" /* reboot() constants */ +#if DEBUG_SEGV_HANDLER +# undef _GNU_SOURCE +# define _GNU_SOURCE 1 +# undef __USE_GNU +# define __USE_GNU 1 +# include +# include +#endif + /* Used only for sanitizing purposes in set_sane_term() below. On systems where * the baud rate is stored in a separate field, we can safely disable them. */ #ifndef CBAUD @@ -957,6 +968,33 @@ static int check_delayed_sigs(void) } } +#if DEBUG_SEGV_HANDLER +static +void handle_sigsegv(int sig, siginfo_t *info, void *ucontext) +{ + long ip; + ucontext_t *uc; + + uc = ucontext; + ip = uc->uc_mcontext.gregs[REG_EIP]; + fdprintf(2, "signal:%d address:0x%lx ip:0x%lx\n", + sig, + /* this is void*, but using %p would print "(null)" + * even for ptrs which are not exactly 0, but, say, 0x123: + */ + (long)info->si_addr, + ip); + { + /* glibc extension */ + void *array[50]; + int size; + size = backtrace(array, 50); + backtrace_symbols_fd(array, size, 2); + } + for (;;) sleep(9999); +} +#endif + int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int init_main(int argc UNUSED_PARAM, char **argv) { @@ -964,6 +1002,19 @@ int init_main(int argc UNUSED_PARAM, char **argv) return kill(1, SIGHUP); } +#if DEBUG_SEGV_HANDLER + { + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = handle_sigsegv; + sa.sa_flags = SA_SIGINFO; + sigaction(SIGSEGV, &sa, NULL); + sigaction(SIGILL, &sa, NULL); + sigaction(SIGFPE, &sa, NULL); + sigaction(SIGBUS, &sa, NULL); + } +#endif + if (!DEBUG_INIT) { /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */ if (getpid() != 1 -- cgit v1.2.3-55-g6feb From 7eaa03709b337b586b11c4b9b53c9675f4de690c Mon Sep 17 00:00:00 2001 From: Sergey Naumov Date: Mon, 30 Jan 2012 12:52:56 +0100 Subject: login: -f should not ask for password even with PAM Signed-off-by: Sergey Naumov Signed-off-by: Denys Vlasenko --- loginutils/login.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/loginutils/login.c b/loginutils/login.c index 73db8fa63..bf43f3aba 100644 --- a/loginutils/login.c +++ b/loginutils/login.c @@ -342,14 +342,16 @@ int login_main(int argc UNUSED_PARAM, char **argv) goto pam_auth_failed; } } - pamret = pam_authenticate(pamh, 0); - if (pamret != PAM_SUCCESS) { - failed_msg = "authenticate"; - goto pam_auth_failed; - /* TODO: or just "goto auth_failed" - * since user seems to enter wrong password - * (in this case pamret == 7) - */ + if (!(opt & LOGIN_OPT_f)) { + pamret = pam_authenticate(pamh, 0); + if (pamret != PAM_SUCCESS) { + failed_msg = "authenticate"; + goto pam_auth_failed; + /* TODO: or just "goto auth_failed" + * since user seems to enter wrong password + * (in this case pamret == 7) + */ + } } /* check that the account is healthy */ pamret = pam_acct_mgmt(pamh, 0); -- cgit v1.2.3-55-g6feb From 800a9a056a3703b4001bf55ebc30b1c14cf55acc Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 31 Jan 2012 14:10:26 +0100 Subject: vi: move mark[i] pointers if text[] moves after realloc While at it, optimized :s/find/repl/ a bit function old new delta text_hole_make 120 150 +30 colon 2848 2844 -4 Signed-off-by: Denys Vlasenko --- editors/vi.c | 64 +++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 4a2d5d4f1..f7b9f3873 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -1040,13 +1040,13 @@ static void colon(char *buf) goto ret; #if ENABLE_FEATURE_VI_YANKMARK - if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) { + if (Ureg >= 0 && Ureg < 28) { free(reg[Ureg]); // free orig line reg- for 'U' - reg[Ureg]= 0; + reg[Ureg] = NULL; } - if (YDreg >= 0 && YDreg < 28 && reg[YDreg] != 0) { + if (YDreg >= 0 && YDreg < 28) { free(reg[YDreg]); // free default yank/delete register - reg[YDreg]= 0; + reg[YDreg] = NULL; } #endif // how many lines in text[]? @@ -1225,51 +1225,53 @@ static void colon(char *buf) #endif /* FEATURE_VI_SET */ #if ENABLE_FEATURE_VI_SEARCH } else if (cmd[0] == 's') { // substitute a pattern with a replacement pattern - char *ls, *F, *R; - int gflag; + char *F, *R, *flags; + size_t len_F, len_R; + int gflag; // global replace flag // F points to the "find" pattern // R points to the "replace" pattern - // replace the cmd line delimiters "/" with NULLs - gflag = 0; // global replace flag + // replace the cmd line delimiters "/" with NULs c = orig_buf[1]; // what is the delimiter F = orig_buf + 2; // start of "find" R = strchr(F, c); // middle delimiter if (!R) goto colon_s_fail; + len_F = R - F; *R++ = '\0'; // terminate "find" - buf1 = strchr(R, c); - if (!buf1) + flags = strchr(R, c); + if (!flags) goto colon_s_fail; - *buf1++ = '\0'; // terminate "replace" - if (*buf1 == 'g') { // :s/foo/bar/g - buf1++; - gflag++; // turn on gflag - } + len_R = flags - R; + *flags++ = '\0'; // terminate "replace" + gflag = *flags; + q = begin_line(q); if (b < 0) { // maybe :s/foo/bar/ - q = begin_line(dot); // start with cur line - b = count_lines(text, q); // cur line number + q = begin_line(dot); // start with cur line + b = count_lines(text, q); // cur line number } if (e < 0) e = b; // maybe :.s/foo/bar/ + for (i = b; i <= e; i++) { // so, :20,23 s \0 find \0 replace \0 - ls = q; // orig line start + char *ls = q; // orig line start + char *found; vc4: - buf1 = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find" - if (buf1) { + found = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find" + if (found) { uintptr_t bias; // we found the "find" pattern - delete it - text_hole_delete(buf1, buf1 + strlen(F) - 1); + text_hole_delete(found, found + len_F - 1); // inset the "replace" patern - bias = string_insert(buf1, R); // insert the string - buf1 += bias; + bias = string_insert(found, R); // insert the string + found += bias; ls += bias; /*q += bias; - recalculated anyway */ // check for "global" :s/foo/bar/g - if (gflag == 1) { - if ((buf1 + strlen(R)) < end_line(ls)) { - q = buf1 + strlen(R); + if (gflag == 'g') { + if ((found + len_R) < end_line(ls)) { + q = found + len_R; goto vc4; // don't let q move past cur line } } @@ -2073,6 +2075,14 @@ static uintptr_t text_hole_make(char *p, int size) // at "p", make a 'size' byte dot += bias; end += bias; p += bias; +#if ENABLE_FEATURE_VI_YANKMARK + { + int i; + for (i = 0; i < ARRAY_SIZE(mark); i++) + if (mark[i]) + mark[i] += bias; + } +#endif text = new_text; } memmove(p + size, p, end - size - p); @@ -3305,7 +3315,7 @@ static void do_cmd(int c) end_cmd_q(); // stop adding to q break; case 'U': // U- Undo; replace current line with original version - if (reg[Ureg] != 0) { + if (reg[Ureg] != NULL) { p = begin_line(dot); q = end_line(dot); p = text_hole_delete(p, q); // delete cur line -- cgit v1.2.3-55-g6feb From c0657e0d0a3a818e2c857f99f0b0ddf936324fdb Mon Sep 17 00:00:00 2001 From: Dennis Groenen Date: Tue, 31 Jan 2012 14:12:38 +0100 Subject: vi: add ":prev" command support function old new delta colon 2844 2891 +47 vi_main 243 255 +12 text_yank 54 56 +2 refresh 780 774 -6 Signed-off-by: Dennis Groenen Signed-off-by: Denys Vlasenko --- editors/vi.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index f7b9f3873..b4ad12e5c 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -278,7 +278,6 @@ struct globals { smallint cmd_mode; // 0=command 1=insert 2=replace int file_modified; // buffer contents changed (counter, not flag!) int last_file_modified; // = -1; - int fn_start; // index of first cmd line file name int save_argc; // how many file names on cmd line int cmdcnt; // repetition count unsigned rows, columns; // the terminal screen is this size @@ -363,7 +362,6 @@ struct globals { #define cmd_mode (G.cmd_mode ) #define file_modified (G.file_modified ) #define last_file_modified (G.last_file_modified ) -#define fn_start (G.fn_start ) #define save_argc (G.save_argc ) #define cmdcnt (G.cmdcnt ) #define rows (G.rows ) @@ -599,9 +597,10 @@ int vi_main(int argc, char **argv) } // The argv array can be used by the ":next" and ":rewind" commands - // save optind. - fn_start = optind; // remember first file name for :next and :rew + argv += optind; + argc -= optind; save_argc = argc; + optind = 0; //----- This is the main file handling loop -------------- while (1) { @@ -1021,7 +1020,7 @@ static void colon(char *buf) } else if (strncmp(cmd, "edit", i) == 0) { // Edit a file // don't edit, if the current file has been modified if (file_modified && !useforce) { - status_line_bold("No write since last change (:edit! overrides)"); + status_line_bold("No write since last change (:%s! overrides)", cmd); goto ret; } if (args[0]) { @@ -1111,11 +1110,12 @@ static void colon(char *buf) Hit_Return(); } else if (strncmp(cmd, "quit", i) == 0 // quit || strncmp(cmd, "next", i) == 0 // edit next file + || strncmp(cmd, "prev", i) == 0 // edit previous file ) { int n; if (useforce) { - // force end of argv list if (*cmd == 'q') { + // force end of argv list optind = save_argc; } editing = 0; @@ -1123,8 +1123,7 @@ static void colon(char *buf) } // don't exit if the file been modified if (file_modified) { - status_line_bold("No write since last change (:%s! overrides)", - (*cmd == 'q' ? "quit" : "next")); + status_line_bold("No write since last change (:%s! overrides)", cmd); goto ret; } // are there other file to edit @@ -1137,6 +1136,14 @@ static void colon(char *buf) status_line_bold("No more files to edit"); goto ret; } + if (*cmd == 'p') { + // are there previous files to edit + if (optind < 1) { + status_line_bold("No previous files to edit"); + goto ret; + } + optind -= 2; + } editing = 0; } else if (strncmp(cmd, "read", i) == 0) { // read file into text[] fn = args; @@ -1172,10 +1179,10 @@ static void colon(char *buf) } } else if (strncmp(cmd, "rewind", i) == 0) { // rewind cmd line args if (file_modified && !useforce) { - status_line_bold("No write since last change (:rewind! overrides)"); + status_line_bold("No write since last change (:%s! overrides)", cmd); } else { // reset the filenames to edit - optind = fn_start - 1; + optind = -1; /* start from 0th file */ editing = 0; } #if ENABLE_FEATURE_VI_SET @@ -3507,7 +3514,7 @@ static void do_cmd(int c) || strncmp(p, "q!", cnt) == 0 // delete lines ) { if (file_modified && p[1] != '!') { - status_line_bold("No write since last change (:quit! overrides)"); + status_line_bold("No write since last change (:%s! overrides)", p); } else { editing = 0; } -- cgit v1.2.3-55-g6feb From 428bd2d4337dbd83feb3c7d1fc04d840f548003c Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Tue, 31 Jan 2012 14:55:15 +0100 Subject: modprobe: accept -b even if blacklist functionality is disabled Signed-off-by: Felipe Contreras Signed-off-by: Denys Vlasenko --- modutils/modprobe-small.c | 2 +- modutils/modprobe.c | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/modutils/modprobe-small.c b/modutils/modprobe-small.c index f5b283b47..5ea1be99d 100644 --- a/modutils/modprobe-small.c +++ b/modutils/modprobe-small.c @@ -805,7 +805,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) opt_complementary = "-1"; /* only -q (quiet) and -r (rmmod), * the rest are accepted and ignored (compat) */ - getopt32(argv, "qrfsvw"); + getopt32(argv, "qrfsvwb"); argv += optind; /* are we rmmod? -> simulate modprobe -r */ diff --git a/modutils/modprobe.c b/modutils/modprobe.c index c1a1828d7..fb6c65990 100644 --- a/modutils/modprobe.c +++ b/modutils/modprobe.c @@ -101,12 +101,15 @@ //usage: ) //usage:#endif /* !ENABLE_MODPROBE_SMALL */ -/* Note that usage text doesn't document various 2.4 options - * we pull in through INSMOD_OPTS define */ -#define MODPROBE_OPTS "alrD" IF_FEATURE_MODPROBE_BLACKLIST("b") +/* Note: usage text doesn't document various 2.4 options + * we pull in through INSMOD_OPTS define + * Note2: -b is always accepted, but if !FEATURE_MODPROBE_BLACKLIST, + * it is a no-op. + */ +#define MODPROBE_OPTS "alrDb" /* -a and -D _are_ in fact compatible */ #define MODPROBE_COMPLEMENTARY ("q-v:v-q:l--arD:r--alD:a--lr:D--rl") -//#define MODPROBE_OPTS "acd:lnrt:C:" IF_FEATURE_MODPROBE_BLACKLIST("b") +//#define MODPROBE_OPTS "acd:lnrt:C:b" //#define MODPROBE_COMPLEMENTARY "q-v:v-q:l--acr:a--lr:r--al" enum { OPT_INSERT_ALL = (INSMOD_OPT_UNUSED << 0), /* a */ @@ -133,10 +136,8 @@ static const char modprobe_longopts[] ALIGN1 = /* module-init-tools 3.11.1 has only long opt --show-depends * but no short -D, we provide long opt for scripts which * were written for 3.11.1: */ - "show-depends\0" No_argument "D" - // IF_FEATURE_MODPROBE_BLACKLIST( + "show-depends\0" No_argument "D" // "use-blacklist\0" No_argument "b" - // ) ; #endif -- cgit v1.2.3-55-g6feb From 35def51c9747895d38c11e3c41e62c3c68c92438 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 1 Feb 2012 02:42:54 +0100 Subject: httpd: fix MD5-encrypted-in-httpd.conf password logic function old new delta check_user_passwd 467 492 +25 Signed-off-by: Denys Vlasenko --- networking/Config.src | 16 ++++++++++++---- networking/httpd.c | 50 +++++++++++++++++++++++++++----------------------- 2 files changed, 39 insertions(+), 27 deletions(-) diff --git a/networking/Config.src b/networking/Config.src index 8aeba0ef9..fb7dca7d4 100644 --- a/networking/Config.src +++ b/networking/Config.src @@ -199,14 +199,22 @@ config FEATURE_HTTPD_BASIC_AUTH help Utilizes password settings from /etc/httpd.conf for basic authentication on a per url basis. + Example for httpd.conf file: + /adm:toor:PaSsWd config FEATURE_HTTPD_AUTH_MD5 bool "Support MD5 crypted passwords for http Authentication" default y depends on FEATURE_HTTPD_BASIC_AUTH help - Enables basic per URL authentication from /etc/httpd.conf - using md5 passwords. + Enables encrypted passwords, and wildcard user/passwords + in httpd.conf file. + User '*' means 'any system user name is ok', + password of '*' means 'use system password for this user' + Examples: + /adm:toor:$1$P/eKnWXS$aI1aPGxT.dJD5SzqAKWrF0 + /adm:root:* + /wiki:*:* config FEATURE_HTTPD_CGI bool "Support Common Gateway Interface (CGI)" @@ -223,8 +231,8 @@ config FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR help This option enables support for running scripts through an interpreter. Turn this on if you want PHP scripts to work - properly. You need to supply an additional line in your httpd - config file: + properly. You need to supply an additional line in your + httpd.conf file: *.php:/path/to/your/php config FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV diff --git a/networking/httpd.c b/networking/httpd.c index 3f4e6aab7..0e4c697f8 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -1776,6 +1776,16 @@ static int check_user_passwd(const char *path, char *user_and_passwd) colon_after_user = strchr(user_and_passwd, ':'); if (!colon_after_user) goto bad_input; + + /* compare "user:" */ + if (cur->after_colon[0] != '*' + && strncmp(cur->after_colon, user_and_passwd, + colon_after_user - user_and_passwd + 1) != 0 + ) { + continue; + } + /* this cfg entry is '*' or matches username from peer */ + passwd = strchr(cur->after_colon, ':'); if (!passwd) goto bad_input; @@ -1786,13 +1796,6 @@ static int check_user_passwd(const char *path, char *user_and_passwd) struct pam_conv conv_info = { &pam_talker, (void *) &userinfo }; pam_handle_t *pamh; - /* compare "user:" */ - if (cur->after_colon[0] != '*' - && strncmp(cur->after_colon, user_and_passwd, colon_after_user - user_and_passwd + 1) != 0 - ) { - continue; - } - /* this cfg entry is '*' or matches username from peer */ *colon_after_user = '\0'; userinfo.name = user_and_passwd; userinfo.pw = colon_after_user + 1; @@ -1828,31 +1831,32 @@ static int check_user_passwd(const char *path, char *user_and_passwd) passwd = result->sp_pwdp; } # endif + /* In this case, passwd is ALWAYS encrypted: + * it came from /etc/passwd or /etc/shadow! + */ + goto check_encrypted; # endif /* ENABLE_PAM */ } - - /* compare "user:" */ - if (cur->after_colon[0] != '*' - && strncmp(cur->after_colon, user_and_passwd, colon_after_user - user_and_passwd + 1) != 0 - ) { - continue; - } - /* this cfg entry is '*' or matches username from peer */ - - /* encrypt pwd from peer and check match with local one */ - { - char *encrypted = pw_encrypt( - /* pwd: */ colon_after_user + 1, + /* Else: passwd is from httpd.conf, it is either plaintext or encrypted */ + + if (passwd[0] == '$' && isdigit(passwd[1])) { + char *encrypted; + check_encrypted: + /* encrypt pwd from peer and check match with local one */ + encrypted = pw_encrypt( + /* pwd (from peer): */ colon_after_user + 1, /* salt: */ passwd, /* cleanup: */ 0 ); r = strcmp(encrypted, passwd); free(encrypted); - goto end_check_passwd; + } else { + /* local passwd is from httpd.conf and it's plaintext */ + r = strcmp(colon_after_user + 1, passwd); } - bad_input: ; + goto end_check_passwd; } - + bad_input: /* Comparing plaintext "user:pass" in one go */ r = strcmp(cur->after_colon, user_and_passwd); end_check_passwd: -- cgit v1.2.3-55-g6feb From 9ec3cd400ad9930a8cd3de371271202de49adea9 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 2 Feb 2012 11:29:43 +0100 Subject: tweak comment, no code changes Signed-off-by: Denys Vlasenko --- libbb/procps.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libbb/procps.c b/libbb/procps.c index e15ddd1e5..0e3f2f9da 100644 --- a/libbb/procps.c +++ b/libbb/procps.c @@ -198,7 +198,7 @@ int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total, memset(&currec, 0, sizeof(currec)); while (fgets(buf, PROCPS_BUFSIZE, file)) { // Each mapping datum has this form: - // f7d29000-f7d39000 rw-s ADR M:m OFS FILE + // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME // Size: nnn kB // Rss: nnn kB // ..... @@ -223,7 +223,7 @@ int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total, tp = strchr(buf, '-'); if (tp) { // We reached next mapping - the line of this form: - // f7d29000-f7d39000 rw-s ADR M:m OFS FILE + // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME if (cb) { /* If we have a previous record, there's nothing more @@ -242,7 +242,7 @@ int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total, strncpy(currec.smap_mode, tp, sizeof(currec.smap_mode)-1); - // skipping "rw-s ADR M:m OFS " + // skipping "rw-s FILEOFS M:m INODE " tp = skip_whitespace(skip_fields(tp, 4)); // filter out /dev/something (something != zero) if (strncmp(tp, "/dev/", 5) != 0 || strcmp(tp, "/dev/zero\n") == 0) { -- cgit v1.2.3-55-g6feb From ef43beac63aa7e4b2bccb069e47b5e4902bb895f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 4 Feb 2012 21:37:17 +0100 Subject: httpd: fix sendfile of files larger than 2 Gb. Closes 4754 When built with "sendfile" support, httpd was unable to send large files (>2 GB) in one single connection, terminating it before the full file has been sent. Signed-off-by: Denys Vlasenko --- networking/httpd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/httpd.c b/networking/httpd.c index 0e4c697f8..ba956318c 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -1623,7 +1623,7 @@ static NOINLINE void send_file_and_exit(const char *url, int what) break; /* fall back to read/write loop */ goto fin; } - IF_FEATURE_HTTPD_RANGES(range_len -= sz;) + IF_FEATURE_HTTPD_RANGES(range_len -= count;) if (count == 0 || range_len == 0) log_and_exit(); } -- cgit v1.2.3-55-g6feb From 6e9d047c1558f92531ea12b9e3206023ab77cf51 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sat, 4 Feb 2012 21:55:01 +0100 Subject: cttyhack: handle multiple consoles found in sysfs If multiple consoles are found from the sysfs file, cttyhack fails: cttyhack: can't open '/dev/tty0 ttyS0': No such file or directory In such cases take the last one as the kernel will use that one for /dev/console. Signed-off-by: Aaro Koskinen Signed-off-by: Denys Vlasenko --- shell/cttyhack.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/shell/cttyhack.c b/shell/cttyhack.c index 6ff867413..f9b59c263 100644 --- a/shell/cttyhack.c +++ b/shell/cttyhack.c @@ -123,15 +123,22 @@ int cttyhack_main(int argc UNUSED_PARAM, char **argv) * TIOCGSERIAL check, which assumes that all * serial lines follow /dev/ttySn convention - * which is not always the case. - * Therefore, we use this methos first: + * Therefore, we use this method first: */ int s = open_read_close("/sys/class/tty/console/active", console + 5, sizeof(console) - 5); if (s > 0) { - /* found active console via sysfs (Linux 2.6.38+) - * sysfs string looks like "ttyS0\n" so zap the newline: + char *last; + /* Found active console via sysfs (Linux 2.6.38+). + * It looks like "[tty0 ]ttyS0\n" so zap the newline: */ console[4 + s] = '\0'; + /* If there are multiple consoles, + * take the last one: + */ + last = strrchr(console + 5, ' '); + if (last) + overlapping_strcpy(console + 5, last + 1); break; } -- cgit v1.2.3-55-g6feb From bbf1e3c144c1ee93409a0e0546cb56b34eccfcfd Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 5 Feb 2012 15:08:08 +0100 Subject: acpid: do not install handlers for fatal signals For acpid, it's ok to die at once. Signed-off-by: Denys Vlasenko --- util-linux/acpid.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/util-linux/acpid.c b/util-linux/acpid.c index 361a2b206..1b22f3a01 100644 --- a/util-linux/acpid.c +++ b/util-linux/acpid.c @@ -268,8 +268,12 @@ int acpid_main(int argc UNUSED_PARAM, char **argv) xchdir(opt_dir); + /* We spawn children but don't wait for them. Prevent zombies: */ bb_signals((1 << SIGCHLD), SIG_IGN); - bb_signals(BB_FATAL_SIGS, record_signo); + // If you enable this, (1) explain why, (2) + // make sure while(poll) loop below is still interruptible + // by SIGTERM et al: + //bb_signals(BB_FATAL_SIGS, record_signo); pfd = NULL; nfd = 0; @@ -337,7 +341,7 @@ int acpid_main(int argc UNUSED_PARAM, char **argv) } if (!event) continue; - // spawn event handler + /* spawn event handler */ process_event(event); } } -- cgit v1.2.3-55-g6feb From 638dbc34b3dd2a6e340a2370056913ed5770d196 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 6 Feb 2012 01:00:00 +0100 Subject: mdev: add a comment. no code changes Signed-off-by: Denys Vlasenko --- util-linux/mdev.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/util-linux/mdev.c b/util-linux/mdev.c index 976568814..67de52d06 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c @@ -565,8 +565,12 @@ static void make_device(char *path, int delete) chown(node_name, rule->ugid.uid, rule->ugid.gid); } if (ENABLE_FEATURE_MDEV_RENAME && alias) { - if (aliaslink == '>') + if (aliaslink == '>') { +//TODO: on devtmpfs, device_name already exists and symlink() fails. +//End result is that instead of symlink, we have two nodes. +//What should be done? symlink(node_name, device_name); + } } } -- cgit v1.2.3-55-g6feb From 9106107a509cfb23806e46765ea2704cdd130654 Mon Sep 17 00:00:00 2001 From: Jonh Wendell Date: Thu, 9 Feb 2012 15:14:33 +0100 Subject: Make unix (local) sockets work without IPv6 enabled The xsocket_type() function had an optional "family" argument that was enabled only if IPv6 is enabled. In the case of the function was called with a valid AF_UNIX argument, and IPv6 is disabled, this argument was silently ignored. This patch makes the "family" argument mandatory, while keeping the old behavior i.e., if AF_UNSPEC is passed, we try first IPv6 (if it's enabled) and fallback to IPv4. Also I changed all callers of xsocket_type() to reflect its new interface. Signed-off-by: Jonh Wendell Signed-off-by: Denys Vlasenko --- include/libbb.h | 5 ----- libbb/xconnect.c | 16 +++++++++------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index 4975b97fe..f743bdfc6 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -568,12 +568,7 @@ enum { * and if kernel doesn't support it, fall back to IPv4. * This is useful if you plan to bind to resulting local lsa. */ -#if ENABLE_FEATURE_IPV6 int xsocket_type(len_and_sockaddr **lsap, int af, int sock_type) FAST_FUNC; -#else -int xsocket_type(len_and_sockaddr **lsap, int sock_type) FAST_FUNC; -#define xsocket_type(lsap, af, sock_type) xsocket_type((lsap), (sock_type)) -#endif int xsocket_stream(len_and_sockaddr **lsap) FAST_FUNC; /* Create server socket bound to bindaddr:port. bindaddr can be NULL, * numeric IP ("N.N.N.N") or numeric IPv6 address, diff --git a/libbb/xconnect.c b/libbb/xconnect.c index 4b7c110d3..1c8bb2b73 100644 --- a/libbb/xconnect.c +++ b/libbb/xconnect.c @@ -322,26 +322,28 @@ len_and_sockaddr* FAST_FUNC xdotted2sockaddr(const char *host, int port) return str2sockaddr(host, port, AF_UNSPEC, AI_NUMERICHOST | DIE_ON_ERROR); } -#undef xsocket_type -int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, IF_FEATURE_IPV6(int family,) int sock_type) +int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, int family, int sock_type) { - IF_NOT_FEATURE_IPV6(enum { family = AF_INET };) len_and_sockaddr *lsa; int fd; int len; -#if ENABLE_FEATURE_IPV6 if (family == AF_UNSPEC) { +#if ENABLE_FEATURE_IPV6 fd = socket(AF_INET6, sock_type, 0); if (fd >= 0) { family = AF_INET6; goto done; } +#endif family = AF_INET; } -#endif + fd = xsocket(family, sock_type, 0); + len = sizeof(struct sockaddr_in); + if (family == AF_UNIX) + len = sizeof(struct sockaddr_un); #if ENABLE_FEATURE_IPV6 if (family == AF_INET6) { done: @@ -357,7 +359,7 @@ int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, IF_FEATURE_IPV6(int family,) int FAST_FUNC xsocket_stream(len_and_sockaddr **lsap) { - return xsocket_type(lsap, IF_FEATURE_IPV6(AF_UNSPEC,) SOCK_STREAM); + return xsocket_type(lsap, AF_UNSPEC, SOCK_STREAM); } static int create_and_bind_or_die(const char *bindaddr, int port, int sock_type) @@ -370,7 +372,7 @@ static int create_and_bind_or_die(const char *bindaddr, int port, int sock_type) /* user specified bind addr dictates family */ fd = xsocket(lsa->u.sa.sa_family, sock_type, 0); } else { - fd = xsocket_type(&lsa, IF_FEATURE_IPV6(AF_UNSPEC,) sock_type); + fd = xsocket_type(&lsa, AF_UNSPEC, sock_type); set_nport(&lsa->u.sa, htons(port)); } setsockopt_reuseaddr(fd); -- cgit v1.2.3-55-g6feb From 594db1e62a060a0a5646f6840112189fd0ce3b81 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 9 Feb 2012 18:17:29 +0100 Subject: getopt: simple code shrink; expand help text function old new delta packed_usage 28978 29184 +206 getopt_main 656 632 -24 Signed-off-by: Denys Vlasenko --- util-linux/getopt.c | 52 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/util-linux/getopt.c b/util-linux/getopt.c index c45edf8ca..6bad3efc2 100644 --- a/util-linux/getopt.c +++ b/util-linux/getopt.c @@ -32,30 +32,48 @@ */ //usage:#define getopt_trivial_usage -//usage: "[OPTIONS]" +//usage: "[OPTIONS] [--] OPTSTRING PARAMS" //usage:#define getopt_full_usage "\n\n" //usage: IF_LONG_OPTS( //usage: " -a,--alternative Allow long options starting with single -" -//usage: "\n -l,--longoptions=longopts Long options to be recognized" -//usage: "\n -n,--name=progname The name under which errors are reported" -//usage: "\n -o,--options=optstring Short options to be recognized" +//usage: "\n -l,--longoptions=LOPT[,...] Long options to be recognized" +//usage: "\n -n,--name=PROGNAME The name under which errors are reported" +//usage: "\n -o,--options=OPTSTRING Short options to be recognized" //usage: "\n -q,--quiet Disable error reporting by getopt(3)" //usage: "\n -Q,--quiet-output No normal output" -//usage: "\n -s,--shell=shell Set shell quoting conventions" +//usage: "\n -s,--shell=SHELL Set shell quoting conventions" //usage: "\n -T,--test Test for getopt(1) version" //usage: "\n -u,--unquoted Don't quote the output" //usage: ) //usage: IF_NOT_LONG_OPTS( //usage: " -a Allow long options starting with single -" -//usage: "\n -l longopts Long options to be recognized" -//usage: "\n -n progname The name under which errors are reported" -//usage: "\n -o optstring Short options to be recognized" +//usage: "\n -l LOPT[,...] Long options to be recognized" +//usage: "\n -n PROGNAME The name under which errors are reported" +//usage: "\n -o OPTSTRING Short options to be recognized" //usage: "\n -q Disable error reporting by getopt(3)" //usage: "\n -Q No normal output" -//usage: "\n -s shell Set shell quoting conventions" +//usage: "\n -s SHELL Set shell quoting conventions" //usage: "\n -T Test for getopt(1) version" //usage: "\n -u Don't quote the output" //usage: ) +//usage: "\n" +//usage: "\nExample:" +//usage: "\n" +//usage: "\nO=`getopt -l bb: -- ab:c:: \"$@\"`" +//usage: "\n[ $? = 0 ] || exit 1" +//usage: "\neval set -- \"$O\"" +//usage: "\nwhile true; do" +//usage: "\n case \"$1\" in" +//usage: "\n -a) echo A; shift;;" +//usage: "\n -b|--bb) echo \"B:'$2'\"; shift 2;;" +//usage: "\n -c) case \"$2\" in" +//usage: "\n \"\") echo C; shift 2;;" +//usage: "\n *) echo \"C:'$2'\"; shift 2;;" +//usage: "\n esac;;" +//usage: "\n --) shift; break;;" +//usage: "\n *) echo Error; exit 1;;" +//usage: "\n esac" +//usage: "\ndone" //usage: //usage:#define getopt_example_usage //usage: "$ cat getopt.test\n" @@ -339,6 +357,7 @@ static const char getopt_longopts[] ALIGN1 = int getopt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int getopt_main(int argc, char **argv) { + int n; char *optstr = NULL; char *name = NULL; unsigned opt; @@ -351,7 +370,7 @@ int getopt_main(int argc, char **argv) compatible = getenv("GETOPT_COMPATIBLE"); /* used as yes/no flag */ - if (argc == 1) { + if (!argv[1]) { if (compatible) { /* For some reason, the original getopt gave no error when there were no arguments. */ @@ -362,10 +381,10 @@ int getopt_main(int argc, char **argv) } if (argv[1][0] != '-' || compatible) { - char *s; + char *s = argv[1]; option_mask32 |= OPT_u; /* quoting off */ - s = xstrdup(argv[1] + strspn(argv[1], "-+")); + s = xstrdup(s + strspn(s, "-+")); argv[1] = argv[0]; return generate_output(argv+1, argc-1, s, long_options); } @@ -392,12 +411,13 @@ int getopt_main(int argc, char **argv) } /* All options controlling the applet have now been parsed */ + n = optind - 1; if (!optstr) { - if (optind >= argc) + optstr = argv[++n]; + if (!optstr) bb_error_msg_and_die("missing optstring argument"); - optstr = argv[optind++]; } - argv[optind-1] = name ? name : argv[0]; - return generate_output(argv+optind-1, argc-optind+1, optstr, long_options); + argv[n] = name ? name : argv[0]; + return generate_output(argv + n, argc - n, optstr, long_options); } -- cgit v1.2.3-55-g6feb From d0222503ff9ff264efa74f6de651b308d20a05b8 Mon Sep 17 00:00:00 2001 From: Pere Orga Date: Thu, 9 Feb 2012 18:23:33 +0100 Subject: applets_sh/*: Add a few more examples of "shell applets" Signed-off-by: Pere Orga Signed-off-by: Denys Vlasenko --- applets_sh/README | 5 +++++ applets_sh/dos2unix | 5 +++++ applets_sh/tac | 7 +++++++ applets_sh/unix2dos | 5 +++++ 4 files changed, 22 insertions(+) create mode 100644 applets_sh/README create mode 100755 applets_sh/dos2unix create mode 100755 applets_sh/tac create mode 100755 applets_sh/unix2dos diff --git a/applets_sh/README b/applets_sh/README new file mode 100644 index 000000000..9dcd38ae3 --- /dev/null +++ b/applets_sh/README @@ -0,0 +1,5 @@ +This directory contains examples of applets implemented as shell scripts. + +So far these scripts are not hooked to the build system and are not +installed by "make install". If you want to use them, +you need to install them by hand. diff --git a/applets_sh/dos2unix b/applets_sh/dos2unix new file mode 100755 index 000000000..0fd5206f6 --- /dev/null +++ b/applets_sh/dos2unix @@ -0,0 +1,5 @@ +#!/bin/sh +# TODO: use getopt to avoid parsing options as filenames, +# and to support -- and --help +[ $# -ne 0 ] && DASH_I=-i +sed $DASH_I -e 's/\r$//' "$@" diff --git a/applets_sh/tac b/applets_sh/tac new file mode 100755 index 000000000..c5a8e39c1 --- /dev/null +++ b/applets_sh/tac @@ -0,0 +1,7 @@ +#!/bin/sh +# TODO: use getopt to avoid parsing options as filenames, +# and to support -- and --help +for i in "$@" +do +sed -e '1!G;h;$!d' "$i" +done diff --git a/applets_sh/unix2dos b/applets_sh/unix2dos new file mode 100755 index 000000000..70e042906 --- /dev/null +++ b/applets_sh/unix2dos @@ -0,0 +1,5 @@ +#!/bin/sh +# TODO: use getopt to avoid parsing options as filenames, +# and to support -- and --help +[ $# -ne 0 ] && DASH_I=-i +sed $DASH_I -e 's/$/\r/' "$@" -- cgit v1.2.3-55-g6feb From 817c230a0c1b5817cbd0af86f1bd90db72f16c3c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 9 Feb 2012 18:39:16 +0100 Subject: getopt: trim help text Signed-off-by: Denys Vlasenko --- util-linux/getopt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/util-linux/getopt.c b/util-linux/getopt.c index 6bad3efc2..d662c813a 100644 --- a/util-linux/getopt.c +++ b/util-linux/getopt.c @@ -59,8 +59,7 @@ //usage: "\n" //usage: "\nExample:" //usage: "\n" -//usage: "\nO=`getopt -l bb: -- ab:c:: \"$@\"`" -//usage: "\n[ $? = 0 ] || exit 1" +//usage: "\nO=`getopt -l bb: -- ab:c:: \"$@\"` || exit 1" //usage: "\neval set -- \"$O\"" //usage: "\nwhile true; do" //usage: "\n case \"$1\" in" -- cgit v1.2.3-55-g6feb From 5a5db93b0f27a5fd090509f9745b63f49b9b7871 Mon Sep 17 00:00:00 2001 From: Lauri Kasanen Date: Sun, 19 Feb 2012 16:33:37 +0100 Subject: depmod: supply help text Signed-off-by: Lauri Kasanen Signed-off-by: Denys Vlasenko --- modutils/depmod.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/modutils/depmod.c b/modutils/depmod.c index f6c0bf33a..775236126 100644 --- a/modutils/depmod.c +++ b/modutils/depmod.c @@ -10,11 +10,6 @@ //applet:IF_DEPMOD(APPLET(depmod, BB_DIR_SBIN, BB_SUID_DROP)) -//usage:#if !ENABLE_MODPROBE_SMALL -//usage:#define depmod_trivial_usage NOUSAGE_STR -//usage:#define depmod_full_usage "" -//usage:#endif - #include "libbb.h" #include "modutils.h" #include /* uname() */ @@ -131,7 +126,16 @@ static void xfreopen_write(const char *file, FILE *f) bb_perror_msg_and_die("can't open '%s'", file); } -/* Usage: +//usage:#if !ENABLE_MODPROBE_SMALL +//usage:#define depmod_trivial_usage "[-n] [-b BASE] [VERSION] [MODFILES]..." +//usage:#define depmod_full_usage "\n\n" +//usage: "Generate modules.dep, alias, and symbols files" +//usage: "\n" +//usage: "\n -b BASE Use BASE/lib/modules/VERSION" +//usage: "\n -n Dry run: print files to stdout" +//usage:#endif + +/* Upstream usage: * [-aAenv] [-C FILE or DIR] [-b BASE] [-F System.map] [VERSION] [MODFILES]... * -a --all * Probe all modules. Default if no MODFILES. @@ -142,7 +146,7 @@ static void xfreopen_write(const char *file, FILE *f) * -C --config FILE or DIR * Path to /etc/depmod.conf or /etc/depmod.d/ * -e --errsyms - * When combined with the -F option, this reports any symbols which + * When combined with the -F option, this reports any symbols * which are not supplied by other modules or kernel. * -F --filesyms System.map * -n --dry-run @@ -154,8 +158,13 @@ static void xfreopen_write(const char *file, FILE *f) * -u No-op * -q No-op * - * So far we only support: [-rn] [-b BASE] [VERSION] [MODFILES]... - * -aAeF are accepted but ignored. -vC are not accepted. + * So far we only support: [-n] [-b BASE] [VERSION] [MODFILES]... + * Accepted but ignored: + * -aAe + * -F System.map + * -C FILE/DIR + * + * Not accepted: -v */ enum { //OPT_a = (1 << 0), /* All modules, ignore mods in argv */ -- cgit v1.2.3-55-g6feb From b2d668872c9d74d31fc3e2f29aa560c9d6c3e006 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 19 Feb 2012 16:57:08 +0100 Subject: modprobe-small: add comment about aliased commands' help text Signed-off-by: Denys Vlasenko --- modutils/modprobe-small.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modutils/modprobe-small.c b/modutils/modprobe-small.c index 5ea1be99d..bd855f628 100644 --- a/modutils/modprobe-small.c +++ b/modutils/modprobe-small.c @@ -696,6 +696,10 @@ The following options are useful for people managing distributions: //usage:#if ENABLE_MODPROBE_SMALL +//// Note: currently, help system shows modprobe --help text for all aliased cmds +//// (see APPLET_ODDNAME macro definition). +//// All other help texts defined below are not used. FIXME? + //usage:#define depmod_trivial_usage NOUSAGE_STR //usage:#define depmod_full_usage "" -- cgit v1.2.3-55-g6feb From 8cce1b3ad8c28b5c34c24d79b32b6cebb75ea2f5 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 19 Feb 2012 17:18:45 +0100 Subject: httpd: make byte ranges which start at 0 work too. Closes 4766 Signed-off-by: Denys Vlasenko --- networking/httpd.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/networking/httpd.c b/networking/httpd.c index ba956318c..f233cb0ba 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -348,7 +348,7 @@ struct globals { #define range_len (G.range_len ) #else enum { - range_start = 0, + range_start = -1, range_end = MAXINT(off_t) - 1, range_len = MAXINT(off_t), }; @@ -370,6 +370,7 @@ enum { #define INIT_G() do { \ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ IF_FEATURE_HTTPD_BASIC_AUTH(g_realm = "Web Server Authentication";) \ + IF_FEATURE_HTTPD_RANGES(range_start = -1;) \ bind_addr_or_port = "80"; \ index_page = index_html; \ file_size = -1; \ @@ -1589,10 +1590,10 @@ static NOINLINE void send_file_and_exit(const char *url, int what) if (what == SEND_BODY /* err pages and ranges don't mix */ || content_gzip /* we are sending compressed page: can't do ranges */ ///why? ) { - range_start = 0; + range_start = -1; } range_len = MAXINT(off_t); - if (range_start) { + if (range_start >= 0) { if (!range_end) { range_end = file_size - 1; } @@ -1600,7 +1601,7 @@ static NOINLINE void send_file_and_exit(const char *url, int what) || lseek(fd, range_start, SEEK_SET) != range_start ) { lseek(fd, 0, SEEK_SET); - range_start = 0; + range_start = -1; } else { range_len = range_end - range_start + 1; send_headers(HTTP_PARTIAL_CONTENT); @@ -2168,11 +2169,11 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) s += sizeof("bytes=")-1; range_start = BB_STRTOOFF(s, &s, 10); if (s[0] != '-' || range_start < 0) { - range_start = 0; + range_start = -1; } else if (s[1]) { range_end = BB_STRTOOFF(s+1, NULL, 10); if (errno || range_end < range_start) - range_start = 0; + range_start = -1; } } } -- cgit v1.2.3-55-g6feb From cfcb1dac83c9e18a06a07f0b212f6701bb87c2ad Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Fri, 17 Feb 2012 19:36:26 +0000 Subject: ifupdown: support metric for static default gw This is useful when you have multiple ISPs with failover. It allows setting the priority of the static gateway and makes it possible to specify multiple static gateways. The ubuntu ifupdown supports it. function old new delta .rodata 116725 116797 +72 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 72/0) Total: 72 bytes text data bss dec hex filename 953343 7313 8984 969640 ecba8 busybox_old 953415 7313 8984 969712 ecbf0 busybox_unstripped Signed-off-by: Natanael Copa Signed-off-by: Denys Vlasenko --- networking/ifupdown.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/networking/ifupdown.c b/networking/ifupdown.c index 73da26085..dfda20670 100644 --- a/networking/ifupdown.c +++ b/networking/ifupdown.c @@ -403,11 +403,11 @@ static int FAST_FUNC static_up6(struct interface_defn_t *ifd, execfn *exec) result = execute("ip addr add %address%/%netmask% dev %iface%[[ label %label%]]", ifd, exec); result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec); /* Was: "[[ ip ....%gateway% ]]". Removed extra spaces w/o checking */ - result += execute("[[ip route add ::/0 via %gateway%]]", ifd, exec); + result += execute("[[ip route add ::/0 via %gateway%]][[ prio %metric%]]", ifd, exec); # else result = execute("ifconfig %iface%[[ media %media%]][[ hw %hwaddress%]][[ mtu %mtu%]] up", ifd, exec); result += execute("ifconfig %iface% add %address%/%netmask%", ifd, exec); - result += execute("[[route -A inet6 add ::/0 gw %gateway%]]", ifd, exec); + result += execute("[[route -A inet6 add ::/0 gw %gateway%[[ metric %metric%]]]]", ifd, exec); # endif return ((result == 3) ? 3 : 0); } @@ -490,7 +490,7 @@ static int FAST_FUNC static_up(struct interface_defn_t *ifd, execfn *exec) result = execute("ip addr add %address%/%bnmask%[[ broadcast %broadcast%]] " "dev %iface%[[ peer %pointopoint%]][[ label %label%]]", ifd, exec); result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec); - result += execute("[[ip route add default via %gateway% dev %iface%]]", ifd, exec); + result += execute("[[ip route add default via %gateway% dev %iface%[[ prio %metric%]]]]", ifd, exec); return ((result == 3) ? 3 : 0); # else /* ifconfig said to set iface up before it processes hw %hwaddress%, @@ -500,7 +500,7 @@ static int FAST_FUNC static_up(struct interface_defn_t *ifd, execfn *exec) result += execute("ifconfig %iface% %address% netmask %netmask%" "[[ broadcast %broadcast%]][[ pointopoint %pointopoint%]] ", ifd, exec); - result += execute("[[route add default gw %gateway% %iface%]]", ifd, exec); + result += execute("[[route add default gw %gateway%[[ metric %metric%]] %iface%]]", ifd, exec); return ((result == 3) ? 3 : 0); # endif } -- cgit v1.2.3-55-g6feb From af36ba206f7cf0eef77a82af741766a2d03c51ad Mon Sep 17 00:00:00 2001 From: Timo Teras Date: Fri, 10 Feb 2012 09:55:24 +0200 Subject: mkdir: fix permissions on 64-bit platforms sizeof(long) != sizeof(mode_t), this causes the compare in bb_make_directory of (long)-1 != (mode_t)-1 to fail and mess up the permissions of final directory by doing chmod((mode_t) -1). Signed-off-by: Timo Teras Signed-off-by: Denys Vlasenko --- coreutils/mkdir.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/coreutils/mkdir.c b/coreutils/mkdir.c index a4429b1cb..b33b6bba3 100644 --- a/coreutils/mkdir.c +++ b/coreutils/mkdir.c @@ -54,7 +54,7 @@ static const char mkdir_longopts[] ALIGN1 = int mkdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int mkdir_main(int argc UNUSED_PARAM, char **argv) { - mode_t mode = (mode_t)(-1); + long mode = -1; int status = EXIT_SUCCESS; int flags = 0; unsigned opt; @@ -68,10 +68,11 @@ int mkdir_main(int argc UNUSED_PARAM, char **argv) #endif opt = getopt32(argv, "m:p" IF_SELINUX("Z:"), &smode IF_SELINUX(,&scontext)); if (opt & 1) { - mode = 0777; - if (!bb_parse_mode(smode, &mode)) { + mode_t mmode = 0777; + if (!bb_parse_mode(smode, &mmode)) { bb_error_msg_and_die("invalid mode '%s'", smode); } + mode = mmode; } if (opt & 2) flags |= FILEUTILS_RECUR; -- cgit v1.2.3-55-g6feb From 6111f967f5299d2eb82fb8eb4bf3b3a4272e3f44 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 23 Feb 2012 13:45:18 +0100 Subject: tar: add support for PAX-encoded path=LONGFILENAME function old new delta get_header_tar 1478 1759 +281 Signed-off-by: Denys Vlasenko --- archival/libarchive/data_extract_all.c | 8 ++-- archival/libarchive/data_extract_to_command.c | 8 ++-- archival/libarchive/get_header_tar.c | 65 ++++++++++++++------------- include/bb_archive.h | 9 ++-- 4 files changed, 46 insertions(+), 44 deletions(-) diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c index f565e5471..3f67b835f 100644 --- a/archival/libarchive/data_extract_all.c +++ b/archival/libarchive/data_extract_all.c @@ -13,13 +13,13 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) int res; #if ENABLE_FEATURE_TAR_SELINUX - char *sctx = archive_handle->tar__next_file_sctx; + char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE]; if (!sctx) - sctx = archive_handle->tar__global_sctx; + sctx = archive_handle->tar__sctx[PAX_GLOBAL]; if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */ setfscreatecon(sctx); - free(archive_handle->tar__next_file_sctx); - archive_handle->tar__next_file_sctx = NULL; + free(archive_handle->tar__sctx[PAX_NEXT_FILE]); + archive_handle->tar__sctx[PAX_NEXT_FILE] = NULL; } #endif diff --git a/archival/libarchive/data_extract_to_command.c b/archival/libarchive/data_extract_to_command.c index cc2ff7798..a2ce33b51 100644 --- a/archival/libarchive/data_extract_to_command.c +++ b/archival/libarchive/data_extract_to_command.c @@ -64,13 +64,13 @@ void FAST_FUNC data_extract_to_command(archive_handle_t *archive_handle) file_header_t *file_header = archive_handle->file_header; #if 0 /* do we need this? ENABLE_FEATURE_TAR_SELINUX */ - char *sctx = archive_handle->tar__next_file_sctx; + char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE]; if (!sctx) - sctx = archive_handle->tar__global_sctx; + sctx = archive_handle->tar__sctx[PAX_GLOBAL]; if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */ setfscreatecon(sctx); - free(archive_handle->tar__next_file_sctx); - archive_handle->tar__next_file_sctx = NULL; + free(archive_handle->tar__sctx[PAX_NEXT_FILE]); + archive_handle->tar__sctx[PAX_NEXT_FILE] = NULL; } #endif diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c index a63c0fb01..8c699754b 100644 --- a/archival/libarchive/get_header_tar.c +++ b/archival/libarchive/get_header_tar.c @@ -90,23 +90,20 @@ static unsigned long long getOctal(char *str, int len) } #define GET_OCTAL(a) getOctal((a), sizeof(a)) -#if ENABLE_FEATURE_TAR_SELINUX -/* Scan a PAX header for SELinux contexts, via "RHT.security.selinux" keyword. - * This is what Red Hat's patched version of tar uses. - */ -# define SELINUX_CONTEXT_KEYWORD "RHT.security.selinux" -static char *get_selinux_sctx_from_pax_hdr(archive_handle_t *archive_handle, unsigned sz) +/* "global" is 0 or 1 */ +static void process_pax_hdr(archive_handle_t *archive_handle, unsigned sz, int global) { char *buf, *p; - char *result; + unsigned blk_sz; + + blk_sz = (sz + 511) & (~511); + p = buf = xmalloc(blk_sz + 1); + xread(archive_handle->src_fd, buf, blk_sz); + archive_handle->offset += blk_sz; - p = buf = xmalloc(sz + 1); /* prevent bb_strtou from running off the buffer */ buf[sz] = '\0'; - xread(archive_handle->src_fd, buf, sz); - archive_handle->offset += sz; - result = NULL; while (sz != 0) { char *end, *value; unsigned len; @@ -133,19 +130,33 @@ static char *get_selinux_sctx_from_pax_hdr(archive_handle_t *archive_handle, uns * (we do not bother to check that it *was* a newline) */ p[-1] = '\0'; - /* Is it selinux security context? */ value = end + 1; + +#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS + if (!global && strncmp(value, "path=", sizeof("path=") - 1) == 0) { + value += sizeof("path=") - 1; + free(archive_handle->tar__longname); + archive_handle->tar__longname = xstrdup(value); + continue; + } +#endif + +#if ENABLE_FEATURE_TAR_SELINUX + /* Scan for SELinux contexts, via "RHT.security.selinux" keyword. + * This is what Red Hat's patched version of tar uses. + */ +# define SELINUX_CONTEXT_KEYWORD "RHT.security.selinux" if (strncmp(value, SELINUX_CONTEXT_KEYWORD"=", sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1) == 0) { value += sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1; - result = xstrdup(value); - break; + free(archive_handle->tar__sctx[global]); + archive_handle->tar__sctx[global] = xstrdup(value); + continue; } +#endif } free(buf); - return result; } -#endif char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) { @@ -418,12 +429,14 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) case 'S': /* Sparse file */ case 'V': /* Volume header */ #endif -#if !ENABLE_FEATURE_TAR_SELINUX case 'g': /* pax global header */ - case 'x': /* pax extended header */ -#else + case 'x': { /* pax extended header */ + if ((uoff_t)file_header->size > 0xfffff) /* paranoia */ + goto skip_ext_hdr; + process_pax_hdr(archive_handle, file_header->size, (tar.typeflag == 'g')); + goto again_after_align; + } skip_ext_hdr: -#endif { off_t sz; bb_error_msg("warning: skipping header '%c'", tar.typeflag); @@ -435,18 +448,6 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) /* return get_header_tar(archive_handle); */ goto again_after_align; } -#if ENABLE_FEATURE_TAR_SELINUX - case 'g': /* pax global header */ - case 'x': { /* pax extended header */ - char **pp; - if ((uoff_t)file_header->size > 0xfffff) /* paranoia */ - goto skip_ext_hdr; - pp = (tar.typeflag == 'g') ? &archive_handle->tar__global_sctx : &archive_handle->tar__next_file_sctx; - free(*pp); - *pp = get_selinux_sctx_from_pax_hdr(archive_handle, file_header->size); - goto again; - } -#endif default: bb_error_msg_and_die("unknown typeflag: 0x%x", tar.typeflag); } diff --git a/include/bb_archive.h b/include/bb_archive.h index d1a9a34ec..4987de6cf 100644 --- a/include/bb_archive.h +++ b/include/bb_archive.h @@ -77,19 +77,20 @@ typedef struct archive_handle_t { off_t offset; /* Archiver specific. Can make it a union if it ever gets big */ +#define PAX_NEXT_FILE 0 +#define PAX_GLOBAL 1 #if ENABLE_TAR || ENABLE_DPKG || ENABLE_DPKG_DEB smallint tar__end; # if ENABLE_FEATURE_TAR_GNU_EXTENSIONS char* tar__longname; char* tar__linkname; # endif -#if ENABLE_FEATURE_TAR_TO_COMMAND +# if ENABLE_FEATURE_TAR_TO_COMMAND char* tar__to_command; const char* tar__to_command_shell; -#endif +# endif # if ENABLE_FEATURE_TAR_SELINUX - char* tar__global_sctx; - char* tar__next_file_sctx; + char* tar__sctx[2]; # endif #endif #if ENABLE_CPIO || ENABLE_RPM2CPIO || ENABLE_RPM -- cgit v1.2.3-55-g6feb From 16c52a5d7bfdfe7f1b9f86a223623a45c7074fa5 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 23 Feb 2012 14:28:47 +0100 Subject: ntpd: increase OPT_qq constant to not collide with -L Signed-off-by: Denys Vlasenko --- networking/ntpd.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/networking/ntpd.c b/networking/ntpd.c index 206af00c7..1df6476c1 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -255,7 +255,7 @@ enum { OPT_S = (1 << 6), OPT_l = (1 << 7) * ENABLE_FEATURE_NTPD_SERVER, /* We hijack some bits for other purposes */ - OPT_qq = (1 << 8), + OPT_qq = (1 << 31), }; struct globals { @@ -606,7 +606,7 @@ filter_datapoints(peer_t *p) sum = SQRT(sum / NUM_DATAPOINTS); p->filter_jitter = sum > G_precision_sec ? sum : G_precision_sec; - VERB3 bb_error_msg("filter offset:%f(corr:%e) disp:%f jitter:%f", + VERB3 bb_error_msg("filter offset:%+f(corr:%e) disp:%f jitter:%f", p->filter_offset, x, p->filter_dispersion, p->filter_jitter); @@ -831,7 +831,7 @@ step_time(double offset) for (item = G.ntp_peers; item != NULL; item = item->link) { peer_t *pp = (peer_t *) item->data; reset_peer_stats(pp, offset); - //bb_error_msg("offset:%f pp->next_action_time:%f -> %f", + //bb_error_msg("offset:%+f pp->next_action_time:%f -> %f", // offset, pp->next_action_time, pp->next_action_time + offset); pp->next_action_time += offset; } @@ -1167,7 +1167,7 @@ select_and_cluster(void) } G.last_update_peer = p; keep_old: - VERB3 bb_error_msg("selected peer %s filter_offset:%f age:%f", + VERB3 bb_error_msg("selected peer %s filter_offset:%+f age:%f", p->p_dotted, p->filter_offset, G.cur_time - p->lastpkt_recv_time @@ -1258,7 +1258,7 @@ update_local_clock(peer_t *p) switch (G.discipline_state) { case STATE_SYNC: /* The first outlyer: ignore it, switch to SPIK state */ - VERB3 bb_error_msg("offset:%f - spike detected", offset); + VERB3 bb_error_msg("offset:%+f - spike detected", offset); G.discipline_state = STATE_SPIK; return -1; /* "decrease poll interval" */ @@ -1295,7 +1295,7 @@ update_local_clock(peer_t *p) * is always suppressed, even at the longer poll * intervals. */ - VERB3 bb_error_msg("stepping time by %f; poll_exp=MINPOLL", offset); + VERB3 bb_error_msg("stepping time by %+f; poll_exp=MINPOLL", offset); step_time(offset); if (option_mask32 & OPT_q) { /* We were only asked to set time once. Done. */ @@ -1319,7 +1319,7 @@ update_local_clock(peer_t *p) } else { /* abs_offset <= STEP_THRESHOLD */ if (G.poll_exp < MINPOLL && G.initial_poll_complete) { - VERB3 bb_error_msg("small offset:%f, disabling burst mode", offset); + VERB3 bb_error_msg("small offset:%+f, disabling burst mode", offset); G.polladj_count = 0; G.poll_exp = MINPOLL; } @@ -1444,7 +1444,7 @@ update_local_clock(peer_t *p) memset(&tmx, 0, sizeof(tmx)); if (adjtimex(&tmx) < 0) bb_perror_msg_and_die("adjtimex"); - VERB3 bb_error_msg("p adjtimex freq:%ld offset:%ld constant:%ld status:0x%x", + VERB3 bb_error_msg("p adjtimex freq:%ld offset:%+ld constant:%ld status:0x%x", tmx.freq, tmx.offset, tmx.constant, tmx.status); } @@ -1476,7 +1476,7 @@ update_local_clock(peer_t *p) /* NB: here kernel returns constant == G.poll_exp, not == G.poll_exp - 4. * Not sure why. Perhaps it is normal. */ - VERB3 bb_error_msg("adjtimex:%d freq:%ld offset:%ld constant:%ld status:0x%x", + VERB3 bb_error_msg("adjtimex:%d freq:%ld offset:%+ld constant:%ld status:0x%x", rc, tmx.freq, tmx.offset, tmx.constant, tmx.status); #if 0 VERB3 { @@ -1484,12 +1484,12 @@ update_local_clock(peer_t *p) memset(&tmx, 0, sizeof(tmx)); if (adjtimex(&tmx) < 0) bb_perror_msg_and_die("adjtimex"); - VERB3 bb_error_msg("c adjtimex freq:%ld offset:%ld constant:%ld status:0x%x", + VERB3 bb_error_msg("c adjtimex freq:%ld offset:%+ld constant:%ld status:0x%x", tmx.freq, tmx.offset, tmx.constant, tmx.status); } #endif G.kernel_freq_drift = tmx.freq / 65536; - VERB2 bb_error_msg("update peer:%s, offset:%f, clock drift:%ld ppm", + VERB2 bb_error_msg("update peer:%s, offset:%+f, clock drift:%+ld ppm", p->p_dotted, G.last_update_offset, G.kernel_freq_drift); return 1; /* "ok to increase poll interval" */ @@ -1633,7 +1633,7 @@ recv_and_process_peer_pkt(peer_t *p) p->reachable_bits |= 1; if ((MAX_VERBOSE && G.verbose) || (option_mask32 & OPT_w)) { - bb_error_msg("reply from %s: reach 0x%02x offset %f delay %f status 0x%02x strat %d refid 0x%08x rootdelay %f", + bb_error_msg("reply from %s: reach 0x%02x offset %+f delay %f status 0x%02x strat %d refid 0x%08x rootdelay %f", p->p_dotted, p->reachable_bits, datapoint->d_offset, @@ -1660,7 +1660,7 @@ recv_and_process_peer_pkt(peer_t *p) * drop poll interval one step down. */ if (fabs(q->filter_offset) >= POLLDOWN_OFFSET) { - VERB3 bb_error_msg("offset:%f > POLLDOWN_OFFSET", q->filter_offset); + VERB3 bb_error_msg("offset:%+f > POLLDOWN_OFFSET", q->filter_offset); goto poll_down; } } @@ -1675,7 +1675,7 @@ recv_and_process_peer_pkt(peer_t *p) * helps calm the dance. Works best using burst mode. */ VERB4 if (rc > 0) { - bb_error_msg("offset:%f POLLADJ_GATE*discipline_jitter:%f poll:%s", + bb_error_msg("offset:%+f POLLADJ_GATE*discipline_jitter:%f poll:%s", q->filter_offset, POLLADJ_GATE * G.discipline_jitter, fabs(q->filter_offset) < POLLADJ_GATE * G.discipline_jitter ? "grows" : "falls" -- cgit v1.2.3-55-g6feb From fc4ebd0d0b189813fa7f8866b0ef590f1ef44f74 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 28 Feb 2012 02:45:00 +0100 Subject: ntpd: fix offset adjustment after step; better step printing Signed-off-by: Denys Vlasenko --- networking/ntpd.c | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/networking/ntpd.c b/networking/ntpd.c index 1df6476c1..a8738951f 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -111,8 +111,8 @@ #define MAXPOLL 12 /* maximum poll interval (12: 1.1h, 17: 36.4h). std ntpd uses 17 */ /* Actively lower poll when we see such big offsets. * With STEP_THRESHOLD = 0.125, it means we try to sync more aggressively - * if offset increases over 0.03 sec */ -#define POLLDOWN_OFFSET (STEP_THRESHOLD / 4) + * if offset increases over ~0.04 sec */ +#define POLLDOWN_OFFSET (STEP_THRESHOLD / 3) #define MINDISP 0.01 /* minimum dispersion (sec) */ #define MAXDISP 16 /* maximum dispersion (sec) */ #define MAXSTRAT 16 /* maximum stratum (infinity metric) */ @@ -127,9 +127,9 @@ * we grow a counter: += MINPOLL. When it goes over POLLADJ_LIMIT, * we poll_exp++. If offset isn't small, counter -= poll_exp*2, * and when it goes below -POLLADJ_LIMIT, we poll_exp-- - * (bumped from 30 to 36 since otherwise I often see poll_exp going *2* steps down) + * (bumped from 30 to 40 since otherwise I often see poll_exp going *2* steps down) */ -#define POLLADJ_LIMIT 36 +#define POLLADJ_LIMIT 40 /* If offset < POLLADJ_GATE * discipline_jitter, then we can increase * poll interval (we think we can't improve timekeeping * by staying at smaller poll). @@ -622,7 +622,11 @@ reset_peer_stats(peer_t *p, double offset) if (small_ofs) { p->filter_datapoint[i].d_recv_time += offset; if (p->filter_datapoint[i].d_offset != 0) { - p->filter_datapoint[i].d_offset += offset; + p->filter_datapoint[i].d_offset -= offset; + //bb_error_msg("p->filter_datapoint[%d].d_offset %f -> %f", + // i, + // p->filter_datapoint[i].d_offset + offset, + // p->filter_datapoint[i].d_offset); } } else { p->filter_datapoint[i].d_recv_time = G.cur_time; @@ -808,22 +812,24 @@ step_time(double offset) { llist_t *item; double dtime; - struct timeval tv; - char buf[80]; + struct timeval tvc, tvn; + char buf[sizeof("yyyy-mm-dd hh:mm:ss") + /*paranoia:*/ 4]; time_t tval; - gettimeofday(&tv, NULL); /* never fails */ - dtime = offset + tv.tv_sec; - dtime += 1.0e-6 * tv.tv_usec; - d_to_tv(dtime, &tv); - - if (settimeofday(&tv, NULL) == -1) + gettimeofday(&tvc, NULL); /* never fails */ + dtime = tvc.tv_sec + (1.0e-6 * tvc.tv_usec) + offset; + d_to_tv(dtime, &tvn); + if (settimeofday(&tvn, NULL) == -1) bb_perror_msg_and_die("settimeofday"); - tval = tv.tv_sec; - strftime(buf, sizeof(buf), "%a %b %e %H:%M:%S %Z %Y", localtime(&tval)); - - bb_error_msg("setting clock to %s (offset %fs)", buf, offset); + VERB2 { + tval = tvc.tv_sec; + strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&tval)); + bb_error_msg("current time is %s.%06u", buf, (unsigned)tvc.tv_usec); + } + tval = tvn.tv_sec; + strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&tval)); + bb_error_msg("setting time to %s.%06u (offset %+fs)", buf, (unsigned)tvn.tv_usec, offset); /* Correct various fields which contain time-relative values: */ -- cgit v1.2.3-55-g6feb From 694738f4eb26e8c46e72be7f9c0be64b3a785161 Mon Sep 17 00:00:00 2001 From: Ian Wienand Date: Tue, 28 Feb 2012 03:10:31 +0100 Subject: du: use long long for size field du has issues with files reporting large block counts on 32-bit systems with 4 byte longs. From looking at the stat.c code, it seems the preference is to use 'long long', rather than blkcnt_t. function old new delta du 420 444 +24 du_main 317 321 +4 print 43 41 -2 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/1 up/down: 28/-2) Total: 26 bytes Signed-off-by: Ian Wienand Signed-off-by: Denys Vlasenko --- coreutils/du.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/coreutils/du.c b/coreutils/du.c index 34a549f02..09a908c69 100644 --- a/coreutils/du.c +++ b/coreutils/du.c @@ -91,7 +91,7 @@ struct globals { #define INIT_G() do { } while (0) -static void print(unsigned long size, const char *filename) +static void print(unsigned long long size, const char *filename) { /* TODO - May not want to defer error checking here. */ #if ENABLE_FEATURE_HUMAN_READABLE @@ -105,15 +105,15 @@ static void print(unsigned long size, const char *filename) size++; size >>= 1; } - printf("%lu\t%s\n", size, filename); + printf("%llu\t%s\n", size, filename); #endif } /* tiny recursive du */ -static unsigned long du(const char *filename) +static unsigned long long du(const char *filename) { struct stat statbuf; - unsigned long sum; + unsigned long long sum; if (lstat(filename, &statbuf) != 0) { bb_simple_perror_msg(filename); @@ -190,7 +190,7 @@ static unsigned long du(const char *filename) int du_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int du_main(int argc UNUSED_PARAM, char **argv) { - unsigned long total; + unsigned long long total; int slink_depth_save; unsigned opt; -- cgit v1.2.3-55-g6feb From 0b170e6a096b0d5010e29a39f3b270c3a7bc4945 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 28 Feb 2012 03:36:49 +0100 Subject: libbb/procps.c: make fast_strtoul_10() stop on '\n' too This is needed for parsing /proc data on linux 2.4 Signed-off-by: Denys Vlasenko --- libbb/procps.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libbb/procps.c b/libbb/procps.c index 0e3f2f9da..c06ff1d70 100644 --- a/libbb/procps.c +++ b/libbb/procps.c @@ -127,7 +127,8 @@ static unsigned long fast_strtoul_16(char **endptr) char *str = *endptr; unsigned long n = 0; - while ((c = *str++) != ' ') { + /* need to stop on both ' ' and '\n' */ + while ((c = *str++) > ' ') { c = ((c|0x20) - '0'); if (c > 9) // c = c + '0' - 'a' + 10: -- cgit v1.2.3-55-g6feb From cd09e81520b7917adebcffd7c361671f913325eb Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Thu, 23 Feb 2012 14:20:22 +0000 Subject: grep: support for -x, match whole line Specified in POSIX. http://pubs.opengroup.org/onlinepubs/009604499/utilities/grep.html Signed-off-by: Natanael Copa Signed-off-by: Denys Vlasenko --- findutils/grep.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/findutils/grep.c b/findutils/grep.c index 5f4224203..f14d6e6c1 100644 --- a/findutils/grep.c +++ b/findutils/grep.c @@ -85,6 +85,7 @@ //usage: "\n -r Recurse" //usage: "\n -i Ignore case" //usage: "\n -w Match whole words only" +//usage: "\n -x Match whole lines only" //usage: "\n -F PATTERN is a literal (not regexp)" //usage: IF_FEATURE_GREP_EGREP_ALIAS( //usage: "\n -E PATTERN is an extended regexp" @@ -113,7 +114,7 @@ //usage:#define fgrep_full_usage "" #define OPTSTR_GREP \ - "lnqvscFiHhe:f:Lorm:w" \ + "lnqvscFiHhe:f:Lorm:wx" \ IF_FEATURE_GREP_CONTEXT("A:B:C:") \ IF_FEATURE_GREP_EGREP_ALIAS("E") \ IF_EXTRA_COMPAT("z") \ @@ -138,6 +139,7 @@ enum { OPTBIT_r, /* recurse dirs */ OPTBIT_m, /* -m MAX_MATCHES */ OPTBIT_w, /* -w whole word match */ + OPTBIT_x, /* -x whole line match */ IF_FEATURE_GREP_CONTEXT( OPTBIT_A ,) /* -A NUM: after-match context */ IF_FEATURE_GREP_CONTEXT( OPTBIT_B ,) /* -B NUM: before-match context */ IF_FEATURE_GREP_CONTEXT( OPTBIT_C ,) /* -C NUM: -A and -B combined */ @@ -160,6 +162,7 @@ enum { OPT_r = 1 << OPTBIT_r, OPT_m = 1 << OPTBIT_m, OPT_w = 1 << OPTBIT_w, + OPT_x = 1 << OPTBIT_x, OPT_A = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_A)) + 0, OPT_B = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_B)) + 0, OPT_C = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_C)) + 0, @@ -370,9 +373,12 @@ static int grep_file(FILE *file) &gl->matched_range) >= 0 #endif ) { - if (!(option_mask32 & OPT_w)) + if (option_mask32 & OPT_x) { + found = (gl->matched_range.rm_so == 0 + && line[gl->matched_range.rm_eo] == '\0'); + } else if (!(option_mask32 & OPT_w)) { found = 1; - else { + } else { char c = ' '; if (gl->matched_range.rm_so) c = line[gl->matched_range.rm_so - 1]; -- cgit v1.2.3-55-g6feb From 62c006d508552a6ac547b807eb9ad0a32a76e1c9 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 28 Feb 2012 11:16:21 +0100 Subject: libbb/procps.c: make fast_strtoul_10() stop on '\n' too This time for real :) Signed-off-by: Denys Vlasenko --- libbb/procps.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libbb/procps.c b/libbb/procps.c index c06ff1d70..40587db82 100644 --- a/libbb/procps.c +++ b/libbb/procps.c @@ -127,11 +127,11 @@ static unsigned long fast_strtoul_16(char **endptr) char *str = *endptr; unsigned long n = 0; - /* need to stop on both ' ' and '\n' */ + /* Need to stop on both ' ' and '\n' */ while ((c = *str++) > ' ') { c = ((c|0x20) - '0'); if (c > 9) - // c = c + '0' - 'a' + 10: + /* c = c + '0' - 'a' + 10: */ c = c - ('a' - '0' - 10); n = n*16 + c; } @@ -144,11 +144,12 @@ static unsigned long fast_strtoul_16(char **endptr) /* We cut a lot of corners here for speed */ static unsigned long fast_strtoul_10(char **endptr) { - char c; + unsigned char c; char *str = *endptr; unsigned long n = *str - '0'; - while ((c = *++str) != ' ') + /* Need to stop on both ' ' and '\n' */ + while ((c = *++str) > ' ') n = n*10 + (c - '0'); *endptr = str + 1; /* We skip trailing space! */ -- cgit v1.2.3-55-g6feb From 3ac066c25670ccf6a992c49340287379c9a342bc Mon Sep 17 00:00:00 2001 From: Yin Kangkai Date: Thu, 23 Feb 2012 15:56:36 +0800 Subject: fbsplash: use line_length instead of xres * bytes_per_pixel In some system (e.g. my "strange" device), line_length is not equal xres * bytes_per_pixel, so we need to use line_length in scr_fix to mmap and draw rectangle etc. My "strange" device output this: bytes_per_pixel: 4 xres: 600, yres: 1024 yoffset: 0, xoffset: 0, line_length: 2432 G.addr: b74da000 Signed-off-by: Yin Kangkai Signed-off-by: Denys Vlasenko --- miscutils/fbsplash.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/miscutils/fbsplash.c b/miscutils/fbsplash.c index 04d583df6..988439b25 100644 --- a/miscutils/fbsplash.c +++ b/miscutils/fbsplash.c @@ -143,7 +143,7 @@ static void fb_open(const char *strfb_device) // map the device in memory G.addr = mmap(NULL, - G.scr_var.xres * G.scr_var.yres * G.bytes_per_pixel, + G.scr_var.yres * G.scr_fix.line_length, PROT_WRITE, MAP_SHARED, fbfd, 0); if (G.addr == MAP_FAILED) bb_perror_msg_and_die("mmap"); @@ -213,8 +213,8 @@ static void fb_drawrectangle(void) thispix = fb_pixel_value(nred, ngreen, nblue); // horizontal lines - ptr1 = G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx) * G.bytes_per_pixel; - ptr2 = G.addr + ((G.nbar_posy + G.nbar_height - 1) * G.scr_var.xres + G.nbar_posx) * G.bytes_per_pixel; + ptr1 = G.addr + G.nbar_posy * G.scr_fix.line_length + G.nbar_posx * G.bytes_per_pixel; + ptr2 = G.addr + (G.nbar_posy + G.nbar_height - 1) * G.scr_fix.line_length + G.nbar_posx * G.bytes_per_pixel; cnt = G.nbar_width - 1; do { fb_write_pixel(ptr1, thispix); @@ -224,14 +224,14 @@ static void fb_drawrectangle(void) } while (--cnt >= 0); // vertical lines - ptr1 = G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx) * G.bytes_per_pixel; - ptr2 = G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx + G.nbar_width - 1) * G.bytes_per_pixel; + ptr1 = G.addr + G.nbar_posy * G.scr_fix.line_length + G.nbar_posx * G.bytes_per_pixel; + ptr2 = G.addr + G.nbar_posy * G.scr_fix.line_length + (G.nbar_posx + G.nbar_width - 1) * G.bytes_per_pixel; cnt = G.nbar_height - 1; do { fb_write_pixel(ptr1, thispix); fb_write_pixel(ptr2, thispix); - ptr1 += G.scr_var.xres * G.bytes_per_pixel; - ptr2 += G.scr_var.xres * G.bytes_per_pixel; + ptr1 += G.scr_fix.line_length; + ptr2 += G.scr_fix.line_length; } while (--cnt >= 0); } @@ -254,7 +254,7 @@ static void fb_drawfullrectangle(int nx1pos, int ny1pos, int nx2pos, int ny2pos, cnt1 = ny2pos - ny1pos; nypos = ny1pos; do { - ptr = G.addr + (nypos * G.scr_var.xres + nx1pos) * G.bytes_per_pixel; + ptr = G.addr + nypos * G.scr_fix.line_length + nx1pos * G.bytes_per_pixel; cnt2 = nx2pos - nx1pos; do { fb_write_pixel(ptr, thispix); -- cgit v1.2.3-55-g6feb From 03a99e3d5c654d3dd8103199e20c8252dab8e091 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 1 Mar 2012 08:36:07 +0100 Subject: date: extend help text to explain compat date format. Closes 4820 Signed-off-by: Denys Vlasenko --- coreutils/date.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/coreutils/date.c b/coreutils/date.c index 6a7d5fac3..767e0d4a2 100644 --- a/coreutils/date.c +++ b/coreutils/date.c @@ -129,6 +129,9 @@ //usage: "\n [YYYY.]MM.DD-hh:mm[:ss]" //usage: "\n YYYY-MM-DD hh:mm[:ss]" //usage: "\n [[[[[YY]YY]MM]DD]hh]mm[.ss]" +//usage: IF_FEATURE_DATE_COMPAT( +//usage: "\n 'date TIME' form accepts MMDDhhmm[[YY]YY][.ss] instead" +//usage: ) //usage: //usage:#define date_example_usage //usage: "$ date\n" -- cgit v1.2.3-55-g6feb From 74584b86656113391763a21ea32fbff6d9fb6a9a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 2 Mar 2012 01:22:40 +0100 Subject: ntpd: log jitter on update too; increase assumed clock precision x2 - to 2ms Signed-off-by: Denys Vlasenko --- networking/ntpd.c | 45 ++++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/networking/ntpd.c b/networking/ntpd.c index a8738951f..e7e992205 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -276,11 +276,12 @@ struct globals { unsigned verbose; unsigned peer_cnt; /* refid: 32-bit code identifying the particular server or reference clock - * in stratum 0 packets this is a four-character ASCII string, - * called the kiss code, used for debugging and monitoring - * in stratum 1 packets this is a four-character ASCII string - * assigned to the reference clock by IANA. Example: "GPS " - * in stratum 2+ packets, it's IPv4 address or 4 first bytes of MD5 hash of IPv6 + * in stratum 0 packets this is a four-character ASCII string, + * called the kiss code, used for debugging and monitoring + * in stratum 1 packets this is a four-character ASCII string + * assigned to the reference clock by IANA. Example: "GPS " + * in stratum 2+ packets, it's IPv4 address or 4 first bytes + * of MD5 hash of IPv6 */ uint32_t refid; uint8_t ntp_status; @@ -289,27 +290,35 @@ struct globals { * mains-frequency clock incrementing at 60 Hz is 16 ms, even when the * system clock hardware representation is to the nanosecond. * - * Delays, jitters of various kinds are clamper down to precision. + * Delays, jitters of various kinds are clamped down to precision. * * If precision_sec is too large, discipline_jitter gets clamped to it - * and if offset is much smaller than discipline_jitter, poll interval - * grows even though we really can benefit from staying at smaller one, - * collecting non-lagged datapoits and correcting the offset. + * and if offset is smaller than discipline_jitter * POLLADJ_GATE, poll + * interval grows even though we really can benefit from staying at + * smaller one, collecting non-lagged datapoits and correcting offset. * (Lagged datapoits exist when poll_exp is large but we still have * systematic offset error - the time distance between datapoints - * is significat and older datapoints have smaller offsets. + * is significant and older datapoints have smaller offsets. * This makes our offset estimation a bit smaller than reality) * Due to this effect, setting G_precision_sec close to * STEP_THRESHOLD isn't such a good idea - offsets may grow * too big and we will step. I observed it with -6. * - * OTOH, setting precision too small would result in futile attempts - * to syncronize to the unachievable precision. + * OTOH, setting precision_sec far too small would result in futile + * attempts to syncronize to an unachievable precision. * * -6 is 1/64 sec, -7 is 1/128 sec and so on. + * -8 is 1/256 ~= 0.003906 (worked well for me --vda) + * -9 is 1/512 ~= 0.001953 (let's try this for some time) */ -#define G_precision_exp -8 -#define G_precision_sec (1.0 / (1 << (- G_precision_exp))) +#define G_precision_exp -9 + /* + * G_precision_exp is used only for construction outgoing packets. + * It's ok to set G_precision_sec to a slightly different value + * (One which is "nicer looking" in logs). + * Exact value would be (1.0 / (1 << (- G_precision_exp))): + */ +#define G_precision_sec 0.002 uint8_t stratum; /* Bool. After set to 1, never goes back to 0: */ smallint initial_poll_complete; @@ -1334,8 +1343,10 @@ update_local_clock(peer_t *p) * weighted offset differences. Used by the poll adjust code. */ etemp = SQUARE(G.discipline_jitter); - dtemp = SQUARE(MAXD(fabs(offset - G.last_update_offset), G_precision_sec)); + dtemp = SQUARE(offset - G.last_update_offset); G.discipline_jitter = SQRT(etemp + (dtemp - etemp) / AVG); + if (G.discipline_jitter < G_precision_sec) + G.discipline_jitter = G_precision_sec; VERB3 bb_error_msg("discipline jitter=%f", G.discipline_jitter); switch (G.discipline_state) { @@ -1495,8 +1506,8 @@ update_local_clock(peer_t *p) } #endif G.kernel_freq_drift = tmx.freq / 65536; - VERB2 bb_error_msg("update peer:%s, offset:%+f, clock drift:%+ld ppm", - p->p_dotted, G.last_update_offset, G.kernel_freq_drift); + VERB2 bb_error_msg("update peer:%s, offset:%+f, jitter:%f, clock drift:%+ld ppm", + p->p_dotted, G.last_update_offset, G.discipline_jitter, G.kernel_freq_drift); return 1; /* "ok to increase poll interval" */ } -- cgit v1.2.3-55-g6feb From b124c3491b8cb86dd7e978c375aa2b83eaca1462 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 2 Mar 2012 15:51:43 +0100 Subject: ntpd: log clock drift with three digits after decimal point +15 bytes. Signed-off-by: Denys Vlasenko --- networking/ntpd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/networking/ntpd.c b/networking/ntpd.c index e7e992205..e86f72f83 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -1506,8 +1506,8 @@ update_local_clock(peer_t *p) } #endif G.kernel_freq_drift = tmx.freq / 65536; - VERB2 bb_error_msg("update peer:%s, offset:%+f, jitter:%f, clock drift:%+ld ppm", - p->p_dotted, G.last_update_offset, G.discipline_jitter, G.kernel_freq_drift); + VERB2 bb_error_msg("update peer:%s, offset:%+f, jitter:%f, clock drift:%+.3f ppm", + p->p_dotted, G.last_update_offset, G.discipline_jitter, (double)tmx.freq / 65536); return 1; /* "ok to increase poll interval" */ } -- cgit v1.2.3-55-g6feb From e8ce285395d801e551811ed3eb9df25a6d46df0e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 3 Mar 2012 12:15:46 +0100 Subject: ntpd: avoid printing messages between send and recv. good for fast networks function old new delta ntpd_main 887 929 +42 Signed-off-by: Denys Vlasenko --- networking/ntpd.c | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/networking/ntpd.c b/networking/ntpd.c index e86f72f83..938c7f040 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -107,7 +107,10 @@ #define FREQ_TOLERANCE 0.000015 /* frequency tolerance (15 PPM) */ #define BURSTPOLL 0 /* initial poll */ #define MINPOLL 5 /* minimum poll interval. std ntpd uses 6 (6: 64 sec) */ -#define BIGPOLL 10 /* drop to lower poll at any trouble (10: 17 min) */ +/* If offset > discipline_jitter * POLLADJ_GATE, and poll interval is >= 2^BIGPOLL, + * then it is decreased _at once_. (If < 2^BIGPOLL, it will be decreased _eventually_). + */ +#define BIGPOLL 10 /* 2^10 sec ~= 17 min */ #define MAXPOLL 12 /* maximum poll interval (12: 1.1h, 17: 36.4h). std ntpd uses 17 */ /* Actively lower poll when we see such big offsets. * With STEP_THRESHOLD = 0.125, it means we try to sync more aggressively @@ -124,13 +127,13 @@ /* Poll-adjust threshold. * When we see that offset is small enough compared to discipline jitter, - * we grow a counter: += MINPOLL. When it goes over POLLADJ_LIMIT, + * we grow a counter: += MINPOLL. When counter goes over POLLADJ_LIMIT, * we poll_exp++. If offset isn't small, counter -= poll_exp*2, - * and when it goes below -POLLADJ_LIMIT, we poll_exp-- - * (bumped from 30 to 40 since otherwise I often see poll_exp going *2* steps down) + * and when it goes below -POLLADJ_LIMIT, we poll_exp--. + * (Bumped from 30 to 40 since otherwise I often see poll_exp going *2* steps down) */ #define POLLADJ_LIMIT 40 -/* If offset < POLLADJ_GATE * discipline_jitter, then we can increase +/* If offset < discipline_jitter * POLLADJ_GATE, then we decide to increase * poll interval (we think we can't improve timekeeping * by staying at smaller poll). */ @@ -732,6 +735,12 @@ send_query_to_peer(peer_t *p) free(local_lsa); } + /* Emit message _before_ attempted send. Think of a very short + * roundtrip networks: we need to go back to recv loop ASAP, + * to reduce delay. Printing messages after send works against that. + */ + VERB1 bb_error_msg("sending query to %s", p->p_dotted); + /* * Send out a random 64-bit number as our transmit time. The NTP * server will copy said number into the originate field on the @@ -759,7 +768,6 @@ send_query_to_peer(peer_t *p) } p->reachable_bits <<= 1; - VERB1 bb_error_msg("sent query to %s", p->p_dotted); set_next(p, RESPONSE_INTERVAL); } @@ -2077,8 +2085,23 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv) timeout++; /* (nextaction - G.cur_time) rounds down, compensating */ /* Here we may block */ - VERB2 bb_error_msg("poll %us, sockets:%u, poll interval:%us", timeout, i, 1 << G.poll_exp); + VERB2 { + if (i > ENABLE_FEATURE_NTPD_SERVER) { + /* We wait for at least one reply. + * Poll for it, without wasting time for message. + * Since replies often come under 1 second, this also + * reduces clutter in logs. + */ + nfds = poll(pfd, i, 1000); + if (nfds != 0) + goto did_poll; + if (--timeout <= 0) + goto did_poll; + } + bb_error_msg("poll %us, sockets:%u, poll interval:%us", timeout, i, 1 << G.poll_exp); + } nfds = poll(pfd, i, timeout * 1000); + did_poll: gettime1900d(); /* sets G.cur_time */ if (nfds <= 0) { if (G.script_name && G.cur_time - G.last_script_run > 11*60) { -- cgit v1.2.3-55-g6feb From 97e528164183c9a9b4768b0d078b3039a1a6ae36 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 3 Mar 2012 13:50:31 +0100 Subject: ntpd: fix the "are we a server" check in previous commit Signed-off-by: Denys Vlasenko --- networking/ntpd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/ntpd.c b/networking/ntpd.c index 938c7f040..ba666b513 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -2086,7 +2086,7 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv) /* Here we may block */ VERB2 { - if (i > ENABLE_FEATURE_NTPD_SERVER) { + if (i > (ENABLE_FEATURE_NTPD_SERVER && G.listen_fd != -1)) { /* We wait for at least one reply. * Poll for it, without wasting time for message. * Since replies often come under 1 second, this also -- cgit v1.2.3-55-g6feb From e8cfc3f693e8a0cbfc489564c76e00c074f63066 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 3 Mar 2012 15:09:07 +0100 Subject: blkid: if parameters are given, do not scan /dev Signed-off-by: Denys Vlasenko --- include/volume_id.h | 2 +- util-linux/blkid.c | 5 ++++- util-linux/volume_id/get_devname.c | 24 ++++++++++++------------ 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/include/volume_id.h b/include/volume_id.h index 4a78cd1e4..a83da899e 100644 --- a/include/volume_id.h +++ b/include/volume_id.h @@ -20,7 +20,7 @@ char *get_devname_from_label(const char *spec); char *get_devname_from_uuid(const char *spec); -void display_uuid_cache(void); +void display_uuid_cache(int scan_devices); /* Returns: * 0: no UUID= or LABEL= prefix found diff --git a/util-linux/blkid.c b/util-linux/blkid.c index a9fd9f361..1bbc80311 100644 --- a/util-linux/blkid.c +++ b/util-linux/blkid.c @@ -18,11 +18,14 @@ int blkid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int blkid_main(int argc UNUSED_PARAM, char **argv) { + int scan_devices = 1; + while (*++argv) { /* Note: bogus device names don't cause any error messages */ add_to_uuid_cache(*argv); + scan_devices = 0; } - display_uuid_cache(); + display_uuid_cache(scan_devices); return 0; } diff --git a/util-linux/volume_id/get_devname.c b/util-linux/volume_id/get_devname.c index d81e24438..230102d89 100644 --- a/util-linux/volume_id/get_devname.c +++ b/util-linux/volume_id/get_devname.c @@ -115,7 +115,7 @@ uuidcache_check_device(const char *device, } static struct uuidCache_s* -uuidcache_init(void) +uuidcache_init(int scan_devices) { dbg("DBG: uuidCache=%x, uuidCache"); if (uuidCache) @@ -131,12 +131,12 @@ uuidcache_init(void) * This is unacceptably complex. Let's just scan /dev. * (Maybe add scanning of /sys/block/XXX/dev for devices * somehow not having their /dev/XXX entries created?) */ - - recursive_action("/dev", ACTION_RECURSE, - uuidcache_check_device, /* file_action */ - NULL, /* dir_action */ - NULL, /* userData */ - 0 /* depth */); + if (scan_devices) + recursive_action("/dev", ACTION_RECURSE, + uuidcache_check_device, /* file_action */ + NULL, /* dir_action */ + NULL, /* userData */ + 0 /* depth */); return uuidCache; } @@ -150,7 +150,7 @@ get_spec_by_x(int n, const char *t, int *majorPtr, int *minorPtr) { struct uuidCache_s *uc; - uc = uuidcache_init(); + uc = uuidcache_init(/*scan_devices:*/ 1); while (uc) { switch (n) { case UUID: @@ -215,11 +215,11 @@ get_spec_by_volume_label(const char *s, int *major, int *minor) #endif // UNUSED /* Used by blkid */ -void display_uuid_cache(void) +void display_uuid_cache(int scan_devices) { struct uuidCache_s *uc; - uc = uuidcache_init(); + uc = uuidcache_init(scan_devices); while (uc) { printf("%s:", uc->device); if (uc->label[0]) @@ -264,7 +264,7 @@ char *get_devname_from_label(const char *spec) { struct uuidCache_s *uc; - uc = uuidcache_init(); + uc = uuidcache_init(/*scan_devices:*/ 1); while (uc) { if (uc->label[0] && strcmp(spec, uc->label) == 0) { return xstrdup(uc->device); @@ -278,7 +278,7 @@ char *get_devname_from_uuid(const char *spec) { struct uuidCache_s *uc; - uc = uuidcache_init(); + uc = uuidcache_init(/*scan_devices:*/ 1); while (uc) { /* case of hex numbers doesn't matter */ if (strcasecmp(spec, uc->uc_uuid) == 0) { -- cgit v1.2.3-55-g6feb From 132b044f4b09cd9334718b3f58dbb498ca63f82e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 5 Mar 2012 00:51:48 +0100 Subject: ntpd: experimental code to correct frequency a bit more aggressively function old new delta update_local_clock 730 792 +62 recv_and_process_peer_pkt 850 835 -15 Signed-off-by: Denys Vlasenko --- networking/ntpd.c | 52 +++++++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/networking/ntpd.c b/networking/ntpd.c index ba666b513..b0bfe440f 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -138,6 +138,7 @@ * by staying at smaller poll). */ #define POLLADJ_GATE 4 +#define TIMECONST_HACK_GATE 2 /* Compromise Allan intercept (sec). doc uses 1500, std ntpd uses 512 */ #define ALLAN 512 /* PLL loop gain */ @@ -339,6 +340,7 @@ struct globals { double last_update_offset; // c.last double last_update_recv_time; // s.t double discipline_jitter; // c.jitter + double offset_to_jitter_ratio; //double cluster_offset; // s.offset //double cluster_jitter; // s.jitter #if !USING_KERNEL_PLL_LOOP @@ -1337,7 +1339,8 @@ update_local_clock(peer_t *p) return 1; /* "ok to increase poll interval" */ } #endif - set_new_values(STATE_SYNC, /*offset:*/ 0, recv_time); + offset = 0; + set_new_values(STATE_SYNC, offset, recv_time); } else { /* abs_offset <= STEP_THRESHOLD */ @@ -1355,6 +1358,7 @@ update_local_clock(peer_t *p) G.discipline_jitter = SQRT(etemp + (dtemp - etemp) / AVG); if (G.discipline_jitter < G_precision_sec) G.discipline_jitter = G_precision_sec; + G.offset_to_jitter_ratio = fabs(offset) / G.discipline_jitter; VERB3 bb_error_msg("discipline jitter=%f", G.discipline_jitter); switch (G.discipline_state) { @@ -1443,7 +1447,7 @@ update_local_clock(peer_t *p) /* We are in STATE_SYNC now, but did not do adjtimex yet. * (Any other state does not reach this, they all return earlier) - * By this time, freq_drift and G.last_update_offset are set + * By this time, freq_drift and offset are set * to values suitable for adjtimex. */ #if !USING_KERNEL_PLL_LOOP @@ -1482,40 +1486,42 @@ update_local_clock(peer_t *p) tmx.modes = ADJ_FREQUENCY | ADJ_OFFSET; /* 65536 is one ppm */ tmx.freq = G.discipline_freq_drift * 65536e6; - tmx.offset = G.last_update_offset * 1000000; /* usec */ #endif tmx.modes = ADJ_OFFSET | ADJ_STATUS | ADJ_TIMECONST;// | ADJ_MAXERROR | ADJ_ESTERROR; - tmx.offset = (G.last_update_offset * 1000000); /* usec */ - /* + (G.last_update_offset < 0 ? -0.5 : 0.5) - too small to bother */ + tmx.offset = (offset * 1000000); /* usec */ tmx.status = STA_PLL; if (G.ntp_status & LI_PLUSSEC) tmx.status |= STA_INS; if (G.ntp_status & LI_MINUSSEC) tmx.status |= STA_DEL; + tmx.constant = G.poll_exp - 4; - //tmx.esterror = (u_int32)(clock_jitter * 1e6); - //tmx.maxerror = (u_int32)((sys_rootdelay / 2 + sys_rootdisp) * 1e6); + /* EXPERIMENTAL. + * The below if statement should be unnecessary, but... + * It looks like Linux kernel's PLL is far too gentle in changing + * tmx.freq in response to clock offset. Offset keeps growing + * and eventually we fall back to smaller poll intervals. + * We can make correction more agressive (about x2) by supplying + * PLL time constant which is one less than the real one. + * To be on a safe side, let's do it only if offset is significantly + * larger than jitter. + */ + if (tmx.constant > 0 && G.offset_to_jitter_ratio > TIMECONST_HACK_GATE) + tmx.constant--; + + //tmx.esterror = (uint32_t)(clock_jitter * 1e6); + //tmx.maxerror = (uint32_t)((sys_rootdelay / 2 + sys_rootdisp) * 1e6); rc = adjtimex(&tmx); if (rc < 0) bb_perror_msg_and_die("adjtimex"); /* NB: here kernel returns constant == G.poll_exp, not == G.poll_exp - 4. * Not sure why. Perhaps it is normal. */ - VERB3 bb_error_msg("adjtimex:%d freq:%ld offset:%+ld constant:%ld status:0x%x", - rc, tmx.freq, tmx.offset, tmx.constant, tmx.status); -#if 0 - VERB3 { - /* always gives the same output as above msg */ - memset(&tmx, 0, sizeof(tmx)); - if (adjtimex(&tmx) < 0) - bb_perror_msg_and_die("adjtimex"); - VERB3 bb_error_msg("c adjtimex freq:%ld offset:%+ld constant:%ld status:0x%x", - tmx.freq, tmx.offset, tmx.constant, tmx.status); - } -#endif + VERB3 bb_error_msg("adjtimex:%d freq:%ld offset:%+ld status:0x%x", + rc, tmx.freq, tmx.offset, tmx.status); G.kernel_freq_drift = tmx.freq / 65536; - VERB2 bb_error_msg("update peer:%s, offset:%+f, jitter:%f, clock drift:%+.3f ppm", - p->p_dotted, G.last_update_offset, G.discipline_jitter, (double)tmx.freq / 65536); + VERB2 bb_error_msg("update peer:%s, offset:%+f, jitter:%f, clock drift:%+.3f ppm, tc:%d", + p->p_dotted, offset, G.discipline_jitter, (double)tmx.freq / 65536, (int)tmx.constant); return 1; /* "ok to increase poll interval" */ } @@ -1651,7 +1657,7 @@ recv_and_process_peer_pkt(peer_t *p) if (!p->reachable_bits) { /* 1st datapoint ever - replicate offset in every element */ int i; - for (i = 1; i < NUM_DATAPOINTS; i++) { + for (i = 0; i < NUM_DATAPOINTS; i++) { p->filter_datapoint[i].d_offset = datapoint->d_offset; } } @@ -1706,7 +1712,7 @@ recv_and_process_peer_pkt(peer_t *p) ? "grows" : "falls" ); } - if (rc > 0 && fabs(q->filter_offset) < POLLADJ_GATE * G.discipline_jitter) { + if (rc > 0 && G.offset_to_jitter_ratio < POLLADJ_GATE) { /* was += G.poll_exp but it is a bit * too optimistic for my taste at high poll_exp's */ G.polladj_count += MINPOLL; -- cgit v1.2.3-55-g6feb From 81b6bf1852174e5b82ad23c18489af9efd2673f1 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 5 Mar 2012 09:52:19 +0100 Subject: du: remove stray whitespace in help text Signed-off-by: Denys Vlasenko --- coreutils/du.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreutils/du.c b/coreutils/du.c index 09a908c69..790ff0f8e 100644 --- a/coreutils/du.c +++ b/coreutils/du.c @@ -40,7 +40,7 @@ //usage: "\n -s Display only a total for each argument" //usage: "\n -x Skip directories on different filesystems" //usage: IF_FEATURE_HUMAN_READABLE( -//usage: "\n -h Sizes in human readable format (e.g., 1K 243M 2G )" +//usage: "\n -h Sizes in human readable format (e.g., 1K 243M 2G)" //usage: "\n -m Sizes in megabytes" //usage: ) //usage: "\n -k Sizes in kilobytes" -- cgit v1.2.3-55-g6feb From bb9254a3b2bfdaf1f1ebf8e14efb2e395de355f5 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 5 Mar 2012 09:59:56 +0100 Subject: du: trim help text a bit more Signed-off-by: Denys Vlasenko --- coreutils/du.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/coreutils/du.c b/coreutils/du.c index 790ff0f8e..19a0319f1 100644 --- a/coreutils/du.c +++ b/coreutils/du.c @@ -26,11 +26,7 @@ //usage:#define du_trivial_usage //usage: "[-aHLdclsx" IF_FEATURE_HUMAN_READABLE("hm") "k] [FILE]..." //usage:#define du_full_usage "\n\n" -//usage: "Summarize disk space used for each FILE and/or directory.\n" -//usage: "Disk space is printed in units of " -//usage: IF_FEATURE_DU_DEFAULT_BLOCKSIZE_1K("1024") -//usage: IF_NOT_FEATURE_DU_DEFAULT_BLOCKSIZE_1K("512") -//usage: " bytes.\n" +//usage: "Summarize disk space used for each FILE and/or directory\n" //usage: "\n -a Show file sizes too" //usage: "\n -L Follow all symlinks" //usage: "\n -H Follow symlinks on command line" @@ -43,8 +39,10 @@ //usage: "\n -h Sizes in human readable format (e.g., 1K 243M 2G)" //usage: "\n -m Sizes in megabytes" //usage: ) -//usage: "\n -k Sizes in kilobytes" -//usage: IF_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(" (default)") +//usage: "\n -k Sizes in kilobytes" IF_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(" (default)") +//usage: IF_NOT_FEATURE_DU_DEFAULT_BLOCKSIZE_1K( +//usage: "\n Default unit is 512 bytes" +//usage: ) //usage: //usage:#define du_example_usage //usage: "$ du\n" -- cgit v1.2.3-55-g6feb From b3439d4727b9813ae373d0015720d49d5a0fc72d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 5 Mar 2012 10:09:18 +0100 Subject: cp: trim help text Signed-off-by: Denys Vlasenko --- coreutils/cp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreutils/cp.c b/coreutils/cp.c index e48e21c97..de2e512be 100644 --- a/coreutils/cp.c +++ b/coreutils/cp.c @@ -16,9 +16,9 @@ */ //usage:#define cp_trivial_usage -//usage: "[OPTIONS] SOURCE DEST" +//usage: "[OPTIONS] SOURCE... DEST" //usage:#define cp_full_usage "\n\n" -//usage: "Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY\n" +//usage: "Copy SOURCE(s) to DEST\n" //usage: "\n -a Same as -dpR" //usage: IF_SELINUX( //usage: "\n -c Preserve security context" -- cgit v1.2.3-55-g6feb From 547ee7926e4107d8c37d768959975f0787a66b3d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 5 Mar 2012 10:18:00 +0100 Subject: ntpd: fix a case when discipline_jitter = 0 if we step Signed-off-by: Denys Vlasenko --- networking/ntpd.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/networking/ntpd.c b/networking/ntpd.c index b0bfe440f..e9805087c 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -340,7 +340,10 @@ struct globals { double last_update_offset; // c.last double last_update_recv_time; // s.t double discipline_jitter; // c.jitter - double offset_to_jitter_ratio; + /* Since we only compare it with ints, can simplify code + * by not making this variable floating point: + */ + unsigned offset_to_jitter_ratio; //double cluster_offset; // s.offset //double cluster_jitter; // s.jitter #if !USING_KERNEL_PLL_LOOP @@ -1339,7 +1342,7 @@ update_local_clock(peer_t *p) return 1; /* "ok to increase poll interval" */ } #endif - offset = 0; + abs_offset = offset = 0; set_new_values(STATE_SYNC, offset, recv_time); } else { /* abs_offset <= STEP_THRESHOLD */ @@ -1356,10 +1359,6 @@ update_local_clock(peer_t *p) etemp = SQUARE(G.discipline_jitter); dtemp = SQUARE(offset - G.last_update_offset); G.discipline_jitter = SQRT(etemp + (dtemp - etemp) / AVG); - if (G.discipline_jitter < G_precision_sec) - G.discipline_jitter = G_precision_sec; - G.offset_to_jitter_ratio = fabs(offset) / G.discipline_jitter; - VERB3 bb_error_msg("discipline jitter=%f", G.discipline_jitter); switch (G.discipline_state) { case STATE_NSET: @@ -1436,6 +1435,10 @@ update_local_clock(peer_t *p) } } + if (G.discipline_jitter < G_precision_sec) + G.discipline_jitter = G_precision_sec; + G.offset_to_jitter_ratio = abs_offset / G.discipline_jitter; + G.reftime = G.cur_time; G.ntp_status = p->lastpkt_status; G.refid = p->lastpkt_refid; @@ -1473,7 +1476,7 @@ update_local_clock(peer_t *p) memset(&tmx, 0, sizeof(tmx)); if (adjtimex(&tmx) < 0) bb_perror_msg_and_die("adjtimex"); - VERB3 bb_error_msg("p adjtimex freq:%ld offset:%+ld constant:%ld status:0x%x", + bb_error_msg("p adjtimex freq:%ld offset:%+ld constant:%ld status:0x%x", tmx.freq, tmx.offset, tmx.constant, tmx.status); } @@ -1506,7 +1509,7 @@ update_local_clock(peer_t *p) * To be on a safe side, let's do it only if offset is significantly * larger than jitter. */ - if (tmx.constant > 0 && G.offset_to_jitter_ratio > TIMECONST_HACK_GATE) + if (tmx.constant > 0 && G.offset_to_jitter_ratio >= TIMECONST_HACK_GATE) tmx.constant--; //tmx.esterror = (uint32_t)(clock_jitter * 1e6); @@ -1520,7 +1523,7 @@ update_local_clock(peer_t *p) VERB3 bb_error_msg("adjtimex:%d freq:%ld offset:%+ld status:0x%x", rc, tmx.freq, tmx.offset, tmx.status); G.kernel_freq_drift = tmx.freq / 65536; - VERB2 bb_error_msg("update peer:%s, offset:%+f, jitter:%f, clock drift:%+.3f ppm, tc:%d", + VERB2 bb_error_msg("update from:%s offset:%+f jitter:%f clock drift:%+.3fppm tc:%d", p->p_dotted, offset, G.discipline_jitter, (double)tmx.freq / 65536, (int)tmx.constant); return 1; /* "ok to increase poll interval" */ @@ -1705,14 +1708,7 @@ recv_and_process_peer_pkt(peer_t *p) * is increased, otherwise it is decreased. A bit of hysteresis * helps calm the dance. Works best using burst mode. */ - VERB4 if (rc > 0) { - bb_error_msg("offset:%+f POLLADJ_GATE*discipline_jitter:%f poll:%s", - q->filter_offset, POLLADJ_GATE * G.discipline_jitter, - fabs(q->filter_offset) < POLLADJ_GATE * G.discipline_jitter - ? "grows" : "falls" - ); - } - if (rc > 0 && G.offset_to_jitter_ratio < POLLADJ_GATE) { + if (rc > 0 && G.offset_to_jitter_ratio <= POLLADJ_GATE) { /* was += G.poll_exp but it is a bit * too optimistic for my taste at high poll_exp's */ G.polladj_count += MINPOLL; -- cgit v1.2.3-55-g6feb From fa737cebe7fc3be0c74b1a9958e73d0626fd5b02 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 5 Mar 2012 14:22:33 +0100 Subject: uuencode: tweak help text Signed-off-by: Denys Vlasenko --- coreutils/uuencode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreutils/uuencode.c b/coreutils/uuencode.c index 84a489a11..673ef36e7 100644 --- a/coreutils/uuencode.c +++ b/coreutils/uuencode.c @@ -9,9 +9,9 @@ */ //usage:#define uuencode_trivial_usage -//usage: "[-m] [INFILE] STORED_FILENAME" +//usage: "[-m] [FILE] STORED_FILENAME" //usage:#define uuencode_full_usage "\n\n" -//usage: "Uuencode a file to stdout\n" +//usage: "Uuencode FILE (or stdin) to stdout\n" //usage: "\n -m Use base64 encoding per RFC1521" //usage: //usage:#define uuencode_example_usage -- cgit v1.2.3-55-g6feb From 11e61d5c7116cb83794a270b4fc9e2a1fadaa5cd Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 5 Mar 2012 14:23:26 +0100 Subject: uudecode: tweak help text Signed-off-by: Denys Vlasenko --- coreutils/uudecode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreutils/uudecode.c b/coreutils/uudecode.c index 23ff711fa..b298fcb95 100644 --- a/coreutils/uudecode.c +++ b/coreutils/uudecode.c @@ -15,7 +15,7 @@ //usage: "[-o OUTFILE] [INFILE]" //usage:#define uudecode_full_usage "\n\n" //usage: "Uudecode a file\n" -//usage: "Finds outfile name in uuencoded source unless -o is given" +//usage: "Finds OUTFILE in uuencoded source unless -o is given" //usage: //usage:#define uudecode_example_usage //usage: "$ uudecode -o busybox busybox.uu\n" -- cgit v1.2.3-55-g6feb From 17eedcad9406c43beddab3906c8c693626c351fb Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 5 Mar 2012 16:28:07 +0100 Subject: ssd: compat: match -x EXECUTABLE by /proc/pid/exe too Signed-off-by: Denys Vlasenko --- debianutils/start_stop_daemon.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c index 495ed0a09..7dadc3c9e 100644 --- a/debianutils/start_stop_daemon.c +++ b/debianutils/start_stop_daemon.c @@ -31,7 +31,8 @@ Options controlling process matching [TODO: can PROCESS_NAME be a full pathname? Should we require full match then with /proc/$PID/exe or argv[0] (comm can't be matched, it never contains path)] -x,--exec EXECUTABLE Look for processes that were started with this - command in /proc/$PID/cmdline. + command in /proc/$PID/exe and /proc/$PID/cmdline + (/proc/$PID/cmdline is a bbox extension) Unlike -n, we match against the full path: "ntpd" != "./ntpd" != "/path/to/ntpd" -p,--pidfile PID_FILE Look for processes with PID from this file @@ -68,7 +69,7 @@ Misc options: //usage: "\n -n,--name NAME Match processes with NAME" //usage: "\n in comm field in /proc/PID/stat" //usage: "\n -x,--exec EXECUTABLE Match processes with this command" -//usage: "\n in /proc/PID/cmdline" +//usage: "\n in /proc/PID/{exe,cmdline}" //usage: "\n -p,--pidfile FILE Match a process with PID from the file" //usage: "\n All specified conditions must match" //usage: "\n-S only:" @@ -198,8 +199,18 @@ static int pid_is_exec(pid_t pid) { ssize_t bytes; char buf[sizeof("/proc/%u/cmdline") + sizeof(int)*3]; + char *procname, *exelink; + int match; - sprintf(buf, "/proc/%u/cmdline", (unsigned)pid); + procname = buf + sprintf(buf, "/proc/%u/exe", (unsigned)pid) - 3; + + exelink = xmalloc_readlink(buf); + match = (exelink && strcmp(execname, exelink) == 0); + free(exelink); + if (match) + return match; + + strcpy(procname, "cmdline"); bytes = open_read_close(buf, G.execname_cmpbuf, G.execname_sizeof); if (bytes > 0) { G.execname_cmpbuf[bytes] = '\0'; -- cgit v1.2.3-55-g6feb From 59655077c5bf176f01d8d277665ebb92263704ed Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 6 Mar 2012 16:23:50 +0100 Subject: preparatory cleanups for seamless uncompression improvements unpack_gz_stream_with_info: fix buggy error check man: fix possible accesses past the end of a string move seamless uncompression helpers from read_printf.c to open_transformer.c function old new delta show_manpage 153 212 +59 unpack_gz_stream_with_info 520 539 +19 Signed-off-by: Denys Vlasenko --- archival/libarchive/decompress_uncompress.c | 12 +-- archival/libarchive/decompress_unzip.c | 26 +++--- archival/libarchive/open_transformer.c | 140 ++++++++++++++++++++++++++++ include/libbb.h | 8 ++ libbb/read_printf.c | 139 --------------------------- miscutils/man.c | 41 ++++---- 6 files changed, 187 insertions(+), 179 deletions(-) diff --git a/archival/libarchive/decompress_uncompress.c b/archival/libarchive/decompress_uncompress.c index c6040d04b..289f9e233 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(int fd_in, int fd_out) +unpack_Z_stream(int src_fd, int dst_fd) { IF_DESKTOP(long long total_written = 0;) IF_DESKTOP(long long) int retval = -1; @@ -105,14 +105,14 @@ unpack_Z_stream(int fd_in, int fd_out) inbuf = xzalloc(IBUFSIZ + 64); outbuf = xzalloc(OBUFSIZ + 2048); - htab = xzalloc(HSIZE); /* wsn't zeroed out before, maybe can xmalloc? */ + htab = xzalloc(HSIZE); /* wasn't zeroed out before, maybe can xmalloc? */ codetab = xzalloc(HSIZE * sizeof(codetab[0])); insize = 0; /* 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(fd_in, inbuf, 1) != 1) { + if (full_read(src_fd, inbuf, 1) != 1) { bb_error_msg("short read"); goto err; } @@ -162,7 +162,7 @@ unpack_Z_stream(int fd_in, int fd_out) } if (insize < (int) (IBUFSIZ + 64) - IBUFSIZ) { - rsize = safe_read(fd_in, inbuf + insize, IBUFSIZ); + rsize = safe_read(src_fd, inbuf + insize, IBUFSIZ); if (rsize < 0) bb_error_msg_and_die(bb_msg_read_error); insize += rsize; @@ -268,7 +268,7 @@ unpack_Z_stream(int fd_in, int fd_out) } if (outpos >= OBUFSIZ) { - xwrite(fd_out, outbuf, outpos); + xwrite(dst_fd, outbuf, outpos); IF_DESKTOP(total_written += outpos;) outpos = 0; } @@ -296,7 +296,7 @@ unpack_Z_stream(int fd_in, int fd_out) } while (rsize > 0); if (outpos > 0) { - xwrite(fd_out, outbuf, outpos); + xwrite(dst_fd, outbuf, outpos); IF_DESKTOP(total_written += outpos;) } diff --git a/archival/libarchive/decompress_unzip.c b/archival/libarchive/decompress_unzip.c index aa5d22d0a..50873e3f6 100644 --- a/archival/libarchive/decompress_unzip.c +++ b/archival/libarchive/decompress_unzip.c @@ -1182,33 +1182,37 @@ static int check_header_gzip(STATE_PARAM unpack_info_t *info) } IF_DESKTOP(long long) int FAST_FUNC -unpack_gz_stream_with_info(int in, int out, unpack_info_t *info) +unpack_gz_stream_with_info(int src_fd, int dst_fd, unpack_info_t *info) { uint32_t v32; - IF_DESKTOP(long long) int n; + IF_DESKTOP(long long) int total, n; DECLARE_STATE; - n = 0; + total = 0; ALLOC_STATE; to_read = -1; // bytebuffer_max = 0x8000; bytebuffer = xmalloc(bytebuffer_max); - gunzip_src_fd = in; + gunzip_src_fd = src_fd; again: if (!check_header_gzip(PASS_STATE info)) { bb_error_msg("corrupted data"); - n = -1; + total = -1; goto ret; } - n += inflate_unzip_internal(PASS_STATE in, out); - if (n < 0) + + n = inflate_unzip_internal(PASS_STATE src_fd, dst_fd); + if (n < 0) { + total = -1; goto ret; + } + total += n; if (!top_up(PASS_STATE 8)) { bb_error_msg("corrupted data"); - n = -1; + total = -1; goto ret; } @@ -1216,7 +1220,7 @@ unpack_gz_stream_with_info(int in, int out, unpack_info_t *info) v32 = buffer_read_le_u32(PASS_STATE_ONLY); if ((~gunzip_crc) != v32) { bb_error_msg("crc error"); - n = -1; + total = -1; goto ret; } @@ -1224,7 +1228,7 @@ unpack_gz_stream_with_info(int in, int out, unpack_info_t *info) v32 = buffer_read_le_u32(PASS_STATE_ONLY); if ((uint32_t)gunzip_bytes_out != v32) { bb_error_msg("incorrect length"); - n = -1; + total = -1; } if (!top_up(PASS_STATE 2)) @@ -1242,7 +1246,7 @@ unpack_gz_stream_with_info(int in, int out, unpack_info_t *info) ret: free(bytebuffer); DEALLOC_STATE; - return n; + return total; } IF_DESKTOP(long long) int FAST_FUNC diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c index aa8c1021c..743ffee02 100644 --- a/archival/libarchive/open_transformer.c +++ b/archival/libarchive/open_transformer.c @@ -6,6 +6,16 @@ #include "libbb.h" #include "bb_archive.h" +#define ZIPPED (ENABLE_FEATURE_SEAMLESS_LZMA \ + || ENABLE_FEATURE_SEAMLESS_BZ2 \ + || ENABLE_FEATURE_SEAMLESS_GZ \ + /* || ENABLE_FEATURE_SEAMLESS_Z */ \ +) + +#if ZIPPED +# include "bb_archive.h" +#endif + /* transformer(), more than meets the eye */ /* * On MMU machine, the transform_prog is removed by macro magic @@ -52,3 +62,133 @@ void FAST_FUNC open_transformer(int fd, close(fd_pipe.wr); /* don't want to write to the child */ xmove_fd(fd_pipe.rd, fd); } + + +/* Used by e.g. rpm which gives us a fd without filename, + * thus we can't guess the format from filename's extension. + */ +#if ZIPPED +void FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) +{ + const int fail_if_not_detected = 1; + union { + uint8_t b[4]; + uint16_t b16[2]; + uint32_t b32[1]; + } magic; + int offset = -2; +# if BB_MMU + IF_DESKTOP(long long) int FAST_FUNC (*xformer)(int src_fd, int dst_fd); + enum { xformer_prog = 0 }; +# else + enum { xformer = 0 }; + const char *xformer_prog; +# endif + + /* .gz and .bz2 both have 2-byte signature, and their + * unpack_XXX_stream wants this header skipped. */ + xread(fd, magic.b16, sizeof(magic.b16[0])); + if (ENABLE_FEATURE_SEAMLESS_GZ + && magic.b16[0] == GZIP_MAGIC + ) { +# if BB_MMU + xformer = unpack_gz_stream; +# else + xformer_prog = "gunzip"; +# endif + goto found_magic; + } + if (ENABLE_FEATURE_SEAMLESS_BZ2 + && magic.b16[0] == BZIP2_MAGIC + ) { +# if BB_MMU + xformer = unpack_bz2_stream; +# else + xformer_prog = "bunzip2"; +# endif + goto found_magic; + } + if (ENABLE_FEATURE_SEAMLESS_XZ + && magic.b16[0] == XZ_MAGIC1 + ) { + offset = -6; + xread(fd, magic.b32, sizeof(magic.b32[0])); + if (magic.b32[0] == XZ_MAGIC2) { +# if BB_MMU + xformer = unpack_xz_stream; + /* unpack_xz_stream wants fd at position 6, no need to seek */ + //xlseek(fd, offset, SEEK_CUR); +# else + xformer_prog = "unxz"; +# endif + goto found_magic; + } + } + + /* No known magic seen */ + if (fail_if_not_detected) + bb_error_msg_and_die("no gzip" + IF_FEATURE_SEAMLESS_BZ2("/bzip2") + IF_FEATURE_SEAMLESS_XZ("/xz") + " magic"); + xlseek(fd, offset, SEEK_CUR); + return; + + found_magic: +# if !BB_MMU + /* NOMMU version of open_transformer execs + * an external unzipper that wants + * file position at the start of the file */ + xlseek(fd, offset, SEEK_CUR); +# endif + open_transformer(fd, xformer, xformer_prog); +} +#endif /* ZIPPED */ + +int FAST_FUNC open_zipped(const char *fname) +{ +#if !ZIPPED + return open(fname, O_RDONLY); +#else + char *sfx; + int fd; + + fd = open(fname, O_RDONLY); + if (fd < 0) + return fd; + + sfx = strrchr(fname, '.'); + if (sfx) { + sfx++; + if (ENABLE_FEATURE_SEAMLESS_LZMA && strcmp(sfx, "lzma") == 0) + /* .lzma has no header/signature, just trust it */ + open_transformer(fd, unpack_lzma_stream, "unlzma"); + else + if ((ENABLE_FEATURE_SEAMLESS_GZ && strcmp(sfx, "gz") == 0) + || (ENABLE_FEATURE_SEAMLESS_BZ2 && strcmp(sfx, "bz2") == 0) + || (ENABLE_FEATURE_SEAMLESS_XZ && strcmp(sfx, "xz") == 0) + ) { + setup_unzip_on_fd(fd /*, fail_if_not_detected: 1*/); + } + } + + return fd; +#endif +} + +void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) +{ + int fd; + char *image; + + fd = open_zipped(fname); + if (fd < 0) + return NULL; + + image = xmalloc_read(fd, maxsz_p); + if (!image) + bb_perror_msg("read error from '%s'", fname); + close(fd); + + return image; +} diff --git a/include/libbb.h b/include/libbb.h index f743bdfc6..c896e5484 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -713,6 +713,14 @@ extern void *xmalloc_read(int fd, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; extern void *xmalloc_open_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; /* Never returns NULL */ extern void *xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; + +#define SEAMLESS_COMPRESSION (0 \ + || ENABLE_FEATURE_SEAMLESS_XZ \ + || ENABLE_FEATURE_SEAMLESS_LZMA \ + || ENABLE_FEATURE_SEAMLESS_BZ2 \ + || ENABLE_FEATURE_SEAMLESS_GZ \ + || ENABLE_FEATURE_SEAMLESS_Z) + /* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */ #if ENABLE_FEATURE_SEAMLESS_LZMA \ || ENABLE_FEATURE_SEAMLESS_BZ2 \ diff --git a/libbb/read_printf.c b/libbb/read_printf.c index 0bbf7802a..5ed6e3632 100644 --- a/libbb/read_printf.c +++ b/libbb/read_printf.c @@ -8,16 +8,6 @@ */ #include "libbb.h" -#define ZIPPED (ENABLE_FEATURE_SEAMLESS_LZMA \ - || ENABLE_FEATURE_SEAMLESS_BZ2 \ - || ENABLE_FEATURE_SEAMLESS_GZ \ - /* || ENABLE_FEATURE_SEAMLESS_Z */ \ -) - -#if ZIPPED -# include "bb_archive.h" -#endif - /* Suppose that you are a shell. You start child processes. * They work and eventually exit. You want to get user input. @@ -244,132 +234,3 @@ void* FAST_FUNC xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p) bb_perror_msg_and_die("can't read '%s'", filename); return buf; } - -/* Used by e.g. rpm which gives us a fd without filename, - * thus we can't guess the format from filename's extension. - */ -#if ZIPPED -void FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) -{ - const int fail_if_not_detected = 1; - union { - uint8_t b[4]; - uint16_t b16[2]; - uint32_t b32[1]; - } magic; - int offset = -2; -# if BB_MMU - IF_DESKTOP(long long) int FAST_FUNC (*xformer)(int src_fd, int dst_fd); - enum { xformer_prog = 0 }; -# else - enum { xformer = 0 }; - const char *xformer_prog; -# endif - - /* .gz and .bz2 both have 2-byte signature, and their - * unpack_XXX_stream wants this header skipped. */ - xread(fd, magic.b16, sizeof(magic.b16[0])); - if (ENABLE_FEATURE_SEAMLESS_GZ - && magic.b16[0] == GZIP_MAGIC - ) { -# if BB_MMU - xformer = unpack_gz_stream; -# else - xformer_prog = "gunzip"; -# endif - goto found_magic; - } - if (ENABLE_FEATURE_SEAMLESS_BZ2 - && magic.b16[0] == BZIP2_MAGIC - ) { -# if BB_MMU - xformer = unpack_bz2_stream; -# else - xformer_prog = "bunzip2"; -# endif - goto found_magic; - } - if (ENABLE_FEATURE_SEAMLESS_XZ - && magic.b16[0] == XZ_MAGIC1 - ) { - offset = -6; - xread(fd, magic.b32, sizeof(magic.b32[0])); - if (magic.b32[0] == XZ_MAGIC2) { -# if BB_MMU - xformer = unpack_xz_stream; - /* unpack_xz_stream wants fd at position 6, no need to seek */ - //xlseek(fd, offset, SEEK_CUR); -# else - xformer_prog = "unxz"; -# endif - goto found_magic; - } - } - - /* No known magic seen */ - if (fail_if_not_detected) - bb_error_msg_and_die("no gzip" - IF_FEATURE_SEAMLESS_BZ2("/bzip2") - IF_FEATURE_SEAMLESS_XZ("/xz") - " magic"); - xlseek(fd, offset, SEEK_CUR); - return; - - found_magic: -# if !BB_MMU - /* NOMMU version of open_transformer execs - * an external unzipper that wants - * file position at the start of the file */ - xlseek(fd, offset, SEEK_CUR); -# endif - open_transformer(fd, xformer, xformer_prog); -} -#endif /* ZIPPED */ - -int FAST_FUNC open_zipped(const char *fname) -{ -#if !ZIPPED - return open(fname, O_RDONLY); -#else - char *sfx; - int fd; - - fd = open(fname, O_RDONLY); - if (fd < 0) - return fd; - - sfx = strrchr(fname, '.'); - if (sfx) { - sfx++; - if (ENABLE_FEATURE_SEAMLESS_LZMA && strcmp(sfx, "lzma") == 0) - /* .lzma has no header/signature, just trust it */ - open_transformer(fd, unpack_lzma_stream, "unlzma"); - else - if ((ENABLE_FEATURE_SEAMLESS_GZ && strcmp(sfx, "gz") == 0) - || (ENABLE_FEATURE_SEAMLESS_BZ2 && strcmp(sfx, "bz2") == 0) - || (ENABLE_FEATURE_SEAMLESS_XZ && strcmp(sfx, "xz") == 0) - ) { - setup_unzip_on_fd(fd /*, fail_if_not_detected: 1*/); - } - } - - return fd; -#endif -} - -void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) -{ - int fd; - char *image; - - fd = open_zipped(fname); - if (fd < 0) - return NULL; - - image = xmalloc_read(fd, maxsz_p); - if (!image) - bb_perror_msg("read error from '%s'", fname); - close(fd); - - return image; -} diff --git a/miscutils/man.c b/miscutils/man.c index 3bf7e84b6..611466349 100644 --- a/miscutils/man.c +++ b/miscutils/man.c @@ -30,16 +30,6 @@ echo ".pl \n(nlu+10" */ -#if ENABLE_FEATURE_SEAMLESS_LZMA -#define Z_SUFFIX ".lzma" -#elif ENABLE_FEATURE_SEAMLESS_BZ2 -#define Z_SUFFIX ".bz2" -#elif ENABLE_FEATURE_SEAMLESS_GZ -#define Z_SUFFIX ".gz" -#else -#define Z_SUFFIX "" -#endif - static int show_manpage(const char *pager, char *man_filename, int man, int level); static int run_pipe(const char *pager, char *man_filename, int man, int level) @@ -102,7 +92,7 @@ static int run_pipe(const char *pager, char *man_filename, int man, int level) /* Links do not have .gz extensions, even if manpage * is compressed */ - man_filename = xasprintf("%s/%s" Z_SUFFIX, man_filename, linkname); + man_filename = xasprintf("%s/%s", man_filename, linkname); free(line); /* Note: we leak "new" man_filename string as well... */ if (show_manpage(pager, man_filename, man, level + 1)) @@ -124,32 +114,37 @@ static int run_pipe(const char *pager, char *man_filename, int man, int level) return 1; } -/* man_filename is of the form "/dir/dir/dir/name.s" Z_SUFFIX */ +/* man_filename is of the form "/dir/dir/dir/name.s" */ static int show_manpage(const char *pager, char *man_filename, int man, int level) { +#if SEAMLESS_COMPRESSION + /* We leak this allocation... */ + char *filename_with_zext = xasprintf("%s.lzma", man_filename); + char *ext = strrchr(filename_with_zext, '.') + 1; +#endif + #if ENABLE_FEATURE_SEAMLESS_LZMA + if (run_pipe(pager, filename_with_zext, man, level)) + return 1; +#endif +#if ENABLE_FEATURE_SEAMLESS_XZ + strcpy(ext, "xz"); if (run_pipe(pager, man_filename, man, level)) return 1; #endif - #if ENABLE_FEATURE_SEAMLESS_BZ2 -#if ENABLE_FEATURE_SEAMLESS_LZMA - strcpy(strrchr(man_filename, '.') + 1, "bz2"); -#endif + strcpy(ext, "bz2"); if (run_pipe(pager, man_filename, man, level)) return 1; #endif - #if ENABLE_FEATURE_SEAMLESS_GZ -#if ENABLE_FEATURE_SEAMLESS_LZMA || ENABLE_FEATURE_SEAMLESS_BZ2 - strcpy(strrchr(man_filename, '.') + 1, "gz"); -#endif + strcpy(ext, "gz"); if (run_pipe(pager, man_filename, man, level)) return 1; #endif -#if ENABLE_FEATURE_SEAMLESS_LZMA || ENABLE_FEATURE_SEAMLESS_BZ2 || ENABLE_FEATURE_SEAMLESS_GZ - *strrchr(man_filename, '.') = '\0'; +#if SEAMLESS_COMPRESSION + ext[-1] = '\0'; #endif if (run_pipe(pager, man_filename, man, level)) return 1; @@ -262,7 +257,7 @@ int man_main(int argc UNUSED_PARAM, char **argv) /* Search for cat, then man page */ while (cat0man1 < 2) { int found_here; - man_filename = xasprintf("%s/%s%.*s/%s.%.*s" Z_SUFFIX, + man_filename = xasprintf("%s/%s%.*s/%s.%.*s", cur_path, "cat\0man" + (cat0man1 * 4), sect_len, cur_sect, -- cgit v1.2.3-55-g6feb From 774bce8e8ba1e424c953e8f13aee8f0778c8a911 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 6 Mar 2012 16:26:20 +0100 Subject: archival/libarchive/decompress_unzip.c -> decompress_gunzip.c. no code changes Signed-off-by: Denys Vlasenko --- archival/libarchive/Kbuild.src | 10 +- archival/libarchive/decompress_gunzip.c | 1256 +++++++++++++++++++++++++++++++ archival/libarchive/decompress_unzip.c | 1256 ------------------------------- docs/keep_data_small.txt | 2 +- 4 files changed, 1262 insertions(+), 1262 deletions(-) create mode 100644 archival/libarchive/decompress_gunzip.c delete mode 100644 archival/libarchive/decompress_unzip.c diff --git a/archival/libarchive/Kbuild.src b/archival/libarchive/Kbuild.src index b0bc4e5aa..a0a7cca5f 100644 --- a/archival/libarchive/Kbuild.src +++ b/archival/libarchive/Kbuild.src @@ -42,16 +42,16 @@ lib-$(CONFIG_UNXZ) += decompress_unxz.o lib-$(CONFIG_CPIO) += get_header_cpio.o lib-$(CONFIG_DPKG) += $(DPKG_FILES) lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES) -lib-$(CONFIG_GUNZIP) += decompress_unzip.o -lib-$(CONFIG_RPM2CPIO) += decompress_unzip.o get_header_cpio.o -lib-$(CONFIG_RPM) += open_transformer.o decompress_unzip.o get_header_cpio.o +lib-$(CONFIG_GUNZIP) += decompress_gunzip.o +lib-$(CONFIG_RPM2CPIO) += decompress_gunzip.o get_header_cpio.o +lib-$(CONFIG_RPM) += open_transformer.o decompress_gunzip.o get_header_cpio.o lib-$(CONFIG_TAR) += get_header_tar.o lib-$(CONFIG_UNCOMPRESS) += decompress_uncompress.o -lib-$(CONFIG_UNZIP) += decompress_unzip.o +lib-$(CONFIG_UNZIP) += decompress_gunzip.o lib-$(CONFIG_LZOP) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o lib-$(CONFIG_LZOP_COMPR_HIGH) += lzo1x_9x.o lib-$(CONFIG_FEATURE_SEAMLESS_Z) += open_transformer.o decompress_uncompress.o -lib-$(CONFIG_FEATURE_SEAMLESS_GZ) += open_transformer.o decompress_unzip.o get_header_tar_gz.o +lib-$(CONFIG_FEATURE_SEAMLESS_GZ) += open_transformer.o decompress_gunzip.o get_header_tar_gz.o lib-$(CONFIG_FEATURE_SEAMLESS_BZ2) += open_transformer.o decompress_bunzip2.o get_header_tar_bz2.o lib-$(CONFIG_FEATURE_SEAMLESS_LZMA) += open_transformer.o decompress_unlzma.o get_header_tar_lzma.o lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o diff --git a/archival/libarchive/decompress_gunzip.c b/archival/libarchive/decompress_gunzip.c new file mode 100644 index 000000000..50873e3f6 --- /dev/null +++ b/archival/libarchive/decompress_gunzip.c @@ -0,0 +1,1256 @@ +/* vi: set sw=4 ts=4: */ +/* + * gunzip implementation for busybox + * + * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly. + * + * Originally adjusted for busybox by Sven Rudolph + * based on gzip sources + * + * Adjusted further by Erik Andersen to support + * files as well as stdin/stdout, and to generally behave itself wrt + * command line handling. + * + * General cleanup to better adhere to the style guide and make use of standard + * busybox functions by Glenn McGrath + * + * read_gz interface + associated hacking by Laurence Anderson + * + * Fixed huft_build() so decoding end-of-block code does not grab more bits + * than necessary (this is required by unzip applet), added inflate_cleanup() + * to free leaked bytebuffer memory (used in unzip.c), and some minor style + * guide cleanups by Ed Clark + * + * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface + * Copyright (C) 1992-1993 Jean-loup Gailly + * The unzip code was written and put in the public domain by Mark Adler. + * Portions of the lzw code are derived from the public domain 'compress' + * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies, + * Ken Turkowski, Dave Mack and Peter Jannesen. + * + * See the file algorithm.doc for the compression algorithms and file formats. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#include +#include "libbb.h" +#include "bb_archive.h" + +typedef struct huft_t { + unsigned char e; /* number of extra bits or operation */ + unsigned char b; /* number of bits in this code or subcode */ + union { + unsigned short n; /* literal, length base, or distance base */ + struct huft_t *t; /* pointer to next level of table */ + } v; +} huft_t; + +enum { + /* gunzip_window size--must be a power of two, and + * at least 32K for zip's deflate method */ + GUNZIP_WSIZE = 0x8000, + /* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ + BMAX = 16, /* maximum bit length of any code (16 for explode) */ + N_MAX = 288, /* maximum number of codes in any set */ +}; + + +/* This is somewhat complex-looking arrangement, but it allows + * to place decompressor state either in bss or in + * malloc'ed space simply by changing #defines below. + * Sizes on i386: + * text data bss dec hex + * 5256 0 108 5364 14f4 - bss + * 4915 0 0 4915 1333 - malloc + */ +#define STATE_IN_BSS 0 +#define STATE_IN_MALLOC 1 + + +typedef struct state_t { + off_t gunzip_bytes_out; /* number of output bytes */ + uint32_t gunzip_crc; + + int gunzip_src_fd; + unsigned gunzip_outbuf_count; /* bytes in output buffer */ + + unsigned char *gunzip_window; + + uint32_t *gunzip_crc_table; + + /* bitbuffer */ + unsigned gunzip_bb; /* bit buffer */ + unsigned char gunzip_bk; /* bits in bit buffer */ + + /* input (compressed) data */ + unsigned char *bytebuffer; /* buffer itself */ + off_t to_read; /* compressed bytes to read (unzip only, -1 for gunzip) */ +// unsigned bytebuffer_max; /* buffer size */ + unsigned bytebuffer_offset; /* buffer position */ + unsigned bytebuffer_size; /* how much data is there (size <= max) */ + + /* private data of inflate_codes() */ + unsigned inflate_codes_ml; /* masks for bl and bd bits */ + unsigned inflate_codes_md; /* masks for bl and bd bits */ + unsigned inflate_codes_bb; /* bit buffer */ + unsigned inflate_codes_k; /* number of bits in bit buffer */ + unsigned inflate_codes_w; /* current gunzip_window position */ + huft_t *inflate_codes_tl; + huft_t *inflate_codes_td; + unsigned inflate_codes_bl; + unsigned inflate_codes_bd; + unsigned inflate_codes_nn; /* length and index for copy */ + unsigned inflate_codes_dd; + + smallint resume_copy; + + /* private data of inflate_get_next_window() */ + smallint method; /* method == -1 for stored, -2 for codes */ + smallint need_another_block; + smallint end_reached; + + /* private data of inflate_stored() */ + unsigned inflate_stored_n; + unsigned inflate_stored_b; + unsigned inflate_stored_k; + unsigned inflate_stored_w; + + const char *error_msg; + jmp_buf error_jmp; +} state_t; +#define gunzip_bytes_out (S()gunzip_bytes_out ) +#define gunzip_crc (S()gunzip_crc ) +#define gunzip_src_fd (S()gunzip_src_fd ) +#define gunzip_outbuf_count (S()gunzip_outbuf_count) +#define gunzip_window (S()gunzip_window ) +#define gunzip_crc_table (S()gunzip_crc_table ) +#define gunzip_bb (S()gunzip_bb ) +#define gunzip_bk (S()gunzip_bk ) +#define to_read (S()to_read ) +// #define bytebuffer_max (S()bytebuffer_max ) +// Both gunzip and unzip can use constant buffer size now (16k): +#define bytebuffer_max 0x4000 +#define bytebuffer (S()bytebuffer ) +#define bytebuffer_offset (S()bytebuffer_offset ) +#define bytebuffer_size (S()bytebuffer_size ) +#define inflate_codes_ml (S()inflate_codes_ml ) +#define inflate_codes_md (S()inflate_codes_md ) +#define inflate_codes_bb (S()inflate_codes_bb ) +#define inflate_codes_k (S()inflate_codes_k ) +#define inflate_codes_w (S()inflate_codes_w ) +#define inflate_codes_tl (S()inflate_codes_tl ) +#define inflate_codes_td (S()inflate_codes_td ) +#define inflate_codes_bl (S()inflate_codes_bl ) +#define inflate_codes_bd (S()inflate_codes_bd ) +#define inflate_codes_nn (S()inflate_codes_nn ) +#define inflate_codes_dd (S()inflate_codes_dd ) +#define resume_copy (S()resume_copy ) +#define method (S()method ) +#define need_another_block (S()need_another_block ) +#define end_reached (S()end_reached ) +#define inflate_stored_n (S()inflate_stored_n ) +#define inflate_stored_b (S()inflate_stored_b ) +#define inflate_stored_k (S()inflate_stored_k ) +#define inflate_stored_w (S()inflate_stored_w ) +#define error_msg (S()error_msg ) +#define error_jmp (S()error_jmp ) + +/* This is a generic part */ +#if STATE_IN_BSS /* Use global data segment */ +#define DECLARE_STATE /*nothing*/ +#define ALLOC_STATE /*nothing*/ +#define DEALLOC_STATE ((void)0) +#define S() state. +#define PASS_STATE /*nothing*/ +#define PASS_STATE_ONLY /*nothing*/ +#define STATE_PARAM /*nothing*/ +#define STATE_PARAM_ONLY void +static state_t state; +#endif + +#if STATE_IN_MALLOC /* Use malloc space */ +#define DECLARE_STATE state_t *state +#define ALLOC_STATE (state = xzalloc(sizeof(*state))) +#define DEALLOC_STATE free(state) +#define S() state-> +#define PASS_STATE state, +#define PASS_STATE_ONLY state +#define STATE_PARAM state_t *state, +#define STATE_PARAM_ONLY state_t *state +#endif + + +static const uint16_t mask_bits[] ALIGN2 = { + 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +/* Copy lengths for literal codes 257..285 */ +static const uint16_t cplens[] ALIGN2 = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, + 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 +}; + +/* note: see note #13 above about the 258 in this list. */ +/* Extra bits for literal codes 257..285 */ +static const uint8_t cplext[] ALIGN1 = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, + 5, 5, 5, 0, 99, 99 +}; /* 99 == invalid */ + +/* Copy offsets for distance codes 0..29 */ +static const uint16_t cpdist[] ALIGN2 = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, + 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 +}; + +/* Extra bits for distance codes */ +static const uint8_t cpdext[] ALIGN1 = { + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, + 11, 11, 12, 12, 13, 13 +}; + +/* Tables for deflate from PKZIP's appnote.txt. */ +/* Order of the bit length code lengths */ +static const uint8_t border[] ALIGN1 = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 +}; + + +/* + * Free the malloc'ed tables built by huft_build(), which makes a linked + * list of the tables it made, with the links in a dummy first entry of + * each table. + * t: table to free + */ +static void huft_free(huft_t *p) +{ + huft_t *q; + + /* Go through linked list, freeing from the malloced (t[-1]) address. */ + while (p) { + q = (--p)->v.t; + free(p); + p = q; + } +} + +static void huft_free_all(STATE_PARAM_ONLY) +{ + huft_free(inflate_codes_tl); + huft_free(inflate_codes_td); + inflate_codes_tl = NULL; + inflate_codes_td = NULL; +} + +static void abort_unzip(STATE_PARAM_ONLY) NORETURN; +static void abort_unzip(STATE_PARAM_ONLY) +{ + huft_free_all(PASS_STATE_ONLY); + longjmp(error_jmp, 1); +} + +static unsigned fill_bitbuffer(STATE_PARAM unsigned bitbuffer, unsigned *current, const unsigned required) +{ + while (*current < required) { + if (bytebuffer_offset >= bytebuffer_size) { + unsigned sz = bytebuffer_max - 4; + if (to_read >= 0 && to_read < sz) /* unzip only */ + sz = to_read; + /* Leave the first 4 bytes empty so we can always unwind the bitbuffer + * to the front of the bytebuffer */ + bytebuffer_size = safe_read(gunzip_src_fd, &bytebuffer[4], sz); + if ((int)bytebuffer_size < 1) { + error_msg = "unexpected end of file"; + abort_unzip(PASS_STATE_ONLY); + } + if (to_read >= 0) /* unzip only */ + to_read -= bytebuffer_size; + bytebuffer_size += 4; + bytebuffer_offset = 4; + } + bitbuffer |= ((unsigned) bytebuffer[bytebuffer_offset]) << *current; + bytebuffer_offset++; + *current += 8; + } + return bitbuffer; +} + + +/* Given a list of code lengths and a maximum table size, make a set of + * tables to decode that set of codes. Return zero on success, one if + * the given code set is incomplete (the tables are still built in this + * case), two if the input is invalid (all zero length codes or an + * oversubscribed set of lengths) - in this case stores NULL in *t. + * + * b: code lengths in bits (all assumed <= BMAX) + * n: number of codes (assumed <= N_MAX) + * s: number of simple-valued codes (0..s-1) + * d: list of base values for non-simple codes + * e: list of extra bits for non-simple codes + * t: result: starting table + * m: maximum lookup bits, returns actual + */ +static int huft_build(const unsigned *b, const unsigned n, + const unsigned s, const unsigned short *d, + const unsigned char *e, huft_t **t, unsigned *m) +{ + unsigned a; /* counter for codes of length k */ + unsigned c[BMAX + 1]; /* bit length count table */ + unsigned eob_len; /* length of end-of-block code (value 256) */ + unsigned f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int htl; /* table level */ + unsigned i; /* counter, current code */ + unsigned j; /* counter */ + int k; /* number of bits in current code */ + unsigned *p; /* pointer into c[], b[], or v[] */ + huft_t *q; /* points to current table */ + huft_t r; /* table entry for structure assignment */ + huft_t *u[BMAX]; /* table stack */ + unsigned v[N_MAX]; /* values in order of bit length */ + int ws[BMAX + 1]; /* bits decoded stack */ + int w; /* bits decoded */ + unsigned x[BMAX + 1]; /* bit offsets, then code stack */ + unsigned *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + unsigned z; /* number of entries in current table */ + + /* Length of EOB code, if any */ + eob_len = n > 256 ? b[256] : BMAX; + + *t = NULL; + + /* Generate counts for each bit length */ + memset(c, 0, sizeof(c)); + p = (unsigned *) b; /* cast allows us to reuse p for pointing to b */ + i = n; + do { + c[*p]++; /* assume all entries <= BMAX */ + p++; /* can't combine with above line (Solaris bug) */ + } while (--i); + if (c[0] == n) { /* null input - all zero length codes */ + *m = 0; + return 2; + } + + /* Find minimum and maximum length, bound *m by those */ + for (j = 1; (c[j] == 0) && (j <= BMAX); j++) + continue; + k = j; /* minimum code length */ + for (i = BMAX; (c[i] == 0) && i; i--) + continue; + g = i; /* maximum code length */ + *m = (*m < j) ? j : ((*m > i) ? i : *m); + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) { + y -= c[j]; + if (y < 0) + return 2; /* bad input: more codes than bits */ + } + y -= c[i]; + if (y < 0) + return 2; + c[i] += y; + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; + xp = x + 2; + while (--i) { /* note that i == g from above */ + j += *p++; + *xp++ = j; + } + + /* Make a table of values in order of bit lengths */ + p = (unsigned *) b; + i = 0; + do { + j = *p++; + if (j != 0) { + v[x[j]++] = i; + } + } while (++i < n); + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + htl = -1; /* no tables yet--level -1 */ + w = ws[0] = 0; /* bits decoded */ + u[0] = NULL; /* just to keep compilers happy */ + q = NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) { + a = c[k]; + while (a--) { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > ws[htl + 1]) { + w = ws[++htl]; + + /* compute minimum size table less than or equal to *m bits */ + z = g - w; + z = z > *m ? *m : z; /* upper limit on table size */ + j = k - w; + f = 1 << j; + if (f > a + 1) { /* try a k-w bit table */ + /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + while (++j < z) { /* try smaller tables up to z bits */ + f <<= 1; + if (f <= *++xp) { + break; /* enough codes to use up j bits */ + } + f -= *xp; /* else deduct codes from patterns */ + } + } + j = (w + j > eob_len && w < eob_len) ? eob_len - w : j; /* make EOB code end at table */ + z = 1 << j; /* table entries for j-bit table */ + ws[htl+1] = w + j; /* set bits decoded in stack */ + + /* allocate and link in new table */ + q = xzalloc((z + 1) * sizeof(huft_t)); + *t = q + 1; /* link to list for huft_free() */ + t = &(q->v.t); + u[htl] = ++q; /* table starts after link */ + + /* connect to last table, if there is one */ + if (htl) { + x[htl] = i; /* save pattern for backing up */ + r.b = (unsigned char) (w - ws[htl - 1]); /* bits to dump before this table */ + r.e = (unsigned char) (16 + j); /* bits in this table */ + r.v.t = q; /* pointer to this table */ + j = (i & ((1 << w) - 1)) >> ws[htl - 1]; + u[htl - 1][j] = r; /* connect to last table */ + } + } + + /* set up table entry in r */ + r.b = (unsigned char) (k - w); + if (p >= v + n) { + r.e = 99; /* out of values--invalid code */ + } else if (*p < s) { + r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is EOB code */ + r.v.n = (unsigned short) (*p++); /* simple code is just the value */ + } else { + r.e = (unsigned char) e[*p - s]; /* non-simple--look up in lists */ + r.v.n = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) { + q[j] = r; + } + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) { + i ^= j; + } + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != x[htl]) { + w = ws[--htl]; + } + } + } + + /* return actual size of base table */ + *m = ws[1]; + + /* Return 1 if we were given an incomplete table */ + return y != 0 && g != 1; +} + + +/* + * inflate (decompress) the codes in a deflated (compressed) block. + * Return an error code or zero if it all goes ok. + * + * tl, td: literal/length and distance decoder tables + * bl, bd: number of bits decoded by tl[] and td[] + */ +/* called once from inflate_block */ + +/* map formerly local static variables to globals */ +#define ml inflate_codes_ml +#define md inflate_codes_md +#define bb inflate_codes_bb +#define k inflate_codes_k +#define w inflate_codes_w +#define tl inflate_codes_tl +#define td inflate_codes_td +#define bl inflate_codes_bl +#define bd inflate_codes_bd +#define nn inflate_codes_nn +#define dd inflate_codes_dd +static void inflate_codes_setup(STATE_PARAM unsigned my_bl, unsigned my_bd) +{ + bl = my_bl; + bd = my_bd; + /* make local copies of globals */ + bb = gunzip_bb; /* initialize bit buffer */ + k = gunzip_bk; + w = gunzip_outbuf_count; /* initialize gunzip_window position */ + /* inflate the coded data */ + ml = mask_bits[bl]; /* precompute masks for speed */ + md = mask_bits[bd]; +} +/* called once from inflate_get_next_window */ +static NOINLINE int inflate_codes(STATE_PARAM_ONLY) +{ + unsigned e; /* table entry flag/number of extra bits */ + huft_t *t; /* pointer to table entry */ + + if (resume_copy) + goto do_copy; + + while (1) { /* do until end of block */ + bb = fill_bitbuffer(PASS_STATE bb, &k, bl); + t = tl + ((unsigned) bb & ml); + e = t->e; + if (e > 16) + do { + if (e == 99) + abort_unzip(PASS_STATE_ONLY);; + bb >>= t->b; + k -= t->b; + e -= 16; + bb = fill_bitbuffer(PASS_STATE bb, &k, e); + t = t->v.t + ((unsigned) bb & mask_bits[e]); + e = t->e; + } while (e > 16); + bb >>= t->b; + k -= t->b; + if (e == 16) { /* then it's a literal */ + gunzip_window[w++] = (unsigned char) t->v.n; + if (w == GUNZIP_WSIZE) { + gunzip_outbuf_count = w; + //flush_gunzip_window(); + w = 0; + return 1; // We have a block to read + } + } else { /* it's an EOB or a length */ + /* exit if end of block */ + if (e == 15) { + break; + } + + /* get length of block to copy */ + bb = fill_bitbuffer(PASS_STATE bb, &k, e); + nn = t->v.n + ((unsigned) bb & mask_bits[e]); + bb >>= e; + k -= e; + + /* decode distance of block to copy */ + bb = fill_bitbuffer(PASS_STATE bb, &k, bd); + t = td + ((unsigned) bb & md); + e = t->e; + if (e > 16) + do { + if (e == 99) + abort_unzip(PASS_STATE_ONLY); + bb >>= t->b; + k -= t->b; + e -= 16; + bb = fill_bitbuffer(PASS_STATE bb, &k, e); + t = t->v.t + ((unsigned) bb & mask_bits[e]); + e = t->e; + } while (e > 16); + bb >>= t->b; + k -= t->b; + bb = fill_bitbuffer(PASS_STATE bb, &k, e); + dd = w - t->v.n - ((unsigned) bb & mask_bits[e]); + bb >>= e; + k -= e; + + /* do the copy */ + do_copy: + do { + /* Was: nn -= (e = (e = GUNZIP_WSIZE - ((dd &= GUNZIP_WSIZE - 1) > w ? dd : w)) > nn ? nn : e); */ + /* Who wrote THAT?? rewritten as: */ + unsigned delta; + + dd &= GUNZIP_WSIZE - 1; + e = GUNZIP_WSIZE - (dd > w ? dd : w); + delta = w > dd ? w - dd : dd - w; + if (e > nn) e = nn; + nn -= e; + + /* copy to new buffer to prevent possible overwrite */ + if (delta >= e) { + memcpy(gunzip_window + w, gunzip_window + dd, e); + w += e; + dd += e; + } else { + /* do it slow to avoid memcpy() overlap */ + /* !NOMEMCPY */ + do { + gunzip_window[w++] = gunzip_window[dd++]; + } while (--e); + } + if (w == GUNZIP_WSIZE) { + gunzip_outbuf_count = w; + resume_copy = (nn != 0); + //flush_gunzip_window(); + w = 0; + return 1; + } + } while (nn); + resume_copy = 0; + } + } + + /* restore the globals from the locals */ + gunzip_outbuf_count = w; /* restore global gunzip_window pointer */ + gunzip_bb = bb; /* restore global bit buffer */ + gunzip_bk = k; + + /* normally just after call to inflate_codes, but save code by putting it here */ + /* free the decoding tables (tl and td), return */ + huft_free_all(PASS_STATE_ONLY); + + /* done */ + return 0; +} +#undef ml +#undef md +#undef bb +#undef k +#undef w +#undef tl +#undef td +#undef bl +#undef bd +#undef nn +#undef dd + + +/* called once from inflate_block */ +static void inflate_stored_setup(STATE_PARAM int my_n, int my_b, int my_k) +{ + inflate_stored_n = my_n; + inflate_stored_b = my_b; + inflate_stored_k = my_k; + /* initialize gunzip_window position */ + inflate_stored_w = gunzip_outbuf_count; +} +/* called once from inflate_get_next_window */ +static int inflate_stored(STATE_PARAM_ONLY) +{ + /* read and output the compressed data */ + while (inflate_stored_n--) { + inflate_stored_b = fill_bitbuffer(PASS_STATE inflate_stored_b, &inflate_stored_k, 8); + gunzip_window[inflate_stored_w++] = (unsigned char) inflate_stored_b; + if (inflate_stored_w == GUNZIP_WSIZE) { + gunzip_outbuf_count = inflate_stored_w; + //flush_gunzip_window(); + inflate_stored_w = 0; + inflate_stored_b >>= 8; + inflate_stored_k -= 8; + return 1; /* We have a block */ + } + inflate_stored_b >>= 8; + inflate_stored_k -= 8; + } + + /* restore the globals from the locals */ + gunzip_outbuf_count = inflate_stored_w; /* restore global gunzip_window pointer */ + gunzip_bb = inflate_stored_b; /* restore global bit buffer */ + gunzip_bk = inflate_stored_k; + return 0; /* Finished */ +} + + +/* + * decompress an inflated block + * e: last block flag + * + * GLOBAL VARIABLES: bb, kk, + */ +/* Return values: -1 = inflate_stored, -2 = inflate_codes */ +/* One callsite in inflate_get_next_window */ +static int inflate_block(STATE_PARAM smallint *e) +{ + unsigned ll[286 + 30]; /* literal/length and distance code lengths */ + unsigned t; /* block type */ + unsigned b; /* bit buffer */ + unsigned k; /* number of bits in bit buffer */ + + /* make local bit buffer */ + + b = gunzip_bb; + k = gunzip_bk; + + /* read in last block bit */ + b = fill_bitbuffer(PASS_STATE b, &k, 1); + *e = b & 1; + b >>= 1; + k -= 1; + + /* read in block type */ + b = fill_bitbuffer(PASS_STATE b, &k, 2); + t = (unsigned) b & 3; + b >>= 2; + k -= 2; + + /* restore the global bit buffer */ + gunzip_bb = b; + gunzip_bk = k; + + /* Do we see block type 1 often? Yes! + * TODO: fix performance problem (see below) */ + //bb_error_msg("blktype %d", t); + + /* inflate that block type */ + switch (t) { + case 0: /* Inflate stored */ + { + unsigned n; /* number of bytes in block */ + unsigned b_stored; /* bit buffer */ + unsigned k_stored; /* number of bits in bit buffer */ + + /* make local copies of globals */ + b_stored = gunzip_bb; /* initialize bit buffer */ + k_stored = gunzip_bk; + + /* go to byte boundary */ + n = k_stored & 7; + b_stored >>= n; + k_stored -= n; + + /* get the length and its complement */ + b_stored = fill_bitbuffer(PASS_STATE b_stored, &k_stored, 16); + n = ((unsigned) b_stored & 0xffff); + b_stored >>= 16; + k_stored -= 16; + + b_stored = fill_bitbuffer(PASS_STATE b_stored, &k_stored, 16); + if (n != (unsigned) ((~b_stored) & 0xffff)) { + abort_unzip(PASS_STATE_ONLY); /* error in compressed data */ + } + b_stored >>= 16; + k_stored -= 16; + + inflate_stored_setup(PASS_STATE n, b_stored, k_stored); + + return -1; + } + case 1: + /* Inflate fixed + * decompress an inflated type 1 (fixed Huffman codes) block. We should + * either replace this with a custom decoder, or at least precompute the + * Huffman tables. TODO */ + { + int i; /* temporary variable */ + unsigned bl; /* lookup bits for tl */ + unsigned bd; /* lookup bits for td */ + /* gcc 4.2.1 is too dumb to reuse stackspace. Moved up... */ + //unsigned ll[288]; /* length list for huft_build */ + + /* set up literal table */ + for (i = 0; i < 144; i++) + ll[i] = 8; + for (; i < 256; i++) + ll[i] = 9; + for (; i < 280; i++) + ll[i] = 7; + for (; i < 288; i++) /* make a complete, but wrong code set */ + ll[i] = 8; + bl = 7; + huft_build(ll, 288, 257, cplens, cplext, &inflate_codes_tl, &bl); + /* huft_build() never return nonzero - we use known data */ + + /* set up distance table */ + for (i = 0; i < 30; i++) /* make an incomplete code set */ + ll[i] = 5; + bd = 5; + huft_build(ll, 30, 0, cpdist, cpdext, &inflate_codes_td, &bd); + + /* set up data for inflate_codes() */ + inflate_codes_setup(PASS_STATE bl, bd); + + /* huft_free code moved into inflate_codes */ + + return -2; + } + case 2: /* Inflate dynamic */ + { + enum { dbits = 6 }; /* bits in base distance lookup table */ + enum { lbits = 9 }; /* bits in base literal/length lookup table */ + + huft_t *td; /* distance code table */ + unsigned i; /* temporary variables */ + unsigned j; + unsigned l; /* last length */ + unsigned m; /* mask for bit lengths table */ + unsigned n; /* number of lengths to get */ + unsigned bl; /* lookup bits for tl */ + unsigned bd; /* lookup bits for td */ + unsigned nb; /* number of bit length codes */ + unsigned nl; /* number of literal/length codes */ + unsigned nd; /* number of distance codes */ + + //unsigned ll[286 + 30];/* literal/length and distance code lengths */ + unsigned b_dynamic; /* bit buffer */ + unsigned k_dynamic; /* number of bits in bit buffer */ + + /* make local bit buffer */ + b_dynamic = gunzip_bb; + k_dynamic = gunzip_bk; + + /* read in table lengths */ + b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 5); + nl = 257 + ((unsigned) b_dynamic & 0x1f); /* number of literal/length codes */ + + b_dynamic >>= 5; + k_dynamic -= 5; + b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 5); + nd = 1 + ((unsigned) b_dynamic & 0x1f); /* number of distance codes */ + + b_dynamic >>= 5; + k_dynamic -= 5; + b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 4); + nb = 4 + ((unsigned) b_dynamic & 0xf); /* number of bit length codes */ + + b_dynamic >>= 4; + k_dynamic -= 4; + if (nl > 286 || nd > 30) + abort_unzip(PASS_STATE_ONLY); /* bad lengths */ + + /* read in bit-length-code lengths */ + for (j = 0; j < nb; j++) { + b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 3); + ll[border[j]] = (unsigned) b_dynamic & 7; + b_dynamic >>= 3; + k_dynamic -= 3; + } + for (; j < 19; j++) + ll[border[j]] = 0; + + /* build decoding table for trees - single level, 7 bit lookup */ + bl = 7; + i = huft_build(ll, 19, 19, NULL, NULL, &inflate_codes_tl, &bl); + if (i != 0) { + abort_unzip(PASS_STATE_ONLY); //return i; /* incomplete code set */ + } + + /* read in literal and distance code lengths */ + n = nl + nd; + m = mask_bits[bl]; + i = l = 0; + while ((unsigned) i < n) { + b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, (unsigned)bl); + td = inflate_codes_tl + ((unsigned) b_dynamic & m); + j = td->b; + b_dynamic >>= j; + k_dynamic -= j; + j = td->v.n; + if (j < 16) { /* length of code in bits (0..15) */ + ll[i++] = l = j; /* save last length in l */ + } else if (j == 16) { /* repeat last length 3 to 6 times */ + b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 2); + j = 3 + ((unsigned) b_dynamic & 3); + b_dynamic >>= 2; + k_dynamic -= 2; + if ((unsigned) i + j > n) { + abort_unzip(PASS_STATE_ONLY); //return 1; + } + while (j--) { + ll[i++] = l; + } + } else if (j == 17) { /* 3 to 10 zero length codes */ + b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 3); + j = 3 + ((unsigned) b_dynamic & 7); + b_dynamic >>= 3; + k_dynamic -= 3; + if ((unsigned) i + j > n) { + abort_unzip(PASS_STATE_ONLY); //return 1; + } + while (j--) { + ll[i++] = 0; + } + l = 0; + } else { /* j == 18: 11 to 138 zero length codes */ + b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 7); + j = 11 + ((unsigned) b_dynamic & 0x7f); + b_dynamic >>= 7; + k_dynamic -= 7; + if ((unsigned) i + j > n) { + abort_unzip(PASS_STATE_ONLY); //return 1; + } + while (j--) { + ll[i++] = 0; + } + l = 0; + } + } + + /* free decoding table for trees */ + huft_free(inflate_codes_tl); + + /* restore the global bit buffer */ + gunzip_bb = b_dynamic; + gunzip_bk = k_dynamic; + + /* build the decoding tables for literal/length and distance codes */ + bl = lbits; + + i = huft_build(ll, nl, 257, cplens, cplext, &inflate_codes_tl, &bl); + if (i != 0) + abort_unzip(PASS_STATE_ONLY); + bd = dbits; + i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &inflate_codes_td, &bd); + if (i != 0) + abort_unzip(PASS_STATE_ONLY); + + /* set up data for inflate_codes() */ + inflate_codes_setup(PASS_STATE bl, bd); + + /* huft_free code moved into inflate_codes */ + + return -2; + } + default: + abort_unzip(PASS_STATE_ONLY); + } +} + +/* Two callsites, both in inflate_get_next_window */ +static void calculate_gunzip_crc(STATE_PARAM_ONLY) +{ + gunzip_crc = crc32_block_endian0(gunzip_crc, gunzip_window, gunzip_outbuf_count, gunzip_crc_table); + gunzip_bytes_out += gunzip_outbuf_count; +} + +/* One callsite in inflate_unzip_internal */ +static int inflate_get_next_window(STATE_PARAM_ONLY) +{ + gunzip_outbuf_count = 0; + + while (1) { + int ret; + + if (need_another_block) { + if (end_reached) { + calculate_gunzip_crc(PASS_STATE_ONLY); + end_reached = 0; + /* NB: need_another_block is still set */ + return 0; /* Last block */ + } + method = inflate_block(PASS_STATE &end_reached); + need_another_block = 0; + } + + switch (method) { + case -1: + ret = inflate_stored(PASS_STATE_ONLY); + break; + case -2: + ret = inflate_codes(PASS_STATE_ONLY); + break; + default: /* cannot happen */ + abort_unzip(PASS_STATE_ONLY); + } + + if (ret == 1) { + calculate_gunzip_crc(PASS_STATE_ONLY); + return 1; /* more data left */ + } + need_another_block = 1; /* end of that block */ + } + /* Doesnt get here */ +} + + +/* Called from unpack_gz_stream() and inflate_unzip() */ +static IF_DESKTOP(long long) int +inflate_unzip_internal(STATE_PARAM int in, int out) +{ + IF_DESKTOP(long long) int n = 0; + ssize_t nwrote; + + /* Allocate all global buffers (for DYN_ALLOC option) */ + gunzip_window = xmalloc(GUNZIP_WSIZE); + gunzip_outbuf_count = 0; + gunzip_bytes_out = 0; + gunzip_src_fd = in; + + /* (re) initialize state */ + method = -1; + need_another_block = 1; + resume_copy = 0; + gunzip_bk = 0; + gunzip_bb = 0; + + /* Create the crc table */ + gunzip_crc_table = crc32_filltable(NULL, 0); + gunzip_crc = ~0; + + error_msg = "corrupted data"; + if (setjmp(error_jmp)) { + /* Error from deep inside zip machinery */ + n = -1; + goto ret; + } + + 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"); + n = -1; + goto ret; + } + IF_DESKTOP(n += nwrote;) + if (r == 0) break; + } + + /* Store unused bytes in a global buffer so calling applets can access it */ + if (gunzip_bk >= 8) { + /* Undo too much lookahead. The next read will be byte aligned + * so we can discard unused bits in the last meaningful byte. */ + bytebuffer_offset--; + bytebuffer[bytebuffer_offset] = gunzip_bb & 0xff; + gunzip_bb >>= 8; + gunzip_bk -= 8; + } + ret: + /* Cleanup */ + free(gunzip_window); + free(gunzip_crc_table); + return n; +} + + +/* External entry points */ + +/* For unzip */ + +IF_DESKTOP(long long) int FAST_FUNC +inflate_unzip(inflate_unzip_result *res, off_t compr_size, int in, int out) +{ + IF_DESKTOP(long long) int n; + DECLARE_STATE; + + ALLOC_STATE; + + to_read = compr_size; +// bytebuffer_max = 0x8000; + bytebuffer_offset = 4; + bytebuffer = xmalloc(bytebuffer_max); + n = inflate_unzip_internal(PASS_STATE in, out); + free(bytebuffer); + + res->crc = gunzip_crc; + res->bytes_out = gunzip_bytes_out; + DEALLOC_STATE; + return n; +} + + +/* For gunzip */ + +/* helpers first */ + +/* Top up the input buffer with at least n bytes. */ +static int top_up(STATE_PARAM unsigned n) +{ + int count = bytebuffer_size - bytebuffer_offset; + + if (count < (int)n) { + memmove(bytebuffer, &bytebuffer[bytebuffer_offset], count); + bytebuffer_offset = 0; + bytebuffer_size = full_read(gunzip_src_fd, &bytebuffer[count], bytebuffer_max - count); + if ((int)bytebuffer_size < 0) { + bb_error_msg(bb_msg_read_error); + return 0; + } + bytebuffer_size += count; + if (bytebuffer_size < n) + return 0; + } + return 1; +} + +static uint16_t buffer_read_le_u16(STATE_PARAM_ONLY) +{ + uint16_t res; +#if BB_LITTLE_ENDIAN + move_from_unaligned16(res, &bytebuffer[bytebuffer_offset]); +#else + res = bytebuffer[bytebuffer_offset]; + res |= bytebuffer[bytebuffer_offset + 1] << 8; +#endif + bytebuffer_offset += 2; + return res; +} + +static uint32_t buffer_read_le_u32(STATE_PARAM_ONLY) +{ + uint32_t res; +#if BB_LITTLE_ENDIAN + move_from_unaligned32(res, &bytebuffer[bytebuffer_offset]); +#else + res = bytebuffer[bytebuffer_offset]; + res |= bytebuffer[bytebuffer_offset + 1] << 8; + res |= bytebuffer[bytebuffer_offset + 2] << 16; + res |= bytebuffer[bytebuffer_offset + 3] << 24; +#endif + bytebuffer_offset += 4; + return res; +} + +static int check_header_gzip(STATE_PARAM unpack_info_t *info) +{ + union { + unsigned char raw[8]; + struct { + uint8_t gz_method; + uint8_t flags; + uint32_t mtime; + uint8_t xtra_flags_UNUSED; + uint8_t os_flags_UNUSED; + } PACKED formatted; + } header; + struct BUG_header { + char BUG_header[sizeof(header) == 8 ? 1 : -1]; + }; + + /* + * Rewind bytebuffer. We use the beginning because the header has 8 + * bytes, leaving enough for unwinding afterwards. + */ + bytebuffer_size -= bytebuffer_offset; + memmove(bytebuffer, &bytebuffer[bytebuffer_offset], bytebuffer_size); + bytebuffer_offset = 0; + + if (!top_up(PASS_STATE 8)) + return 0; + memcpy(header.raw, &bytebuffer[bytebuffer_offset], 8); + bytebuffer_offset += 8; + + /* Check the compression method */ + if (header.formatted.gz_method != 8) { + return 0; + } + + if (header.formatted.flags & 0x04) { + /* bit 2 set: extra field present */ + unsigned extra_short; + + if (!top_up(PASS_STATE 2)) + return 0; + extra_short = buffer_read_le_u16(PASS_STATE_ONLY); + if (!top_up(PASS_STATE extra_short)) + return 0; + /* Ignore extra field */ + bytebuffer_offset += extra_short; + } + + /* Discard original name and file comment if any */ + /* bit 3 set: original file name present */ + /* bit 4 set: file comment present */ + if (header.formatted.flags & 0x18) { + while (1) { + do { + if (!top_up(PASS_STATE 1)) + return 0; + } while (bytebuffer[bytebuffer_offset++] != 0); + if ((header.formatted.flags & 0x18) != 0x18) + break; + header.formatted.flags &= ~0x18; + } + } + + if (info) + info->mtime = SWAP_LE32(header.formatted.mtime); + + /* Read the header checksum */ + if (header.formatted.flags & 0x02) { + if (!top_up(PASS_STATE 2)) + return 0; + bytebuffer_offset += 2; + } + return 1; +} + +IF_DESKTOP(long long) int FAST_FUNC +unpack_gz_stream_with_info(int src_fd, int dst_fd, unpack_info_t *info) +{ + uint32_t v32; + IF_DESKTOP(long long) int total, n; + DECLARE_STATE; + + total = 0; + + ALLOC_STATE; + to_read = -1; +// bytebuffer_max = 0x8000; + bytebuffer = xmalloc(bytebuffer_max); + gunzip_src_fd = src_fd; + + again: + if (!check_header_gzip(PASS_STATE info)) { + bb_error_msg("corrupted data"); + total = -1; + goto ret; + } + + n = inflate_unzip_internal(PASS_STATE src_fd, dst_fd); + if (n < 0) { + total = -1; + goto ret; + } + total += n; + + if (!top_up(PASS_STATE 8)) { + bb_error_msg("corrupted data"); + total = -1; + goto ret; + } + + /* Validate decompression - crc */ + v32 = buffer_read_le_u32(PASS_STATE_ONLY); + if ((~gunzip_crc) != v32) { + bb_error_msg("crc error"); + total = -1; + goto ret; + } + + /* Validate decompression - size */ + v32 = buffer_read_le_u32(PASS_STATE_ONLY); + if ((uint32_t)gunzip_bytes_out != v32) { + bb_error_msg("incorrect length"); + total = -1; + } + + if (!top_up(PASS_STATE 2)) + goto ret; /* EOF */ + + if (bytebuffer[bytebuffer_offset] == 0x1f + && bytebuffer[bytebuffer_offset + 1] == 0x8b + ) { + bytebuffer_offset += 2; + goto again; + } + /* GNU gzip says: */ + /*bb_error_msg("decompression OK, trailing garbage ignored");*/ + + ret: + free(bytebuffer); + DEALLOC_STATE; + return total; +} + +IF_DESKTOP(long long) int FAST_FUNC +unpack_gz_stream(int in, int out) +{ + return unpack_gz_stream_with_info(in, out, NULL); +} diff --git a/archival/libarchive/decompress_unzip.c b/archival/libarchive/decompress_unzip.c deleted file mode 100644 index 50873e3f6..000000000 --- a/archival/libarchive/decompress_unzip.c +++ /dev/null @@ -1,1256 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * gunzip implementation for busybox - * - * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly. - * - * Originally adjusted for busybox by Sven Rudolph - * based on gzip sources - * - * Adjusted further by Erik Andersen to support - * files as well as stdin/stdout, and to generally behave itself wrt - * command line handling. - * - * General cleanup to better adhere to the style guide and make use of standard - * busybox functions by Glenn McGrath - * - * read_gz interface + associated hacking by Laurence Anderson - * - * Fixed huft_build() so decoding end-of-block code does not grab more bits - * than necessary (this is required by unzip applet), added inflate_cleanup() - * to free leaked bytebuffer memory (used in unzip.c), and some minor style - * guide cleanups by Ed Clark - * - * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface - * Copyright (C) 1992-1993 Jean-loup Gailly - * The unzip code was written and put in the public domain by Mark Adler. - * Portions of the lzw code are derived from the public domain 'compress' - * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies, - * Ken Turkowski, Dave Mack and Peter Jannesen. - * - * See the file algorithm.doc for the compression algorithms and file formats. - * - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ - -#include -#include "libbb.h" -#include "bb_archive.h" - -typedef struct huft_t { - unsigned char e; /* number of extra bits or operation */ - unsigned char b; /* number of bits in this code or subcode */ - union { - unsigned short n; /* literal, length base, or distance base */ - struct huft_t *t; /* pointer to next level of table */ - } v; -} huft_t; - -enum { - /* gunzip_window size--must be a power of two, and - * at least 32K for zip's deflate method */ - GUNZIP_WSIZE = 0x8000, - /* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ - BMAX = 16, /* maximum bit length of any code (16 for explode) */ - N_MAX = 288, /* maximum number of codes in any set */ -}; - - -/* This is somewhat complex-looking arrangement, but it allows - * to place decompressor state either in bss or in - * malloc'ed space simply by changing #defines below. - * Sizes on i386: - * text data bss dec hex - * 5256 0 108 5364 14f4 - bss - * 4915 0 0 4915 1333 - malloc - */ -#define STATE_IN_BSS 0 -#define STATE_IN_MALLOC 1 - - -typedef struct state_t { - off_t gunzip_bytes_out; /* number of output bytes */ - uint32_t gunzip_crc; - - int gunzip_src_fd; - unsigned gunzip_outbuf_count; /* bytes in output buffer */ - - unsigned char *gunzip_window; - - uint32_t *gunzip_crc_table; - - /* bitbuffer */ - unsigned gunzip_bb; /* bit buffer */ - unsigned char gunzip_bk; /* bits in bit buffer */ - - /* input (compressed) data */ - unsigned char *bytebuffer; /* buffer itself */ - off_t to_read; /* compressed bytes to read (unzip only, -1 for gunzip) */ -// unsigned bytebuffer_max; /* buffer size */ - unsigned bytebuffer_offset; /* buffer position */ - unsigned bytebuffer_size; /* how much data is there (size <= max) */ - - /* private data of inflate_codes() */ - unsigned inflate_codes_ml; /* masks for bl and bd bits */ - unsigned inflate_codes_md; /* masks for bl and bd bits */ - unsigned inflate_codes_bb; /* bit buffer */ - unsigned inflate_codes_k; /* number of bits in bit buffer */ - unsigned inflate_codes_w; /* current gunzip_window position */ - huft_t *inflate_codes_tl; - huft_t *inflate_codes_td; - unsigned inflate_codes_bl; - unsigned inflate_codes_bd; - unsigned inflate_codes_nn; /* length and index for copy */ - unsigned inflate_codes_dd; - - smallint resume_copy; - - /* private data of inflate_get_next_window() */ - smallint method; /* method == -1 for stored, -2 for codes */ - smallint need_another_block; - smallint end_reached; - - /* private data of inflate_stored() */ - unsigned inflate_stored_n; - unsigned inflate_stored_b; - unsigned inflate_stored_k; - unsigned inflate_stored_w; - - const char *error_msg; - jmp_buf error_jmp; -} state_t; -#define gunzip_bytes_out (S()gunzip_bytes_out ) -#define gunzip_crc (S()gunzip_crc ) -#define gunzip_src_fd (S()gunzip_src_fd ) -#define gunzip_outbuf_count (S()gunzip_outbuf_count) -#define gunzip_window (S()gunzip_window ) -#define gunzip_crc_table (S()gunzip_crc_table ) -#define gunzip_bb (S()gunzip_bb ) -#define gunzip_bk (S()gunzip_bk ) -#define to_read (S()to_read ) -// #define bytebuffer_max (S()bytebuffer_max ) -// Both gunzip and unzip can use constant buffer size now (16k): -#define bytebuffer_max 0x4000 -#define bytebuffer (S()bytebuffer ) -#define bytebuffer_offset (S()bytebuffer_offset ) -#define bytebuffer_size (S()bytebuffer_size ) -#define inflate_codes_ml (S()inflate_codes_ml ) -#define inflate_codes_md (S()inflate_codes_md ) -#define inflate_codes_bb (S()inflate_codes_bb ) -#define inflate_codes_k (S()inflate_codes_k ) -#define inflate_codes_w (S()inflate_codes_w ) -#define inflate_codes_tl (S()inflate_codes_tl ) -#define inflate_codes_td (S()inflate_codes_td ) -#define inflate_codes_bl (S()inflate_codes_bl ) -#define inflate_codes_bd (S()inflate_codes_bd ) -#define inflate_codes_nn (S()inflate_codes_nn ) -#define inflate_codes_dd (S()inflate_codes_dd ) -#define resume_copy (S()resume_copy ) -#define method (S()method ) -#define need_another_block (S()need_another_block ) -#define end_reached (S()end_reached ) -#define inflate_stored_n (S()inflate_stored_n ) -#define inflate_stored_b (S()inflate_stored_b ) -#define inflate_stored_k (S()inflate_stored_k ) -#define inflate_stored_w (S()inflate_stored_w ) -#define error_msg (S()error_msg ) -#define error_jmp (S()error_jmp ) - -/* This is a generic part */ -#if STATE_IN_BSS /* Use global data segment */ -#define DECLARE_STATE /*nothing*/ -#define ALLOC_STATE /*nothing*/ -#define DEALLOC_STATE ((void)0) -#define S() state. -#define PASS_STATE /*nothing*/ -#define PASS_STATE_ONLY /*nothing*/ -#define STATE_PARAM /*nothing*/ -#define STATE_PARAM_ONLY void -static state_t state; -#endif - -#if STATE_IN_MALLOC /* Use malloc space */ -#define DECLARE_STATE state_t *state -#define ALLOC_STATE (state = xzalloc(sizeof(*state))) -#define DEALLOC_STATE free(state) -#define S() state-> -#define PASS_STATE state, -#define PASS_STATE_ONLY state -#define STATE_PARAM state_t *state, -#define STATE_PARAM_ONLY state_t *state -#endif - - -static const uint16_t mask_bits[] ALIGN2 = { - 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, - 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff -}; - -/* Copy lengths for literal codes 257..285 */ -static const uint16_t cplens[] ALIGN2 = { - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, - 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 -}; - -/* note: see note #13 above about the 258 in this list. */ -/* Extra bits for literal codes 257..285 */ -static const uint8_t cplext[] ALIGN1 = { - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, - 5, 5, 5, 0, 99, 99 -}; /* 99 == invalid */ - -/* Copy offsets for distance codes 0..29 */ -static const uint16_t cpdist[] ALIGN2 = { - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, - 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 -}; - -/* Extra bits for distance codes */ -static const uint8_t cpdext[] ALIGN1 = { - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, - 11, 11, 12, 12, 13, 13 -}; - -/* Tables for deflate from PKZIP's appnote.txt. */ -/* Order of the bit length code lengths */ -static const uint8_t border[] ALIGN1 = { - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 -}; - - -/* - * Free the malloc'ed tables built by huft_build(), which makes a linked - * list of the tables it made, with the links in a dummy first entry of - * each table. - * t: table to free - */ -static void huft_free(huft_t *p) -{ - huft_t *q; - - /* Go through linked list, freeing from the malloced (t[-1]) address. */ - while (p) { - q = (--p)->v.t; - free(p); - p = q; - } -} - -static void huft_free_all(STATE_PARAM_ONLY) -{ - huft_free(inflate_codes_tl); - huft_free(inflate_codes_td); - inflate_codes_tl = NULL; - inflate_codes_td = NULL; -} - -static void abort_unzip(STATE_PARAM_ONLY) NORETURN; -static void abort_unzip(STATE_PARAM_ONLY) -{ - huft_free_all(PASS_STATE_ONLY); - longjmp(error_jmp, 1); -} - -static unsigned fill_bitbuffer(STATE_PARAM unsigned bitbuffer, unsigned *current, const unsigned required) -{ - while (*current < required) { - if (bytebuffer_offset >= bytebuffer_size) { - unsigned sz = bytebuffer_max - 4; - if (to_read >= 0 && to_read < sz) /* unzip only */ - sz = to_read; - /* Leave the first 4 bytes empty so we can always unwind the bitbuffer - * to the front of the bytebuffer */ - bytebuffer_size = safe_read(gunzip_src_fd, &bytebuffer[4], sz); - if ((int)bytebuffer_size < 1) { - error_msg = "unexpected end of file"; - abort_unzip(PASS_STATE_ONLY); - } - if (to_read >= 0) /* unzip only */ - to_read -= bytebuffer_size; - bytebuffer_size += 4; - bytebuffer_offset = 4; - } - bitbuffer |= ((unsigned) bytebuffer[bytebuffer_offset]) << *current; - bytebuffer_offset++; - *current += 8; - } - return bitbuffer; -} - - -/* Given a list of code lengths and a maximum table size, make a set of - * tables to decode that set of codes. Return zero on success, one if - * the given code set is incomplete (the tables are still built in this - * case), two if the input is invalid (all zero length codes or an - * oversubscribed set of lengths) - in this case stores NULL in *t. - * - * b: code lengths in bits (all assumed <= BMAX) - * n: number of codes (assumed <= N_MAX) - * s: number of simple-valued codes (0..s-1) - * d: list of base values for non-simple codes - * e: list of extra bits for non-simple codes - * t: result: starting table - * m: maximum lookup bits, returns actual - */ -static int huft_build(const unsigned *b, const unsigned n, - const unsigned s, const unsigned short *d, - const unsigned char *e, huft_t **t, unsigned *m) -{ - unsigned a; /* counter for codes of length k */ - unsigned c[BMAX + 1]; /* bit length count table */ - unsigned eob_len; /* length of end-of-block code (value 256) */ - unsigned f; /* i repeats in table every f entries */ - int g; /* maximum code length */ - int htl; /* table level */ - unsigned i; /* counter, current code */ - unsigned j; /* counter */ - int k; /* number of bits in current code */ - unsigned *p; /* pointer into c[], b[], or v[] */ - huft_t *q; /* points to current table */ - huft_t r; /* table entry for structure assignment */ - huft_t *u[BMAX]; /* table stack */ - unsigned v[N_MAX]; /* values in order of bit length */ - int ws[BMAX + 1]; /* bits decoded stack */ - int w; /* bits decoded */ - unsigned x[BMAX + 1]; /* bit offsets, then code stack */ - unsigned *xp; /* pointer into x */ - int y; /* number of dummy codes added */ - unsigned z; /* number of entries in current table */ - - /* Length of EOB code, if any */ - eob_len = n > 256 ? b[256] : BMAX; - - *t = NULL; - - /* Generate counts for each bit length */ - memset(c, 0, sizeof(c)); - p = (unsigned *) b; /* cast allows us to reuse p for pointing to b */ - i = n; - do { - c[*p]++; /* assume all entries <= BMAX */ - p++; /* can't combine with above line (Solaris bug) */ - } while (--i); - if (c[0] == n) { /* null input - all zero length codes */ - *m = 0; - return 2; - } - - /* Find minimum and maximum length, bound *m by those */ - for (j = 1; (c[j] == 0) && (j <= BMAX); j++) - continue; - k = j; /* minimum code length */ - for (i = BMAX; (c[i] == 0) && i; i--) - continue; - g = i; /* maximum code length */ - *m = (*m < j) ? j : ((*m > i) ? i : *m); - - /* Adjust last length count to fill out codes, if needed */ - for (y = 1 << j; j < i; j++, y <<= 1) { - y -= c[j]; - if (y < 0) - return 2; /* bad input: more codes than bits */ - } - y -= c[i]; - if (y < 0) - return 2; - c[i] += y; - - /* Generate starting offsets into the value table for each length */ - x[1] = j = 0; - p = c + 1; - xp = x + 2; - while (--i) { /* note that i == g from above */ - j += *p++; - *xp++ = j; - } - - /* Make a table of values in order of bit lengths */ - p = (unsigned *) b; - i = 0; - do { - j = *p++; - if (j != 0) { - v[x[j]++] = i; - } - } while (++i < n); - - /* Generate the Huffman codes and for each, make the table entries */ - x[0] = i = 0; /* first Huffman code is zero */ - p = v; /* grab values in bit order */ - htl = -1; /* no tables yet--level -1 */ - w = ws[0] = 0; /* bits decoded */ - u[0] = NULL; /* just to keep compilers happy */ - q = NULL; /* ditto */ - z = 0; /* ditto */ - - /* go through the bit lengths (k already is bits in shortest code) */ - for (; k <= g; k++) { - a = c[k]; - while (a--) { - /* here i is the Huffman code of length k bits for value *p */ - /* make tables up to required level */ - while (k > ws[htl + 1]) { - w = ws[++htl]; - - /* compute minimum size table less than or equal to *m bits */ - z = g - w; - z = z > *m ? *m : z; /* upper limit on table size */ - j = k - w; - f = 1 << j; - if (f > a + 1) { /* try a k-w bit table */ - /* too few codes for k-w bit table */ - f -= a + 1; /* deduct codes from patterns left */ - xp = c + k; - while (++j < z) { /* try smaller tables up to z bits */ - f <<= 1; - if (f <= *++xp) { - break; /* enough codes to use up j bits */ - } - f -= *xp; /* else deduct codes from patterns */ - } - } - j = (w + j > eob_len && w < eob_len) ? eob_len - w : j; /* make EOB code end at table */ - z = 1 << j; /* table entries for j-bit table */ - ws[htl+1] = w + j; /* set bits decoded in stack */ - - /* allocate and link in new table */ - q = xzalloc((z + 1) * sizeof(huft_t)); - *t = q + 1; /* link to list for huft_free() */ - t = &(q->v.t); - u[htl] = ++q; /* table starts after link */ - - /* connect to last table, if there is one */ - if (htl) { - x[htl] = i; /* save pattern for backing up */ - r.b = (unsigned char) (w - ws[htl - 1]); /* bits to dump before this table */ - r.e = (unsigned char) (16 + j); /* bits in this table */ - r.v.t = q; /* pointer to this table */ - j = (i & ((1 << w) - 1)) >> ws[htl - 1]; - u[htl - 1][j] = r; /* connect to last table */ - } - } - - /* set up table entry in r */ - r.b = (unsigned char) (k - w); - if (p >= v + n) { - r.e = 99; /* out of values--invalid code */ - } else if (*p < s) { - r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is EOB code */ - r.v.n = (unsigned short) (*p++); /* simple code is just the value */ - } else { - r.e = (unsigned char) e[*p - s]; /* non-simple--look up in lists */ - r.v.n = d[*p++ - s]; - } - - /* fill code-like entries with r */ - f = 1 << (k - w); - for (j = i >> w; j < z; j += f) { - q[j] = r; - } - - /* backwards increment the k-bit code i */ - for (j = 1 << (k - 1); i & j; j >>= 1) { - i ^= j; - } - i ^= j; - - /* backup over finished tables */ - while ((i & ((1 << w) - 1)) != x[htl]) { - w = ws[--htl]; - } - } - } - - /* return actual size of base table */ - *m = ws[1]; - - /* Return 1 if we were given an incomplete table */ - return y != 0 && g != 1; -} - - -/* - * inflate (decompress) the codes in a deflated (compressed) block. - * Return an error code or zero if it all goes ok. - * - * tl, td: literal/length and distance decoder tables - * bl, bd: number of bits decoded by tl[] and td[] - */ -/* called once from inflate_block */ - -/* map formerly local static variables to globals */ -#define ml inflate_codes_ml -#define md inflate_codes_md -#define bb inflate_codes_bb -#define k inflate_codes_k -#define w inflate_codes_w -#define tl inflate_codes_tl -#define td inflate_codes_td -#define bl inflate_codes_bl -#define bd inflate_codes_bd -#define nn inflate_codes_nn -#define dd inflate_codes_dd -static void inflate_codes_setup(STATE_PARAM unsigned my_bl, unsigned my_bd) -{ - bl = my_bl; - bd = my_bd; - /* make local copies of globals */ - bb = gunzip_bb; /* initialize bit buffer */ - k = gunzip_bk; - w = gunzip_outbuf_count; /* initialize gunzip_window position */ - /* inflate the coded data */ - ml = mask_bits[bl]; /* precompute masks for speed */ - md = mask_bits[bd]; -} -/* called once from inflate_get_next_window */ -static NOINLINE int inflate_codes(STATE_PARAM_ONLY) -{ - unsigned e; /* table entry flag/number of extra bits */ - huft_t *t; /* pointer to table entry */ - - if (resume_copy) - goto do_copy; - - while (1) { /* do until end of block */ - bb = fill_bitbuffer(PASS_STATE bb, &k, bl); - t = tl + ((unsigned) bb & ml); - e = t->e; - if (e > 16) - do { - if (e == 99) - abort_unzip(PASS_STATE_ONLY);; - bb >>= t->b; - k -= t->b; - e -= 16; - bb = fill_bitbuffer(PASS_STATE bb, &k, e); - t = t->v.t + ((unsigned) bb & mask_bits[e]); - e = t->e; - } while (e > 16); - bb >>= t->b; - k -= t->b; - if (e == 16) { /* then it's a literal */ - gunzip_window[w++] = (unsigned char) t->v.n; - if (w == GUNZIP_WSIZE) { - gunzip_outbuf_count = w; - //flush_gunzip_window(); - w = 0; - return 1; // We have a block to read - } - } else { /* it's an EOB or a length */ - /* exit if end of block */ - if (e == 15) { - break; - } - - /* get length of block to copy */ - bb = fill_bitbuffer(PASS_STATE bb, &k, e); - nn = t->v.n + ((unsigned) bb & mask_bits[e]); - bb >>= e; - k -= e; - - /* decode distance of block to copy */ - bb = fill_bitbuffer(PASS_STATE bb, &k, bd); - t = td + ((unsigned) bb & md); - e = t->e; - if (e > 16) - do { - if (e == 99) - abort_unzip(PASS_STATE_ONLY); - bb >>= t->b; - k -= t->b; - e -= 16; - bb = fill_bitbuffer(PASS_STATE bb, &k, e); - t = t->v.t + ((unsigned) bb & mask_bits[e]); - e = t->e; - } while (e > 16); - bb >>= t->b; - k -= t->b; - bb = fill_bitbuffer(PASS_STATE bb, &k, e); - dd = w - t->v.n - ((unsigned) bb & mask_bits[e]); - bb >>= e; - k -= e; - - /* do the copy */ - do_copy: - do { - /* Was: nn -= (e = (e = GUNZIP_WSIZE - ((dd &= GUNZIP_WSIZE - 1) > w ? dd : w)) > nn ? nn : e); */ - /* Who wrote THAT?? rewritten as: */ - unsigned delta; - - dd &= GUNZIP_WSIZE - 1; - e = GUNZIP_WSIZE - (dd > w ? dd : w); - delta = w > dd ? w - dd : dd - w; - if (e > nn) e = nn; - nn -= e; - - /* copy to new buffer to prevent possible overwrite */ - if (delta >= e) { - memcpy(gunzip_window + w, gunzip_window + dd, e); - w += e; - dd += e; - } else { - /* do it slow to avoid memcpy() overlap */ - /* !NOMEMCPY */ - do { - gunzip_window[w++] = gunzip_window[dd++]; - } while (--e); - } - if (w == GUNZIP_WSIZE) { - gunzip_outbuf_count = w; - resume_copy = (nn != 0); - //flush_gunzip_window(); - w = 0; - return 1; - } - } while (nn); - resume_copy = 0; - } - } - - /* restore the globals from the locals */ - gunzip_outbuf_count = w; /* restore global gunzip_window pointer */ - gunzip_bb = bb; /* restore global bit buffer */ - gunzip_bk = k; - - /* normally just after call to inflate_codes, but save code by putting it here */ - /* free the decoding tables (tl and td), return */ - huft_free_all(PASS_STATE_ONLY); - - /* done */ - return 0; -} -#undef ml -#undef md -#undef bb -#undef k -#undef w -#undef tl -#undef td -#undef bl -#undef bd -#undef nn -#undef dd - - -/* called once from inflate_block */ -static void inflate_stored_setup(STATE_PARAM int my_n, int my_b, int my_k) -{ - inflate_stored_n = my_n; - inflate_stored_b = my_b; - inflate_stored_k = my_k; - /* initialize gunzip_window position */ - inflate_stored_w = gunzip_outbuf_count; -} -/* called once from inflate_get_next_window */ -static int inflate_stored(STATE_PARAM_ONLY) -{ - /* read and output the compressed data */ - while (inflate_stored_n--) { - inflate_stored_b = fill_bitbuffer(PASS_STATE inflate_stored_b, &inflate_stored_k, 8); - gunzip_window[inflate_stored_w++] = (unsigned char) inflate_stored_b; - if (inflate_stored_w == GUNZIP_WSIZE) { - gunzip_outbuf_count = inflate_stored_w; - //flush_gunzip_window(); - inflate_stored_w = 0; - inflate_stored_b >>= 8; - inflate_stored_k -= 8; - return 1; /* We have a block */ - } - inflate_stored_b >>= 8; - inflate_stored_k -= 8; - } - - /* restore the globals from the locals */ - gunzip_outbuf_count = inflate_stored_w; /* restore global gunzip_window pointer */ - gunzip_bb = inflate_stored_b; /* restore global bit buffer */ - gunzip_bk = inflate_stored_k; - return 0; /* Finished */ -} - - -/* - * decompress an inflated block - * e: last block flag - * - * GLOBAL VARIABLES: bb, kk, - */ -/* Return values: -1 = inflate_stored, -2 = inflate_codes */ -/* One callsite in inflate_get_next_window */ -static int inflate_block(STATE_PARAM smallint *e) -{ - unsigned ll[286 + 30]; /* literal/length and distance code lengths */ - unsigned t; /* block type */ - unsigned b; /* bit buffer */ - unsigned k; /* number of bits in bit buffer */ - - /* make local bit buffer */ - - b = gunzip_bb; - k = gunzip_bk; - - /* read in last block bit */ - b = fill_bitbuffer(PASS_STATE b, &k, 1); - *e = b & 1; - b >>= 1; - k -= 1; - - /* read in block type */ - b = fill_bitbuffer(PASS_STATE b, &k, 2); - t = (unsigned) b & 3; - b >>= 2; - k -= 2; - - /* restore the global bit buffer */ - gunzip_bb = b; - gunzip_bk = k; - - /* Do we see block type 1 often? Yes! - * TODO: fix performance problem (see below) */ - //bb_error_msg("blktype %d", t); - - /* inflate that block type */ - switch (t) { - case 0: /* Inflate stored */ - { - unsigned n; /* number of bytes in block */ - unsigned b_stored; /* bit buffer */ - unsigned k_stored; /* number of bits in bit buffer */ - - /* make local copies of globals */ - b_stored = gunzip_bb; /* initialize bit buffer */ - k_stored = gunzip_bk; - - /* go to byte boundary */ - n = k_stored & 7; - b_stored >>= n; - k_stored -= n; - - /* get the length and its complement */ - b_stored = fill_bitbuffer(PASS_STATE b_stored, &k_stored, 16); - n = ((unsigned) b_stored & 0xffff); - b_stored >>= 16; - k_stored -= 16; - - b_stored = fill_bitbuffer(PASS_STATE b_stored, &k_stored, 16); - if (n != (unsigned) ((~b_stored) & 0xffff)) { - abort_unzip(PASS_STATE_ONLY); /* error in compressed data */ - } - b_stored >>= 16; - k_stored -= 16; - - inflate_stored_setup(PASS_STATE n, b_stored, k_stored); - - return -1; - } - case 1: - /* Inflate fixed - * decompress an inflated type 1 (fixed Huffman codes) block. We should - * either replace this with a custom decoder, or at least precompute the - * Huffman tables. TODO */ - { - int i; /* temporary variable */ - unsigned bl; /* lookup bits for tl */ - unsigned bd; /* lookup bits for td */ - /* gcc 4.2.1 is too dumb to reuse stackspace. Moved up... */ - //unsigned ll[288]; /* length list for huft_build */ - - /* set up literal table */ - for (i = 0; i < 144; i++) - ll[i] = 8; - for (; i < 256; i++) - ll[i] = 9; - for (; i < 280; i++) - ll[i] = 7; - for (; i < 288; i++) /* make a complete, but wrong code set */ - ll[i] = 8; - bl = 7; - huft_build(ll, 288, 257, cplens, cplext, &inflate_codes_tl, &bl); - /* huft_build() never return nonzero - we use known data */ - - /* set up distance table */ - for (i = 0; i < 30; i++) /* make an incomplete code set */ - ll[i] = 5; - bd = 5; - huft_build(ll, 30, 0, cpdist, cpdext, &inflate_codes_td, &bd); - - /* set up data for inflate_codes() */ - inflate_codes_setup(PASS_STATE bl, bd); - - /* huft_free code moved into inflate_codes */ - - return -2; - } - case 2: /* Inflate dynamic */ - { - enum { dbits = 6 }; /* bits in base distance lookup table */ - enum { lbits = 9 }; /* bits in base literal/length lookup table */ - - huft_t *td; /* distance code table */ - unsigned i; /* temporary variables */ - unsigned j; - unsigned l; /* last length */ - unsigned m; /* mask for bit lengths table */ - unsigned n; /* number of lengths to get */ - unsigned bl; /* lookup bits for tl */ - unsigned bd; /* lookup bits for td */ - unsigned nb; /* number of bit length codes */ - unsigned nl; /* number of literal/length codes */ - unsigned nd; /* number of distance codes */ - - //unsigned ll[286 + 30];/* literal/length and distance code lengths */ - unsigned b_dynamic; /* bit buffer */ - unsigned k_dynamic; /* number of bits in bit buffer */ - - /* make local bit buffer */ - b_dynamic = gunzip_bb; - k_dynamic = gunzip_bk; - - /* read in table lengths */ - b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 5); - nl = 257 + ((unsigned) b_dynamic & 0x1f); /* number of literal/length codes */ - - b_dynamic >>= 5; - k_dynamic -= 5; - b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 5); - nd = 1 + ((unsigned) b_dynamic & 0x1f); /* number of distance codes */ - - b_dynamic >>= 5; - k_dynamic -= 5; - b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 4); - nb = 4 + ((unsigned) b_dynamic & 0xf); /* number of bit length codes */ - - b_dynamic >>= 4; - k_dynamic -= 4; - if (nl > 286 || nd > 30) - abort_unzip(PASS_STATE_ONLY); /* bad lengths */ - - /* read in bit-length-code lengths */ - for (j = 0; j < nb; j++) { - b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 3); - ll[border[j]] = (unsigned) b_dynamic & 7; - b_dynamic >>= 3; - k_dynamic -= 3; - } - for (; j < 19; j++) - ll[border[j]] = 0; - - /* build decoding table for trees - single level, 7 bit lookup */ - bl = 7; - i = huft_build(ll, 19, 19, NULL, NULL, &inflate_codes_tl, &bl); - if (i != 0) { - abort_unzip(PASS_STATE_ONLY); //return i; /* incomplete code set */ - } - - /* read in literal and distance code lengths */ - n = nl + nd; - m = mask_bits[bl]; - i = l = 0; - while ((unsigned) i < n) { - b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, (unsigned)bl); - td = inflate_codes_tl + ((unsigned) b_dynamic & m); - j = td->b; - b_dynamic >>= j; - k_dynamic -= j; - j = td->v.n; - if (j < 16) { /* length of code in bits (0..15) */ - ll[i++] = l = j; /* save last length in l */ - } else if (j == 16) { /* repeat last length 3 to 6 times */ - b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 2); - j = 3 + ((unsigned) b_dynamic & 3); - b_dynamic >>= 2; - k_dynamic -= 2; - if ((unsigned) i + j > n) { - abort_unzip(PASS_STATE_ONLY); //return 1; - } - while (j--) { - ll[i++] = l; - } - } else if (j == 17) { /* 3 to 10 zero length codes */ - b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 3); - j = 3 + ((unsigned) b_dynamic & 7); - b_dynamic >>= 3; - k_dynamic -= 3; - if ((unsigned) i + j > n) { - abort_unzip(PASS_STATE_ONLY); //return 1; - } - while (j--) { - ll[i++] = 0; - } - l = 0; - } else { /* j == 18: 11 to 138 zero length codes */ - b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 7); - j = 11 + ((unsigned) b_dynamic & 0x7f); - b_dynamic >>= 7; - k_dynamic -= 7; - if ((unsigned) i + j > n) { - abort_unzip(PASS_STATE_ONLY); //return 1; - } - while (j--) { - ll[i++] = 0; - } - l = 0; - } - } - - /* free decoding table for trees */ - huft_free(inflate_codes_tl); - - /* restore the global bit buffer */ - gunzip_bb = b_dynamic; - gunzip_bk = k_dynamic; - - /* build the decoding tables for literal/length and distance codes */ - bl = lbits; - - i = huft_build(ll, nl, 257, cplens, cplext, &inflate_codes_tl, &bl); - if (i != 0) - abort_unzip(PASS_STATE_ONLY); - bd = dbits; - i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &inflate_codes_td, &bd); - if (i != 0) - abort_unzip(PASS_STATE_ONLY); - - /* set up data for inflate_codes() */ - inflate_codes_setup(PASS_STATE bl, bd); - - /* huft_free code moved into inflate_codes */ - - return -2; - } - default: - abort_unzip(PASS_STATE_ONLY); - } -} - -/* Two callsites, both in inflate_get_next_window */ -static void calculate_gunzip_crc(STATE_PARAM_ONLY) -{ - gunzip_crc = crc32_block_endian0(gunzip_crc, gunzip_window, gunzip_outbuf_count, gunzip_crc_table); - gunzip_bytes_out += gunzip_outbuf_count; -} - -/* One callsite in inflate_unzip_internal */ -static int inflate_get_next_window(STATE_PARAM_ONLY) -{ - gunzip_outbuf_count = 0; - - while (1) { - int ret; - - if (need_another_block) { - if (end_reached) { - calculate_gunzip_crc(PASS_STATE_ONLY); - end_reached = 0; - /* NB: need_another_block is still set */ - return 0; /* Last block */ - } - method = inflate_block(PASS_STATE &end_reached); - need_another_block = 0; - } - - switch (method) { - case -1: - ret = inflate_stored(PASS_STATE_ONLY); - break; - case -2: - ret = inflate_codes(PASS_STATE_ONLY); - break; - default: /* cannot happen */ - abort_unzip(PASS_STATE_ONLY); - } - - if (ret == 1) { - calculate_gunzip_crc(PASS_STATE_ONLY); - return 1; /* more data left */ - } - need_another_block = 1; /* end of that block */ - } - /* Doesnt get here */ -} - - -/* Called from unpack_gz_stream() and inflate_unzip() */ -static IF_DESKTOP(long long) int -inflate_unzip_internal(STATE_PARAM int in, int out) -{ - IF_DESKTOP(long long) int n = 0; - ssize_t nwrote; - - /* Allocate all global buffers (for DYN_ALLOC option) */ - gunzip_window = xmalloc(GUNZIP_WSIZE); - gunzip_outbuf_count = 0; - gunzip_bytes_out = 0; - gunzip_src_fd = in; - - /* (re) initialize state */ - method = -1; - need_another_block = 1; - resume_copy = 0; - gunzip_bk = 0; - gunzip_bb = 0; - - /* Create the crc table */ - gunzip_crc_table = crc32_filltable(NULL, 0); - gunzip_crc = ~0; - - error_msg = "corrupted data"; - if (setjmp(error_jmp)) { - /* Error from deep inside zip machinery */ - n = -1; - goto ret; - } - - 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"); - n = -1; - goto ret; - } - IF_DESKTOP(n += nwrote;) - if (r == 0) break; - } - - /* Store unused bytes in a global buffer so calling applets can access it */ - if (gunzip_bk >= 8) { - /* Undo too much lookahead. The next read will be byte aligned - * so we can discard unused bits in the last meaningful byte. */ - bytebuffer_offset--; - bytebuffer[bytebuffer_offset] = gunzip_bb & 0xff; - gunzip_bb >>= 8; - gunzip_bk -= 8; - } - ret: - /* Cleanup */ - free(gunzip_window); - free(gunzip_crc_table); - return n; -} - - -/* External entry points */ - -/* For unzip */ - -IF_DESKTOP(long long) int FAST_FUNC -inflate_unzip(inflate_unzip_result *res, off_t compr_size, int in, int out) -{ - IF_DESKTOP(long long) int n; - DECLARE_STATE; - - ALLOC_STATE; - - to_read = compr_size; -// bytebuffer_max = 0x8000; - bytebuffer_offset = 4; - bytebuffer = xmalloc(bytebuffer_max); - n = inflate_unzip_internal(PASS_STATE in, out); - free(bytebuffer); - - res->crc = gunzip_crc; - res->bytes_out = gunzip_bytes_out; - DEALLOC_STATE; - return n; -} - - -/* For gunzip */ - -/* helpers first */ - -/* Top up the input buffer with at least n bytes. */ -static int top_up(STATE_PARAM unsigned n) -{ - int count = bytebuffer_size - bytebuffer_offset; - - if (count < (int)n) { - memmove(bytebuffer, &bytebuffer[bytebuffer_offset], count); - bytebuffer_offset = 0; - bytebuffer_size = full_read(gunzip_src_fd, &bytebuffer[count], bytebuffer_max - count); - if ((int)bytebuffer_size < 0) { - bb_error_msg(bb_msg_read_error); - return 0; - } - bytebuffer_size += count; - if (bytebuffer_size < n) - return 0; - } - return 1; -} - -static uint16_t buffer_read_le_u16(STATE_PARAM_ONLY) -{ - uint16_t res; -#if BB_LITTLE_ENDIAN - move_from_unaligned16(res, &bytebuffer[bytebuffer_offset]); -#else - res = bytebuffer[bytebuffer_offset]; - res |= bytebuffer[bytebuffer_offset + 1] << 8; -#endif - bytebuffer_offset += 2; - return res; -} - -static uint32_t buffer_read_le_u32(STATE_PARAM_ONLY) -{ - uint32_t res; -#if BB_LITTLE_ENDIAN - move_from_unaligned32(res, &bytebuffer[bytebuffer_offset]); -#else - res = bytebuffer[bytebuffer_offset]; - res |= bytebuffer[bytebuffer_offset + 1] << 8; - res |= bytebuffer[bytebuffer_offset + 2] << 16; - res |= bytebuffer[bytebuffer_offset + 3] << 24; -#endif - bytebuffer_offset += 4; - return res; -} - -static int check_header_gzip(STATE_PARAM unpack_info_t *info) -{ - union { - unsigned char raw[8]; - struct { - uint8_t gz_method; - uint8_t flags; - uint32_t mtime; - uint8_t xtra_flags_UNUSED; - uint8_t os_flags_UNUSED; - } PACKED formatted; - } header; - struct BUG_header { - char BUG_header[sizeof(header) == 8 ? 1 : -1]; - }; - - /* - * Rewind bytebuffer. We use the beginning because the header has 8 - * bytes, leaving enough for unwinding afterwards. - */ - bytebuffer_size -= bytebuffer_offset; - memmove(bytebuffer, &bytebuffer[bytebuffer_offset], bytebuffer_size); - bytebuffer_offset = 0; - - if (!top_up(PASS_STATE 8)) - return 0; - memcpy(header.raw, &bytebuffer[bytebuffer_offset], 8); - bytebuffer_offset += 8; - - /* Check the compression method */ - if (header.formatted.gz_method != 8) { - return 0; - } - - if (header.formatted.flags & 0x04) { - /* bit 2 set: extra field present */ - unsigned extra_short; - - if (!top_up(PASS_STATE 2)) - return 0; - extra_short = buffer_read_le_u16(PASS_STATE_ONLY); - if (!top_up(PASS_STATE extra_short)) - return 0; - /* Ignore extra field */ - bytebuffer_offset += extra_short; - } - - /* Discard original name and file comment if any */ - /* bit 3 set: original file name present */ - /* bit 4 set: file comment present */ - if (header.formatted.flags & 0x18) { - while (1) { - do { - if (!top_up(PASS_STATE 1)) - return 0; - } while (bytebuffer[bytebuffer_offset++] != 0); - if ((header.formatted.flags & 0x18) != 0x18) - break; - header.formatted.flags &= ~0x18; - } - } - - if (info) - info->mtime = SWAP_LE32(header.formatted.mtime); - - /* Read the header checksum */ - if (header.formatted.flags & 0x02) { - if (!top_up(PASS_STATE 2)) - return 0; - bytebuffer_offset += 2; - } - return 1; -} - -IF_DESKTOP(long long) int FAST_FUNC -unpack_gz_stream_with_info(int src_fd, int dst_fd, unpack_info_t *info) -{ - uint32_t v32; - IF_DESKTOP(long long) int total, n; - DECLARE_STATE; - - total = 0; - - ALLOC_STATE; - to_read = -1; -// bytebuffer_max = 0x8000; - bytebuffer = xmalloc(bytebuffer_max); - gunzip_src_fd = src_fd; - - again: - if (!check_header_gzip(PASS_STATE info)) { - bb_error_msg("corrupted data"); - total = -1; - goto ret; - } - - n = inflate_unzip_internal(PASS_STATE src_fd, dst_fd); - if (n < 0) { - total = -1; - goto ret; - } - total += n; - - if (!top_up(PASS_STATE 8)) { - bb_error_msg("corrupted data"); - total = -1; - goto ret; - } - - /* Validate decompression - crc */ - v32 = buffer_read_le_u32(PASS_STATE_ONLY); - if ((~gunzip_crc) != v32) { - bb_error_msg("crc error"); - total = -1; - goto ret; - } - - /* Validate decompression - size */ - v32 = buffer_read_le_u32(PASS_STATE_ONLY); - if ((uint32_t)gunzip_bytes_out != v32) { - bb_error_msg("incorrect length"); - total = -1; - } - - if (!top_up(PASS_STATE 2)) - goto ret; /* EOF */ - - if (bytebuffer[bytebuffer_offset] == 0x1f - && bytebuffer[bytebuffer_offset + 1] == 0x8b - ) { - bytebuffer_offset += 2; - goto again; - } - /* GNU gzip says: */ - /*bb_error_msg("decompression OK, trailing garbage ignored");*/ - - ret: - free(bytebuffer); - DEALLOC_STATE; - return total; -} - -IF_DESKTOP(long long) int FAST_FUNC -unpack_gz_stream(int in, int out) -{ - return unpack_gz_stream_with_info(in, out, NULL); -} diff --git a/docs/keep_data_small.txt b/docs/keep_data_small.txt index 21d732674..9e77a9097 100644 --- a/docs/keep_data_small.txt +++ b/docs/keep_data_small.txt @@ -59,7 +59,7 @@ wait Example 1 One example how to reduce global data usage is in -archival/libarchive/decompress_unzip.c: +archival/libarchive/decompress_gunzip.c: /* This is somewhat complex-looking arrangement, but it allows * to place decompressor state either in bss or in -- cgit v1.2.3-55-g6feb From 8a6a2f9c9c214b94bd945acd97ac8b28c25e194e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 6 Mar 2012 16:27:48 +0100 Subject: update seamless uncompression code This change makes "tar tf hello_world.txz" work without adding special-casing for ".txz" extension. It also removes ever-growing magic checking code in rpm2cpio and get_header_tar - we reuse one which lives in setup_unzip_on_fd. function old new delta unpack_gz_stream 7 566 +559 check_signature16 - 70 +70 setup_unzip_on_fd 99 142 +43 handle_SIGCHLD - 41 +41 unpack_bz2_stream 342 376 +34 unzip_main 2352 2385 +33 bbunpack 503 533 +30 open_transformer 74 102 +28 unpack_Z_stream 1278 1304 +26 unpack_gunzip 101 123 +22 init_transformer_aux_data - 18 +18 unpack_xz_stream 2388 2402 +14 open_zipped 131 141 +10 rpm_main 1358 1363 +5 get_header_tar_lzma 52 57 +5 get_header_tar_bz2 52 57 +5 unpack_lzma_stream 2698 2702 +4 hash_find 234 233 -1 get_header_tar 1759 1733 -26 get_header_tar_gz 92 57 -35 unpack_uncompress 51 12 -39 rpm2cpio_main 201 147 -54 unpack_unxz 67 12 -55 unpack_bz2_stream_prime 55 - -55 get_header_tar_Z 86 - -86 unpack_gz_stream_with_info 539 - -539 ------------------------------------------------------------------------------ (add/remove: 3/3 grow/shrink: 14/6 up/down: 947/-890) Total: 57 bytes Signed-off-by: Denys Vlasenko --- archival/bbunzip.c | 78 ++++++++----------- archival/bzip2.c | 2 +- archival/gzip.c | 2 +- archival/libarchive/decompress_bunzip2.c | 18 ++--- archival/libarchive/decompress_gunzip.c | 27 +++---- archival/libarchive/decompress_uncompress.c | 5 +- archival/libarchive/decompress_unlzma.c | 2 +- archival/libarchive/decompress_unxz.c | 12 ++- archival/libarchive/get_header_tar.c | 35 ++------- archival/libarchive/get_header_tar_bz2.c | 2 +- archival/libarchive/get_header_tar_gz.c | 17 +---- archival/libarchive/get_header_tar_lzma.c | 2 +- archival/libarchive/open_transformer.c | 113 ++++++++++++++-------------- archival/lzop.c | 2 +- archival/rpm.c | 2 +- archival/rpm2cpio.c | 73 ++++++++---------- archival/tar.c | 71 ++++++++--------- archival/unzip.c | 10 ++- docs/keep_data_small.txt | 2 +- include/bb_archive.h | 56 +++++++------- include/libbb.h | 14 ++-- 21 files changed, 233 insertions(+), 312 deletions(-) diff --git a/archival/bbunzip.c b/archival/bbunzip.c index 853c653c0..1bc04ed33 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c @@ -33,7 +33,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)(unpack_info_t *info), + IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(transformer_aux_data_t *aux), char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext), const char *expected_ext ) @@ -42,7 +42,7 @@ int FAST_FUNC bbunpack(char **argv, IF_DESKTOP(long long) int status; char *filename, *new_name; smallint exitcode = 0; - unpack_info_t info; + transformer_aux_data_t aux; do { /* NB: new_name is *maybe* malloc'ed! */ @@ -98,9 +98,9 @@ int FAST_FUNC bbunpack(char **argv, "use -f to force it"); } - /* memset(&info, 0, sizeof(info)); */ - info.mtime = 0; /* so far it has one member only */ - status = unpacker(&info); + init_transformer_aux_data(&aux); + aux.check_signature = 1; + status = unpacker(&aux); if (status < 0) exitcode = 1; @@ -111,10 +111,10 @@ int FAST_FUNC bbunpack(char **argv, char *del = new_name; if (status >= 0) { /* TODO: restore other things? */ - if (info.mtime) { + if (aux.mtime != 0) { struct timeval times[2]; - times[1].tv_sec = times[0].tv_sec = info.mtime; + times[1].tv_sec = times[0].tv_sec = aux.mtime; times[1].tv_usec = times[0].tv_usec = 0; /* Note: we closed it first. * On some systems calling utimes @@ -182,16 +182,9 @@ char* FAST_FUNC make_new_name_generic(char *filename, const char *expected_ext) #if ENABLE_UNCOMPRESS static -IF_DESKTOP(long long) int FAST_FUNC unpack_uncompress(unpack_info_t *info UNUSED_PARAM) +IF_DESKTOP(long long) int FAST_FUNC unpack_uncompress(transformer_aux_data_t *aux) { - IF_DESKTOP(long long) int status = -1; - - if ((xread_char(STDIN_FILENO) != 0x1f) || (xread_char(STDIN_FILENO) != 0x9d)) { - bb_error_msg("invalid magic"); - } else { - status = unpack_Z_stream(STDIN_FILENO, STDOUT_FILENO); - } - return status; + return unpack_Z_stream(aux, STDIN_FILENO, STDOUT_FILENO); } int uncompress_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int uncompress_main(int argc UNUSED_PARAM, char **argv) @@ -279,30 +272,30 @@ 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(unpack_info_t *info) +IF_DESKTOP(long long) int FAST_FUNC unpack_gunzip(transformer_aux_data_t *aux) { IF_DESKTOP(long long) int status = -1; + uint16_t magic2; - /* do the decompression, and cleanup */ - if (xread_char(STDIN_FILENO) == 0x1f) { - unsigned char magic2; - - magic2 = xread_char(STDIN_FILENO); - if (ENABLE_FEATURE_SEAMLESS_Z && magic2 == 0x9d) { - status = unpack_Z_stream(STDIN_FILENO, STDOUT_FILENO); - } else if (magic2 == 0x8b) { - status = unpack_gz_stream_with_info(STDIN_FILENO, STDOUT_FILENO, info); - } else { - goto bad_magic; - } - if (status < 0) { - bb_error_msg("error inflating"); - } +//TODO: fold below into unpack_gz_stream? Then the whole level of indirection +// unpack_FOO() -> unpack_FOO_stream can be collapsed in this module! + + aux->check_signature = 0; /* we will check it here, not in unpack_*_stream */ + + if (full_read(STDIN_FILENO, &magic2, 2) != 2) + goto bad_magic; + if (ENABLE_FEATURE_SEAMLESS_Z && magic2 == COMPRESS_MAGIC) { + status = unpack_Z_stream(aux, STDIN_FILENO, STDOUT_FILENO); + } else if (magic2 == GZIP_MAGIC) { + status = unpack_gz_stream(aux, STDIN_FILENO, STDOUT_FILENO); } else { bad_magic: bb_error_msg("invalid magic"); /* status is still == -1 */ } + if (status < 0) { + bb_error_msg("error inflating"); + } return status; } /* @@ -352,9 +345,9 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv) //applet:IF_BUNZIP2(APPLET_ODDNAME(bzcat, bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP, bzcat)) #if ENABLE_BUNZIP2 static -IF_DESKTOP(long long) int FAST_FUNC unpack_bunzip2(unpack_info_t *info UNUSED_PARAM) +IF_DESKTOP(long long) int FAST_FUNC unpack_bunzip2(transformer_aux_data_t *aux) { - return unpack_bz2_stream_prime(STDIN_FILENO, STDOUT_FILENO); + return unpack_bz2_stream(aux, STDIN_FILENO, STDOUT_FILENO); } int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int bunzip2_main(int argc UNUSED_PARAM, char **argv) @@ -420,9 +413,9 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_UNLZMA static -IF_DESKTOP(long long) int FAST_FUNC unpack_unlzma(unpack_info_t *info UNUSED_PARAM) +IF_DESKTOP(long long) int FAST_FUNC unpack_unlzma(transformer_aux_data_t *aux) { - return unpack_lzma_stream(STDIN_FILENO, STDOUT_FILENO); + return unpack_lzma_stream(aux, STDIN_FILENO, STDOUT_FILENO); } int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int unlzma_main(int argc UNUSED_PARAM, char **argv) @@ -445,18 +438,9 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_UNXZ static -IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(unpack_info_t *info UNUSED_PARAM) +IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(transformer_aux_data_t *aux) { - struct { - uint32_t v1; - uint16_t v2; - } magic; - xread(STDIN_FILENO, &magic, 6); - if (magic.v1 != XZ_MAGIC1a || magic.v2 != XZ_MAGIC2a) { - bb_error_msg("invalid magic"); - return -1; - } - return unpack_xz_stream(STDIN_FILENO, STDOUT_FILENO); + return unpack_xz_stream(aux, 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 0716fa89b..dd77c8efc 100644 --- a/archival/bzip2.c +++ b/archival/bzip2.c @@ -111,7 +111,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(unpack_info_t *info UNUSED_PARAM) +IF_DESKTOP(long long) int FAST_FUNC compressStream(transformer_aux_data_t *aux UNUSED_PARAM) { IF_DESKTOP(long long) int total; ssize_t count; diff --git a/archival/gzip.c b/archival/gzip.c index 929107389..80db4f969 100644 --- a/archival/gzip.c +++ b/archival/gzip.c @@ -2015,7 +2015,7 @@ static void zip(ulg time_stamp) /* ======================================================================== */ static -IF_DESKTOP(long long) int FAST_FUNC pack_gzip(unpack_info_t *info UNUSED_PARAM) +IF_DESKTOP(long long) int FAST_FUNC pack_gzip(transformer_aux_data_t *aux UNUSED_PARAM) { struct stat s; diff --git a/archival/libarchive/decompress_bunzip2.c b/archival/libarchive/decompress_bunzip2.c index c4640d489..dc252bb82 100644 --- a/archival/libarchive/decompress_bunzip2.c +++ b/archival/libarchive/decompress_bunzip2.c @@ -721,7 +721,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(int src_fd, int dst_fd) +unpack_bz2_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) { IF_DESKTOP(long long total_written = 0;) bunzip_data *bd; @@ -729,6 +729,9 @@ unpack_bz2_stream(int src_fd, int dst_fd) int i; unsigned len; + if (check_signature16(aux, src_fd, BZIP2_MAGIC)) + return -1; + outbuf = xmalloc(IOBUF_SIZE); len = 0; while (1) { /* "Process one BZ... stream" loop */ @@ -794,17 +797,6 @@ unpack_bz2_stream(int src_fd, int dst_fd) return i ? i : IF_DESKTOP(total_written) + 0; } -IF_DESKTOP(long long) int FAST_FUNC -unpack_bz2_stream_prime(int src_fd, int dst_fd) -{ - uint16_t magic2; - xread(src_fd, &magic2, 2); - if (magic2 != BZIP2_MAGIC) { - bb_error_msg_and_die("invalid magic"); - } - return unpack_bz2_stream(src_fd, dst_fd); -} - #ifdef TESTING static char *const bunzip_errors[] = { @@ -819,7 +811,7 @@ int main(int argc, char **argv) int i; char c; - int i = unpack_bz2_stream_prime(0, 1); + int i = unpack_bz2_stream(0, 1); if (i < 0) fprintf(stderr, "%s\n", bunzip_errors[-i]); else if (read(STDIN_FILENO, &c, 1)) diff --git a/archival/libarchive/decompress_gunzip.c b/archival/libarchive/decompress_gunzip.c index 50873e3f6..f1c9a79e5 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(inflate_unzip_result *res, off_t compr_size, int in, int out) +inflate_unzip(transformer_aux_data_t *aux, int in, int out) { IF_DESKTOP(long long) int n; DECLARE_STATE; ALLOC_STATE; - to_read = compr_size; + to_read = aux->bytes_in; // bytebuffer_max = 0x8000; bytebuffer_offset = 4; bytebuffer = xmalloc(bytebuffer_max); n = inflate_unzip_internal(PASS_STATE in, out); free(bytebuffer); - res->crc = gunzip_crc; - res->bytes_out = gunzip_bytes_out; + aux->crc32 = gunzip_crc; + aux->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 unpack_info_t *info) +static int check_header_gzip(STATE_PARAM transformer_aux_data_t *aux) { union { unsigned char raw[8]; @@ -1169,8 +1169,8 @@ static int check_header_gzip(STATE_PARAM unpack_info_t *info) } } - if (info) - info->mtime = SWAP_LE32(header.formatted.mtime); + if (aux) + aux->mtime = SWAP_LE32(header.formatted.mtime); /* Read the header checksum */ if (header.formatted.flags & 0x02) { @@ -1182,12 +1182,15 @@ static int check_header_gzip(STATE_PARAM unpack_info_t *info) } IF_DESKTOP(long long) int FAST_FUNC -unpack_gz_stream_with_info(int src_fd, int dst_fd, unpack_info_t *info) +unpack_gz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) { uint32_t v32; IF_DESKTOP(long long) int total, n; DECLARE_STATE; + if (check_signature16(aux, src_fd, GZIP_MAGIC)) + return -1; + total = 0; ALLOC_STATE; @@ -1197,7 +1200,7 @@ unpack_gz_stream_with_info(int src_fd, int dst_fd, unpack_info_t *info) gunzip_src_fd = src_fd; again: - if (!check_header_gzip(PASS_STATE info)) { + if (!check_header_gzip(PASS_STATE aux)) { bb_error_msg("corrupted data"); total = -1; goto ret; @@ -1248,9 +1251,3 @@ unpack_gz_stream_with_info(int src_fd, int dst_fd, unpack_info_t *info) DEALLOC_STATE; return total; } - -IF_DESKTOP(long long) int FAST_FUNC -unpack_gz_stream(int in, int out) -{ - return unpack_gz_stream_with_info(in, out, NULL); -} diff --git a/archival/libarchive/decompress_uncompress.c b/archival/libarchive/decompress_uncompress.c index 289f9e233..e9bbfb9bd 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(int src_fd, int dst_fd) +unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) { IF_DESKTOP(long long total_written = 0;) IF_DESKTOP(long long) int retval = -1; @@ -103,6 +103,9 @@ unpack_Z_stream(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)) + return -1; + inbuf = xzalloc(IBUFSIZ + 64); outbuf = xzalloc(OBUFSIZ + 2048); htab = xzalloc(HSIZE); /* wasn't zeroed out before, maybe can xmalloc? */ diff --git a/archival/libarchive/decompress_unlzma.c b/archival/libarchive/decompress_unlzma.c index 3631b50cc..cfde8ea56 100644 --- a/archival/libarchive/decompress_unlzma.c +++ b/archival/libarchive/decompress_unlzma.c @@ -213,7 +213,7 @@ enum { IF_DESKTOP(long long) int FAST_FUNC -unpack_lzma_stream(int src_fd, int dst_fd) +unpack_lzma_stream(transformer_aux_data_t *aux 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 3e5d4edca..79b48a152 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(int src_fd, int dst_fd) +unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) { struct xz_buf iobuf; struct xz_dec *state; @@ -49,13 +49,17 @@ unpack_xz_stream(int src_fd, int dst_fd) global_crc32_table = crc32_filltable(NULL, /*endian:*/ 0); memset(&iobuf, 0, sizeof(iobuf)); - /* Preload XZ file signature */ - membuf = (void*) strcpy(xmalloc(2 * BUFSIZ), HEADER_MAGIC); + membuf = xmalloc(2 * BUFSIZ); iobuf.in = membuf; - iobuf.in_size = HEADER_MAGIC_SIZE; iobuf.out = membuf + BUFSIZ; iobuf.out_size = BUFSIZ; + if (!aux || aux->check_signature == 0) { + /* Preload XZ file signature */ + strcpy((char*)membuf, HEADER_MAGIC); + iobuf.in_size = HEADER_MAGIC_SIZE; + } /* else: let xz code read & check it */ + /* Limit memory usage to about 64 MiB. */ state = xz_dec_init(XZ_DYNALLOC, 64*1024*1024); diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c index 8c699754b..80a709144 100644 --- a/archival/libarchive/get_header_tar.c +++ b/archival/libarchive/get_header_tar.c @@ -235,43 +235,18 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) || memcmp(tar.magic, "\0\0\0\0", 5) != 0) ) { #if ENABLE_FEATURE_TAR_AUTODETECT - char FAST_FUNC (*get_header_ptr)(archive_handle_t *); - uint16_t magic2; - autodetect: - magic2 = *(bb__aliased_uint16_t*)tar.name; - /* tar gz/bz autodetect: check for gz/bz2 magic. - * If we see the magic, and it is the very first block, - * we can switch to get_header_tar_gz/bz2/lzma(). - * Needs seekable fd. I wish recv(MSG_PEEK) works - * on any fd... */ -# if ENABLE_FEATURE_SEAMLESS_GZ - if (magic2 == GZIP_MAGIC) { - get_header_ptr = get_header_tar_gz; - } else -# endif -# if ENABLE_FEATURE_SEAMLESS_BZ2 - if (magic2 == BZIP2_MAGIC - && tar.name[2] == 'h' && isdigit(tar.name[3]) - ) { /* bzip2 */ - get_header_ptr = get_header_tar_bz2; - } else -# endif -# if ENABLE_FEATURE_SEAMLESS_XZ - //TODO: if (magic2 == XZ_MAGIC1)... - //else -# endif - goto err; /* Two different causes for lseek() != 0: * unseekable fd (would like to support that too, but...), * or not first block (false positive, it's not .gz/.bz2!) */ if (lseek(archive_handle->src_fd, -i, SEEK_CUR) != 0) goto err; - while (get_header_ptr(archive_handle) == EXIT_SUCCESS) - continue; - return EXIT_FAILURE; + if (setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_detected:*/ 0) != 0) err: -#endif /* FEATURE_TAR_AUTODETECT */ + bb_error_msg_and_die("invalid tar magic"); + archive_handle->offset = 0; + goto again_after_align; +#endif bb_error_msg_and_die("invalid tar magic"); } diff --git a/archival/libarchive/get_header_tar_bz2.c b/archival/libarchive/get_header_tar_bz2.c index e012dec3b..0ee00df53 100644 --- a/archival/libarchive/get_header_tar_bz2.c +++ b/archival/libarchive/get_header_tar_bz2.c @@ -11,7 +11,7 @@ char FAST_FUNC get_header_tar_bz2(archive_handle_t *archive_handle) /* Can't lseek over pipes */ archive_handle->seek = seek_by_read; - open_transformer(archive_handle->src_fd, unpack_bz2_stream_prime, "bunzip2"); + open_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 b9679b0bd..03284342b 100644 --- a/archival/libarchive/get_header_tar_gz.c +++ b/archival/libarchive/get_header_tar_gz.c @@ -8,25 +8,10 @@ char FAST_FUNC get_header_tar_gz(archive_handle_t *archive_handle) { -#if BB_MMU - uint16_t magic; -#endif - /* Can't lseek over pipes */ archive_handle->seek = seek_by_read; - /* Check gzip magic only if open_transformer will invoke unpack_gz_stream (MMU case). - * Otherwise, it will invoke an external helper "gunzip -cf" (NOMMU case) which will - * need the header. */ -#if BB_MMU - xread(archive_handle->src_fd, &magic, 2); - /* Can skip this check, but error message will be less clear */ - if (magic != GZIP_MAGIC) { - bb_error_msg_and_die("invalid gzip magic"); - } -#endif - - open_transformer(archive_handle->src_fd, unpack_gz_stream, "gunzip"); + open_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 666700729..d565a217d 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(archive_handle->src_fd, unpack_lzma_stream, "unlzma"); + open_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 743ffee02..693ae9995 100644 --- a/archival/libarchive/open_transformer.c +++ b/archival/libarchive/open_transformer.c @@ -6,24 +6,36 @@ #include "libbb.h" #include "bb_archive.h" -#define ZIPPED (ENABLE_FEATURE_SEAMLESS_LZMA \ - || ENABLE_FEATURE_SEAMLESS_BZ2 \ - || ENABLE_FEATURE_SEAMLESS_GZ \ - /* || ENABLE_FEATURE_SEAMLESS_Z */ \ -) +void FAST_FUNC init_transformer_aux_data(transformer_aux_data_t *aux) +{ + memset(aux, 0, sizeof(*aux)); +} -#if ZIPPED -# include "bb_archive.h" +int FAST_FUNC check_signature16(transformer_aux_data_t *aux, int src_fd, unsigned magic16) +{ + if (aux && aux->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) + xfunc_die(); #endif + return -1; + } + } + return 0; +} /* transformer(), more than meets the eye */ -/* - * On MMU machine, the transform_prog is removed by macro magic - * in include/archive.h. On NOMMU, transformer is removed. - */ +#if BB_MMU void FAST_FUNC open_transformer(int fd, - IF_DESKTOP(long long) int FAST_FUNC (*transformer)(int src_fd, int dst_fd), - const char *transform_prog) + int check_signature, + IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd) +) +#else +void FAST_FUNC open_transformer(int fd, const char *transform_prog) +#endif { struct fd_pair fd_pipe; int pid; @@ -35,13 +47,18 @@ void FAST_FUNC open_transformer(int fd, close(fd_pipe.rd); /* we don't want to read from the parent */ // FIXME: error check? #if BB_MMU - transformer(fd, fd_pipe.wr); - if (ENABLE_FEATURE_CLEAN_UP) { - close(fd_pipe.wr); /* send EOF */ - close(fd); + { + transformer_aux_data_t aux; + init_transformer_aux_data(&aux); + aux.check_signature = check_signature; + transformer(&aux, fd, fd_pipe.wr); + if (ENABLE_FEATURE_CLEAN_UP) { + close(fd_pipe.wr); /* send EOF */ + close(fd); + } + /* must be _exit! bug was actually seen here */ + _exit(EXIT_SUCCESS); } - /* must be _exit! bug was actually seen here */ - _exit(EXIT_SUCCESS); #else { char *argv[4]; @@ -64,26 +81,21 @@ void FAST_FUNC open_transformer(int fd, } +#if SEAMLESS_COMPRESSION + /* Used by e.g. rpm which gives us a fd without filename, * thus we can't guess the format from filename's extension. */ -#if ZIPPED -void FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) +int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_detected) { - const int fail_if_not_detected = 1; union { uint8_t b[4]; uint16_t b16[2]; uint32_t b32[1]; } magic; int offset = -2; -# if BB_MMU - IF_DESKTOP(long long) int FAST_FUNC (*xformer)(int src_fd, int dst_fd); - enum { xformer_prog = 0 }; -# else - enum { xformer = 0 }; - const char *xformer_prog; -# endif + USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd);) + USE_FOR_NOMMU(const char *xformer_prog;) /* .gz and .bz2 both have 2-byte signature, and their * unpack_XXX_stream wants this header skipped. */ @@ -91,21 +103,15 @@ void FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) if (ENABLE_FEATURE_SEAMLESS_GZ && magic.b16[0] == GZIP_MAGIC ) { -# if BB_MMU - xformer = unpack_gz_stream; -# else - xformer_prog = "gunzip"; -# endif + USE_FOR_MMU(xformer = unpack_gz_stream;) + USE_FOR_NOMMU(xformer_prog = "gunzip";) goto found_magic; } if (ENABLE_FEATURE_SEAMLESS_BZ2 && magic.b16[0] == BZIP2_MAGIC ) { -# if BB_MMU - xformer = unpack_bz2_stream; -# else - xformer_prog = "bunzip2"; -# endif + USE_FOR_MMU(xformer = unpack_bz2_stream;) + USE_FOR_NOMMU(xformer_prog = "bunzip2";) goto found_magic; } if (ENABLE_FEATURE_SEAMLESS_XZ @@ -114,13 +120,8 @@ void FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) offset = -6; xread(fd, magic.b32, sizeof(magic.b32[0])); if (magic.b32[0] == XZ_MAGIC2) { -# if BB_MMU - xformer = unpack_xz_stream; - /* unpack_xz_stream wants fd at position 6, no need to seek */ - //xlseek(fd, offset, SEEK_CUR); -# else - xformer_prog = "unxz"; -# endif + USE_FOR_MMU(xformer = unpack_xz_stream;) + USE_FOR_NOMMU(xformer_prog = "unxz";) goto found_magic; } } @@ -132,24 +133,23 @@ void FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) IF_FEATURE_SEAMLESS_XZ("/xz") " magic"); xlseek(fd, offset, SEEK_CUR); - return; + return 1; found_magic: -# if !BB_MMU +# if BB_MMU + open_transformer_with_no_sig(fd, 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); # endif - open_transformer(fd, xformer, xformer_prog); + return 0; } -#endif /* ZIPPED */ int FAST_FUNC open_zipped(const char *fname) { -#if !ZIPPED - return open(fname, O_RDONLY); -#else char *sfx; int fd; @@ -162,20 +162,21 @@ int FAST_FUNC open_zipped(const char *fname) sfx++; if (ENABLE_FEATURE_SEAMLESS_LZMA && strcmp(sfx, "lzma") == 0) /* .lzma has no header/signature, just trust it */ - open_transformer(fd, unpack_lzma_stream, "unlzma"); + open_transformer_with_sig(fd, unpack_lzma_stream, "unlzma"); else if ((ENABLE_FEATURE_SEAMLESS_GZ && strcmp(sfx, "gz") == 0) || (ENABLE_FEATURE_SEAMLESS_BZ2 && strcmp(sfx, "bz2") == 0) || (ENABLE_FEATURE_SEAMLESS_XZ && strcmp(sfx, "xz") == 0) ) { - setup_unzip_on_fd(fd /*, fail_if_not_detected: 1*/); + setup_unzip_on_fd(fd, /*fail_if_not_detected:*/ 1); } } return fd; -#endif } +#endif /* SEAMLESS_COMPRESSION */ + void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) { int fd; diff --git a/archival/lzop.c b/archival/lzop.c index 67baeff7e..fbe08417d 100644 --- a/archival/lzop.c +++ b/archival/lzop.c @@ -1077,7 +1077,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(unpack_info_t *info UNUSED_PARAM) +static IF_DESKTOP(long long) int FAST_FUNC pack_lzop(transformer_aux_data_t *aux UNUSED_PARAM) { if (option_mask32 & OPT_DECOMPRESS) return do_lzo_decompress(); diff --git a/archival/rpm.c b/archival/rpm.c index 089b68983..6757a6ceb 100644 --- a/archival/rpm.c +++ b/archival/rpm.c @@ -236,7 +236,7 @@ static void extract_cpio(int fd, const char *source_rpm) archive_handle->src_fd = fd; /*archive_handle->offset = 0; - init_handle() did it */ - setup_unzip_on_fd(archive_handle->src_fd /*, fail_if_not_detected: 1*/); + setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_detected:*/ 1); while (get_header_cpio(archive_handle) == EXIT_SUCCESS) continue; } diff --git a/archival/rpm2cpio.c b/archival/rpm2cpio.c index 28b43a181..7256aae6b 100644 --- a/archival/rpm2cpio.c +++ b/archival/rpm2cpio.c @@ -42,6 +42,26 @@ static unsigned skip_header(void) return sizeof(header) + len; } +#if SEAMLESS_COMPRESSION +static void handle_SIGCHLD(int signo UNUSED_PARAM) +{ + int status; + + /* Wait for any child without blocking */ + for (;;) { + if (wait_any_nohang(&status) < 0) + /* wait failed?! I'm confused... */ + return; + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) + /* this child exited with 0 */ + continue; + /* Cannot happen? + if (!WIFSIGNALED(status) && !WIFEXITED(status)) ???; */ + bb_got_signal = 1; + } +} +#endif + /* No getopt required */ int rpm2cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) @@ -66,54 +86,23 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) /* Skip the main header */ skip_header(); -#if 0 +#if SEAMLESS_COMPRESSION + /* We need to know whether child (gzip/bzip/etc) exits abnormally */ + signal(SIGCHLD, handle_SIGCHLD); +#endif + /* This works, but doesn't report uncompress errors (they happen in child) */ - setup_unzip_on_fd(rpm_fd /*fail_if_not_detected: 1*/); + setup_unzip_on_fd(rpm_fd, /*fail_if_not_detected:*/ 1); if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0) bb_error_msg_and_die("error unpacking"); -#else - /* BLOAT */ - { - union { - uint8_t b[4]; - uint16_t b16[2]; - uint32_t b32[1]; - } magic; - IF_DESKTOP(long long) int FAST_FUNC (*unpack)(int src_fd, int dst_fd); - - xread(rpm_fd, magic.b16, sizeof(magic.b16[0])); - if (magic.b16[0] == GZIP_MAGIC) { - unpack = unpack_gz_stream; - } else - if (ENABLE_FEATURE_SEAMLESS_BZ2 - && magic.b16[0] == BZIP2_MAGIC - ) { - unpack = unpack_bz2_stream; - } else - if (ENABLE_FEATURE_SEAMLESS_XZ - && magic.b16[0] == XZ_MAGIC1 - ) { - xread(rpm_fd, magic.b32, sizeof(magic.b32[0])); - if (magic.b32[0] != XZ_MAGIC2) - goto no_magic; - /* unpack_xz_stream wants fd at position 6, no need to seek */ - //xlseek(rpm_fd, -6, SEEK_CUR); - unpack = unpack_xz_stream; - } else { - no_magic: - bb_error_msg_and_die("no gzip" - IF_FEATURE_SEAMLESS_BZ2("/bzip2") - IF_FEATURE_SEAMLESS_XZ("/xz") - " magic"); - } - if (unpack(rpm_fd, STDOUT_FILENO) < 0) - bb_error_msg_and_die("error unpacking"); - } -#endif if (ENABLE_FEATURE_CLEAN_UP) { close(rpm_fd); } - return 0; +#if SEAMLESS_COMPRESSION + return bb_got_signal; +#else + return EXIT_SUCCESS; +#endif } diff --git a/archival/tar.c b/archival/tar.c index 766b79b2b..af38ac59f 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -690,31 +690,6 @@ static llist_t *append_file_list_to_list(llist_t *list) # define append_file_list_to_list(x) 0 #endif -#if ENABLE_FEATURE_SEAMLESS_Z -static char FAST_FUNC get_header_tar_Z(archive_handle_t *archive_handle) -{ - /* Can't lseek over pipes */ - archive_handle->seek = seek_by_read; - - /* do the decompression, and cleanup */ - if (xread_char(archive_handle->src_fd) != 0x1f - || xread_char(archive_handle->src_fd) != 0x9d - ) { - bb_error_msg_and_die("invalid magic"); - } - - open_transformer(archive_handle->src_fd, unpack_Z_stream, "uncompress"); - archive_handle->offset = 0; - while (get_header_tar(archive_handle) == EXIT_SUCCESS) - continue; - - /* Can only do one file at a time */ - return EXIT_FAILURE; -} -#else -# define get_header_tar_Z NULL -#endif - #ifdef CHECK_FOR_CHILD_EXITCODE /* Looks like it isn't needed - tar detects malformed (truncated) * archive if e.g. bunzip2 fails */ @@ -843,6 +818,8 @@ enum { OPT_NUMERIC_OWNER = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER )) + 0, // numeric-owner OPT_NOPRESERVE_PERM = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0, // no-same-permissions OPT_OVERWRITE = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE )) + 0, // overwrite + + OPT_ANY_COMPRESS = (OPT_BZIP2 | OPT_LZMA | OPT_GZIP | OPT_COMPRESS), }; #if ENABLE_FEATURE_TAR_LONG_OPTIONS static const char tar_longopts[] ALIGN1 = @@ -901,7 +878,6 @@ static const char tar_longopts[] ALIGN1 = int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int tar_main(int argc UNUSED_PARAM, char **argv) { - char FAST_FUNC (*get_header_ptr)(archive_handle_t *) = get_header_tar; archive_handle_t *tar_handle; char *base_dir = NULL; const char *tar_filename = "-"; @@ -1017,18 +993,6 @@ int tar_main(int argc UNUSED_PARAM, char **argv) tar_handle->ah_flags |= ARCHIVE_O_TRUNC; } - if (opt & OPT_GZIP) - get_header_ptr = get_header_tar_gz; - - if (opt & OPT_BZIP2) - get_header_ptr = get_header_tar_bz2; - - if (opt & OPT_LZMA) - get_header_ptr = get_header_tar_lzma; - - if (opt & OPT_COMPRESS) - get_header_ptr = get_header_tar_Z; - if (opt & OPT_NOPRESERVE_TIME) tar_handle->ah_flags &= ~ARCHIVE_RESTORE_DATE; @@ -1081,7 +1045,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) } else { if (ENABLE_FEATURE_TAR_AUTODETECT && flags == O_RDONLY - && get_header_ptr == get_header_tar + && !(opt & OPT_ANY_COMPRESS) ) { tar_handle->src_fd = open_zipped(tar_filename); if (tar_handle->src_fd < 0) @@ -1115,7 +1079,30 @@ int tar_main(int argc UNUSED_PARAM, char **argv) tar_handle->reject, zipMode); } - while (get_header_ptr(tar_handle) == EXIT_SUCCESS) + 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_NOMMU(const char *xformer_prog;) + + if (opt & OPT_COMPRESS) + USE_FOR_MMU(xformer = unpack_Z_stream;) + USE_FOR_NOMMU(xformer_prog = "uncompress";) + if (opt & OPT_GZIP) + USE_FOR_MMU(xformer = unpack_gz_stream;) + USE_FOR_NOMMU(xformer_prog = "gunzip";) + if (opt & OPT_BZIP2) + USE_FOR_MMU(xformer = unpack_bz2_stream;) + USE_FOR_NOMMU(xformer_prog = "bunzip2";) + if (opt & OPT_LZMA) + USE_FOR_MMU(xformer = unpack_lzma_stream;) + USE_FOR_NOMMU(xformer_prog = "unlzma";) + + open_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 */ + } + + while (get_header_tar(tar_handle) == EXIT_SUCCESS) continue; /* Check that every file that should have been extracted was */ @@ -1131,5 +1118,9 @@ int tar_main(int argc UNUSED_PARAM, char **argv) if (ENABLE_FEATURE_CLEAN_UP /* && tar_handle->src_fd != STDIN_FILENO */) close(tar_handle->src_fd); +#ifdef CHECK_FOR_CHILD_EXITCODE + return bb_got_signal; +#else return EXIT_SUCCESS; +#endif } diff --git a/archival/unzip.c b/archival/unzip.c index 3a11f78a5..3c76cdafc 100644 --- a/archival/unzip.c +++ b/archival/unzip.c @@ -249,15 +249,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 */ - inflate_unzip_result res; - if (inflate_unzip(&res, zip_header->formatted.cmpsize, zip_fd, dst_fd) < 0) + 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) bb_error_msg_and_die("inflate error"); /* Validate decompression - crc */ - if (zip_header->formatted.crc32 != (res.crc ^ 0xffffffffL)) { + if (zip_header->formatted.crc32 != (aux.crc32 ^ 0xffffffffL)) { bb_error_msg_and_die("crc error"); } /* Validate decompression - size */ - if (zip_header->formatted.ucmpsize != res.bytes_out) { + if (zip_header->formatted.ucmpsize != aux.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/docs/keep_data_small.txt b/docs/keep_data_small.txt index 9e77a9097..21d732674 100644 --- a/docs/keep_data_small.txt +++ b/docs/keep_data_small.txt @@ -59,7 +59,7 @@ wait Example 1 One example how to reduce global data usage is in -archival/libarchive/decompress_gunzip.c: +archival/libarchive/decompress_unzip.c: /* This is somewhat complex-looking arrangement, but it allows * to place decompressor state either in bss or in diff --git a/include/bb_archive.h b/include/bb_archive.h index 4987de6cf..bd08115da 100644 --- a/include/bb_archive.h +++ b/include/bb_archive.h @@ -156,12 +156,6 @@ struct BUG_tar_header { -/* Info struct unpackers can fill out to inform users of thing like - * timestamps of unpacked files */ -typedef struct unpack_info_t { - time_t mtime; -} unpack_info_t; - archive_handle_t *init_handle(void) FAST_FUNC; char filter_accept_all(archive_handle_t *archive_handle) FAST_FUNC; @@ -204,40 +198,46 @@ int start_bunzip(bunzip_data **bdp, int in_fd, const void *inbuf, int len) FAST_ int read_bunzip(bunzip_data *bd, char *outbuf, int len) FAST_FUNC; void dealloc_bunzip(bunzip_data *bd) FAST_FUNC; -typedef struct inflate_unzip_result { - off_t bytes_out; - uint32_t crc; -} inflate_unzip_result; - -IF_DESKTOP(long long) int inflate_unzip(inflate_unzip_result *res, off_t compr_size, int src_fd, int dst_fd) FAST_FUNC; -/* xz unpacker takes .xz stream from offset 6 */ -IF_DESKTOP(long long) int unpack_xz_stream(int src_fd, int dst_fd) FAST_FUNC; -/* lzma unpacker takes .lzma stream from offset 0 */ -IF_DESKTOP(long long) int unpack_lzma_stream(int src_fd, int dst_fd) FAST_FUNC; -/* the rest wants 2 first bytes already skipped by the caller */ -IF_DESKTOP(long long) int unpack_bz2_stream(int src_fd, int dst_fd) FAST_FUNC; -IF_DESKTOP(long long) int unpack_gz_stream(int src_fd, int dst_fd) FAST_FUNC; -IF_DESKTOP(long long) int unpack_gz_stream_with_info(int src_fd, int dst_fd, unpack_info_t *info) FAST_FUNC; -IF_DESKTOP(long long) int unpack_Z_stream(int src_fd, int dst_fd) FAST_FUNC; -/* wrapper which checks first two bytes to be "BZ" */ -IF_DESKTOP(long long) int unpack_bz2_stream_prime(int src_fd, int dst_fd) FAST_FUNC; +/* Meaning and direction (input/output) of the fields are transformer-specific */ +typedef struct transformer_aux_data_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; + +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; + +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; char* append_ext(char *filename, const char *expected_ext) FAST_FUNC; int bbunpack(char **argv, - IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(unpack_info_t *info), + IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(transformer_aux_data_t *aux), char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext), const char *expected_ext ) FAST_FUNC; #if BB_MMU void open_transformer(int fd, - IF_DESKTOP(long long) int FAST_FUNC (*transformer)(int src_fd, int dst_fd)) FAST_FUNC; -#define open_transformer(fd, transformer, transform_prog) open_transformer(fd, transformer) + int check_signature, + IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_aux_data_t *aux, 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)) #else -void open_transformer(int src_fd, const char *transform_prog) FAST_FUNC; -#define open_transformer(fd, transformer, transform_prog) open_transformer(fd, transform_prog) +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 */ #endif + POP_SAVED_FUNCTION_VISIBILITY #endif diff --git a/include/libbb.h b/include/libbb.h index c896e5484..2cc146631 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -721,17 +721,15 @@ extern void *xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p) FAS || ENABLE_FEATURE_SEAMLESS_GZ \ || ENABLE_FEATURE_SEAMLESS_Z) +#if SEAMLESS_COMPRESSION /* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */ -#if ENABLE_FEATURE_SEAMLESS_LZMA \ - || ENABLE_FEATURE_SEAMLESS_BZ2 \ - || ENABLE_FEATURE_SEAMLESS_GZ \ - /* || ENABLE_FEATURE_SEAMLESS_Z */ -extern void setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) FAST_FUNC; -#else -# define setup_unzip_on_fd(...) ((void)0) -#endif +extern int setup_unzip_on_fd(int fd, int fail_if_not_detected) FAST_FUNC; /* Autodetects .gz etc */ extern int open_zipped(const char *fname) FAST_FUNC; +#else +# define setup_unzip_on_fd(...) (0) +# define open_zipped(fname) open((fname), O_RDONLY); +#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; -- cgit v1.2.3-55-g6feb From 02c3c3842004d88207b46450dbd19f80e6596c7e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 6 Mar 2012 16:32:06 +0100 Subject: Move seamless .Z support into unpack_gz_stream unpack_gz_stream 566 643 +77 unpack_gunzip 123 12 -111 Signed-off-by: Denys Vlasenko --- archival/Config.src | 4 ++-- archival/bbunzip.c | 24 +----------------------- archival/libarchive/decompress_gunzip.c | 18 ++++++++++++++++++ 3 files changed, 21 insertions(+), 25 deletions(-) diff --git a/archival/Config.src b/archival/Config.src index 885cb5bcc..ae1afc594 100644 --- a/archival/Config.src +++ b/archival/Config.src @@ -32,10 +32,10 @@ config FEATURE_SEAMLESS_GZ Make tar, rpm, modprobe etc understand .gz data. config FEATURE_SEAMLESS_Z - bool "Make tar and gunzip understand .Z data" + bool "tar, rpm, modprobe etc understand .Z data" default n help - Make tar and gunzip understand .Z data. + Make tar, rpm, modprobe etc understand .Z data. config AR bool "ar" diff --git a/archival/bbunzip.c b/archival/bbunzip.c index 1bc04ed33..94d8a81c9 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c @@ -274,29 +274,7 @@ char* FAST_FUNC make_new_name_gunzip(char *filename, const char *expected_ext UN static IF_DESKTOP(long long) int FAST_FUNC unpack_gunzip(transformer_aux_data_t *aux) { - IF_DESKTOP(long long) int status = -1; - uint16_t magic2; - -//TODO: fold below into unpack_gz_stream? Then the whole level of indirection -// unpack_FOO() -> unpack_FOO_stream can be collapsed in this module! - - aux->check_signature = 0; /* we will check it here, not in unpack_*_stream */ - - if (full_read(STDIN_FILENO, &magic2, 2) != 2) - goto bad_magic; - if (ENABLE_FEATURE_SEAMLESS_Z && magic2 == COMPRESS_MAGIC) { - status = unpack_Z_stream(aux, STDIN_FILENO, STDOUT_FILENO); - } else if (magic2 == GZIP_MAGIC) { - status = unpack_gz_stream(aux, STDIN_FILENO, STDOUT_FILENO); - } else { - bad_magic: - bb_error_msg("invalid magic"); - /* status is still == -1 */ - } - if (status < 0) { - bb_error_msg("error inflating"); - } - return status; + return unpack_gz_stream(aux, STDIN_FILENO, STDOUT_FILENO); } /* * Linux kernel build uses gzip -d -n. We accept and ignore it. diff --git a/archival/libarchive/decompress_gunzip.c b/archival/libarchive/decompress_gunzip.c index f1c9a79e5..66152a853 100644 --- a/archival/libarchive/decompress_gunzip.c +++ b/archival/libarchive/decompress_gunzip.c @@ -1188,8 +1188,26 @@ unpack_gz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) IF_DESKTOP(long long) int total, n; DECLARE_STATE; +#if !ENABLE_FEATURE_SEAMLESS_Z if (check_signature16(aux, src_fd, GZIP_MAGIC)) return -1; +#else + if (aux && aux->check_signature) { + uint16_t magic2; + + if (full_read(STDIN_FILENO, &magic2, 2) != 2) { + bad_magic: + bb_error_msg("invalid magic"); + return -1; + } + if (magic2 == COMPRESS_MAGIC) { + aux->check_signature = 0; + return unpack_Z_stream(aux, src_fd, dst_fd); + } + if (magic2 != GZIP_MAGIC) + goto bad_magic; + } +#endif total = 0; -- cgit v1.2.3-55-g6feb From faac1d3e6e87dc6882e69b62f1c71907d892c876 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 6 Mar 2012 16:33:42 +0100 Subject: tar,rpm2cpio: check that child decompressor did not error out function old new delta check_errors_in_children - 57 +57 tar_main 833 848 +15 get_header_tar 1720 1733 +13 rpm2cpio_main 147 140 -7 handle_SIGCHLD 41 - -41 ------------------------------------------------------------------------------ (add/remove: 1/1 grow/shrink: 2/1 up/down: 85/-48) Total: 37 bytes Signed-off-by: Denys Vlasenko --- archival/libarchive/open_transformer.c | 26 +++++++++++++++++++++++ archival/rpm2cpio.c | 35 +++++++------------------------ archival/tar.c | 38 +++++++--------------------------- include/bb_archive.h | 1 + 4 files changed, 41 insertions(+), 59 deletions(-) diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c index 693ae9995..dae04aa57 100644 --- a/archival/libarchive/open_transformer.c +++ b/archival/libarchive/open_transformer.c @@ -27,6 +27,32 @@ int FAST_FUNC check_signature16(transformer_aux_data_t *aux, int src_fd, unsigne return 0; } +void check_errors_in_children(int signo) +{ + int status; + + if (!signo) { + /* block waiting for any child */ + if (wait(&status) < 0) + return; /* probably there are no children */ + goto check_status; + } + + /* Wait for any child without blocking */ + for (;;) { + if (wait_any_nohang(&status) < 0) + /* wait failed?! I'm confused... */ + return; + check_status: + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) + /* this child exited with 0 */ + continue; + /* Cannot happen? + if (!WIFSIGNALED(status) && !WIFEXITED(status)) ???; */ + bb_got_signal = 1; + } +} + /* transformer(), more than meets the eye */ #if BB_MMU void FAST_FUNC open_transformer(int fd, diff --git a/archival/rpm2cpio.c b/archival/rpm2cpio.c index 7256aae6b..f3dfa5159 100644 --- a/archival/rpm2cpio.c +++ b/archival/rpm2cpio.c @@ -42,26 +42,6 @@ static unsigned skip_header(void) return sizeof(header) + len; } -#if SEAMLESS_COMPRESSION -static void handle_SIGCHLD(int signo UNUSED_PARAM) -{ - int status; - - /* Wait for any child without blocking */ - for (;;) { - if (wait_any_nohang(&status) < 0) - /* wait failed?! I'm confused... */ - return; - if (WIFEXITED(status) && WEXITSTATUS(status) == 0) - /* this child exited with 0 */ - continue; - /* Cannot happen? - if (!WIFSIGNALED(status) && !WIFEXITED(status)) ???; */ - bb_got_signal = 1; - } -} -#endif - /* No getopt required */ int rpm2cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) @@ -86,10 +66,9 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) /* Skip the main header */ skip_header(); -#if SEAMLESS_COMPRESSION - /* We need to know whether child (gzip/bzip/etc) exits abnormally */ - signal(SIGCHLD, handle_SIGCHLD); -#endif + //if (SEAMLESS_COMPRESSION) + // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ + // signal(SIGCHLD, check_errors_in_children); /* This works, but doesn't report uncompress errors (they happen in child) */ setup_unzip_on_fd(rpm_fd, /*fail_if_not_detected:*/ 1); @@ -100,9 +79,9 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) close(rpm_fd); } -#if SEAMLESS_COMPRESSION - return bb_got_signal; -#else + if (SEAMLESS_COMPRESSION) { + check_errors_in_children(0); + return bb_got_signal; + } return EXIT_SUCCESS; -#endif } diff --git a/archival/tar.c b/archival/tar.c index af38ac59f..cf972c24c 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -690,29 +690,6 @@ static llist_t *append_file_list_to_list(llist_t *list) # define append_file_list_to_list(x) 0 #endif -#ifdef CHECK_FOR_CHILD_EXITCODE -/* Looks like it isn't needed - tar detects malformed (truncated) - * archive if e.g. bunzip2 fails */ -static int child_error; - -static void handle_SIGCHLD(int status) -{ - /* Actually, 'status' is a signo. We reuse it for other needs */ - - /* Wait for any child without blocking */ - if (wait_any_nohang(&status) < 0) - /* wait failed?! I'm confused... */ - return; - - if (WIFEXITED(status) && WEXITSTATUS(status) == 0) - /* child exited with 0 */ - return; - /* Cannot happen? - if (!WIFSIGNALED(status) && !WIFEXITED(status)) return; */ - child_error = 1; -} -#endif - //usage:#define tar_trivial_usage //usage: "-[" IF_FEATURE_TAR_CREATE("c") "xt" //usage: IF_FEATURE_SEAMLESS_Z("Z") @@ -1059,10 +1036,9 @@ int tar_main(int argc UNUSED_PARAM, char **argv) if (base_dir) xchdir(base_dir); -#ifdef CHECK_FOR_CHILD_EXITCODE - /* We need to know whether child (gzip/bzip/etc) exits abnormally */ - signal(SIGCHLD, handle_SIGCHLD); -#endif + //if (SEAMLESS_COMPRESSION || OPT_COMPRESS) + // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ + // signal(SIGCHLD, check_errors_in_children); /* Create an archive */ if (opt & OPT_CREATE) { @@ -1118,9 +1094,9 @@ int tar_main(int argc UNUSED_PARAM, char **argv) if (ENABLE_FEATURE_CLEAN_UP /* && tar_handle->src_fd != STDIN_FILENO */) close(tar_handle->src_fd); -#ifdef CHECK_FOR_CHILD_EXITCODE - return bb_got_signal; -#else + if (SEAMLESS_COMPRESSION || OPT_COMPRESS) { + check_errors_in_children(0); + return bb_got_signal; + } return EXIT_SUCCESS; -#endif } diff --git a/include/bb_archive.h b/include/bb_archive.h index bd08115da..2043d8570 100644 --- a/include/bb_archive.h +++ b/include/bb_archive.h @@ -224,6 +224,7 @@ int bbunpack(char **argv, const char *expected_ext ) FAST_FUNC; +void check_errors_in_children(int signo); #if BB_MMU void open_transformer(int fd, int check_signature, -- cgit v1.2.3-55-g6feb From b5d6ae9a336ae64958fbc49a7a98d66f2e4cbcd6 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 6 Mar 2012 16:34:23 +0100 Subject: Don't compile get_header_tar_FOO function if they are not needed Now get_header_tar_gz, get_header_tar_bz2, get_header_tar_lzma are only used if dpkg is built. Signed-off-by: Denys Vlasenko --- archival/libarchive/Kbuild.src | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/archival/libarchive/Kbuild.src b/archival/libarchive/Kbuild.src index a0a7cca5f..39c18f264 100644 --- a/archival/libarchive/Kbuild.src +++ b/archival/libarchive/Kbuild.src @@ -28,10 +28,13 @@ COMMON_FILES:= \ init_handle.o DPKG_FILES:= \ - get_header_ar.o \ unpack_ar_archive.o \ + filter_accept_list_reassign.o \ + get_header_ar.o \ get_header_tar.o \ - filter_accept_list_reassign.o + get_header_tar_gz.o \ + get_header_tar_bz2.o \ + get_header_tar_lzma.o \ INSERT @@ -51,9 +54,9 @@ lib-$(CONFIG_UNZIP) += decompress_gunzip.o lib-$(CONFIG_LZOP) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o lib-$(CONFIG_LZOP_COMPR_HIGH) += lzo1x_9x.o lib-$(CONFIG_FEATURE_SEAMLESS_Z) += open_transformer.o decompress_uncompress.o -lib-$(CONFIG_FEATURE_SEAMLESS_GZ) += open_transformer.o decompress_gunzip.o get_header_tar_gz.o -lib-$(CONFIG_FEATURE_SEAMLESS_BZ2) += open_transformer.o decompress_bunzip2.o get_header_tar_bz2.o -lib-$(CONFIG_FEATURE_SEAMLESS_LZMA) += open_transformer.o decompress_unlzma.o get_header_tar_lzma.o +lib-$(CONFIG_FEATURE_SEAMLESS_GZ) += open_transformer.o decompress_gunzip.o +lib-$(CONFIG_FEATURE_SEAMLESS_BZ2) += open_transformer.o decompress_bunzip2.o +lib-$(CONFIG_FEATURE_SEAMLESS_LZMA) += open_transformer.o decompress_unlzma.o lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += decompress_bunzip2.o lib-$(CONFIG_FEATURE_COMPRESS_BBCONFIG) += decompress_bunzip2.o -- cgit v1.2.3-55-g6feb From d29c946f931730a9acf0132da5f3d73fed0113df Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 6 Mar 2012 16:46:25 +0100 Subject: fix trivial bug in unpack_gz_stream (wrong fd used in read) Signed-off-by: Denys Vlasenko --- archival/libarchive/decompress_gunzip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archival/libarchive/decompress_gunzip.c b/archival/libarchive/decompress_gunzip.c index 66152a853..2d5ab3eb3 100644 --- a/archival/libarchive/decompress_gunzip.c +++ b/archival/libarchive/decompress_gunzip.c @@ -1195,7 +1195,7 @@ unpack_gz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) if (aux && aux->check_signature) { uint16_t magic2; - if (full_read(STDIN_FILENO, &magic2, 2) != 2) { + if (full_read(src_fd, &magic2, 2) != 2) { bad_magic: bb_error_msg("invalid magic"); return -1; -- cgit v1.2.3-55-g6feb From bb8d7db597e73f8bd7cb10e3d319be4c93128ccc Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 6 Mar 2012 16:57:01 +0100 Subject: testsuite: add a test that tar detects XZ-compressed data Signed-off-by: Denys Vlasenko --- testsuite/tar.tests | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/testsuite/tar.tests b/testsuite/tar.tests index 39ece5feb..7927020c1 100755 --- a/testsuite/tar.tests +++ b/testsuite/tar.tests @@ -170,6 +170,25 @@ Ok "" "" SKIP= +# Do we detect XZ-compressed data (even w/o .tar.xz or txz extension)? +# (the uuencoded hello_world.txz contains one empty file named "hello_world") +optional UUDECODE FEATURE_TAR_AUTODETECT FEATURE_SEAMLESS_XZ +testing "tar extract txz" "\ +uudecode -o input && tar tf input && echo Ok +" "\ +hello_world +Ok +" \ +"" "\ +begin-base64 644 hello_world.txz +/Td6WFoAAATm1rRGAgAhARYAAAB0L+Wj4AX/AEldADQZSe6ODIZQ3rSQ8kAJ +SnMPTX+XWGKW3Yu/Rwqg4Ik5wqgQKgVH97J8yA8IvZ4ahaCQogUNHRkXibr2 +Q615wcb2G7fJU49AhWAAAAAAUA8gu9DyXfAAAWWADAAAAB5FXGCxxGf7AgAA +AAAEWVo= +==== +" +SKIP= + # On extract, everything up to and including last ".." component is stripped optional FEATURE_TAR_CREATE testing "tar strips /../ on extract" "\ -- cgit v1.2.3-55-g6feb From 8be49c3a800a2c43d71d29fc1b0b61567ed4541d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 6 Mar 2012 19:16:50 +0100 Subject: ntpd: tweak log messages format Signed-off-by: Denys Vlasenko --- networking/ntpd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/networking/ntpd.c b/networking/ntpd.c index e9805087c..9c16b2b6b 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -1476,8 +1476,8 @@ update_local_clock(peer_t *p) memset(&tmx, 0, sizeof(tmx)); if (adjtimex(&tmx) < 0) bb_perror_msg_and_die("adjtimex"); - bb_error_msg("p adjtimex freq:%ld offset:%+ld constant:%ld status:0x%x", - tmx.freq, tmx.offset, tmx.constant, tmx.status); + bb_error_msg("p adjtimex freq:%ld offset:%+ld status:0x%x tc:%ld", + tmx.freq, tmx.offset, tmx.status, tmx.constant); } memset(&tmx, 0, sizeof(tmx)); @@ -1667,7 +1667,7 @@ recv_and_process_peer_pkt(peer_t *p) p->reachable_bits |= 1; if ((MAX_VERBOSE && G.verbose) || (option_mask32 & OPT_w)) { - bb_error_msg("reply from %s: reach 0x%02x offset %+f delay %f status 0x%02x strat %d refid 0x%08x rootdelay %f", + bb_error_msg("reply from:%s reach:0x%02x offset:%+f delay:%f status:0x%02x strat:%d refid:0x%08x rootdelay:%f", p->p_dotted, p->reachable_bits, datapoint->d_offset, @@ -2100,7 +2100,7 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv) if (--timeout <= 0) goto did_poll; } - bb_error_msg("poll %us, sockets:%u, poll interval:%us", timeout, i, 1 << G.poll_exp); + bb_error_msg("poll:%us sockets:%u interval:%us", timeout, i, 1 << G.poll_exp); } nfds = poll(pfd, i, timeout * 1000); did_poll: -- cgit v1.2.3-55-g6feb From d4acaf70c586ea72fce0e4af4cba87d4a6d00655 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 7 Mar 2012 11:44:15 +0100 Subject: printf: trim help text Signed-off-by: Denys Vlasenko --- coreutils/printf.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/coreutils/printf.c b/coreutils/printf.c index f53aa4787..1437951a8 100644 --- a/coreutils/printf.c +++ b/coreutils/printf.c @@ -36,13 +36,12 @@ David MacKenzie */ -// 19990508 Busy Boxed! Dave Cinege +/* 19990508 Busy Boxed! Dave Cinege */ //usage:#define printf_trivial_usage -//usage: "FORMAT [ARGUMENT]..." +//usage: "FORMAT [ARG]..." //usage:#define printf_full_usage "\n\n" -//usage: "Format and print ARGUMENT(s) according to FORMAT,\n" -//usage: "where FORMAT controls the output exactly as in C printf" +//usage: "Format and print ARG(s) according to FORMAT (a-la C printf)" //usage: //usage:#define printf_example_usage //usage: "$ printf \"Val=%d\\n\" 5\n" -- cgit v1.2.3-55-g6feb From 69d81a1c1b2e4881b751ee24f8eb70c0dfaa05d9 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 7 Mar 2012 11:57:47 +0100 Subject: printf: fix this case: printf "%b" '\0057usr\0057bin\n' It was not accepting \0NNN. Standard printf tool does. function old new delta printf_main 869 886 +17 Signed-off-by: Denys Vlasenko --- coreutils/printf.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/coreutils/printf.c b/coreutils/printf.c index 1437951a8..3dd43a978 100644 --- a/coreutils/printf.c +++ b/coreutils/printf.c @@ -131,13 +131,28 @@ static double my_xstrtod(const char *arg) return result; } +/* Handles %b */ static void print_esc_string(const char *str) { char c; while ((c = *str) != '\0') { str++; - if (c == '\\') - c = bb_process_escape_sequence(&str); + if (c == '\\') { + /* %b also accepts 4-digit octals of the form \0### */ + if (*str == '0') { + if ((unsigned char)(str[1] - '0') < 8) { + /* 2nd char is 0..7: skip leading '0' */ + str++; + } + } + { + /* optimization: don't force arg to be on-stack, + * use another variable for that. */ + const char *z = str; + c = bb_process_escape_sequence(&z); + str = z; + } + } putchar(c); } } -- cgit v1.2.3-55-g6feb From bf6343796e834183ff1b0c1b9416676e8488afa5 Mon Sep 17 00:00:00 2001 From: Rob Walker Date: Wed, 7 Mar 2012 12:25:53 +0100 Subject: Add SYSROOT, EXTRA_{LDFLAGS,LDLIBS} config opts; sample Android NDK config Signed-off-by: Rob Walker Signed-off-by: Denys Vlasenko --- Config.in | 27 ++ Makefile.flags | 15 + configs/android_ndk_defconfig | 1016 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1058 insertions(+) create mode 100644 configs/android_ndk_defconfig diff --git a/Config.in b/Config.in index 79fe8ff9a..17bdc895a 100644 --- a/Config.in +++ b/Config.in @@ -600,12 +600,39 @@ config CROSS_COMPILER_PREFIX Native builds leave this empty. +config SYSROOT + string "Path to sysroot" + default "" + help + If you want to build BusyBox with a cross compiler, then you + might also need to specify where /usr/include and /usr/lib + will be found. + + For example, BusyBox can be built against an installed + Android NDK, platform version 9, for ARM ABI with + + CONFIG_SYSROOT=/opt/android-ndk/platforms/android-9/arch-arm + + Native builds leave this empty. + config EXTRA_CFLAGS string "Additional CFLAGS" default "" help Additional CFLAGS to pass to the compiler verbatim. +config EXTRA_LDFLAGS + string "Additional LDFLAGS" + default "" + help + Additional LDFLAGS to pass to the linker verbatim. + +config EXTRA_LDLIBS + string "Additional LDLIBS" + default "" + help + Additional LDLIBS to pass to the linker with -l. + endmenu menu 'Debugging Options' diff --git a/Makefile.flags b/Makefile.flags index ee4c518d8..68dfa57ec 100644 --- a/Makefile.flags +++ b/Makefile.flags @@ -104,6 +104,11 @@ else LDLIBS += m endif +ifneq ($(CONFIG_SYSROOT),) +CFLAGS += --sysroot=$(CONFIG_SYSROOT) +export SYSROOT=$(CONFIG_SYSROOT) +endif + ifeq ($(CONFIG_PAM),y) # libpam uses libpthread, so for static builds busybox must be linked to # libpthread. On some platforms that requires an explicit -lpthread, so @@ -137,6 +142,16 @@ ifneq (,$(findstring $(W_ELF2FLT),$(LDFLAGS) $(CFLAGS_busybox))) SKIP_STRIP = y endif +ifneq ($(CONFIG_EXTRA_LDFLAGS),) +EXTRA_LDFLAGS += $(strip $(subst ",,$(CONFIG_EXTRA_LDFLAGS))) +#")) +endif + +ifneq ($(CONFIG_EXTRA_LDLIBS),) +LDLIBS += $(strip $(subst ",,$(CONFIG_EXTRA_LDLIBS))) +#")) +endif + # Busybox is a stack-fatty so make sure we increase default size # TODO: use "make stksizes" to find & fix big stack users # (we stole scripts/checkstack.pl from the kernel... thanks guys!) diff --git a/configs/android_ndk_defconfig b/configs/android_ndk_defconfig new file mode 100644 index 000000000..bf8827a58 --- /dev/null +++ b/configs/android_ndk_defconfig @@ -0,0 +1,1016 @@ +# +# Automatically generated make config: don't edit +# Busybox version: 1.20.0.git +# Fri Mar 2 16:53:26 2012 +# +CONFIG_HAVE_DOT_CONFIG=y + +# +# Busybox Settings +# + +# +# General Configuration +# +CONFIG_DESKTOP=y +# CONFIG_EXTRA_COMPAT is not set +# CONFIG_INCLUDE_SUSv2 is not set +# CONFIG_USE_PORTABLE_CODE is not set +CONFIG_PLATFORM_LINUX=y +CONFIG_FEATURE_BUFFERS_USE_MALLOC=y +# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set +# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set +# CONFIG_SHOW_USAGE is not set +# CONFIG_FEATURE_VERBOSE_USAGE is not set +# CONFIG_FEATURE_COMPRESS_USAGE is not set +# CONFIG_FEATURE_INSTALLER is not set +# CONFIG_INSTALL_NO_USR is not set +# CONFIG_LOCALE_SUPPORT is not set +# CONFIG_UNICODE_SUPPORT is not set +# CONFIG_UNICODE_USING_LOCALE is not set +# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set +CONFIG_SUBST_WCHAR=0 +CONFIG_LAST_SUPPORTED_WCHAR=0 +# CONFIG_UNICODE_COMBINING_WCHARS is not set +# CONFIG_UNICODE_WIDE_WCHARS is not set +# CONFIG_UNICODE_BIDI_SUPPORT is not set +# CONFIG_UNICODE_NEUTRAL_TABLE is not set +# CONFIG_UNICODE_PRESERVE_BROKEN is not set +# CONFIG_LONG_OPTS is not set +# CONFIG_FEATURE_DEVPTS is not set +# CONFIG_FEATURE_CLEAN_UP is not set +# CONFIG_FEATURE_UTMP is not set +# CONFIG_FEATURE_WTMP is not set +# CONFIG_FEATURE_PIDFILE is not set +# CONFIG_FEATURE_SUID is not set +# CONFIG_FEATURE_SUID_CONFIG is not set +# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set +# CONFIG_SELINUX is not set +# CONFIG_FEATURE_PREFER_APPLETS is not set +CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" +CONFIG_FEATURE_SYSLOG=y +# CONFIG_FEATURE_HAVE_RPC is not set + +# +# Build Options +# +# CONFIG_STATIC is not set +# CONFIG_PIE is not set +# CONFIG_NOMMU is not set +# CONFIG_BUILD_LIBBUSYBOX is not set +# CONFIG_FEATURE_INDIVIDUAL is not set +# CONFIG_FEATURE_SHARED_BUSYBOX is not set +# CONFIG_LFS is not set +CONFIG_CROSS_COMPILER_PREFIX="arm-linux-androideabi-" +CONFIG_SYSROOT="/opt/android-ndk/platforms/android-9/arch-arm" +CONFIG_EXTRA_CFLAGS="-DANDROID -D__ANDROID__ -DSK_RELEASE -nostdlib -march=armv7-a -msoft-float -mfloat-abi=softfp -mfpu=neon -mthumb -mthumb-interwork -fpic -fno-short-enums -fgcse-after-reload -frename-registers" +CONFIG_EXTRA_LDFLAGS="-Xlinker -z -Xlinker muldefs -nostdlib -Bdynamic -Xlinker -dynamic-linker -Xlinker /system/bin/linker -Xlinker -z -Xlinker nocopyreloc -Xlinker --no-undefined ${SYSROOT}/usr/lib/crtbegin_dynamic.o ${SYSROOT}/usr/lib/crtend_android.o" +CONFIG_EXTRA_LDLIBS="dl m c gcc" + + +# +# Debugging Options +# +# CONFIG_DEBUG is not set +# CONFIG_DEBUG_PESSIMIZE is not set +# CONFIG_WERROR is not set +CONFIG_NO_DEBUG_LIB=y +# CONFIG_DMALLOC is not set +# CONFIG_EFENCE is not set + +# +# Installation Options ("make install" behavior) +# +CONFIG_INSTALL_APPLET_SYMLINKS=y +# CONFIG_INSTALL_APPLET_HARDLINKS is not set +# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set +# CONFIG_INSTALL_APPLET_DONT is not set +# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set +# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set +# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set +CONFIG_PREFIX="./_install" + +# +# Busybox Library Tuning +# +# CONFIG_FEATURE_SYSTEMD is not set +# CONFIG_FEATURE_RTMINMAX is not set +CONFIG_PASSWORD_MINLEN=6 +CONFIG_MD5_SMALL=1 +# CONFIG_FEATURE_FAST_TOP is not set +# CONFIG_FEATURE_ETC_NETWORKS is not set +CONFIG_FEATURE_USE_TERMIOS=y +# CONFIG_FEATURE_EDITING is not set +CONFIG_FEATURE_EDITING_MAX_LEN=0 +# CONFIG_FEATURE_EDITING_VI is not set +CONFIG_FEATURE_EDITING_HISTORY=0 +# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set +# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set +# CONFIG_FEATURE_REVERSE_SEARCH is not set +# CONFIG_FEATURE_TAB_COMPLETION is not set +# CONFIG_FEATURE_USERNAME_COMPLETION is not set +# CONFIG_FEATURE_EDITING_FANCY_PROMPT is not set +# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set +# CONFIG_FEATURE_NON_POSIX_CP is not set +# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set +CONFIG_FEATURE_COPYBUF_KB=4 +# CONFIG_FEATURE_SKIP_ROOTFS is not set +# CONFIG_MONOTONIC_SYSCALL is not set +# CONFIG_IOCTL_HEX2STR_ERROR is not set +# CONFIG_FEATURE_HWIB is not set + +# +# Applets +# + +# +# Archival Utilities +# +CONFIG_FEATURE_SEAMLESS_XZ=y +CONFIG_FEATURE_SEAMLESS_LZMA=y +CONFIG_FEATURE_SEAMLESS_BZ2=y +CONFIG_FEATURE_SEAMLESS_GZ=y +CONFIG_FEATURE_SEAMLESS_Z=y +CONFIG_AR=y +CONFIG_FEATURE_AR_LONG_FILENAMES=y +CONFIG_FEATURE_AR_CREATE=y +CONFIG_BUNZIP2=y +CONFIG_BZIP2=y +CONFIG_CPIO=y +CONFIG_FEATURE_CPIO_O=y +CONFIG_FEATURE_CPIO_P=y +CONFIG_DPKG=y +CONFIG_DPKG_DEB=y +# CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY is not set +CONFIG_GUNZIP=y +CONFIG_GZIP=y +# CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set +CONFIG_GZIP_FAST=0 +CONFIG_LZOP=y +CONFIG_LZOP_COMPR_HIGH=y +CONFIG_RPM2CPIO=y +CONFIG_RPM=y +CONFIG_TAR=y +CONFIG_FEATURE_TAR_CREATE=y +CONFIG_FEATURE_TAR_AUTODETECT=y +CONFIG_FEATURE_TAR_FROM=y +CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y +CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY=y +CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y +# CONFIG_FEATURE_TAR_LONG_OPTIONS is not set +# CONFIG_FEATURE_TAR_TO_COMMAND is not set +CONFIG_FEATURE_TAR_UNAME_GNAME=y +CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y +# CONFIG_FEATURE_TAR_SELINUX is not set +CONFIG_UNCOMPRESS=y +CONFIG_UNLZMA=y +CONFIG_FEATURE_LZMA_FAST=y +CONFIG_LZMA=y +CONFIG_UNXZ=y +CONFIG_XZ=y +CONFIG_UNZIP=y + +# +# Coreutils +# +CONFIG_BASENAME=y +CONFIG_CAT=y +# CONFIG_DATE is not set +# CONFIG_FEATURE_DATE_ISOFMT is not set +# CONFIG_FEATURE_DATE_NANO is not set +# CONFIG_FEATURE_DATE_COMPAT is not set +# CONFIG_HOSTID is not set +# CONFIG_ID is not set +# CONFIG_GROUPS is not set +CONFIG_TEST=y +CONFIG_FEATURE_TEST_64=y +CONFIG_TOUCH=y +CONFIG_FEATURE_TOUCH_SUSV3=y +CONFIG_TR=y +CONFIG_FEATURE_TR_CLASSES=y +CONFIG_FEATURE_TR_EQUIV=y +CONFIG_BASE64=y +# CONFIG_WHO is not set +# CONFIG_USERS is not set +CONFIG_CAL=y +CONFIG_CATV=y +CONFIG_CHGRP=y +CONFIG_CHMOD=y +CONFIG_CHOWN=y +# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set +CONFIG_CHROOT=y +CONFIG_CKSUM=y +CONFIG_COMM=y +CONFIG_CP=y +# CONFIG_FEATURE_CP_LONG_OPTIONS is not set +CONFIG_CUT=y +CONFIG_DD=y +CONFIG_FEATURE_DD_SIGNAL_HANDLING=y +CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y +CONFIG_FEATURE_DD_IBS_OBS=y +# CONFIG_DF is not set +# CONFIG_FEATURE_DF_FANCY is not set +CONFIG_DIRNAME=y +CONFIG_DOS2UNIX=y +CONFIG_UNIX2DOS=y +CONFIG_DU=y +CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y +CONFIG_ECHO=y +CONFIG_FEATURE_FANCY_ECHO=y +CONFIG_ENV=y +# CONFIG_FEATURE_ENV_LONG_OPTIONS is not set +CONFIG_EXPAND=y +# CONFIG_FEATURE_EXPAND_LONG_OPTIONS is not set +CONFIG_EXPR=y +CONFIG_EXPR_MATH_SUPPORT_64=y +CONFIG_FALSE=y +CONFIG_FOLD=y +CONFIG_FSYNC=y +CONFIG_HEAD=y +CONFIG_FEATURE_FANCY_HEAD=y +CONFIG_INSTALL=y +# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set +CONFIG_LN=y +# CONFIG_LOGNAME is not set +CONFIG_LS=y +CONFIG_FEATURE_LS_FILETYPES=y +CONFIG_FEATURE_LS_FOLLOWLINKS=y +CONFIG_FEATURE_LS_RECURSIVE=y +CONFIG_FEATURE_LS_SORTFILES=y +CONFIG_FEATURE_LS_TIMESTAMPS=y +CONFIG_FEATURE_LS_USERNAME=y +# CONFIG_FEATURE_LS_COLOR is not set +# CONFIG_FEATURE_LS_COLOR_IS_DEFAULT is not set +CONFIG_MD5SUM=y +CONFIG_MKDIR=y +# CONFIG_FEATURE_MKDIR_LONG_OPTIONS is not set +CONFIG_MKFIFO=y +CONFIG_MKNOD=y +CONFIG_MV=y +# CONFIG_FEATURE_MV_LONG_OPTIONS is not set +CONFIG_NICE=y +CONFIG_NOHUP=y +CONFIG_OD=y +CONFIG_PRINTENV=y +CONFIG_PRINTF=y +CONFIG_PWD=y +CONFIG_READLINK=y +CONFIG_FEATURE_READLINK_FOLLOW=y +CONFIG_REALPATH=y +CONFIG_RM=y +CONFIG_RMDIR=y +# CONFIG_FEATURE_RMDIR_LONG_OPTIONS is not set +CONFIG_SEQ=y +CONFIG_SHA1SUM=y +CONFIG_SHA256SUM=y +CONFIG_SHA512SUM=y +CONFIG_SLEEP=y +CONFIG_FEATURE_FANCY_SLEEP=y +CONFIG_FEATURE_FLOAT_SLEEP=y +CONFIG_SORT=y +CONFIG_FEATURE_SORT_BIG=y +CONFIG_SPLIT=y +CONFIG_FEATURE_SPLIT_FANCY=y +# CONFIG_STAT is not set +# CONFIG_FEATURE_STAT_FORMAT is not set +CONFIG_STTY=y +CONFIG_SUM=y +CONFIG_SYNC=y +CONFIG_TAC=y +CONFIG_TAIL=y +CONFIG_FEATURE_FANCY_TAIL=y +CONFIG_TEE=y +CONFIG_FEATURE_TEE_USE_BLOCK_IO=y +CONFIG_TRUE=y +# CONFIG_TTY is not set +CONFIG_UNAME=y +CONFIG_UNEXPAND=y +# CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS is not set +CONFIG_UNIQ=y +CONFIG_USLEEP=y +CONFIG_UUDECODE=y +CONFIG_UUENCODE=y +CONFIG_WC=y +CONFIG_FEATURE_WC_LARGE=y +CONFIG_WHOAMI=y +CONFIG_YES=y + +# +# Common options for cp and mv +# +CONFIG_FEATURE_PRESERVE_HARDLINKS=y + +# +# Common options for ls, more and telnet +# +CONFIG_FEATURE_AUTOWIDTH=y + +# +# Common options for df, du, ls +# +CONFIG_FEATURE_HUMAN_READABLE=y + +# +# Common options for md5sum, sha1sum, sha256sum, sha512sum +# +CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y + +# +# Console Utilities +# +CONFIG_CHVT=y +CONFIG_FGCONSOLE=y +CONFIG_CLEAR=y +CONFIG_DEALLOCVT=y +CONFIG_DUMPKMAP=y +# CONFIG_KBD_MODE is not set +# CONFIG_LOADFONT is not set +CONFIG_LOADKMAP=y +CONFIG_OPENVT=y +CONFIG_RESET=y +CONFIG_RESIZE=y +CONFIG_FEATURE_RESIZE_PRINT=y +CONFIG_SETCONSOLE=y +# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set +# CONFIG_SETFONT is not set +# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set +CONFIG_DEFAULT_SETFONT_DIR="" +CONFIG_SETKEYCODES=y +CONFIG_SETLOGCONS=y +CONFIG_SHOWKEY=y +# CONFIG_FEATURE_LOADFONT_PSF2 is not set +# CONFIG_FEATURE_LOADFONT_RAW is not set + +# +# Debian Utilities +# +CONFIG_MKTEMP=y +CONFIG_PIPE_PROGRESS=y +CONFIG_RUN_PARTS=y +# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set +CONFIG_FEATURE_RUN_PARTS_FANCY=y +CONFIG_START_STOP_DAEMON=y +CONFIG_FEATURE_START_STOP_DAEMON_FANCY=y +# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set +CONFIG_WHICH=y + +# +# Editors +# +CONFIG_PATCH=y +CONFIG_VI=y +CONFIG_FEATURE_VI_MAX_LEN=4096 +CONFIG_FEATURE_VI_8BIT=y +CONFIG_FEATURE_VI_COLON=y +CONFIG_FEATURE_VI_YANKMARK=y +CONFIG_FEATURE_VI_SEARCH=y +# CONFIG_FEATURE_VI_REGEX_SEARCH is not set +CONFIG_FEATURE_VI_USE_SIGNALS=y +CONFIG_FEATURE_VI_DOT_CMD=y +CONFIG_FEATURE_VI_READONLY=y +CONFIG_FEATURE_VI_SETOPTS=y +CONFIG_FEATURE_VI_SET=y +CONFIG_FEATURE_VI_WIN_RESIZE=y +CONFIG_FEATURE_VI_ASK_TERMINAL=y +CONFIG_FEATURE_VI_OPTIMIZE_CURSOR=y +CONFIG_AWK=y +CONFIG_FEATURE_AWK_LIBM=y +CONFIG_CMP=y +CONFIG_DIFF=y +# CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set +CONFIG_FEATURE_DIFF_DIR=y +CONFIG_ED=y +CONFIG_SED=y +CONFIG_FEATURE_ALLOW_EXEC=y + +# +# Finding Utilities +# +CONFIG_FIND=y +CONFIG_FEATURE_FIND_PRINT0=y +CONFIG_FEATURE_FIND_MTIME=y +CONFIG_FEATURE_FIND_MMIN=y +CONFIG_FEATURE_FIND_PERM=y +CONFIG_FEATURE_FIND_TYPE=y +CONFIG_FEATURE_FIND_XDEV=y +CONFIG_FEATURE_FIND_MAXDEPTH=y +CONFIG_FEATURE_FIND_NEWER=y +CONFIG_FEATURE_FIND_INUM=y +CONFIG_FEATURE_FIND_EXEC=y +CONFIG_FEATURE_FIND_USER=y +CONFIG_FEATURE_FIND_GROUP=y +CONFIG_FEATURE_FIND_NOT=y +CONFIG_FEATURE_FIND_DEPTH=y +CONFIG_FEATURE_FIND_PAREN=y +CONFIG_FEATURE_FIND_SIZE=y +CONFIG_FEATURE_FIND_PRUNE=y +CONFIG_FEATURE_FIND_DELETE=y +CONFIG_FEATURE_FIND_PATH=y +CONFIG_FEATURE_FIND_REGEX=y +# CONFIG_FEATURE_FIND_CONTEXT is not set +CONFIG_FEATURE_FIND_LINKS=y +CONFIG_GREP=y +CONFIG_FEATURE_GREP_EGREP_ALIAS=y +CONFIG_FEATURE_GREP_FGREP_ALIAS=y +CONFIG_FEATURE_GREP_CONTEXT=y +CONFIG_XARGS=y +CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y +CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y +CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y +CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y + +# +# Init Utilities +# +CONFIG_BOOTCHARTD=y +CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER=y +CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE=y +CONFIG_HALT=y +# CONFIG_FEATURE_CALL_TELINIT is not set +CONFIG_TELINIT_PATH="" +CONFIG_INIT=y +CONFIG_FEATURE_USE_INITTAB=y +# CONFIG_FEATURE_KILL_REMOVED is not set +CONFIG_FEATURE_KILL_DELAY=0 +CONFIG_FEATURE_INIT_SCTTY=y +CONFIG_FEATURE_INIT_SYSLOG=y +CONFIG_FEATURE_EXTRA_QUIET=y +CONFIG_FEATURE_INIT_COREDUMPS=y +CONFIG_FEATURE_INITRD=y +CONFIG_INIT_TERMINAL_TYPE="linux" +CONFIG_MESG=y +CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP=y + +# +# Login/Password Management Utilities +# +# CONFIG_ADD_SHELL is not set +# CONFIG_REMOVE_SHELL is not set +# CONFIG_FEATURE_SHADOWPASSWDS is not set +# CONFIG_USE_BB_PWD_GRP is not set +# CONFIG_USE_BB_SHADOW is not set +# CONFIG_USE_BB_CRYPT is not set +# CONFIG_USE_BB_CRYPT_SHA is not set +# CONFIG_ADDUSER is not set +# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set +# CONFIG_FEATURE_CHECK_NAMES is not set +CONFIG_FIRST_SYSTEM_ID=0 +CONFIG_LAST_SYSTEM_ID=0 +# CONFIG_ADDGROUP is not set +# CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS is not set +# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set +# CONFIG_DELUSER is not set +# CONFIG_DELGROUP is not set +# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set +# CONFIG_GETTY is not set +# CONFIG_LOGIN is not set +# CONFIG_LOGIN_SESSION_AS_CHILD is not set +# CONFIG_PAM is not set +# CONFIG_LOGIN_SCRIPTS is not set +# CONFIG_FEATURE_NOLOGIN is not set +# CONFIG_FEATURE_SECURETTY is not set +# CONFIG_PASSWD is not set +# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set +# CONFIG_CRYPTPW is not set +# CONFIG_CHPASSWD is not set +CONFIG_FEATURE_DEFAULT_PASSWD_ALGO="" +# CONFIG_SU is not set +# CONFIG_FEATURE_SU_SYSLOG is not set +# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set +# CONFIG_SULOGIN is not set +# CONFIG_VLOCK is not set + +# +# Linux Ext2 FS Progs +# +CONFIG_CHATTR=y +# CONFIG_FSCK is not set +CONFIG_LSATTR=y +CONFIG_TUNE2FS=y + +# +# Linux Module Utilities +# +CONFIG_MODINFO=y +CONFIG_MODPROBE_SMALL=y +CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE=y +CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED=y +# CONFIG_INSMOD is not set +# CONFIG_RMMOD is not set +# CONFIG_LSMOD is not set +# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set +# CONFIG_MODPROBE is not set +# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set +# CONFIG_DEPMOD is not set + +# +# Options common to multiple modutils +# +# CONFIG_FEATURE_2_4_MODULES is not set +# CONFIG_FEATURE_INSMOD_TRY_MMAP is not set +# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set +# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set +# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set +# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set +# CONFIG_FEATURE_MODUTILS_ALIAS is not set +# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set +CONFIG_DEFAULT_MODULES_DIR="/lib/modules" +CONFIG_DEFAULT_DEPMOD_FILE="modules.dep" + +# +# Linux System Utilities +# +CONFIG_BLOCKDEV=y +CONFIG_MDEV=y +CONFIG_FEATURE_MDEV_CONF=y +CONFIG_FEATURE_MDEV_RENAME=y +CONFIG_FEATURE_MDEV_RENAME_REGEXP=y +CONFIG_FEATURE_MDEV_EXEC=y +CONFIG_FEATURE_MDEV_LOAD_FIRMWARE=y +CONFIG_REV=y +# CONFIG_ACPID is not set +# CONFIG_FEATURE_ACPID_COMPAT is not set +CONFIG_BLKID=y +CONFIG_FEATURE_BLKID_TYPE=y +CONFIG_DMESG=y +CONFIG_FEATURE_DMESG_PRETTY=y +CONFIG_FBSET=y +CONFIG_FEATURE_FBSET_FANCY=y +CONFIG_FEATURE_FBSET_READMODE=y +CONFIG_FDFLUSH=y +CONFIG_FDFORMAT=y +CONFIG_FDISK=y +CONFIG_FDISK_SUPPORT_LARGE_DISKS=y +CONFIG_FEATURE_FDISK_WRITABLE=y +# CONFIG_FEATURE_AIX_LABEL is not set +# CONFIG_FEATURE_SGI_LABEL is not set +# CONFIG_FEATURE_SUN_LABEL is not set +# CONFIG_FEATURE_OSF_LABEL is not set +# CONFIG_FEATURE_GPT_LABEL is not set +CONFIG_FEATURE_FDISK_ADVANCED=y +CONFIG_FINDFS=y +CONFIG_FLOCK=y +CONFIG_FREERAMDISK=y +# CONFIG_FSCK_MINIX is not set +# CONFIG_MKFS_EXT2 is not set +# CONFIG_MKFS_MINIX is not set +# CONFIG_FEATURE_MINIX2 is not set +# CONFIG_MKFS_REISER is not set +# CONFIG_MKFS_VFAT is not set +CONFIG_GETOPT=y +CONFIG_FEATURE_GETOPT_LONG=y +CONFIG_HEXDUMP=y +CONFIG_FEATURE_HEXDUMP_REVERSE=y +CONFIG_HD=y +CONFIG_HWCLOCK=y +# CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set +# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set +# CONFIG_IPCRM is not set +# CONFIG_IPCS is not set +CONFIG_LOSETUP=y +CONFIG_LSPCI=y +CONFIG_LSUSB=y +CONFIG_MKSWAP=y +CONFIG_FEATURE_MKSWAP_UUID=y +CONFIG_MORE=y +# CONFIG_MOUNT is not set +# CONFIG_FEATURE_MOUNT_FAKE is not set +# CONFIG_FEATURE_MOUNT_VERBOSE is not set +# CONFIG_FEATURE_MOUNT_HELPERS is not set +# CONFIG_FEATURE_MOUNT_LABEL is not set +# CONFIG_FEATURE_MOUNT_NFS is not set +# CONFIG_FEATURE_MOUNT_CIFS is not set +# CONFIG_FEATURE_MOUNT_FLAGS is not set +# CONFIG_FEATURE_MOUNT_FSTAB is not set +# CONFIG_PIVOT_ROOT is not set +# CONFIG_RDATE is not set +CONFIG_RDEV=y +CONFIG_READPROFILE=y +CONFIG_RTCWAKE=y +CONFIG_SCRIPT=y +CONFIG_SCRIPTREPLAY=y +# CONFIG_SETARCH is not set +# CONFIG_SWAPONOFF is not set +# CONFIG_FEATURE_SWAPON_PRI is not set +CONFIG_SWITCH_ROOT=y +# CONFIG_UMOUNT is not set +# CONFIG_FEATURE_UMOUNT_ALL is not set +# CONFIG_FEATURE_MOUNT_LOOP is not set +# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set +# CONFIG_FEATURE_MTAB_SUPPORT is not set +CONFIG_VOLUMEID=y + +# +# Filesystem/Volume identification +# +CONFIG_FEATURE_VOLUMEID_EXT=y +CONFIG_FEATURE_VOLUMEID_BTRFS=y +CONFIG_FEATURE_VOLUMEID_REISERFS=y +CONFIG_FEATURE_VOLUMEID_FAT=y +CONFIG_FEATURE_VOLUMEID_HFS=y +CONFIG_FEATURE_VOLUMEID_JFS=y +CONFIG_FEATURE_VOLUMEID_XFS=y +CONFIG_FEATURE_VOLUMEID_NTFS=y +CONFIG_FEATURE_VOLUMEID_ISO9660=y +CONFIG_FEATURE_VOLUMEID_UDF=y +CONFIG_FEATURE_VOLUMEID_LUKS=y +CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y +CONFIG_FEATURE_VOLUMEID_CRAMFS=y +CONFIG_FEATURE_VOLUMEID_ROMFS=y +CONFIG_FEATURE_VOLUMEID_SYSV=y +CONFIG_FEATURE_VOLUMEID_OCFS2=y +CONFIG_FEATURE_VOLUMEID_LINUXRAID=y + +# +# Miscellaneous Utilities +# +# CONFIG_CONSPY is not set +CONFIG_LESS=y +CONFIG_FEATURE_LESS_MAXLINES=9999999 +CONFIG_FEATURE_LESS_BRACKETS=y +CONFIG_FEATURE_LESS_FLAGS=y +CONFIG_FEATURE_LESS_MARKS=y +CONFIG_FEATURE_LESS_REGEXP=y +CONFIG_FEATURE_LESS_WINCH=y +CONFIG_FEATURE_LESS_ASK_TERMINAL=y +CONFIG_FEATURE_LESS_DASHCMD=y +CONFIG_FEATURE_LESS_LINENUMS=y +# CONFIG_NANDWRITE is not set +CONFIG_NANDDUMP=y +CONFIG_SETSERIAL=y +# CONFIG_UBIATTACH is not set +# CONFIG_UBIDETACH is not set +# CONFIG_UBIMKVOL is not set +# CONFIG_UBIRMVOL is not set +# CONFIG_UBIRSVOL is not set +# CONFIG_UBIUPDATEVOL is not set +# CONFIG_ADJTIMEX is not set +# CONFIG_BBCONFIG is not set +# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set +CONFIG_BEEP=y +CONFIG_FEATURE_BEEP_FREQ=4000 +CONFIG_FEATURE_BEEP_LENGTH_MS=30 +CONFIG_CHAT=y +CONFIG_FEATURE_CHAT_NOFAIL=y +# CONFIG_FEATURE_CHAT_TTY_HIFI is not set +CONFIG_FEATURE_CHAT_IMPLICIT_CR=y +CONFIG_FEATURE_CHAT_SWALLOW_OPTS=y +CONFIG_FEATURE_CHAT_SEND_ESCAPES=y +CONFIG_FEATURE_CHAT_VAR_ABORT_LEN=y +CONFIG_FEATURE_CHAT_CLR_ABORT=y +CONFIG_CHRT=y +CONFIG_CROND=y +CONFIG_FEATURE_CROND_D=y +CONFIG_FEATURE_CROND_CALL_SENDMAIL=y +CONFIG_FEATURE_CROND_DIR="/var/spool/cron" +CONFIG_CRONTAB=y +CONFIG_DC=y +CONFIG_FEATURE_DC_LIBM=y +# CONFIG_DEVFSD is not set +# CONFIG_DEVFSD_MODLOAD is not set +# CONFIG_DEVFSD_FG_NP is not set +# CONFIG_DEVFSD_VERBOSE is not set +# CONFIG_FEATURE_DEVFS is not set +CONFIG_DEVMEM=y +# CONFIG_EJECT is not set +# CONFIG_FEATURE_EJECT_SCSI is not set +CONFIG_FBSPLASH=y +CONFIG_FLASHCP=y +CONFIG_FLASH_LOCK=y +CONFIG_FLASH_UNLOCK=y +# CONFIG_FLASH_ERASEALL is not set +# CONFIG_IONICE is not set +CONFIG_INOTIFYD=y +# CONFIG_LAST is not set +# CONFIG_FEATURE_LAST_SMALL is not set +# CONFIG_FEATURE_LAST_FANCY is not set +CONFIG_HDPARM=y +CONFIG_FEATURE_HDPARM_GET_IDENTITY=y +CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF=y +CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF=y +CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET=y +CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF=y +CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA=y +CONFIG_MAKEDEVS=y +# CONFIG_FEATURE_MAKEDEVS_LEAF is not set +CONFIG_FEATURE_MAKEDEVS_TABLE=y +CONFIG_MAN=y +# CONFIG_MICROCOM is not set +# CONFIG_MOUNTPOINT is not set +# CONFIG_MT is not set +CONFIG_RAIDAUTORUN=y +# CONFIG_READAHEAD is not set +# CONFIG_RFKILL is not set +# CONFIG_RUNLEVEL is not set +CONFIG_RX=y +CONFIG_SETSID=y +CONFIG_STRINGS=y +# CONFIG_TASKSET is not set +# CONFIG_FEATURE_TASKSET_FANCY is not set +CONFIG_TIME=y +CONFIG_TIMEOUT=y +CONFIG_TTYSIZE=y +CONFIG_VOLNAME=y +# CONFIG_WALL is not set +# CONFIG_WATCHDOG is not set + +# +# Networking Utilities +# +# CONFIG_NAMEIF is not set +# CONFIG_FEATURE_NAMEIF_EXTENDED is not set +CONFIG_NBDCLIENT=y +CONFIG_NC=y +CONFIG_NC_SERVER=y +CONFIG_NC_EXTRA=y +# CONFIG_NC_110_COMPAT is not set +CONFIG_PING=y +# CONFIG_PING6 is not set +CONFIG_FEATURE_FANCY_PING=y +CONFIG_WHOIS=y +# CONFIG_FEATURE_IPV6 is not set +# CONFIG_FEATURE_UNIX_LOCAL is not set +# CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set +# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set +CONFIG_ARP=y +# CONFIG_ARPING is not set +# CONFIG_BRCTL is not set +# CONFIG_FEATURE_BRCTL_FANCY is not set +# CONFIG_FEATURE_BRCTL_SHOW is not set +CONFIG_DNSD=y +# CONFIG_ETHER_WAKE is not set +CONFIG_FAKEIDENTD=y +CONFIG_FTPD=y +CONFIG_FEATURE_FTP_WRITE=y +CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST=y +CONFIG_FTPGET=y +CONFIG_FTPPUT=y +# CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set +# CONFIG_HOSTNAME is not set +CONFIG_HTTPD=y +CONFIG_FEATURE_HTTPD_RANGES=y +CONFIG_FEATURE_HTTPD_USE_SENDFILE=y +CONFIG_FEATURE_HTTPD_SETUID=y +CONFIG_FEATURE_HTTPD_BASIC_AUTH=y +# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set +CONFIG_FEATURE_HTTPD_CGI=y +CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y +CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV=y +CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y +CONFIG_FEATURE_HTTPD_ERROR_PAGES=y +CONFIG_FEATURE_HTTPD_PROXY=y +CONFIG_FEATURE_HTTPD_GZIP=y +CONFIG_IFCONFIG=y +CONFIG_FEATURE_IFCONFIG_STATUS=y +# CONFIG_FEATURE_IFCONFIG_SLIP is not set +CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ=y +CONFIG_FEATURE_IFCONFIG_HW=y +CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS=y +# CONFIG_IFENSLAVE is not set +# CONFIG_IFPLUGD is not set +CONFIG_IFUPDOWN=y +CONFIG_IFUPDOWN_IFSTATE_PATH="/var/run/ifstate" +CONFIG_FEATURE_IFUPDOWN_IP=y +CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN=y +# CONFIG_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN is not set +CONFIG_FEATURE_IFUPDOWN_IPV4=y +# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set +CONFIG_FEATURE_IFUPDOWN_MAPPING=y +CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP=y +# CONFIG_INETD is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set +# CONFIG_FEATURE_INETD_RPC is not set +CONFIG_IP=y +CONFIG_FEATURE_IP_ADDRESS=y +CONFIG_FEATURE_IP_LINK=y +CONFIG_FEATURE_IP_ROUTE=y +CONFIG_FEATURE_IP_TUNNEL=y +CONFIG_FEATURE_IP_RULE=y +CONFIG_FEATURE_IP_SHORT_FORMS=y +# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set +CONFIG_IPADDR=y +CONFIG_IPLINK=y +CONFIG_IPROUTE=y +CONFIG_IPTUNNEL=y +CONFIG_IPRULE=y +CONFIG_IPCALC=y +CONFIG_FEATURE_IPCALC_FANCY=y +# CONFIG_FEATURE_IPCALC_LONG_OPTIONS is not set +CONFIG_NETSTAT=y +CONFIG_FEATURE_NETSTAT_WIDE=y +CONFIG_FEATURE_NETSTAT_PRG=y +# CONFIG_NSLOOKUP is not set +# CONFIG_NTPD is not set +# CONFIG_FEATURE_NTPD_SERVER is not set +CONFIG_PSCAN=y +CONFIG_ROUTE=y +# CONFIG_SLATTACH is not set +CONFIG_TCPSVD=y +CONFIG_TELNET=y +CONFIG_FEATURE_TELNET_TTYPE=y +CONFIG_FEATURE_TELNET_AUTOLOGIN=y +CONFIG_TELNETD=y +CONFIG_FEATURE_TELNETD_STANDALONE=y +CONFIG_FEATURE_TELNETD_INETD_WAIT=y +CONFIG_TFTP=y +CONFIG_TFTPD=y + +# +# Common options for tftp/tftpd +# +CONFIG_FEATURE_TFTP_GET=y +CONFIG_FEATURE_TFTP_PUT=y +CONFIG_FEATURE_TFTP_BLOCKSIZE=y +CONFIG_FEATURE_TFTP_PROGRESS_BAR=y +# CONFIG_TFTP_DEBUG is not set +CONFIG_TRACEROUTE=y +# CONFIG_TRACEROUTE6 is not set +CONFIG_FEATURE_TRACEROUTE_VERBOSE=y +# CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE is not set +# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set +CONFIG_TUNCTL=y +CONFIG_FEATURE_TUNCTL_UG=y +# CONFIG_UDHCPC6 is not set +# CONFIG_UDHCPD is not set +# CONFIG_DHCPRELAY is not set +# CONFIG_DUMPLEASES is not set +# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set +# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set +CONFIG_DHCPD_LEASES_FILE="" +CONFIG_UDHCPC=y +CONFIG_FEATURE_UDHCPC_ARPING=y +CONFIG_FEATURE_UDHCP_PORT=y +CONFIG_UDHCP_DEBUG=9 +CONFIG_FEATURE_UDHCP_RFC3397=y +CONFIG_FEATURE_UDHCP_8021Q=y +CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script" +CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80 +CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="-R -n" +CONFIG_UDPSVD=y +CONFIG_VCONFIG=y +CONFIG_WGET=y +CONFIG_FEATURE_WGET_STATUSBAR=y +CONFIG_FEATURE_WGET_AUTHENTICATION=y +# CONFIG_FEATURE_WGET_LONG_OPTIONS is not set +CONFIG_FEATURE_WGET_TIMEOUT=y +# CONFIG_ZCIP is not set + +# +# Print Utilities +# +CONFIG_LPD=y +CONFIG_LPR=y +CONFIG_LPQ=y + +# +# Mail Utilities +# +CONFIG_MAKEMIME=y +CONFIG_FEATURE_MIME_CHARSET="us-ascii" +CONFIG_POPMAILDIR=y +CONFIG_FEATURE_POPMAILDIR_DELIVERY=y +CONFIG_REFORMIME=y +CONFIG_FEATURE_REFORMIME_COMPAT=y +CONFIG_SENDMAIL=y + +# +# Process Utilities +# +CONFIG_IOSTAT=y +CONFIG_MPSTAT=y +CONFIG_NMETER=y +CONFIG_PMAP=y +CONFIG_POWERTOP=y +CONFIG_PSTREE=y +CONFIG_PWDX=y +CONFIG_SMEMCAP=y +CONFIG_UPTIME=y +# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set +CONFIG_FREE=y +CONFIG_FUSER=y +# CONFIG_KILL is not set +# CONFIG_KILLALL is not set +# CONFIG_KILLALL5 is not set +# CONFIG_PGREP is not set +CONFIG_PIDOF=y +CONFIG_FEATURE_PIDOF_SINGLE=y +CONFIG_FEATURE_PIDOF_OMIT=y +# CONFIG_PKILL is not set +CONFIG_PS=y +# CONFIG_FEATURE_PS_WIDE is not set +# CONFIG_FEATURE_PS_LONG is not set +CONFIG_FEATURE_PS_TIME=y +CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS=y +# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set +CONFIG_RENICE=y +CONFIG_BB_SYSCTL=y +CONFIG_TOP=y +CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y +CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y +CONFIG_FEATURE_TOP_SMP_CPU=y +CONFIG_FEATURE_TOP_DECIMALS=y +CONFIG_FEATURE_TOP_SMP_PROCESS=y +CONFIG_FEATURE_TOPMEM=y +CONFIG_FEATURE_SHOW_THREADS=y +CONFIG_WATCH=y + +# +# Runit Utilities +# +CONFIG_RUNSV=y +CONFIG_RUNSVDIR=y +# CONFIG_FEATURE_RUNSVDIR_LOG is not set +CONFIG_SV=y +CONFIG_SV_DEFAULT_SERVICE_DIR="/var/service" +CONFIG_SVLOGD=y +CONFIG_CHPST=y +CONFIG_SETUIDGID=y +CONFIG_ENVUIDGID=y +CONFIG_ENVDIR=y +CONFIG_SOFTLIMIT=y +# CONFIG_CHCON is not set +# CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set +# CONFIG_GETENFORCE is not set +# CONFIG_GETSEBOOL is not set +# CONFIG_LOAD_POLICY is not set +# CONFIG_MATCHPATHCON is not set +# CONFIG_RESTORECON is not set +# CONFIG_RUNCON is not set +# CONFIG_FEATURE_RUNCON_LONG_OPTIONS is not set +# CONFIG_SELINUXENABLED is not set +# CONFIG_SETENFORCE is not set +# CONFIG_SETFILES is not set +# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set +# CONFIG_SETSEBOOL is not set +# CONFIG_SESTATUS is not set + +# +# Shells +# +# CONFIG_ASH is not set +# CONFIG_ASH_BASH_COMPAT is not set +# CONFIG_ASH_IDLE_TIMEOUT is not set +# CONFIG_ASH_JOB_CONTROL is not set +# CONFIG_ASH_ALIAS is not set +# CONFIG_ASH_GETOPTS is not set +# CONFIG_ASH_BUILTIN_ECHO is not set +# CONFIG_ASH_BUILTIN_PRINTF is not set +# CONFIG_ASH_BUILTIN_TEST is not set +# CONFIG_ASH_CMDCMD is not set +# CONFIG_ASH_MAIL is not set +# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set +# CONFIG_ASH_RANDOM_SUPPORT is not set +# CONFIG_ASH_EXPAND_PRMT is not set +CONFIG_CTTYHACK=y +# CONFIG_HUSH is not set +# CONFIG_HUSH_BASH_COMPAT is not set +# CONFIG_HUSH_BRACE_EXPANSION is not set +# CONFIG_HUSH_HELP is not set +# CONFIG_HUSH_INTERACTIVE is not set +# CONFIG_HUSH_SAVEHISTORY is not set +# CONFIG_HUSH_JOB is not set +# CONFIG_HUSH_TICK is not set +# CONFIG_HUSH_IF is not set +# CONFIG_HUSH_LOOPS is not set +# CONFIG_HUSH_CASE is not set +# CONFIG_HUSH_FUNCTIONS is not set +# CONFIG_HUSH_LOCAL is not set +# CONFIG_HUSH_RANDOM_SUPPORT is not set +# CONFIG_HUSH_EXPORT_N is not set +# CONFIG_HUSH_MODE_X is not set +# CONFIG_MSH is not set +# CONFIG_FEATURE_SH_IS_ASH is not set +# CONFIG_FEATURE_SH_IS_HUSH is not set +CONFIG_FEATURE_SH_IS_NONE=y +# CONFIG_FEATURE_BASH_IS_ASH is not set +# CONFIG_FEATURE_BASH_IS_HUSH is not set +CONFIG_FEATURE_BASH_IS_NONE=y +# CONFIG_SH_MATH_SUPPORT is not set +# CONFIG_SH_MATH_SUPPORT_64 is not set +# CONFIG_FEATURE_SH_EXTRA_QUIET is not set +# CONFIG_FEATURE_SH_STANDALONE is not set +# CONFIG_FEATURE_SH_NOFORK is not set +# CONFIG_FEATURE_SH_HISTFILESIZE is not set + +# +# System Logging Utilities +# +# CONFIG_SYSLOGD is not set +# CONFIG_FEATURE_ROTATE_LOGFILE is not set +# CONFIG_FEATURE_REMOTE_LOG is not set +# CONFIG_FEATURE_SYSLOGD_DUP is not set +# CONFIG_FEATURE_SYSLOGD_CFG is not set +CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0 +# CONFIG_FEATURE_IPC_SYSLOG is not set +CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0 +# CONFIG_LOGREAD is not set +# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set +CONFIG_KLOGD=y +CONFIG_FEATURE_KLOGD_KLOGCTL=y +# CONFIG_LOGGER is not set -- cgit v1.2.3-55-g6feb From 39c2cb2e93e2acc75a5eb6dd91d81f79c787acd5 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 8 Mar 2012 00:20:01 +0100 Subject: build system: fix broken CONFIG_SYSROOT handling Signed-off-by: Denys Vlasenko --- Makefile.flags | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile.flags b/Makefile.flags index 68dfa57ec..92aae6fb5 100644 --- a/Makefile.flags +++ b/Makefile.flags @@ -104,7 +104,9 @@ else LDLIBS += m endif -ifneq ($(CONFIG_SYSROOT),) +# Note: both "" (string consisting of two quote chars) and empty string +# are possible, and should be skipped below. +ifneq ($(subst "",,$(CONFIG_SYSROOT)),) CFLAGS += --sysroot=$(CONFIG_SYSROOT) export SYSROOT=$(CONFIG_SYSROOT) endif -- cgit v1.2.3-55-g6feb From 0687a5b496a05cbc06f3bcdc517a2e6cabc535df Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 8 Mar 2012 00:28:24 +0100 Subject: libbb: make xchroot do a chdir("/") after chroot Signed-off-by: Denys Vlasenko --- coreutils/chroot.c | 1 - libbb/xfuncs_printf.c | 1 + networking/ftpd.c | 3 +-- procps/sysctl.c | 4 ++-- runit/chpst.c | 3 +-- util-linux/switch_root.c | 2 +- 6 files changed, 6 insertions(+), 8 deletions(-) diff --git a/coreutils/chroot.c b/coreutils/chroot.c index ab8beb023..633e66b38 100644 --- a/coreutils/chroot.c +++ b/coreutils/chroot.c @@ -31,7 +31,6 @@ int chroot_main(int argc UNUSED_PARAM, char **argv) if (!*argv) bb_show_usage(); xchroot(*argv); - xchdir("/"); ++argv; if (!*argv) { /* no 2nd param (PROG), use shell */ diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c index 56ee459e4..d8a42ba0b 100644 --- a/libbb/xfuncs_printf.c +++ b/libbb/xfuncs_printf.c @@ -362,6 +362,7 @@ void FAST_FUNC xchroot(const char *path) { if (chroot(path)) bb_perror_msg_and_die("can't change root directory to %s", path); + xchdir("/"); } // Print a warning message if opendir() fails, but don't die. diff --git a/networking/ftpd.c b/networking/ftpd.c index e38138c0a..1c97df564 100644 --- a/networking/ftpd.c +++ b/networking/ftpd.c @@ -1179,8 +1179,7 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv) #endif if (argv[optind]) { - xchdir(argv[optind]); - chroot("."); + xchroot(argv[optind]); } //umask(077); - admin can set umask before starting us diff --git a/procps/sysctl.c b/procps/sysctl.c index cb3b6a25a..5296d0f58 100644 --- a/procps/sysctl.c +++ b/procps/sysctl.c @@ -224,7 +224,7 @@ static int sysctl_handle_preload_file(const char *filename) parser = config_open(filename); /* Must do it _after_ config_open(): */ xchdir("/proc/sys"); - /* xchroot(".") - if you are paranoid */ + /* xchroot("/proc/sys") - if you are paranoid */ //TODO: ';' is comment char too //TODO: comment may be only at line start. "var=1 #abc" - "1 #abc" is the value @@ -260,7 +260,7 @@ int sysctl_main(int argc UNUSED_PARAM, char **argv) return sysctl_handle_preload_file(*argv ? *argv : "/etc/sysctl.conf"); } xchdir("/proc/sys"); - /* xchroot(".") - if you are paranoid */ + /* xchroot("/proc/sys") - if you are paranoid */ if (opt & (FLAG_TABLE_FORMAT | FLAG_SHOW_ALL)) { return sysctl_act_recursive("."); } diff --git a/runit/chpst.c b/runit/chpst.c index 9b8c99bdd..ac296babf 100644 --- a/runit/chpst.c +++ b/runit/chpst.c @@ -417,8 +417,7 @@ int chpst_main(int argc UNUSED_PARAM, char **argv) } if (opt & OPT_root) { - xchdir(root); - xchroot("."); + xchroot(root); } if (opt & OPT_u) { diff --git a/util-linux/switch_root.c b/util-linux/switch_root.c index db6ae3542..a301b365b 100644 --- a/util-linux/switch_root.c +++ b/util-linux/switch_root.c @@ -114,7 +114,7 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv) } xchroot("."); // The chdir is needed to recalculate "." and ".." links - xchdir("/"); + /*xchdir("/"); - done in xchroot */ // If a new console specified, redirect stdin/stdout/stderr to it if (console) { -- cgit v1.2.3-55-g6feb From 4e3beb2e1db3d4739a5a924e003938a9815f98e5 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 8 Mar 2012 00:28:52 +0100 Subject: tftpd: chroot to DIR, not merely chdir. Closes 4874 Signed-off-by: Denys Vlasenko --- networking/tftp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/networking/tftp.c b/networking/tftp.c index 043b879af..ce48a1edd 100644 --- a/networking/tftp.c +++ b/networking/tftp.c @@ -789,8 +789,9 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv) openlog(applet_name, LOG_PID, LOG_DAEMON); logmode = LOGMODE_SYSLOG; } - if (argv[0]) - xchdir(argv[0]); + if (argv[0]) { + xchroot(argv[0]); + } result = recv_from_to(STDIN_FILENO, block_buf, sizeof(block_buf), 0 /* flags */, -- cgit v1.2.3-55-g6feb From d98dc92d6a8bcc68287310c3e33a77efb9fcbe3b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 8 Mar 2012 03:27:49 +0100 Subject: ntpd: drop offset averaging code function old new delta filter_datapoints 475 174 -301 Signed-off-by: Denys Vlasenko --- networking/ntpd.c | 83 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 60 insertions(+), 23 deletions(-) diff --git a/networking/ntpd.c b/networking/ntpd.c index 9c16b2b6b..2bd53f884 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -212,8 +212,8 @@ typedef struct { } msg_t; typedef struct { - double d_recv_time; double d_offset; + double d_recv_time; double d_dispersion; } datapoint_t; @@ -517,23 +517,34 @@ static void filter_datapoints(peer_t *p) { int i, idx; + double sum, wavg; + datapoint_t *fdp; + +#if 0 +/* Simulations have shown that use of *averaged* offset for p->filter_offset + * is in fact worse than simply using last received one: with large poll intervals + * (>= 2048) averaging code uses offset values which are outdated by hours, + * and time/frequency correction goes totally wrong when fed essentially bogus offsets. + */ int got_newest; - double minoff, maxoff, wavg, sum, w; + double minoff, maxoff, w; double x = x; /* for compiler */ double oldest_off = oldest_off; double oldest_age = oldest_age; double newest_off = newest_off; double newest_age = newest_age; - minoff = maxoff = p->filter_datapoint[0].d_offset; + fdp = p->filter_datapoint; + + minoff = maxoff = fdp[0].d_offset; for (i = 1; i < NUM_DATAPOINTS; i++) { - if (minoff > p->filter_datapoint[i].d_offset) - minoff = p->filter_datapoint[i].d_offset; - if (maxoff < p->filter_datapoint[i].d_offset) - maxoff = p->filter_datapoint[i].d_offset; + if (minoff > fdp[i].d_offset) + minoff = fdp[i].d_offset; + if (maxoff < fdp[i].d_offset) + maxoff = fdp[i].d_offset; } - idx = p->datapoint_idx; /* most recent datapoint */ + idx = p->datapoint_idx; /* most recent datapoint's index */ /* Average offset: * Drop two outliers and take weighted average of the rest: * most_recent/2 + older1/4 + older2/8 ... + older5/32 + older6/32 @@ -555,24 +566,24 @@ filter_datapoints(peer_t *p) VERB4 { bb_error_msg("datapoint[%d]: off:%f disp:%f(%f) age:%f%s", i, - p->filter_datapoint[idx].d_offset, - p->filter_datapoint[idx].d_dispersion, dispersion(&p->filter_datapoint[idx]), - G.cur_time - p->filter_datapoint[idx].d_recv_time, - (minoff == p->filter_datapoint[idx].d_offset || maxoff == p->filter_datapoint[idx].d_offset) + fdp[idx].d_offset, + fdp[idx].d_dispersion, dispersion(&fdp[idx]), + G.cur_time - fdp[idx].d_recv_time, + (minoff == fdp[idx].d_offset || maxoff == fdp[idx].d_offset) ? " (outlier by offset)" : "" ); } - sum += dispersion(&p->filter_datapoint[idx]) / (2 << i); + sum += dispersion(&fdp[idx]) / (2 << i); - if (minoff == p->filter_datapoint[idx].d_offset) { + if (minoff == fdp[idx].d_offset) { minoff -= 1; /* so that we don't match it ever again */ } else - if (maxoff == p->filter_datapoint[idx].d_offset) { + if (maxoff == fdp[idx].d_offset) { maxoff += 1; } else { - oldest_off = p->filter_datapoint[idx].d_offset; - oldest_age = G.cur_time - p->filter_datapoint[idx].d_recv_time; + oldest_off = fdp[idx].d_offset; + oldest_age = G.cur_time - fdp[idx].d_recv_time; if (!got_newest) { got_newest = 1; newest_off = oldest_off; @@ -605,6 +616,32 @@ filter_datapoints(peer_t *p) } p->filter_offset = wavg; +#else + + fdp = p->filter_datapoint; + idx = p->datapoint_idx; /* most recent datapoint's index */ + + /* filter_offset: simply use the most recent value */ + p->filter_offset = fdp[idx].d_offset; + + /* n-1 + * --- dispersion(i) + * filter_dispersion = \ ------------- + * / (i+1) + * --- 2 + * i=0 + */ + wavg = 0; + sum = 0; + for (i = 0; i < NUM_DATAPOINTS; i++) { + sum += dispersion(&fdp[idx]) / (2 << i); + wavg += fdp[idx].d_offset; + idx = (idx - 1) & (NUM_DATAPOINTS - 1); + } + wavg /= NUM_DATAPOINTS; + p->filter_dispersion = sum; +#endif + /* +----- -----+ ^ 1/2 * | n-1 | * | --- | @@ -618,13 +655,13 @@ filter_datapoints(peer_t *p) */ sum = 0; for (i = 0; i < NUM_DATAPOINTS; i++) { - sum += SQUARE(wavg - p->filter_datapoint[i].d_offset); + sum += SQUARE(wavg - fdp[i].d_offset); } sum = SQRT(sum / NUM_DATAPOINTS); p->filter_jitter = sum > G_precision_sec ? sum : G_precision_sec; - VERB3 bb_error_msg("filter offset:%+f(corr:%e) disp:%f jitter:%f", - p->filter_offset, x, + VERB3 bb_error_msg("filter offset:%+f disp:%f jitter:%f", + p->filter_offset, p->filter_dispersion, p->filter_jitter); } @@ -1667,15 +1704,15 @@ recv_and_process_peer_pkt(peer_t *p) p->reachable_bits |= 1; if ((MAX_VERBOSE && G.verbose) || (option_mask32 & OPT_w)) { - bb_error_msg("reply from:%s reach:0x%02x offset:%+f delay:%f status:0x%02x strat:%d refid:0x%08x rootdelay:%f", + bb_error_msg("reply from:%s offset:%+f delay:%f status:0x%02x strat:%d refid:0x%08x rootdelay:%f reach:0x%02x", p->p_dotted, - p->reachable_bits, datapoint->d_offset, p->lastpkt_delay, p->lastpkt_status, p->lastpkt_stratum, p->lastpkt_refid, - p->lastpkt_rootdelay + p->lastpkt_rootdelay, + p->reachable_bits /* not shown: m_ppoll, m_precision_exp, m_rootdisp, * m_reftime, m_orgtime, m_rectime, m_xmttime */ -- cgit v1.2.3-55-g6feb From 07fcaab595e9029ebe37f5240a10038c493af545 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 8 Mar 2012 03:50:01 +0100 Subject: test: "test !" was accessing argv past NULL - fix it. Closes 4832 Signed-off-by: Denys Vlasenko --- coreutils/test.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/coreutils/test.c b/coreutils/test.c index 1f5398ad8..0bc008e7c 100644 --- a/coreutils/test.c +++ b/coreutils/test.c @@ -710,7 +710,8 @@ static number_t nexpr(enum token n) if (n == EOI) { /* special case: [ ! ], [ a -a ! ] are valid */ /* IOW, "! ARG" may miss ARG */ - unnest_msg("aexpr(%s)\n", TOKSTR[n]); res = nexpr(n); - dbg_msg("aexpr: nexpr:%lld, next args:%s\n", res, args[1]); + dbg_msg("aexpr: nexpr:%lld, next args:%s(%p)\n", res, args[1], &args[1]); if (check_operator(*++args) == BAND) { - dbg_msg("aexpr: arg is AND, next args:%s\n", args[1]); + dbg_msg("aexpr: arg is AND, next args:%s(%p)\n", args[1], &args[1]); res = aexpr(check_operator(*++args)) && res; unnest_msg("oexpr(%s)\n", TOKSTR[n]); res = aexpr(n); - dbg_msg("oexpr: aexpr:%lld, next args:%s\n", res, args[1]); + dbg_msg("oexpr: aexpr:%lld, next args:%s(%p)\n", res, args[1], &args[1]); if (check_operator(*++args) == BOR) { - dbg_msg("oexpr: next arg is OR, next args:%s\n", args[1]); + dbg_msg("oexpr: next arg is OR, next args:%s(%p)\n", args[1], &args[1]); res = oexpr(check_operator(*++args)) || res; unnest_msg(" Date: Thu, 8 Mar 2012 13:02:52 +0100 Subject: ntpd: make "reply from IP" messages more uniform Signed-off-by: Denys Vlasenko --- networking/ntpd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/ntpd.c b/networking/ntpd.c index 2bd53f884..4d939458c 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -1704,7 +1704,7 @@ recv_and_process_peer_pkt(peer_t *p) p->reachable_bits |= 1; if ((MAX_VERBOSE && G.verbose) || (option_mask32 & OPT_w)) { - bb_error_msg("reply from:%s offset:%+f delay:%f status:0x%02x strat:%d refid:0x%08x rootdelay:%f reach:0x%02x", + bb_error_msg("reply from %s: offset:%+f delay:%f status:0x%02x strat:%d refid:0x%08x rootdelay:%f reach:0x%02x", p->p_dotted, datapoint->d_offset, p->lastpkt_delay, -- cgit v1.2.3-55-g6feb From c528917195498e03c8b776bbcfee4f41ea3a818f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 10 Mar 2012 16:30:00 +0100 Subject: build system: detect missing crypt and drop it from linking Signed-off-by: Denys Vlasenko --- Makefile.flags | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Makefile.flags b/Makefile.flags index 92aae6fb5..2c826bac1 100644 --- a/Makefile.flags +++ b/Makefile.flags @@ -97,13 +97,6 @@ CFLAGS += $(strip $(subst ",,$(CONFIG_EXTRA_CFLAGS))) #")) endif -ifneq ($(CONFIG_CROSS_COMPILER_PREFIX),"arm-linux-androideabi-") -LDLIBS += m crypt -else -# Android libc has no crypt. TODO: make a generic CONFIG_LINK_WITH_CRYPT option? -LDLIBS += m -endif - # Note: both "" (string consisting of two quote chars) and empty string # are possible, and should be skipped below. ifneq ($(subst "",,$(CONFIG_SYSROOT)),) @@ -111,6 +104,14 @@ CFLAGS += --sysroot=$(CONFIG_SYSROOT) export SYSROOT=$(CONFIG_SYSROOT) endif +# Android has no separate crypt library +CRYPT_AVAILABLE := $(shell echo 'int main(void){return 0;}' | $(CC) $(CFLAGS) $(1) -lcrypt -o /dev/null -xc - >/dev/null 2>&1 && echo "y") +ifeq ($(CRYPT_AVAILABLE),y) +LDLIBS += m crypt +else +LDLIBS += m +endif + ifeq ($(CONFIG_PAM),y) # libpam uses libpthread, so for static builds busybox must be linked to # libpthread. On some platforms that requires an explicit -lpthread, so -- cgit v1.2.3-55-g6feb From 65457625a7a6c8939e46d01a4cda566d82ed5343 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 11 Mar 2012 12:17:20 +0100 Subject: build system: remove bogus $(1) in last commit Signed-off-by: Denys Vlasenko --- Makefile.flags | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.flags b/Makefile.flags index 2c826bac1..f745c2fdf 100644 --- a/Makefile.flags +++ b/Makefile.flags @@ -105,7 +105,7 @@ export SYSROOT=$(CONFIG_SYSROOT) endif # Android has no separate crypt library -CRYPT_AVAILABLE := $(shell echo 'int main(void){return 0;}' | $(CC) $(CFLAGS) $(1) -lcrypt -o /dev/null -xc - >/dev/null 2>&1 && echo "y") +CRYPT_AVAILABLE := $(shell echo 'int main(void){return 0;}' | $(CC) $(CFLAGS) -lcrypt -o /dev/null -xc - >/dev/null 2>&1 && echo "y") ifeq ($(CRYPT_AVAILABLE),y) LDLIBS += m crypt else -- cgit v1.2.3-55-g6feb From 7fe1e3f1612f6eb220d6a9796edacf24b7706876 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 11 Mar 2012 18:04:14 +0100 Subject: ubi_tools: add workaround for bad kernel headers. Closes 4838 Signed-off-by: Denys Vlasenko --- miscutils/ubi_tools.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/miscutils/ubi_tools.c b/miscutils/ubi_tools.c index 2a426dbdc..dd99a44f4 100644 --- a/miscutils/ubi_tools.c +++ b/miscutils/ubi_tools.c @@ -60,6 +60,10 @@ //kbuild:lib-$(CONFIG_UBIUPDATEVOL) += ubi_tools.o #include "libbb.h" +/* Some versions of kernel have broken headers, need this hack */ +#ifndef __packed +# define __packed __attribute__((packed)) +#endif #include #define OPTION_M (1 << 0) -- cgit v1.2.3-55-g6feb From 5e896481eb20b5a9738cf5f2e390b63574be28a2 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 19 Mar 2012 01:17:36 +0100 Subject: nc: support "-e PROG" form of -e option function old new delta nc_main 975 1033 +58 doexec 31 45 +14 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 72/0) Total: 72 bytes Signed-off-by: Denys Vlasenko --- networking/nc_bloaty.c | 43 +++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c index d184f689b..62a025116 100644 --- a/networking/nc_bloaty.c +++ b/networking/nc_bloaty.c @@ -115,6 +115,7 @@ struct globals { unsigned wrote_out; /* total stdout bytes */ unsigned wrote_net; /* total net bytes */ #endif + char *proggie0saved; /* ouraddr is never NULL and goes through three states as we progress: 1 - local address before bind (IP/port possibly zero) 2 - local address after bind (port is nonzero) @@ -127,7 +128,6 @@ struct globals { jmp_buf jbuf; /* timer crud */ - /* will malloc up the following globals: */ fd_set ding1; /* for select loop */ fd_set ding2; char bigbuf_in[BIGSIZ]; /* data buffers */ @@ -159,17 +159,16 @@ struct globals { /* Must match getopt32 call! */ enum { - OPT_h = (1 << 0), - OPT_n = (1 << 1), - OPT_p = (1 << 2), - OPT_s = (1 << 3), - OPT_u = (1 << 4), - OPT_v = (1 << 5), - OPT_w = (1 << 6), - OPT_l = (1 << 7) * ENABLE_NC_SERVER, - OPT_i = (1 << (7+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, - OPT_o = (1 << (8+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, - OPT_z = (1 << (9+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, + OPT_n = (1 << 0), + OPT_p = (1 << 1), + OPT_s = (1 << 2), + OPT_u = (1 << 3), + OPT_v = (1 << 4), + OPT_w = (1 << 5), + OPT_l = (1 << 6) * ENABLE_NC_SERVER, + OPT_i = (1 << (6+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, + OPT_o = (1 << (7+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, + OPT_z = (1 << (8+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, }; #define o_nflag (option_mask32 & OPT_n) @@ -263,6 +262,8 @@ Debug("findline returning whole thing: %d", siz); static int doexec(char **proggie) NORETURN; static int doexec(char **proggie) { + if (G.proggie0saved) + proggie[0] = G.proggie0saved; xmove_fd(netfd, 0); dup2(0, 1); /* dup2(0, 2); - do we *really* want this? NO! @@ -726,7 +727,7 @@ int nc_main(int argc UNUSED_PARAM, char **argv) { char *str_p, *str_s; IF_NC_EXTRA(char *str_i, *str_o;) - char *themdotted = themdotted; /* gcc */ + char *themdotted = themdotted; /* for compiler */ char **proggie; int x; unsigned o_lport = 0; @@ -754,13 +755,27 @@ int nc_main(int argc UNUSED_PARAM, char **argv) proggie++; goto e_found; } + /* -e PROG [ARGS] ? */ + /* (aboriginal linux uses this form) */ + if (proggie[0][0] == '-') { + char *optpos = *proggie + 1; + /* Skip all valid opts w/o params */ + optpos = optpos + strspn(optpos, "nuv"IF_NC_SERVER("l")IF_NC_EXTRA("z")); + if (*optpos == 'e' && !optpos[1]) { + *optpos = '\0'; + proggie++; + G.proggie0saved = *proggie; + *proggie = NULL; /* terminate argv for getopt32 */ + goto e_found; + } + } } proggie = NULL; e_found: // -g -G -t -r deleted, unimplemented -a deleted too opt_complementary = "?2:vv:w+"; /* max 2 params; -v is a counter; -w N */ - getopt32(argv, "hnp:s:uvw:" IF_NC_SERVER("l") + getopt32(argv, "np:s:uvw:" IF_NC_SERVER("l") IF_NC_EXTRA("i:o:z"), &str_p, &str_s, &o_wait IF_NC_EXTRA(, &str_i, &str_o), &o_verbose); -- cgit v1.2.3-55-g6feb From 78a3b6739c0152f188eba56ec17e770a11b54b60 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 19 Mar 2012 04:38:00 +0100 Subject: Fix one-applet build for tcpsvd Signed-off-by: Denys Vlasenko --- applets/applet_tables.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/applets/applet_tables.c b/applets/applet_tables.c index a47574737..152d5f441 100644 --- a/applets/applet_tables.c +++ b/applets/applet_tables.c @@ -80,15 +80,8 @@ int main(int argc, char **argv) printf("#define NUM_APPLETS %u\n", NUM_APPLETS); if (NUM_APPLETS == 1) { - char *dash_to_underscore, *p; printf("#define SINGLE_APPLET_STR \"%s\"\n", applets[0].name); - /* Example: "ether-wake" -> "ether_wake" */ - p = dash_to_underscore = strdup(applets[0].name); - p--; - while (*++p) - if (*p == '-') - *p = '_'; - printf("#define SINGLE_APPLET_MAIN %s_main\n", dash_to_underscore); + printf("#define SINGLE_APPLET_MAIN %s_main\n", applets[0].main); } printf("\n"); -- cgit v1.2.3-55-g6feb From cc1bb603e8243654c6941a2eacaf900ef3fcc55d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 19 Mar 2012 12:22:57 +0100 Subject: ftp{get,put}: tweak help text Signed-off-by: Denys Vlasenko --- networking/ftpgetput.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/networking/ftpgetput.c b/networking/ftpgetput.c index abdf94c45..8283366cc 100644 --- a/networking/ftpgetput.c +++ b/networking/ftpgetput.c @@ -16,37 +16,37 @@ //usage:#define ftpget_trivial_usage //usage: "[OPTIONS] HOST [LOCAL_FILE] REMOTE_FILE" //usage:#define ftpget_full_usage "\n\n" -//usage: "Retrieve a remote file via FTP\n" +//usage: "Download a file via FTP\n" //usage: IF_FEATURE_FTPGETPUT_LONG_OPTIONS( -//usage: "\n -c,--continue Continue previous transfer" -//usage: "\n -v,--verbose Verbose" -//usage: "\n -u,--username Username" -//usage: "\n -p,--password Password" -//usage: "\n -P,--port Port number" +//usage: "\n -c,--continue Continue previous transfer" +//usage: "\n -v,--verbose Verbose" +//usage: "\n -u,--username USER Username" +//usage: "\n -p,--password PASS Password" +//usage: "\n -P,--port NUM Port" //usage: ) //usage: IF_NOT_FEATURE_FTPGETPUT_LONG_OPTIONS( //usage: "\n -c Continue previous transfer" //usage: "\n -v Verbose" -//usage: "\n -u Username" -//usage: "\n -p Password" -//usage: "\n -P Port number" +//usage: "\n -u USER Username" +//usage: "\n -p PASS Password" +//usage: "\n -P NUM Port" //usage: ) //usage: //usage:#define ftpput_trivial_usage //usage: "[OPTIONS] HOST [REMOTE_FILE] LOCAL_FILE" //usage:#define ftpput_full_usage "\n\n" -//usage: "Store a local file on a remote machine via FTP\n" +//usage: "Upload a file to a FTP server\n" //usage: IF_FEATURE_FTPGETPUT_LONG_OPTIONS( -//usage: "\n -v,--verbose Verbose" -//usage: "\n -u,--username Username" -//usage: "\n -p,--password Password" -//usage: "\n -P,--port Port number" +//usage: "\n -v,--verbose Verbose" +//usage: "\n -u,--username USER Username" +//usage: "\n -p,--password PASS Password" +//usage: "\n -P,--port NUM Port" //usage: ) //usage: IF_NOT_FEATURE_FTPGETPUT_LONG_OPTIONS( //usage: "\n -v Verbose" -//usage: "\n -u Username" -//usage: "\n -p Password" -//usage: "\n -P Port number" +//usage: "\n -u USER Username" +//usage: "\n -p PASS Password" +//usage: "\n -P NUM Port number" //usage: ) #include "libbb.h" -- cgit v1.2.3-55-g6feb From ba88826c66411affc1da3614742b454654f7298a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 22 Mar 2012 11:15:06 +0100 Subject: busybox: tweak help text Signed-off-by: Denys Vlasenko --- libbb/appletlib.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libbb/appletlib.c b/libbb/appletlib.c index efde3b69d..73f71f1d0 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -632,7 +632,10 @@ static int busybox_main(char **argv) "See source distribution for full notice.\n" "\n" "Usage: busybox [function] [arguments]...\n" - " or: busybox --list[-full]\n" + " or: busybox --list"IF_FEATURE_INSTALLER("[-full]")"\n" + IF_FEATURE_INSTALLER( + " or: busybox --install [-s] [DIR]\n" + ) " or: function [arguments]...\n" "\n" "\tBusyBox is a multi-call binary that combines many common Unix\n" @@ -672,7 +675,7 @@ static int busybox_main(char **argv) dup2(1, 2); while (*a) { # if ENABLE_FEATURE_INSTALLER - if (argv[1][6]) /* --list-path? */ + if (argv[1][6]) /* --list-full? */ full_write2_str(install_dir[APPLET_INSTALL_LOC(i)] + 1); # endif full_write2_str(a); @@ -702,7 +705,7 @@ static int busybox_main(char **argv) * -s: make symlinks * DIR: directory to install links to */ - use_symbolic_links = (argv[2] && strcmp(argv[2], "-s") == 0 && argv++); + use_symbolic_links = (argv[2] && strcmp(argv[2], "-s") == 0 && ++argv); install_links(busybox, use_symbolic_links, argv[2]); return 0; } -- cgit v1.2.3-55-g6feb