From 9ca56f9621d9e7265699997d90902fcaf6ed5aad Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 22 Jun 2016 03:10:21 +0200 Subject: [PATCH 01/41] Start 1.26.0 development cycle Signed-off-by: Denys Vlasenko --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 572da3d88..5cfc76306 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 1 -PATCHLEVEL = 25 +PATCHLEVEL = 26 SUBLEVEL = 0 -EXTRAVERSION = +EXTRAVERSION = .git NAME = Unnamed # *DOCUMENTATION* From 4d5acd2d4264d0a754d3d11c94825fd69d0c7837 Mon Sep 17 00:00:00 2001 From: Jonas Danielsson Date: Thu, 23 Jun 2016 18:26:32 +0200 Subject: [PATCH 02/41] ping: populate icmp_id field for "simple" ping too The ICMP RFC says that identifier and sequence number may be zero. Having them zero for a Echo message, along with a data of zero's as well will result in a Echo reply message with only zero's. Some NAT implementations seem to get the checksum wrong on these packages. Setting a checksum of 0x0 instead of 0xffff. Through NAT: Internet Control Message Protocol Type: 0 (Echo (ping) reply) Code: 0 Checksum: 0x0000 [incorrect, should be 0xffff] Identifier (BE): 0 (0x0000) Identifier (LE): 0 (0x0000) Sequence number (BE): 0 (0x0000) Sequence number (LE): 0 (0x0000) Data (56 bytes) Data: 000000000000000000000000000000000000000000000000... [Length: 56] Without NAT: Internet Control Message Protocol Type: 0 (Echo (ping) reply) Code: 0 Checksum: 0xffff [correct] Identifier (BE): 0 (0x0000) Identifier (LE): 0 (0x0000) Sequence number (BE): 0 (0x0000) Sequence number (LE): 0 (0x0000) [Request frame: 189] [Response time: 0.024 ms] Data (56 bytes) Data: 000000000000000000000000000000000000000000000000... [Length: 56] And this in turn will make some hardware MAC checksum offloading engines drop the packet. (This was seen with a Synopsis MAC, the same one used in for instance the stmmac Ethernet driver in the linux kernel.) This change can be seen as a workaround for bugs in other layers. But just setting an identifier for the Echo message packet will avoid prodding the hornets nest. function old new delta common_ping_main 424 500 +76 Signed-off-by: Jonas Danielsson Signed-off-by: Denys Vlasenko --- networking/ping.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/networking/ping.c b/networking/ping.c index cfe682646..d8767a39f 100644 --- a/networking/ping.c +++ b/networking/ping.c @@ -186,6 +186,7 @@ create_icmp_socket(void) struct globals { char *hostname; char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN]; + uint16_t myid; } FIX_ALIASING; #define G (*(struct globals*)bb_common_bufsiz1) #define INIT_G() do { setup_common_bufsiz(); } while (0) @@ -204,6 +205,7 @@ static void ping4(len_and_sockaddr *lsa) pkt = (struct icmp *) G.packet; /*memset(pkt, 0, sizeof(G.packet)); already is */ pkt->icmp_type = ICMP_ECHO; + pkt->icmp_id = G.myid; pkt->icmp_cksum = inet_cksum((uint16_t *) pkt, sizeof(G.packet)); xsendto(pingsock, G.packet, DEFDATALEN + ICMP_MINLEN, &lsa->u.sa, lsa->len); @@ -228,6 +230,8 @@ static void ping4(len_and_sockaddr *lsa) struct iphdr *iphdr = (struct iphdr *) G.packet; pkt = (struct icmp *) (G.packet + (iphdr->ihl << 2)); /* skip ip hdr */ + if (pkt->icmp_id != G.myid) + continue; /* not our ping */ if (pkt->icmp_type == ICMP_ECHOREPLY) break; } @@ -246,6 +250,7 @@ static void ping6(len_and_sockaddr *lsa) pkt = (struct icmp6_hdr *) G.packet; /*memset(pkt, 0, sizeof(G.packet)); already is */ pkt->icmp6_type = ICMP6_ECHO_REQUEST; + pkt->icmp6_id = G.myid; sockopt = offsetof(struct icmp6_hdr, icmp6_cksum); setsockopt_int(pingsock, SOL_RAW, IPV6_CHECKSUM, sockopt); @@ -269,6 +274,8 @@ static void ping6(len_and_sockaddr *lsa) continue; } if (c >= ICMP_MINLEN) { /* icmp6_hdr */ + if (pkt->icmp6_id != G.myid) + continue; /* not our ping */ if (pkt->icmp6_type == ICMP6_ECHO_REPLY) break; } @@ -317,6 +324,7 @@ static int common_ping_main(sa_family_t af, char **argv) alarm(5); /* give the host 5000ms to respond */ create_icmp_socket(lsa); + G.myid = (uint16_t) getpid(); #if ENABLE_PING6 if (lsa->u.sa.sa_family == AF_INET6) ping6(lsa); From 59f81976249a85cf02bd73c2395f018033069466 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 23 Jun 2016 17:19:50 +0200 Subject: [PATCH 03/41] i2cdump: don't use common_bufsiz1 Commit e6a2f4cc changed the way common_bufsiz1 works. Now it needs to be initialized before using, but i2cdump wasn't updated by said patch. Since the fact that we're using common_bufsiz1 here isn't obvious (no G_INIT() macro, no other global variables), drop it and simply allocate the integer array required for block reads on the stack. Tested with i2c block read on a Lenovo Thinkpad laptop. Signed-off-by: Bartosz Golaszewski Signed-off-by: Denys Vlasenko --- miscutils/i2c_tools.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miscutils/i2c_tools.c b/miscutils/i2c_tools.c index 57bb72ae7..7731466f7 100644 --- a/miscutils/i2c_tools.c +++ b/miscutils/i2c_tools.c @@ -908,7 +908,7 @@ int i2cdump_main(int argc UNUSED_PARAM, char **argv) int bus_num, bus_addr, mode = I2C_SMBUS_BYTE_DATA, even = 0, pec = 0; unsigned first = 0x00, last = 0xff, opts; - int *block = (int *)bb_common_bufsiz1; + int block[I2CDUMP_NUM_REGS]; char *opt_r_str, *dash; int fd, res; From 8f4faa1e3db91fc7b50d633e6f9b2f04bf978bb2 Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Thu, 23 Jun 2016 10:42:40 +0200 Subject: [PATCH 04/41] df: use f_frsize instead of f_bsize for correct sizes Use the correct field f_frsize instead of f_bsize. The statfs f_bsize is the "Optimal transfer block size" while the f_frsize is the "Fragment size (since Linux 2.6)". On some FUSE filesystems those may differ. Fixes bug 9046 URL: https://bugs.busybox.net/show_bug.cgi?id=9046 Signed-off-by: Natanael Copa Signed-off-by: Denys Vlasenko --- coreutils/df.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/coreutils/df.c b/coreutils/df.c index d79c11a6c..06b292018 100644 --- a/coreutils/df.c +++ b/coreutils/df.c @@ -188,7 +188,7 @@ int df_main(int argc UNUSED_PARAM, char **argv) if (opt & OPT_INODE) { s.f_blocks = s.f_files; s.f_bavail = s.f_bfree = s.f_ffree; - s.f_bsize = 1; + s.f_frsize = 1; if (df_disp_hr) df_disp_hr = 1; @@ -246,26 +246,26 @@ int df_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_FEATURE_HUMAN_READABLE printf(" %9s ", - /* f_blocks x f_bsize / df_disp_hr, show one fractional, + /* f_blocks x f_frsize / df_disp_hr, show one fractional, * use suffixes if df_disp_hr == 0 */ - make_human_readable_str(s.f_blocks, s.f_bsize, df_disp_hr)); + make_human_readable_str(s.f_blocks, s.f_frsize, df_disp_hr)); printf(" %9s " + 1, - /* EXPR x f_bsize / df_disp_hr, show one fractional, + /* EXPR x f_frsize / df_disp_hr, show one fractional, * use suffixes if df_disp_hr == 0 */ make_human_readable_str((s.f_blocks - s.f_bfree), - s.f_bsize, df_disp_hr)); + s.f_frsize, df_disp_hr)); printf("%9s %3u%% %s\n", - /* f_bavail x f_bsize / df_disp_hr, show one fractional, + /* f_bavail x f_frsize / df_disp_hr, show one fractional, * use suffixes if df_disp_hr == 0 */ - make_human_readable_str(s.f_bavail, s.f_bsize, df_disp_hr), + make_human_readable_str(s.f_bavail, s.f_frsize, df_disp_hr), blocks_percent_used, mount_point); #else printf(" %9lu %9lu %9lu %3u%% %s\n", - kscale(s.f_blocks, s.f_bsize), - kscale(s.f_blocks - s.f_bfree, s.f_bsize), - kscale(s.f_bavail, s.f_bsize), + kscale(s.f_blocks, s.f_frsize), + kscale(s.f_blocks - s.f_bfree, s.f_frsize), + kscale(s.f_bavail, s.f_frsize), blocks_percent_used, mount_point); #endif } From 5b8c89d1f270909d1a0201478236de6ed89c8ca4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 29 Jun 2016 15:00:52 +0200 Subject: [PATCH 05/41] build system: make CONFIG_FEATURE_USE_BSS_TAIL less funky CONFIG_FEATURE_USE_BSS_TAIL code was aliasing bb_common_bufsiz1 to _end. This is unreliable: _end may be not sufficiently aligned. Change code to simply enlarge COMMON_BUFSIZE when we detect that _end has significant amount of space to the end of page. Signed-off-by: Denys Vlasenko --- scripts/generate_BUFSIZ.sh | 100 +++++++++++-------------------------- 1 file changed, 28 insertions(+), 72 deletions(-) diff --git a/scripts/generate_BUFSIZ.sh b/scripts/generate_BUFSIZ.sh index 844261906..718788e0b 100755 --- a/scripts/generate_BUFSIZ.sh +++ b/scripts/generate_BUFSIZ.sh @@ -36,11 +36,10 @@ generate_std_and_exit() { } generate_big_and_exit() { - $debug && echo "Configuring: bb_common_bufsiz1[] in _end[], COMMON_BUFSIZE = $1" + $debug && echo "Configuring: bb_common_bufsiz1[] in bss, COMMON_BUFSIZE = $1" { echo "enum { COMMON_BUFSIZE = $1 };" - echo "extern char _end[]; /* linker-provided label */" - echo "#define bb_common_bufsiz1 _end" + echo "extern char bb_common_bufsiz1[];" echo "#define setup_common_bufsiz() ((void)0)" } | regenerate "$common_bufsiz_h" echo "$2" >"$common_bufsiz_h.method" @@ -51,20 +50,10 @@ generate_1k_and_exit() { generate_big_and_exit 1024 "1k" } - -generate_malloc_and_exit() { - $debug && echo "Configuring: bb_common_bufsiz1[] is malloced" - { - echo "enum { COMMON_BUFSIZE = 1024 };" - echo "extern char *const bb_common_bufsiz1;" - echo "void setup_common_bufsiz(void);" - } | regenerate "$common_bufsiz_h" - echo "malloc" >"$common_bufsiz_h.method" - $exitcmd -} - round_down_COMMON_BUFSIZE() { - COMMON_BUFSIZE=$(( ($1-32) & 0xfffffe0 )) + COMMON_BUFSIZE=1024 + test "$1" -le 32 && return + COMMON_BUFSIZE=$(( ($1-32) & 0x0ffffff0 )) COMMON_BUFSIZE=$(( COMMON_BUFSIZE < 1024 ? 1024 : COMMON_BUFSIZE )) } @@ -104,77 +93,44 @@ if $postcompile; then test x"$PAGE_SIZE" = x"" && exit 1 $debug && echo "PAGE_SIZE:0x$PAGE_SIZE $((0x$PAGE_SIZE))" PAGE_SIZE=$((0x$PAGE_SIZE)) - test $PAGE_SIZE -lt 512 && exit 1 + test $PAGE_SIZE -lt 1024 && exit 1 # How much space between _end[] and next page? PAGE_MASK=$((PAGE_SIZE-1)) TAIL_SIZE=$(( (-END) & PAGE_MASK )) $debug && echo "TAIL_SIZE:$TAIL_SIZE bytes" - if test x"$method" = x"1k" || test x"$method" = x"big"; then - if test $TAIL_SIZE -lt 1024; then - # _end[] has no enough space for bb_common_bufsiz1[] - echo "Warning! Space in _end[] is too small ($TAIL_SIZE bytes)!" - echo "Rerun make to build a binary which doesn't use it!" - rm -- "$common_bufsiz_h.1k.OK" 2>/dev/null - { md5sum <.config | cut -d' ' -f1; stat -c "%Y" .config; } >"$common_bufsiz_h.1k.FAIL" - rm busybox_unstripped busybox 2>/dev/null -# Note: here we can do either a "malloc" or "std" build. -# "malloc" gives a bit bigger code: -# text bss filename -# 804355 5385 busybox.std -# 804618 4361 busybox.malloc -# but may have a smaller .bss (not guaranteed!). Use "pmap -x" to verify. - exitcmd="exit 1" - generate_malloc_and_exit - else - PREV_SIZE=1024 - test x"$method" = x"big" && PREV_SIZE=`cat -- "$common_bufsiz_h.1k.OK"` - round_down_COMMON_BUFSIZE $PREV_SIZE - PREV_BUFSIZE=$COMMON_BUFSIZE - - rm -- "$common_bufsiz_h.1k.FAIL" 2>/dev/null - echo $TAIL_SIZE >"$common_bufsiz_h.1k.OK" - round_down_COMMON_BUFSIZE $TAIL_SIZE - # emit message only if COMMON_BUFSIZE is indeed larger - test $COMMON_BUFSIZE -gt $PREV_BUFSIZE \ - && echo "Rerun make to use larger COMMON_BUFSIZE ($COMMON_BUFSIZE)" -#TODO: test $PREV_BUFSIZE -lt $TAIL_SIZE && PANIC!!! -#Code size with COMMON_BUFSIZE > 1024 may be bigger than code with COMMON_BUFSIZE = 1024! -#(currently we just hope "-32 and round down to 32" saves us) - - test $COMMON_BUFSIZE = 1024 && generate_1k_and_exit - generate_big_and_exit $COMMON_BUFSIZE "big" - fi + if test x"$method" = x"1k"; then + { + echo $TAIL_SIZE + md5sum <.config | cut -d' ' -f1 + stat -c "%Y" .config + } >"$common_bufsiz_h.1k.OK" + round_down_COMMON_BUFSIZE $((1024 + TAIL_SIZE)) + # emit message only if COMMON_BUFSIZE is indeed larger + test $COMMON_BUFSIZE -gt 1024 \ + && echo "Rerun make to use larger COMMON_BUFSIZE ($COMMON_BUFSIZE)" + test $COMMON_BUFSIZE = 1024 && generate_1k_and_exit + generate_big_and_exit $COMMON_BUFSIZE "big" fi fi # Based on past success/fail of 1k build, decide next build type if test -f "$common_bufsiz_h.1k.OK"; then - # Previous build succeeded fitting 1k into _end[]. - # Try bigger COMMON_BUFSIZE if possible. - TAIL_SIZE=`cat -- "$common_bufsiz_h.1k.OK"` - round_down_COMMON_BUFSIZE $TAIL_SIZE - test $COMMON_BUFSIZE = 1024 && generate_1k_and_exit - generate_big_and_exit $COMMON_BUFSIZE "big" -fi - -if test -f "$common_bufsiz_h.1k.FAIL"; then - # Previous build FAILED to fit 1k into _end[]. - # Was it with same .config? - oldcfg=`cat -- "$common_bufsiz_h.1k.FAIL"` + # previous 1k build succeeded + oldcfg=`tail -n2 -- "$common_bufsiz_h.1k.OK"` curcfg=`md5sum <.config | cut -d' ' -f1; stat -c "%Y" .config` - # If yes, then build a "malloced" version + # config did not change if test x"$oldcfg" = x"$curcfg"; then - echo "Will not try 1k build, it failed before. Touch .config to override" -# Note: here we can do either a "malloc" or "std" build. - generate_malloc_and_exit + # Try bigger COMMON_BUFSIZE if possible + TAIL_SIZE=`head -n1 -- "$common_bufsiz_h.1k.OK"` + round_down_COMMON_BUFSIZE $((1024 + TAIL_SIZE)) + test $COMMON_BUFSIZE = 1024 && generate_1k_and_exit + generate_big_and_exit $COMMON_BUFSIZE "big" fi - # else: try 1k version - echo "New .config, will try 1k build" - rm -- "$common_bufsiz_h.1k.FAIL" - generate_1k_and_exit + # config did change + rm -rf -- "$common_bufsiz_h.1k.OK" fi # There was no 1k build yet. Try it. From aabb0a93e947a2a3cd180b490ae6664396446f63 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 3 Jul 2016 17:58:54 +0200 Subject: [PATCH 06/41] ntpd: daemonize before DNS resolution This resolves the following use case problem: "I start ntpd by default from /etc/init.d There might be no working network connection (not configured properly for whatever reason, hardware problems, whatelse). With busybox 1.25 ntpd seems to loop forever if now NTP servers are found, blocking the boot process and I never get a login to solve a possible pb or to do a first time configuration." Signed-off-by: Denys Vlasenko --- networking/ntpd.c | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/networking/ntpd.c b/networking/ntpd.c index 98158a304..8e7175063 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -2213,6 +2213,31 @@ static NOINLINE void ntp_init(char **argv) // if (opts & OPT_x) /* disable stepping, only slew is allowed */ // G.time_was_stepped = 1; + +#if ENABLE_FEATURE_NTPD_SERVER + G_listen_fd = -1; + if (opts & OPT_l) { + G_listen_fd = create_and_bind_dgram_or_die(NULL, 123); + if (G.if_name) { + if (setsockopt_bindtodevice(G_listen_fd, G.if_name)) + xfunc_die(); + } + socket_want_pktinfo(G_listen_fd); + setsockopt_int(G_listen_fd, IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY); + } +#endif + /* I hesitate to set -20 prio. -15 should be high enough for timekeeping */ + if (opts & OPT_N) + setpriority(PRIO_PROCESS, 0, -15); + + /* add_peers() calls can retry DNS resolution (possibly forever). + * Daemonize before them, or else boot can stall forever. + */ + if (!(opts & OPT_n)) { + bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO, argv); + logmode = LOGMODE_NONE; + } + if (peers) { while (peers) add_peers(llist_pop(&peers)); @@ -2241,26 +2266,6 @@ static NOINLINE void ntp_init(char **argv) /* -l but no peers: "stratum 1 server" mode */ G.stratum = 1; } -#if ENABLE_FEATURE_NTPD_SERVER - G_listen_fd = -1; - if (opts & OPT_l) { - G_listen_fd = create_and_bind_dgram_or_die(NULL, 123); - if (opts & OPT_I) { - if (setsockopt_bindtodevice(G_listen_fd, G.if_name)) - xfunc_die(); - } - socket_want_pktinfo(G_listen_fd); - setsockopt_int(G_listen_fd, IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY); - } -#endif - if (!(opts & OPT_n)) { - bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO, argv); - logmode = LOGMODE_NONE; - } - /* I hesitate to set -20 prio. -15 should be high enough for timekeeping */ - if (opts & OPT_N) - setpriority(PRIO_PROCESS, 0, -15); - /* If network is up, syncronization occurs in ~10 seconds. * We give "ntpd -q" 10 seconds to get first reply, * then another 50 seconds to finish syncing. From 44399e00ffa73270cd7fc108c983d3b1705b9d86 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 3 Jul 2016 20:26:44 +0200 Subject: [PATCH 07/41] udhcpc: run "deconfig" script in manual renew state too. closes 9061 The bug was seen when the following is done: # killall 1 udhpc; killall 2 udhpc Performing a DHCP renew state: 2 -> 5 Sending renew... Entering released state state: 5 -> 6 <<<<<<<<<<<<<< not calling script!!!! Signed-off-by: Denys Vlasenko --- networking/udhcp/d6_dhcpc.c | 6 +++++- networking/udhcp/dhcpc.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c index c77669a31..12f8f1125 100644 --- a/networking/udhcp/d6_dhcpc.c +++ b/networking/udhcp/d6_dhcpc.c @@ -793,7 +793,11 @@ static void perform_renew(void) 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) { + if (state == BOUND + || state == RENEWING + || state == REBINDING + || state == RENEW_REQUESTED + ) { bb_error_msg("unicasting a release"); send_d6_release(server_ipv6, our_cur_ipv6); /* unicast */ d6_run_script(NULL, "deconfig"); diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index fc7b6216d..e58acbaca 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -1118,7 +1118,11 @@ static void perform_release(uint32_t server_addr, uint32_t requested_ip) struct in_addr temp_addr; /* send release packet */ - if (state == BOUND || state == RENEWING || state == REBINDING) { + if (state == BOUND + || state == RENEWING + || state == REBINDING + || state == RENEW_REQUESTED + ) { temp_addr.s_addr = server_addr; strcpy(buffer, inet_ntoa(temp_addr)); temp_addr.s_addr = requested_ip; From ee772a0d90e2775cbe40072fd5217552c260a9aa Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 4 Jul 2016 17:38:01 +0200 Subject: [PATCH 08/41] arp: fix buffer overflow. Closes 9071 function old new delta arp_main 1910 1898 -12 Signed-off-by: Denys Vlasenko --- networking/arp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/networking/arp.c b/networking/arp.c index 9381eb53a..69a5816eb 100644 --- a/networking/arp.c +++ b/networking/arp.c @@ -178,7 +178,7 @@ static int arp_del(char **args) if (flags == 0) flags = 3; - strncpy(req.arp_dev, device, sizeof(req.arp_dev)); + strncpy_IFNAMSIZ(req.arp_dev, device); err = -1; @@ -219,7 +219,7 @@ static void arp_getdevhw(char *ifname, struct sockaddr *sa) struct ifreq ifr; const struct hwtype *xhw; - strcpy(ifr.ifr_name, ifname); + strncpy_IFNAMSIZ(ifr.ifr_name, ifname); ioctl_or_perror_and_die(sockfd, SIOCGIFHWADDR, &ifr, "can't get HW-Address for '%s'", ifname); if (hw_set && (ifr.ifr_hwaddr.sa_family != hw->type)) { @@ -332,7 +332,7 @@ static int arp_set(char **args) /* Fill in the remainder of the request. */ req.arp_flags = flags; - strncpy(req.arp_dev, device, sizeof(req.arp_dev)); + strncpy_IFNAMSIZ(req.arp_dev, device); /* Call the kernel. */ if (option_mask32 & ARP_OPT_v) From 1b0dcc02dd5a101d1a62f2111892a41621be96cf Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Tue, 5 Jul 2016 14:07:50 +0100 Subject: [PATCH 09/41] libbb: suppress warning about run_applet_and_exit When busybox is configured to contain a single applet an unnecessary declaration of run_applet_and_exit results in a warning. Move the declaration to avoid this. Reported-by: Lauri Kasanen Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- libbb/appletlib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libbb/appletlib.c b/libbb/appletlib.c index 480bf50fc..791b81c17 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -52,8 +52,6 @@ #include "usage_compressed.h" -static void run_applet_and_exit(const char *name, char **argv) NORETURN; - #if ENABLE_SHOW_USAGE && !ENABLE_FEATURE_COMPRESS_USAGE static const char usage_messages[] ALIGN1 = UNPACKED_USAGE; #else @@ -711,6 +709,8 @@ static void install_links(const char *busybox UNUSED_PARAM, # endif # if ENABLE_BUSYBOX +static void run_applet_and_exit(const char *name, char **argv) NORETURN; + /* If we were called as "busybox..." */ static int busybox_main(char **argv) { From f4f8fe841cf2df761eaade204a13e6fde6639666 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 5 Jul 2016 21:43:28 +0200 Subject: [PATCH 10/41] build system: fix a few warnings for allnoconfig build Not that allnoconfig build is useful in any way... Signed-off-by: Denys Vlasenko --- applets/usage_pod.c | 2 ++ docs/busybox_footer.pod | 2 -- libbb/appletlib.c | 30 +++++++++++++++++------------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/applets/usage_pod.c b/applets/usage_pod.c index 0b1c4aadb..ccc166aed 100644 --- a/applets/usage_pod.c +++ b/applets/usage_pod.c @@ -90,6 +90,8 @@ int main(void) printf("%s\n\n", usage_array[i].aname); } } + printf("=back\n\n"); + return 0; } diff --git a/docs/busybox_footer.pod b/docs/busybox_footer.pod index c346c736b..92748eb72 100644 --- a/docs/busybox_footer.pod +++ b/docs/busybox_footer.pod @@ -1,5 +1,3 @@ -=back - =head1 LIBC NSS GNU Libc (glibc) uses the Name Service Switch (NSS) to configure the behavior diff --git a/libbb/appletlib.c b/libbb/appletlib.c index 791b81c17..c341817e2 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -841,6 +841,7 @@ static int busybox_main(char **argv) } # endif +# if NUM_APPLETS > 0 void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv) { int argc = 1; @@ -858,15 +859,15 @@ void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv) * "true" and "false" are also special. */ if (1 -#if defined APPLET_NO_test +# if defined APPLET_NO_test && applet_no != APPLET_NO_test -#endif -#if defined APPLET_NO_true +# endif +# if defined APPLET_NO_true && applet_no != APPLET_NO_true -#endif -#if defined APPLET_NO_false +# endif +# if defined APPLET_NO_false && applet_no != APPLET_NO_false -#endif +# endif ) { if (argc == 2 && strcmp(argv[1], "--help") == 0) { /* Make "foo --help" exit with 0: */ @@ -878,19 +879,22 @@ void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv) check_suid(applet_no); exit(applet_main[applet_no](argc, argv)); } +# endif /* NUM_APPLETS > 0 */ static NORETURN void run_applet_and_exit(const char *name, char **argv) { - int applet; - # if ENABLE_BUSYBOX if (is_prefixed_with(name, "busybox")) exit(busybox_main(argv)); # endif +# if NUM_APPLETS > 0 /* find_applet_by_name() search is more expensive, so goes second */ - applet = find_applet_by_name(name); - if (applet >= 0) - run_applet_no_and_exit(applet, argv); + { + int applet = find_applet_by_name(name); + if (applet >= 0) + run_applet_no_and_exit(applet, argv); + } +# endif /*bb_error_msg_and_die("applet not found"); - links in printf */ full_write2_str(applet_name); @@ -957,10 +961,10 @@ int main(int argc UNUSED_PARAM, char **argv) #else lbb_prepare("busybox" IF_FEATURE_INDIVIDUAL(, argv)); -#if !ENABLE_BUSYBOX +# if !ENABLE_BUSYBOX if (argv[1] && is_prefixed_with(bb_basename(argv[0]), "busybox")) argv++; -#endif +# endif applet_name = argv[0]; if (applet_name[0] == '-') applet_name++; From 1035c92e2d1c017eab7cb10badb7e3b407aeba2d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 6 Jul 2016 15:45:41 +0200 Subject: [PATCH 11/41] whois: make it actually work It was doing way too simplistic work of just querying the server, no redirects, no query massaging. This required user to know a lot about whois, and enter at least three queries for each host to get meaningful information. function old new delta whois_main 209 646 +437 Signed-off-by: Denys Vlasenko --- networking/whois.c | 137 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 124 insertions(+), 13 deletions(-) diff --git a/networking/whois.c b/networking/whois.c index bf330334a..5ef83672d 100644 --- a/networking/whois.c +++ b/networking/whois.c @@ -28,36 +28,147 @@ #include "libbb.h" -static void pipe_out(int fd) +static char *query(const char *host, int port, const char *domain) { + int fd; FILE *fp; - char buf[1024]; + bool success; + char *redir = NULL; + const char *pfx = ""; + char linebuf[1024]; + char *buf = NULL; + unsigned bufpos = 0; + again: + printf("[Querying %s:%d '%s%s']\n", host, port, pfx, domain); + fd = create_and_connect_stream_or_die(host, port); + success = 0; + fdprintf(fd, "%s%s\r\n", pfx, domain); fp = xfdopen_for_read(fd); - while (fgets(buf, sizeof(buf), fp)) { - char *p = strpbrk(buf, "\r\n"); - if (p) - *p = '\0'; - puts(buf); + + while (fgets(linebuf, sizeof(linebuf), fp)) { + unsigned len = strcspn(linebuf, "\r\n"); + linebuf[len++] = '\n'; + + buf = xrealloc(buf, bufpos + len + 1); + memcpy(buf + bufpos, linebuf, len); + bufpos += len; + + if (!redir || !success) { + trim(linebuf); + str_tolower(linebuf); + if (!success) { + success = is_prefixed_with(linebuf, "domain:") + || is_prefixed_with(linebuf, "domain name:"); + } + else if (!redir) { + char *p = is_prefixed_with(linebuf, "whois server:"); + if (!p) + p = is_prefixed_with(linebuf, "whois:"); + if (p) + redir = xstrdup(skip_whitespace(p)); + } + } + } + fclose(fp); /* closes fd too */ + if (!success && !pfx[0]) { + /* + * Looking at jwhois.conf, some whois servers use + * "domain = DOMAIN", "DOMAIN ID " + * and "domain=DOMAIN_WITHOUT_LAST_COMPONENT" + * formats, but those are rare. + * (There are a few even more contrived ones.) + * We are trying only "domain DOMAIN", the typical one. + */ + pfx = "domain "; + bufpos = 0; + goto again; } - fclose(fp); /* closes fd too */ + /* Success */ + if (redir && strcmp(redir, host) == 0) { + /* Redirect to self does not count */ + free(redir); + redir = NULL; + } + if (!redir) { + /* Output saved text */ + printf("[%s]\n", host); + buf[bufpos] = '\0'; + fputs(buf, stdout); + } + free(buf); + return redir; } +static void recursive_query(const char *host, int port, const char *domain) +{ + char *free_me = NULL; + char *redir; + again: + redir = query(host, port, domain); + free(free_me); + if (redir) { + printf("[Redirected to %s]\n", redir); + host = free_me = redir; + port = 43; + goto again; + } +} + +/* One of "big" whois implementations has these options: + * + * $ whois --help + * jwhois version 4.0, Copyright (C) 1999-2007 Free Software Foundation, Inc. + * -v, --verbose verbose debug output + * -c FILE, --config=FILE use FILE as configuration file + * -h HOST, --host=HOST explicitly query HOST + * -n, --no-redirect disable content redirection + * -s, --no-whoisservers disable whois-servers.net service support + * -a, --raw disable reformatting of the query + * -i, --display-redirections display all redirects instead of hiding them + * -p PORT, --port=PORT use port number PORT (in conjunction with HOST) + * -r, --rwhois force an rwhois query to be made + * --rwhois-display=DISPLAY sets the display option in rwhois queries + * --rwhois-limit=LIMIT sets the maximum number of matches to return + * + * Example of its output: + * $ whois cnn.com + * [Querying whois.verisign-grs.com] + * [Redirected to whois.corporatedomains.com] + * [Querying whois.corporatedomains.com] + * [whois.corporatedomains.com] + * ...text of the reply... + * + * With -i, reply from each server is printed, after all redirects are done: + * [Querying whois.verisign-grs.com] + * [Redirected to whois.corporatedomains.com] + * [Querying whois.corporatedomains.com] + * [whois.verisign-grs.com] + * ...text of the reply... + * [whois.corporatedomains.com] + * ...text of the reply... + * + * With -a, no "DOMAIN" -> "domain DOMAIN" transformation is attempted. + + * With -n, the first reply is shown, redirects are not followed: + * [Querying whois.verisign-grs.com] + * [whois.verisign-grs.com] + * ...text of the reply... + */ + int whois_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int whois_main(int argc UNUSED_PARAM, char **argv) { int port = 43; - const char *host = "whois-servers.net"; + const char *host = "whois.iana.org"; opt_complementary = "-1:p+"; getopt32(argv, "h:p:", &host, &port); - argv += optind; + do { - int fd = create_and_connect_stream_or_die(host, port); - fdprintf(fd, "%s\r\n", *argv); - pipe_out(fd); + recursive_query(host, port, *argv); } while (*++argv); From 0844b5afe2cd60d46b7f2ad0fac8c2818d0780b3 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 6 Jul 2016 17:16:27 +0200 Subject: [PATCH 12/41] whois: implement -i function old new delta whois_main 654 675 +21 packed_usage 30355 30356 +1 Signed-off-by: Denys Vlasenko --- networking/whois.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/networking/whois.c b/networking/whois.c index 5ef83672d..6ba8dfd20 100644 --- a/networking/whois.c +++ b/networking/whois.c @@ -21,13 +21,18 @@ //kbuild:lib-$(CONFIG_WHOIS) += whois.o //usage:#define whois_trivial_usage -//usage: "[-h SERVER] [-p PORT] NAME..." +//usage: "[-i] [-h SERVER] [-p PORT] NAME..." //usage:#define whois_full_usage "\n\n" //usage: "Query WHOIS info about NAME\n" +//usage: "\n -i Show redirect results too" //usage: "\n -h,-p Server to query" #include "libbb.h" +enum { + OPT_i = (1 << 0), +}; + static char *query(const char *host, int port, const char *domain) { int fd; @@ -53,6 +58,7 @@ static char *query(const char *host, int port, const char *domain) buf = xrealloc(buf, bufpos + len + 1); memcpy(buf + bufpos, linebuf, len); bufpos += len; + buf[bufpos] = '\0'; if (!redir || !success) { trim(linebuf); @@ -73,7 +79,7 @@ static char *query(const char *host, int port, const char *domain) fclose(fp); /* closes fd too */ if (!success && !pfx[0]) { /* - * Looking at jwhois.conf, some whois servers use + * Looking at /etc/jwhois.conf, some whois servers use * "domain = DOMAIN", "DOMAIN ID " * and "domain=DOMAIN_WITHOUT_LAST_COMPONENT" * formats, but those are rare. @@ -91,11 +97,9 @@ static char *query(const char *host, int port, const char *domain) free(redir); redir = NULL; } - if (!redir) { + if (!redir || (option_mask32 & OPT_i)) { /* Output saved text */ - printf("[%s]\n", host); - buf[bufpos] = '\0'; - fputs(buf, stdout); + printf("[%s]\n%s", host, buf ? buf : ""); } free(buf); return redir; @@ -164,7 +168,7 @@ int whois_main(int argc UNUSED_PARAM, char **argv) const char *host = "whois.iana.org"; opt_complementary = "-1:p+"; - getopt32(argv, "h:p:", &host, &port); + getopt32(argv, "ih:p:", &host, &port); argv += optind; do { From 237bedd499c58034a1355484d6d4d906f0180308 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 6 Jul 2016 21:58:02 +0200 Subject: [PATCH 13/41] getopt32: add new syntax of 'o:+' and 'o:*' for -o NUM and -o LIST In many cases, this aqllows to drop use of opt_complementary. Approximately -400 bytes: function old new delta getopt32 1423 1502 +79 opt_string 17 18 +1 OPT_STR 24 25 +1 uniq_main 416 406 -10 timeout_main 279 269 -10 sulogin_main 270 260 -10 readprofile_main 1825 1815 -10 ps_main 543 533 -10 pidof_main 245 235 -10 pgrep_main 611 601 -10 od_main 2600 2590 -10 mkfs_minix_main 2684 2674 -10 mkfs_ext2_main 2603 2593 -10 microcom_main 712 702 -10 makemime_main 315 305 -10 ionice_main 282 272 -10 inetd_main 2074 2064 -10 ifplugd_main 1144 1134 -10 halt_main 353 343 -10 getopt_main 636 626 -10 fdisk_main 2854 2844 -10 env_main 206 196 -10 dmesg_main 319 309 -10 conspy_main 1214 1204 -10 awk_main 981 971 -10 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/22 up/down: 81/-220) Total: -139 bytes text data bss dec hex filename 919373 906 14060 934339 e41c3 busybox_old 918969 906 14060 933935 e402f busybox_unstripped Signed-off-by: Denys Vlasenko --- archival/tar.c | 15 ++++--- coreutils/du.c | 8 ++-- coreutils/env.c | 3 +- coreutils/od_bloaty.c | 3 +- coreutils/sort.c | 5 +-- coreutils/split.c | 4 +- coreutils/tail.c | 4 +- coreutils/uniq.c | 3 +- debianutils/run_parts.c | 4 +- editors/awk.c | 8 +--- editors/diff.c | 4 +- editors/sed.c | 5 +-- findutils/grep.c | 8 ++-- init/halt.c | 3 +- libbb/getopt32.c | 82 ++++++++++++++++++++++++++----------- libbb/parse_config.c | 4 +- loginutils/cryptpw.c | 4 +- loginutils/getty.c | 4 +- loginutils/sulogin.c | 3 +- mailutils/makemime.c | 3 +- mailutils/popmaildir.c | 4 +- mailutils/reformime.c | 4 +- mailutils/sendmail.c | 4 +- miscutils/conspy.c | 4 +- miscutils/ionice.c | 3 +- miscutils/microcom.c | 3 +- miscutils/timeout.c | 3 +- miscutils/ubi_tools.c | 8 ++-- networking/arping.c | 4 +- networking/ftpd.c | 6 +-- networking/ifplugd.c | 5 +-- networking/inetd.c | 4 +- networking/nc_bloaty.c | 4 +- networking/ntpd.c | 4 +- networking/ping.c | 4 +- networking/tcpudp.c | 4 +- networking/telnetd.c | 4 +- networking/traceroute.c | 4 +- networking/udhcp/d6_dhcpc.c | 4 +- networking/udhcp/dhcpc.c | 4 +- networking/wget.c | 3 +- networking/whois.c | 4 +- procps/pgrep.c | 3 +- procps/pidof.c | 3 +- procps/ps.c | 3 +- procps/watch.c | 4 +- runit/chpst.c | 4 +- runit/sv.c | 4 +- selinux/setfiles.c | 6 +-- sysklogd/syslogd.c | 6 +-- util-linux/dmesg.c | 3 +- util-linux/fdisk.c | 3 +- util-linux/getopt.c | 3 +- util-linux/mkfs_ext2.c | 3 +- util-linux/mkfs_minix.c | 3 +- util-linux/mkfs_reiser.c | 4 +- util-linux/mount.c | 4 +- util-linux/readprofile.c | 3 +- 58 files changed, 168 insertions(+), 159 deletions(-) diff --git a/archival/tar.c b/archival/tar.c index 7434e22e4..8e315c610 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -980,7 +980,6 @@ int tar_main(int argc UNUSED_PARAM, char **argv) /* Prepend '-' to the first argument if required */ opt_complementary = "--:" // first arg is options "tt:vv:" // count -t,-v - IF_FEATURE_TAR_FROM("X::T::") // cumulative lists #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM "\xff::" // --exclude=PATTERN is a list #endif @@ -1032,13 +1031,13 @@ int tar_main(int argc UNUSED_PARAM, char **argv) #endif opt = getopt32(argv, "txC:f:Oopvk" - IF_FEATURE_TAR_CREATE( "ch" ) - IF_FEATURE_SEAMLESS_BZ2( "j" ) - IF_FEATURE_SEAMLESS_LZMA("a" ) - IF_FEATURE_TAR_FROM( "T:X:") - IF_FEATURE_SEAMLESS_GZ( "z" ) - IF_FEATURE_SEAMLESS_XZ( "J" ) - IF_FEATURE_SEAMLESS_Z( "Z" ) + IF_FEATURE_TAR_CREATE( "ch" ) + IF_FEATURE_SEAMLESS_BZ2( "j" ) + IF_FEATURE_SEAMLESS_LZMA("a" ) + IF_FEATURE_TAR_FROM( "T:*X:*") + IF_FEATURE_SEAMLESS_GZ( "z" ) + IF_FEATURE_SEAMLESS_XZ( "J" ) + IF_FEATURE_SEAMLESS_Z( "Z" ) IF_FEATURE_TAR_NOPRESERVE_TIME("m") IF_FEATURE_TAR_LONG_OPTIONS("\xf9:") // --strip-components , &base_dir // -C dir diff --git a/coreutils/du.c b/coreutils/du.c index 1240bcbbc..5f104736b 100644 --- a/coreutils/du.c +++ b/coreutils/du.c @@ -226,8 +226,8 @@ int du_main(int argc UNUSED_PARAM, char **argv) * ignore -a. This is consistent with -s being equivalent to -d 0. */ #if ENABLE_FEATURE_HUMAN_READABLE - opt_complementary = "h-km:k-hm:m-hk:H-L:L-H:s-d:d-s:d+"; - opt = getopt32(argv, "aHkLsx" "d:" "lc" "hm", &G.max_print_depth); + opt_complementary = "h-km:k-hm:m-hk:H-L:L-H:s-d:d-s"; + opt = getopt32(argv, "aHkLsx" "d:+" "lc" "hm", &G.max_print_depth); argv += optind; if (opt & OPT_h_for_humans) { G.disp_unit = 0; @@ -239,8 +239,8 @@ int du_main(int argc UNUSED_PARAM, char **argv) G.disp_unit = 1024; } #else - opt_complementary = "H-L:L-H:s-d:d-s:d+"; - opt = getopt32(argv, "aHkLsx" "d:" "lc", &G.max_print_depth); + opt_complementary = "H-L:L-H:s-d:d-s"; + opt = getopt32(argv, "aHkLsx" "d:+" "lc", &G.max_print_depth); argv += optind; #if !ENABLE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K if (opt & OPT_k_kbytes) { diff --git a/coreutils/env.c b/coreutils/env.c index 807ef13e9..cdfc30e14 100644 --- a/coreutils/env.c +++ b/coreutils/env.c @@ -54,11 +54,10 @@ int env_main(int argc UNUSED_PARAM, char **argv) unsigned opts; llist_t *unset_env = NULL; - opt_complementary = "u::"; #if ENABLE_FEATURE_ENV_LONG_OPTIONS applet_long_options = env_longopts; #endif - opts = getopt32(argv, "+iu:", &unset_env); + opts = getopt32(argv, "+iu:+", &unset_env); argv += optind; if (argv[0] && LONE_DASH(argv[0])) { opts |= 1; diff --git a/coreutils/od_bloaty.c b/coreutils/od_bloaty.c index c8a654165..f13bdfc11 100644 --- a/coreutils/od_bloaty.c +++ b/coreutils/od_bloaty.c @@ -62,7 +62,7 @@ enum { }; #define OD_GETOPT32() getopt32(argv, \ - "A:N:abcdfhij:lot:vxsS:w::", \ + "A:N:abcdfhij:lot:*vxsS:w:+:", \ /* -w with optional param */ \ /* -S was -s and also had optional parameter */ \ /* but in coreutils 6.3 it was renamed and now has */ \ @@ -1212,7 +1212,6 @@ int od_main(int argc UNUSED_PARAM, char **argv) address_pad_len_char = '7'; /* Parse command line */ - opt_complementary = "w+:t::"; /* -w N, -t is a list */ #if ENABLE_LONG_OPTS applet_long_options = od_longopts; #endif diff --git a/coreutils/sort.c b/coreutils/sort.c index 9139d9f47..34a41999b 100644 --- a/coreutils/sort.c +++ b/coreutils/sort.c @@ -73,7 +73,7 @@ */ /* These are sort types */ -static const char OPT_STR[] ALIGN1 = "ngMucszbrdfimS:T:o:k:t:"; +static const char OPT_STR[] ALIGN1 = "ngMucszbrdfimS:T:o:k:*t:"; enum { FLAG_n = 1, /* Numeric sort */ FLAG_g = 2, /* Sort using strtod() */ @@ -358,8 +358,7 @@ int sort_main(int argc UNUSED_PARAM, char **argv) /* Parse command line options */ /* -o and -t can be given at most once */ - opt_complementary = "o--o:t--t:" /* -t, -o: at most one of each */ - "k::"; /* -k takes list */ + opt_complementary = "o--o:t--t"; /* -t, -o: at most one of each */ opts = getopt32(argv, OPT_STR, &str_ignored, &str_ignored, &str_o, &lst_k, &str_t); /* global b strips leading and trailing spaces */ if (opts & FLAG_b) diff --git a/coreutils/split.c b/coreutils/split.c index e67c3de66..19d58a21b 100644 --- a/coreutils/split.c +++ b/coreutils/split.c @@ -81,8 +81,8 @@ int split_main(int argc UNUSED_PARAM, char **argv) setup_common_bufsiz(); - opt_complementary = "?2:a+"; /* max 2 args; -a N */ - opt = getopt32(argv, "l:b:a:", &count_p, &count_p, &suffix_len); + opt_complementary = "?2"; /* max 2 args; -a N */ + opt = getopt32(argv, "l:b:a:+", &count_p, &count_p, &suffix_len); if (opt & SPLIT_OPT_l) cnt = XATOOFF(count_p); diff --git a/coreutils/tail.c b/coreutils/tail.c index 39f87679e..57ad0f3b7 100644 --- a/coreutils/tail.c +++ b/coreutils/tail.c @@ -121,8 +121,8 @@ int tail_main(int argc, char **argv) #endif /* -s NUM, -F imlies -f */ - IF_FEATURE_FANCY_TAIL(opt_complementary = "s+:Ff";) - opt = getopt32(argv, "fc:n:" IF_FEATURE_FANCY_TAIL("qs:vF"), + IF_FEATURE_FANCY_TAIL(opt_complementary = "Ff";) + opt = getopt32(argv, "fc:n:" IF_FEATURE_FANCY_TAIL("qs:+vF"), &str_c, &str_n IF_FEATURE_FANCY_TAIL(,&sleep_period)); #define FOLLOW (opt & 0x1) #define COUNT_BYTES (opt & 0x2) diff --git a/coreutils/uniq.c b/coreutils/uniq.c index e0133998a..ec7bde418 100644 --- a/coreutils/uniq.c +++ b/coreutils/uniq.c @@ -50,8 +50,7 @@ int uniq_main(int argc UNUSED_PARAM, char **argv) skip_fields = skip_chars = 0; max_chars = INT_MAX; - opt_complementary = "f+:s+:w+"; - opt = getopt32(argv, "cduf:s:w:", &skip_fields, &skip_chars, &max_chars); + opt = getopt32(argv, "cduf:+s:+w:+", &skip_fields, &skip_chars, &max_chars); argv += optind; input_filename = argv[0]; diff --git a/debianutils/run_parts.c b/debianutils/run_parts.c index c671b9252..0bb666abc 100644 --- a/debianutils/run_parts.c +++ b/debianutils/run_parts.c @@ -181,8 +181,8 @@ int run_parts_main(int argc UNUSED_PARAM, char **argv) applet_long_options = runparts_longopts; #endif /* We require exactly one argument: the directory name */ - opt_complementary = "=1:a::"; - getopt32(argv, "a:u:", &arg_list, &umask_p); + opt_complementary = "=1"; + getopt32(argv, "a:*u:", &arg_list, &umask_p); umask(xstrtou_range(umask_p, 8, 0, 07777)); diff --git a/editors/awk.c b/editors/awk.c index 69816464d..d0269b9f4 100644 --- a/editors/awk.c +++ b/editors/awk.c @@ -72,12 +72,9 @@ #define OPTSTR_AWK \ - "F:v:f:" \ - IF_FEATURE_AWK_GNU_EXTENSIONS("e:") \ + "F:v:*f:*" \ + IF_FEATURE_AWK_GNU_EXTENSIONS("e:*") \ "W:" -#define OPTCOMPLSTR_AWK \ - "v::f::" \ - IF_FEATURE_AWK_GNU_EXTENSIONS("e::") enum { OPTBIT_F, /* define field separator */ OPTBIT_v, /* define variable */ @@ -3209,7 +3206,6 @@ int awk_main(int argc, char **argv) *s1 = '='; } } - opt_complementary = OPTCOMPLSTR_AWK; opt = getopt32(argv, OPTSTR_AWK, &opt_F, &list_v, &list_f, IF_FEATURE_AWK_GNU_EXTENSIONS(&list_e,) NULL); argv += optind; argc -= optind; diff --git a/editors/diff.c b/editors/diff.c index ff269360f..75229ad8c 100644 --- a/editors/diff.c +++ b/editors/diff.c @@ -982,11 +982,11 @@ int diff_main(int argc UNUSED_PARAM, char **argv) INIT_G(); /* exactly 2 params; collect multiple -L