From 22a633962786a7bc97870ced913fc237143cfd68 Mon Sep 17 00:00:00 2001 From: Eivind Versvik Date: Sat, 24 Aug 2019 17:23:48 +0200 Subject: udhcpc6: support stateless DHCPv6 -l will send Information-Request to request configuration parameters function old new delta packed_usage 33114 33180 +66 send_d6_info_request - 62 +62 udhcpc6_main 2534 2593 +59 udhcpc6_longopts 199 211 +12 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 3/0 up/down: 199/0) Total: 199 bytes Signed-off-by: Eivind Versvik Signed-off-by: Denys Vlasenko --- networking/udhcp/d6_dhcpc.c | 81 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 72 insertions(+), 9 deletions(-) diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c index 9d8e17c51..a426b9933 100644 --- a/networking/udhcp/d6_dhcpc.c +++ b/networking/udhcp/d6_dhcpc.c @@ -123,6 +123,7 @@ static const char udhcpc6_longopts[] ALIGN1 = "request-option\0" Required_argument "O" "no-default-options\0" No_argument "o" "foreground\0" No_argument "f" + "stateless\0" No_argument "l" USE_FOR_MMU( "background\0" No_argument "b" ) @@ -147,9 +148,10 @@ enum { OPT_o = 1 << 12, OPT_x = 1 << 13, OPT_f = 1 << 14, - OPT_d = 1 << 15, + OPT_l = 1 << 15, + OPT_d = 1 << 16, /* The rest has variable bit positions, need to be clever */ - OPTBIT_d = 15, + OPTBIT_d = 16, USE_FOR_MMU( OPTBIT_b,) ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) IF_FEATURE_UDHCP_PORT( OPTBIT_P,) @@ -544,6 +546,46 @@ static int d6_mcast_from_client_data_ifindex(struct d6_packet *packet, uint8_t * ); } +/* RFC 3315 18.1.5. Creation and Transmission of Information-request Messages + * + * The client uses an Information-request message to obtain + * configuration information without having addresses assigned to it. + * + * The client sets the "msg-type" field to INFORMATION-REQUEST. The + * client generates a transaction ID and inserts this value in the + * "transaction-id" field. + * + * The client SHOULD include a Client Identifier option to identify + * itself to the server. If the client does not include a Client + * Identifier option, the server will not be able to return any client- + * specific options to the client, or the server may choose not to + * respond to the message at all. The client MUST include a Client + * Identifier option if the Information-Request message will be + * authenticated. + * + * 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_info_request(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_INFORMATION_REQUEST, xid); + + /* Add options: + * "param req" option according to -O, options specified with -x + */ + opt_ptr = add_d6_client_options(opt_ptr); + + bb_error_msg("sending %s", "info request"); + return d6_mcast_from_client_data_ifindex(&packet, opt_ptr); +} + /* Milticast a DHCPv6 Solicit packet to the network, with an optionally requested IP. * * RFC 3315 17.1.1. Creation of Solicit Messages @@ -1129,6 +1171,8 @@ static void client_background(void) //usage: "\n -o Don't request any options (unless -O is given)" //usage: "\n -r IPv6 Request this address ('no' to not request any IP)" //usage: "\n -d Request prefix" +//usage: "\n -l Send 'information request' instead of 'solicit'" +//usage: "\n (used for servers which do not assign IPv6 addresses)" //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" @@ -1181,7 +1225,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) /* Parse command line */ opt = getopt32long(argv, "^" /* O,x: list; -T,-t,-A take numeric param */ - "i:np:qRr:s:T:+t:+SA:+O:*ox:*fd" + "i:np:qRr:s:T:+t:+SA:+O:*ox:*fld" USE_FOR_MMU("b") ///IF_FEATURE_UDHCPC_ARPING("a") IF_FEATURE_UDHCP_PORT("P:") @@ -1198,15 +1242,20 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) ); requested_ipv6 = NULL; option_mask32 |= OPT_r; - if (opt & OPT_r) { + if (opt & OPT_l) { + /* for -l, do not require IPv6 assignment from server */ + option_mask32 &= ~OPT_r; + } else if (opt & OPT_r) { + /* explicit "-r ARG" given */ if (strcmp(str_r, "no") == 0) { - option_mask32 -= OPT_r; + option_mask32 &= ~OPT_r; } else { 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_PORT6 = xatou16(str_P); @@ -1353,7 +1402,10 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) if (packet_num == 0) xid = random_xid(); /* multicast */ - send_d6_discover(xid, requested_ipv6); + if (opt & OPT_l) + send_d6_info_request(xid); + else + send_d6_discover(xid, requested_ipv6); timeout = discover_timeout; packet_num++; continue; @@ -1418,7 +1470,10 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) * Anyway, it does recover by eventually failing through * into INIT_SELECTING state. */ - send_d6_renew(xid, &srv6_buf, requested_ipv6); + if (opt & OPT_l) + send_d6_info_request(xid); + else + send_d6_renew(xid, &srv6_buf, requested_ipv6); timeout >>= 1; continue; } @@ -1432,8 +1487,10 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) /* 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); + if (opt & OPT_l) + send_d6_info_request(xid); + else /* send a broadcast renew request */ + send_d6_renew(xid, /*server_ipv6:*/ NULL, requested_ipv6); timeout >>= 1; continue; } @@ -1740,6 +1797,12 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) prefix_timeout = address_timeout; /* note: "int timeout" will not overflow even with 0xffffffff inputs here: */ timeout = (prefix_timeout < address_timeout ? prefix_timeout : address_timeout) / 2; + if (opt & OPT_l) { + /* TODO: request OPTION_INFORMATION_REFRESH_TIME (32) + * and use its value instead of the default 1 day. + */ + timeout = 24 * 60 * 60; + } /* paranoia: must not be too small */ /* timeout > 60 - ensures at least one unicast renew attempt */ if (timeout < 61) -- cgit v1.2.3-55-g6feb From 7454879a1d9e3948a9af21e31e9d59d5ae8b89f2 Mon Sep 17 00:00:00 2001 From: Brian Foley Date: Thu, 5 Sep 2019 10:46:22 +0200 Subject: dc: execute shouldn't pop if stack head is not a string This matches the behaviour of both GNU dc (as specified in its man page), and BSD dc (where stack_popstring() pops only if the head is a string.) Add a couple of tests to verify this behavior. function old new delta zxc_vm_process 6882 6884 +2 Signed-off-by: Brian Foley Signed-off-by: Denys Vlasenko --- miscutils/bc.c | 3 ++- testsuite/dc.tests | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/miscutils/bc.c b/miscutils/bc.c index 7ac30dd53..4a3ae49c5 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c @@ -6521,7 +6521,7 @@ static BC_STATUS zdc_program_execStr(char *code, size_t *bgn, bool cond) if (s || !BC_PROG_STR(n)) goto exit; sidx = n->rdx; } else - goto exit; + goto exit_nopop; } fidx = sidx + BC_PROG_REQ_FUNCS; @@ -6561,6 +6561,7 @@ static BC_STATUS zdc_program_execStr(char *code, size_t *bgn, bool cond) RETURN_STATUS(BC_STATUS_SUCCESS); exit: bc_vec_pop(&G.prog.results); + exit_nopop: RETURN_STATUS(s); } #define zdc_program_execStr(...) (zdc_program_execStr(__VA_ARGS__) COMMA_SUCCESS) diff --git a/testsuite/dc.tests b/testsuite/dc.tests index 8c3af4156..f74e3f0f5 100755 --- a/testsuite/dc.tests +++ b/testsuite/dc.tests @@ -44,6 +44,16 @@ testing "dc complex without spaces (multiple args)" \ optional FEATURE_DC_BIG # All tests below depend on FEATURE_DC_BIG +testing "dc: x should execute strings" \ + "dc -e'[40 2 +] x f'" \ + "42\n" \ + "" "" + +testing "dc: x should not execute or pop non-strings" \ + "dc -e'42 x f'" \ + "42\n" \ + "" "" + testing "dc read" \ "dc -finput" \ "2\n9\n1\n" \ -- cgit v1.2.3-55-g6feb From b64470be177314e8473fae6c32cab51cacb89fa7 Mon Sep 17 00:00:00 2001 From: Brian Foley Date: Thu, 5 Sep 2019 10:50:13 +0200 Subject: dc: Fix segfault when executing strings generated using asciify function old new delta zxc_vm_process 6884 6891 +7 Signed-off-by: Brian Foley Signed-off-by: Denys Vlasenko --- miscutils/bc.c | 10 ++++++++-- testsuite/dc.tests | 5 +++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/miscutils/bc.c b/miscutils/bc.c index 4a3ae49c5..016300ac1 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c @@ -4973,7 +4973,9 @@ static void dc_parse_string(void) xc_parse_pushInst_and_Index(XC_INST_STR, len); bc_vec_push(&G.prog.strs, &str); - // Explanation needed here + // Add an empty function so that if zdc_program_execStr ever needs to + // parse the string into code (from the 'x' command) there's somewhere + // to store the bytecode. xc_program_add_fn(); p->func = xc_program_func(p->fidx); @@ -6398,7 +6400,11 @@ static BC_STATUS zdc_program_asciify(void) str = xzalloc(2); str[0] = c; //str[1] = '\0'; - already is - bc_vec_push(&G.prog.strs, &str); + idx = bc_vec_push(&G.prog.strs, &str); + // Add an empty function so that if zdc_program_execStr ever needs to + // parse the string into code (from the 'x' command) there's somewhere + // to store the bytecode. + xc_program_add_fn(); dup: res.t = XC_RESULT_STR; res.d.id.idx = idx; diff --git a/testsuite/dc.tests b/testsuite/dc.tests index f74e3f0f5..1fc13c201 100755 --- a/testsuite/dc.tests +++ b/testsuite/dc.tests @@ -54,6 +54,11 @@ testing "dc: x should not execute or pop non-strings" \ "42\n" \ "" "" +testing "dc: x should work with strings created from a" \ + "dc -e'42 112 a x'" \ + "42\n" \ + "" "" + testing "dc read" \ "dc -finput" \ "2\n9\n1\n" \ -- cgit v1.2.3-55-g6feb From 10509a70ee5c28800d23bf891b4f72603447e364 Mon Sep 17 00:00:00 2001 From: Brian Foley Date: Thu, 5 Sep 2019 10:53:21 +0200 Subject: dc: Parse error & fix out of bounds read in xc_program_printString function old new delta xc_program_print 712 735 +23 Signed-off-by: Brian Foley Signed-off-by: Denys Vlasenko --- miscutils/bc.c | 6 ++++-- testsuite/dc.tests | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/miscutils/bc.c b/miscutils/bc.c index 016300ac1..e492f0f50 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c @@ -5456,11 +5456,13 @@ static void xc_program_printString(const char *str) char *n; c = *str++; - n = strchr(esc, c); // note: c can be NUL - if (!n) { + n = strchr(esc, c); // note: if c is NUL, n = \0 at end of esc + if (!n || !c) { // Just print the backslash and following character bb_putchar('\\'); ++G.prog.nchars; + // But if we're at the end of the string, stop + if (!c) break; } else { if (n - esc == 0) // "\n" ? G.prog.nchars = SIZE_MAX; diff --git a/testsuite/dc.tests b/testsuite/dc.tests index 1fc13c201..361bc8459 100755 --- a/testsuite/dc.tests +++ b/testsuite/dc.tests @@ -59,6 +59,26 @@ testing "dc: x should work with strings created from a" \ "42\n" \ "" "" +testing "dc: p should print invalid escapes" \ + "dc -e '[\q] p'" \ + "\\q\n" \ + "" "" + +testing "dc: p should print trailing backslashes" \ + "dc -e '[q\] p'" \ + "q\\\\\n" \ + "" "" + +testing "dc: p should parse/print single backslashes" \ + "dc -e '[\] p'" \ + "\\\\\n" \ + "" "" + +testing "dc: p should print single backslash strings" \ + "dc -e '92 a p'" \ + "\\\\\n" \ + "" "" + testing "dc read" \ "dc -finput" \ "2\n9\n1\n" \ -- cgit v1.2.3-55-g6feb From de82f0b764de4720fed3378f2e5f938a3f4b9d18 Mon Sep 17 00:00:00 2001 From: Daniel Edgecumbe Date: Mon, 2 Sep 2019 22:03:14 +0100 Subject: gzip: default level with ENABLE_FEATURE_GZIP_LEVELS should be 6 Fixes an off-by-one that actually resulted in level 7 being used Signed-off-by: Daniel Edgecumbe Signed-off-by: Denys Vlasenko --- archival/gzip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archival/gzip.c b/archival/gzip.c index 17341de45..37db347b8 100644 --- a/archival/gzip.c +++ b/archival/gzip.c @@ -2222,7 +2222,7 @@ int gzip_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_FEATURE_GZIP_LEVELS opt >>= (BBUNPK_OPTSTRLEN IF_FEATURE_GZIP_DECOMPRESS(+ 2) + 1); /* drop cfkvq[dt]n bits */ if (opt == 0) - opt = 1 << 6; /* default: 6 */ + opt = 1 << 5; /* default: 6 */ opt = ffs(opt >> 4); /* Maps -1..-4 to [0], -5 to [1] ... -9 to [5] */ max_chain_length = 1 << gzip_level_config[opt].chain_shift; good_match = gzip_level_config[opt].good; -- cgit v1.2.3-55-g6feb From ca5d86d52c979cef05a614fb725870c10be9b265 Mon Sep 17 00:00:00 2001 From: Daniel Edgecumbe Date: Mon, 2 Sep 2019 22:05:26 +0100 Subject: gzip: set compression flags correctly as per standard With this change and CONFIG_GZIP_FAST=2, CONFIG_FEATURE_GZIP_LEVELS=y, GNU gzip and BusyBox gzip now produce identical output at each compression level (excluding 1..3, as BusyBox does not implement these levels). Signed-off-by: Daniel Edgecumbe Signed-off-by: Denys Vlasenko --- archival/gzip.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/archival/gzip.c b/archival/gzip.c index 37db347b8..a543d8c36 100644 --- a/archival/gzip.c +++ b/archival/gzip.c @@ -259,6 +259,7 @@ enum { #if !ENABLE_FEATURE_GZIP_LEVELS + comp_level = 9, max_chain_length = 4096, /* To speed up deflation, hash chains are never searched beyond this length. * A higher limit improves compression ratio but degrades the speed. @@ -334,14 +335,16 @@ struct globals { #define head (G1.prev + WSIZE) /* hash head (see deflate.c) */ #if ENABLE_FEATURE_GZIP_LEVELS + unsigned comp_level; unsigned max_chain_length; unsigned max_lazy_match; unsigned good_match; unsigned nice_match; +#define comp_level (G1.comp_level) #define max_chain_length (G1.max_chain_length) #define max_lazy_match (G1.max_lazy_match) -#define good_match (G1.good_match) -#define nice_match (G1.nice_match) +#define good_match (G1.good_match) +#define nice_match (G1.nice_match) #endif /* =========================================================================== */ @@ -1919,7 +1922,7 @@ static void bi_init(void) /* =========================================================================== * Initialize the "longest match" routines for a new file */ -static void lm_init(unsigned *flags16p) +static void lm_init(void) { unsigned j; @@ -1927,8 +1930,6 @@ static void lm_init(unsigned *flags16p) memset(head, 0, HASH_SIZE * sizeof(*head)); /* prev will be initialized on the fly */ - /* speed options for the general purpose bit flag */ - *flags16p |= 2; /* FAST 4, SLOW 2 */ /* ??? reduce max_chain_length for binary files */ //G1.strstart = 0; // globals are zeroed in pack_gzip() @@ -2076,10 +2077,16 @@ static void zip(void) bi_init(); ct_init(); - deflate_flags = 0; /* pkzip -es, -en or -ex equivalent */ - lm_init(&deflate_flags); + lm_init(); - put_16bit(deflate_flags | 0x300); /* extra flags. OS id = 3 (Unix) */ + deflate_flags = 0x300; /* extra flags. OS id = 3 (Unix) */ +#if ENABLE_FEATURE_GZIP_LEVELS + /* Note that comp_level < 4 do not exist in this version of gzip */ + if (comp_level == 9) { + deflate_flags |= 0x02; /* SLOW flag */ + } +#endif + put_16bit(deflate_flags); /* The above 32-bit misaligns outbuf (10 bytes are stored), flush it */ flush_outbuf_if_32bit_optimized(); @@ -2224,6 +2231,9 @@ int gzip_main(int argc UNUSED_PARAM, char **argv) if (opt == 0) opt = 1 << 5; /* default: 6 */ opt = ffs(opt >> 4); /* Maps -1..-4 to [0], -5 to [1] ... -9 to [5] */ + + comp_level = opt + 4; + max_chain_length = 1 << gzip_level_config[opt].chain_shift; good_match = gzip_level_config[opt].good; max_lazy_match = gzip_level_config[opt].lazy2 * 2; -- cgit v1.2.3-55-g6feb From c660cc1b7714fffbac95c9378ff4b73de650a6de Mon Sep 17 00:00:00 2001 From: Daniel Edgecumbe Date: Mon, 2 Sep 2019 22:09:15 +0100 Subject: gzip: set default compression level to 6 when CONFIG_FEATURE_GZIP_LEVELS=n With this change, GNU gzip -n and BusyBox gzip now produce identical output assuming that CONFIG_GZIP_FAST=2. >> Excuse me, but I wonder one thing: Why should we follow >> strictly with gzip on the no-options default behavior? > First, the default 6 compression level is a de-facto standard. BSD gzip > and Apple gzip (on macOS) use this default as well. So there is a > reasonable expectation that different gzip implementations act the same. > For instance, if the default for busybox gzip becomes 9, then someone > writing a script using busybox gzip could reasonably expect that the > compression level will still be 9 when the same script is run on another > system. That would be wrong. Implementations should not deviate from > de-facto standards without a strong reason. > > Second, the inherent reason for this default has not gone away. While > processor speeds have exploded since the default was set, so has the > typical size of compressed files. Multiple gigabytes are nothing unusual > these days. And gzip is often used for compression on the fly, precisely > because it offers a good compromise between speed and compression ratio. > So I believe 6 continues to be a reasonable default. function old new delta deflate 939 927 -12 Signed-off-by: Daniel Edgecumbe Signed-off-by: Denys Vlasenko --- archival/gzip.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/archival/gzip.c b/archival/gzip.c index a543d8c36..b08e60efd 100644 --- a/archival/gzip.c +++ b/archival/gzip.c @@ -52,7 +52,7 @@ aa: 85.1% -- replaced with aa.gz //config: help //config: Enable support for compression levels 4-9. The default level //config: is 6. If levels 1-3 are specified, 4 is used. -//config: If this option is not selected, -N options are ignored and -9 +//config: If this option is not selected, -N options are ignored and -6 //config: is used. //config: //config:config FEATURE_GZIP_DECOMPRESS @@ -259,13 +259,13 @@ enum { #if !ENABLE_FEATURE_GZIP_LEVELS - comp_level = 9, - max_chain_length = 4096, + comp_level = 6, + max_chain_length = 128, /* To speed up deflation, hash chains are never searched beyond this length. * A higher limit improves compression ratio but degrades the speed. */ - max_lazy_match = 258, + max_lazy_match = 16, /* Attempt to find a better match only when the current match is strictly * smaller than this value. This mechanism is used only for compression * levels >= 4. @@ -277,7 +277,7 @@ enum { * max_insert_length is used only for compression levels <= 3. */ - good_match = 32, + good_match = 8, /* Use a faster search when the previous match is longer than this */ /* Values for max_lazy_match, good_match and max_chain_length, depending on @@ -286,7 +286,7 @@ enum { * found for specific files. */ - nice_match = 258, /* Stop searching when current match exceeds this */ + nice_match = 128, /* Stop searching when current match exceeds this */ /* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 * For deflate_fast() (levels <= 3) good is ignored and lazy has a different * meaning. -- cgit v1.2.3-55-g6feb From 750137ef7ce3d21511b4638d25a4fce0a811b60a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 5 Sep 2019 13:22:24 +0200 Subject: gzip: code shrink function old new delta gzip_main 267 264 -3 Signed-off-by: Denys Vlasenko --- archival/gzip.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/archival/gzip.c b/archival/gzip.c index b08e60efd..3966a06b4 100644 --- a/archival/gzip.c +++ b/archival/gzip.c @@ -259,7 +259,7 @@ enum { #if !ENABLE_FEATURE_GZIP_LEVELS - comp_level = 6, + comp_level_minus4 = 6 - 4, max_chain_length = 128, /* To speed up deflation, hash chains are never searched beyond this length. * A higher limit improves compression ratio but degrades the speed. @@ -335,16 +335,16 @@ struct globals { #define head (G1.prev + WSIZE) /* hash head (see deflate.c) */ #if ENABLE_FEATURE_GZIP_LEVELS - unsigned comp_level; + unsigned comp_level_minus4; /* can be a byte */ unsigned max_chain_length; unsigned max_lazy_match; unsigned good_match; unsigned nice_match; -#define comp_level (G1.comp_level) -#define max_chain_length (G1.max_chain_length) -#define max_lazy_match (G1.max_lazy_match) -#define good_match (G1.good_match) -#define nice_match (G1.nice_match) +#define comp_level_minus4 (G1.comp_level_minus4) +#define max_chain_length (G1.max_chain_length) +#define max_lazy_match (G1.max_lazy_match) +#define good_match (G1.good_match) +#define nice_match (G1.nice_match) #endif /* =========================================================================== */ @@ -2082,7 +2082,7 @@ static void zip(void) deflate_flags = 0x300; /* extra flags. OS id = 3 (Unix) */ #if ENABLE_FEATURE_GZIP_LEVELS /* Note that comp_level < 4 do not exist in this version of gzip */ - if (comp_level == 9) { + if (comp_level_minus4 == 9 - 4) { deflate_flags |= 0x02; /* SLOW flag */ } #endif @@ -2232,7 +2232,7 @@ int gzip_main(int argc UNUSED_PARAM, char **argv) opt = 1 << 5; /* default: 6 */ opt = ffs(opt >> 4); /* Maps -1..-4 to [0], -5 to [1] ... -9 to [5] */ - comp_level = opt + 4; + comp_level_minus4 = opt; max_chain_length = 1 << gzip_level_config[opt].chain_shift; good_match = gzip_level_config[opt].good; -- cgit v1.2.3-55-g6feb From 18a90ec846f4c19b3309022d308065237145e7ce Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 5 Sep 2019 14:07:14 +0200 Subject: hush: fix "set -o INVALID" affecting -e flag state Signed-off-by: Denys Vlasenko --- shell/hush.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/shell/hush.c b/shell/hush.c index 19b97e2a5..96a935875 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -9824,9 +9824,12 @@ static int set_mode(int state, char mode, const char *o_opt) IF_HUSH_MODE_X(G_x_mode = state;) IF_HUSH_MODE_X(if (G.x_mode_fd <= 0) G.x_mode_fd = dup_CLOEXEC(2, 10);) break; + case 'e': + G.o_opt[OPT_O_ERREXIT] = state; + break; case 'o': if (!o_opt) { - /* "set -+o" without parameter. + /* "set -o" or "set +o" without parameter. * in bash, set -o produces this output: * pipefail off * and set +o: @@ -9847,9 +9850,7 @@ static int set_mode(int state, char mode, const char *o_opt) G.o_opt[idx] = state; break; } - case 'e': - G.o_opt[OPT_O_ERREXIT] = state; - break; + /* fall through to error */ default: return EXIT_FAILURE; } @@ -10931,8 +10932,10 @@ static int FAST_FUNC builtin_set(char **argv) if (arg[0] != '+' && arg[0] != '-') break; for (n = 1; arg[n]; ++n) { - if (set_mode((arg[0] == '-'), arg[n], argv[1])) - goto error; + if (set_mode((arg[0] == '-'), arg[n], argv[1])) { + bb_error_msg("%s: %s: invalid option", "set", arg); + return EXIT_FAILURE; + } if (arg[n] == 'o' && argv[1]) argv++; } @@ -10962,11 +10965,6 @@ static int FAST_FUNC builtin_set(char **argv) G.global_argc = 1 + string_array_len(pp + 1); return EXIT_SUCCESS; - - /* Nothing known, so abort */ - error: - bb_error_msg("%s: %s: invalid option", "set", arg); - return EXIT_FAILURE; } #endif -- cgit v1.2.3-55-g6feb From 35e349de3c93ab75abd8a990aaa1e01658273650 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 5 Sep 2019 14:31:49 +0200 Subject: ash: add a FIXME comment Signed-off-by: Denys Vlasenko --- shell/ash.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/shell/ash.c b/shell/ash.c index 305fb6348..c5588ea66 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -12393,7 +12393,13 @@ checkend: { for (p = eofmark; STPUTC(c, out), *p; p++) { if (c != *p) goto more_heredoc; - + /* FIXME: fails for backslash-newlined terminator: + * cat < Date: Thu, 5 Sep 2019 14:58:08 +0200 Subject: examples/udhcp/simple.script: up interface on deconfig event Signed-off-by: Denys Vlasenko --- examples/udhcp/simple.script | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/udhcp/simple.script b/examples/udhcp/simple.script index 53974e6d6..29199aa39 100755 --- a/examples/udhcp/simple.script +++ b/examples/udhcp/simple.script @@ -16,9 +16,10 @@ BROADCAST="broadcast +" case "$1" in deconfig) - echo "Setting IP address 0.0.0.0 on $interface" + echo "Clearing IP addresses on $interface, upping it" if command -v ip >/dev/null; then ip addr flush dev $interface + ip link set dev $interface up else ifconfig $interface 0.0.0.0 fi -- cgit v1.2.3-55-g6feb From d327c6b190900dcb0cb7cda9008eb4f9893a92d8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 6 Sep 2019 17:56:57 +0200 Subject: gzip: code shrink Converted a few 16-bit variables and small arrays to 32-bit. Stopped pulling desc->FOO members into temporary local variables in gen_bitlen(): on register-starved arches, this is a loss, temporaries go into stack slots. Sprinkled a few "const" on pointer arguments. function old new delta pack_gzip 742 745 +3 gen_codes 101 97 -4 build_tree 886 833 -53 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/2 up/down: 3/-57) Total: -54 bytes Signed-off-by: Denys Vlasenko --- archival/gzip.c | 88 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/archival/gzip.c b/archival/gzip.c index 3966a06b4..d9c730f13 100644 --- a/archival/gzip.c +++ b/archival/gzip.c @@ -507,7 +507,7 @@ static ALWAYS_INLINE void flush_outbuf_if_32bit_optimized(void) * pointer, then initialize the crc shift register contents instead. * Return the current crc in either case. */ -static void updcrc(uch * s, unsigned n) +static void updcrc(uch *s, unsigned n) { G1.crc = crc32_block_endian0(G1.crc, s, n, global_crc32_table /*G1.crc_32_tab*/); } @@ -610,7 +610,7 @@ static void bi_windup(void) * Copy a stored block to the zip file, storing first the length and its * one's complement if requested. */ -static void copy_block(char *buf, unsigned len, int header) +static void copy_block(const char *buf, unsigned len, int header) { bi_windup(); /* align on byte boundary */ @@ -1010,7 +1010,8 @@ struct globals2 { tree_desc d_desc; tree_desc bl_desc; - ush bl_count[MAX_BITS + 1]; + /* was "ush", but "unsigned" results in smaller code */ + unsigned bl_count[MAX_BITS + 1]; /* The lengths of the bit length codes are sent in order of decreasing * probability, to avoid transmitting the lengths for unused bit length codes. @@ -1121,7 +1122,7 @@ static void init_block(void) (tree[n].Freq < tree[m].Freq \ || (tree[n].Freq == tree[m].Freq && G2.depth[n] <= G2.depth[m])) -static void pqdownheap(ct_data * tree, int k) +static void pqdownheap(const ct_data *tree, int k) { int v = G2.heap[k]; int j = k << 1; /* left son of k */ @@ -1155,22 +1156,15 @@ static void pqdownheap(ct_data * tree, int k) * The length opt_len is updated; static_len is also updated if stree is * not null. */ -static void gen_bitlen(tree_desc * desc) +static void gen_bitlen(const tree_desc *desc) { - ct_data *tree = desc->dyn_tree; - const uint8_t *extra = desc->extra_bits; - int base = desc->extra_base; - int max_code = desc->max_code; - int max_length = desc->max_length; - ct_data *stree = desc->static_tree; - int h; /* heap index */ - int n, m; /* iterate over the tree elements */ - int bits; /* bit length */ - int xbits; /* extra bits */ - ush f; /* frequency */ - int overflow = 0; /* number of elements with bit length too large */ - - for (bits = 0; bits <= MAX_BITS; bits++) +#define tree desc->dyn_tree + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int overflow; /* number of elements with bit length too large */ + + for (bits = 0; bits < ARRAY_SIZE(G2.bl_count); bits++) G2.bl_count[bits] = 0; /* In a first pass, compute the optimal bit lengths (which may @@ -1178,28 +1172,32 @@ static void gen_bitlen(tree_desc * desc) */ tree[G2.heap[G2.heap_max]].Len = 0; /* root of the heap */ + overflow = 0; for (h = G2.heap_max + 1; h < HEAP_SIZE; h++) { + ulg f; /* frequency */ + int xbits; /* extra bits */ + n = G2.heap[h]; bits = tree[tree[n].Dad].Len + 1; - if (bits > max_length) { - bits = max_length; + if (bits > desc->max_length) { + bits = desc->max_length; overflow++; } tree[n].Len = (ush) bits; /* We overwrite tree[n].Dad which is no longer needed */ - if (n > max_code) + if (n > desc->max_code) continue; /* not a leaf node */ G2.bl_count[bits]++; xbits = 0; - if (n >= base) - xbits = extra[n - base]; + if (n >= desc->extra_base) + xbits = desc->extra_bits[n - desc->extra_base]; f = tree[n].Freq; - G2.opt_len += (ulg) f *(bits + xbits); + G2.opt_len += f * (bits + xbits); - if (stree) - G2.static_len += (ulg) f * (stree[n].Len + xbits); + if (desc->static_tree) + G2.static_len += f * (desc->static_tree[n].Len + xbits); } if (overflow == 0) return; @@ -1209,14 +1207,14 @@ static void gen_bitlen(tree_desc * desc) /* Find the first bit length which could increase: */ do { - bits = max_length - 1; + bits = desc->max_length - 1; while (G2.bl_count[bits] == 0) bits--; G2.bl_count[bits]--; /* move one leaf down the tree */ G2.bl_count[bits + 1] += 2; /* move one overflow item as its brother */ - G2.bl_count[max_length]--; + G2.bl_count[desc->max_length]--; /* The brother of the overflow item also moves one step up, - * but this does not affect bl_count[max_length] + * but this does not affect bl_count[desc->max_length] */ overflow -= 2; } while (overflow > 0); @@ -1226,11 +1224,11 @@ static void gen_bitlen(tree_desc * desc) * lengths instead of fixing only the wrong ones. This idea is taken * from 'ar' written by Haruhiko Okumura.) */ - for (bits = max_length; bits != 0; bits--) { + for (bits = desc->max_length; bits != 0; bits--) { n = G2.bl_count[bits]; while (n != 0) { m = G2.heap[--h]; - if (m > max_code) + if (m > desc->max_code) continue; if (tree[m].Len != (unsigned) bits) { Trace((stderr, "code %d bits %d->%d\n", m, tree[m].Len, bits)); @@ -1240,6 +1238,7 @@ static void gen_bitlen(tree_desc * desc) n--; } } +#undef tree } /* =========================================================================== @@ -1250,12 +1249,13 @@ static void gen_bitlen(tree_desc * desc) * OUT assertion: the field code is set for all tree elements of non * zero code length. */ -static void gen_codes(ct_data * tree, int max_code) +static void gen_codes(ct_data *tree, int max_code) { - ush next_code[MAX_BITS + 1]; /* next code value for each bit length */ - ush code = 0; /* running code value */ - int bits; /* bit index */ - int n; /* code index */ + /* next_code[] and code used to be "ush", but "unsigned" results in smaller code */ + unsigned next_code[MAX_BITS + 1]; /* next code value for each bit length */ + unsigned code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ /* The distribution counts are first used to generate the code values * without bit reversal. @@ -1307,7 +1307,7 @@ do { \ pqdownheap(tree, SMALLEST); \ } while (0) -static void build_tree(tree_desc * desc) +static void build_tree(tree_desc *desc) { ct_data *tree = desc->dyn_tree; ct_data *stree = desc->static_tree; @@ -1385,10 +1385,10 @@ static void build_tree(tree_desc * desc) /* At this point, the fields freq and dad are set. We can now * generate the bit lengths. */ - gen_bitlen((tree_desc *) desc); + gen_bitlen(desc); /* The field len is now set, we can generate the bit codes */ - gen_codes((ct_data *) tree, max_code); + gen_codes(tree, max_code); } /* =========================================================================== @@ -1397,7 +1397,7 @@ static void build_tree(tree_desc * desc) * counts. (The contribution of the bit length codes will be added later * during the construction of bl_tree.) */ -static void scan_tree(ct_data * tree, int max_code) +static void scan_tree(ct_data *tree, int max_code) { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ @@ -1449,7 +1449,7 @@ static void scan_tree(ct_data * tree, int max_code) * Send a literal or distance tree in compressed form, using the codes in * bl_tree. */ -static void send_tree(ct_data * tree, int max_code) +static void send_tree(const ct_data *tree, int max_code) { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ @@ -1625,7 +1625,7 @@ static int ct_tally(int dist, int lc) /* =========================================================================== * Send the block data compressed using the given Huffman trees */ -static void compress_block(ct_data * ltree, ct_data * dtree) +static void compress_block(const ct_data *ltree, const ct_data *dtree) { unsigned dist; /* distance of matched string */ int lc; /* match length or unmatched char (if dist == 0) */ @@ -1675,7 +1675,7 @@ static void compress_block(ct_data * ltree, ct_data * dtree) * trees or store, and output the encoded block to the zip file. This function * returns the total compressed length for the file so far. */ -static void flush_block(char *buf, ulg stored_len, int eof) +static void flush_block(const char *buf, ulg stored_len, int eof) { ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ int max_blindex; /* index of last bit length code of non zero freq */ -- cgit v1.2.3-55-g6feb From af18b301eb16eb8496b31e5386b4c21c9045a5e6 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Thu, 12 Sep 2019 12:04:13 +0200 Subject: find: implement -empty function old new delta func_empty - 121 +121 packed_usage 33154 33167 +13 parse_params 1490 1500 +10 static.params 228 235 +7 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 3/0 up/down: 151/0) Total: 151 bytes Signed-off-by: Aaro Koskinen Signed-off-by: Denys Vlasenko --- findutils/find.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/findutils/find.c b/findutils/find.c index d6679bd08..9a2c61b75 100644 --- a/findutils/find.c +++ b/findutils/find.c @@ -203,6 +203,14 @@ //config: WARNING: This option can do much harm if used wrong. Busybox will not //config: try to protect the user from doing stupid things. Use with care. //config: +//config:config FEATURE_FIND_EMPTY +//config: bool "Enable -empty: match empty files or directories" +//config: default y +//config: depends on FIND +//config: help +//config: Support the 'find -empty' option to find empty regular files +//config: or directories. +//config: //config:config FEATURE_FIND_PATH //config: bool "Enable -path: match pathname with shell pattern" //config: default y @@ -315,6 +323,9 @@ //usage: IF_FEATURE_FIND_CONTEXT( //usage: "\n -context CTX File has specified security context" //usage: ) +//usage: IF_FEATURE_FIND_EMPTY( +//usage: "\n -empty Match empty file/directory" +//usage: ) //usage: IF_FEATURE_FIND_PRUNE( //usage: "\n -prune If current file is directory, don't descend into it" //usage: ) @@ -396,6 +407,7 @@ IF_FEATURE_FIND_PAREN( ACTS(paren, action ***subexpr;)) IF_FEATURE_FIND_PRUNE( ACTS(prune)) IF_FEATURE_FIND_QUIT( ACTS(quit)) IF_FEATURE_FIND_DELETE( ACTS(delete)) +IF_FEATURE_FIND_EMPTY( ACTS(empty)) IF_FEATURE_FIND_EXEC( ACTS(exec, char **exec_argv; /* -exec ARGS */ unsigned *subst_count; @@ -824,6 +836,30 @@ ACTF(delete) return TRUE; } #endif +#if ENABLE_FEATURE_FIND_EMPTY +ACTF(empty) +{ + if (S_ISDIR(statbuf->st_mode)) { + DIR *dir; + struct dirent *dent; + + dir = opendir(fileName); + if (!dir) { + bb_simple_perror_msg(fileName); + return FALSE; + } + + while ((dent = readdir(dir)) != NULL + && DOT_OR_DOTDOT(dent->d_name) + ) { + continue; + } + closedir(dir); + return dent == NULL; + } + return S_ISREG(statbuf->st_mode) && statbuf->st_size == 0; +} +#endif #if ENABLE_FEATURE_FIND_CONTEXT ACTF(context) { @@ -989,6 +1025,7 @@ static action*** parse_params(char **argv) IF_FEATURE_FIND_PRUNE( PARM_prune ,) IF_FEATURE_FIND_QUIT( PARM_quit ,) IF_FEATURE_FIND_DELETE( PARM_delete ,) + IF_FEATURE_FIND_EMPTY( PARM_empty ,) IF_FEATURE_FIND_EXEC( PARM_exec ,) IF_FEATURE_FIND_EXECUTABLE(PARM_executable,) IF_FEATURE_FIND_PAREN( PARM_char_brace,) @@ -1034,6 +1071,7 @@ static action*** parse_params(char **argv) IF_FEATURE_FIND_PRUNE( "-prune\0" ) IF_FEATURE_FIND_QUIT( "-quit\0" ) IF_FEATURE_FIND_DELETE( "-delete\0" ) + IF_FEATURE_FIND_EMPTY( "-empty\0" ) IF_FEATURE_FIND_EXEC( "-exec\0" ) IF_FEATURE_FIND_EXECUTABLE("-executable\0") IF_FEATURE_FIND_PAREN( "(\0" ) @@ -1203,6 +1241,12 @@ static action*** parse_params(char **argv) (void) ALLOC_ACTION(delete); } #endif +#if ENABLE_FEATURE_FIND_EMPTY + else if (parm == PARM_empty) { + dbg("%d", __LINE__); + (void) ALLOC_ACTION(empty); + } +#endif #if ENABLE_FEATURE_FIND_EXEC else if (parm == PARM_exec) { int i; -- cgit v1.2.3-55-g6feb From 7f89ebe18ff2f5b3b5e8b2d617d682cb1d56293b Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Tue, 13 Aug 2019 17:41:56 +0200 Subject: examples/udhcp/simple.script: print the filename actually changed Signed-off-by: Rolf Eike Beer Signed-off-by: Denys Vlasenko --- examples/udhcp/simple.script | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/udhcp/simple.script b/examples/udhcp/simple.script index 29199aa39..6658fbeef 100755 --- a/examples/udhcp/simple.script +++ b/examples/udhcp/simple.script @@ -53,7 +53,6 @@ case "$1" in done fi - echo "Recreating $RESOLV_CONF" # If the file is a symlink somewhere (like /etc/resolv.conf # pointing to /run/resolv.conf), make sure things work. if test -L "$RESOLV_CONF"; then @@ -61,6 +60,7 @@ case "$1" in test -e "$RESOLV_CONF" || touch "$RESOLV_CONF" fi realconf=$(readlink -f "$RESOLV_CONF" 2>/dev/null || echo "$RESOLV_CONF") + echo "Recreating $realconf" tmpfile="$realconf-$$" > "$tmpfile" [ -n "$domain" ] && echo "search $domain" >> "$tmpfile" -- cgit v1.2.3-55-g6feb From 4a9daf2b93e455b444f43f9cde309c7f235f6fb5 Mon Sep 17 00:00:00 2001 From: David Demelier Date: Thu, 29 Aug 2019 14:05:27 +0200 Subject: wget: increase redirections limit Some hosting services like sourceforge perform a lot of relocations before actually serving the file. Example of current limitation: busybox wget http://sourceforge.net/projects/fluxbox/files/fluxbox/1.3.7/fluxbox-1.3.7.tar.xz Connecting to sourceforge.net (216.105.38.13:80) Connecting to sourceforge.net (216.105.38.13:443) Connecting to sourceforge.net (216.105.38.13:443) Connecting to sourceforge.net (216.105.38.13:443) Connecting to downloads.sourceforge.net (216.105.38.13:443) wget: too many redirections Signed-off-by: David Demelier Signed-off-by: Denys Vlasenko --- networking/wget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/wget.c b/networking/wget.c index 9e5a40b6f..f2fc9e215 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -1109,7 +1109,7 @@ static void download_one_url(const char *url) * We are not sure it exists on remote side */ } - redir_limit = 5; + redir_limit = 16; resolve_lsa: lsa = xhost2sockaddr(server.host, server.port); if (!(option_mask32 & WGET_OPT_QUIET)) { -- cgit v1.2.3-55-g6feb From f159352112671e3c1e07356ebf6f590d8f79c8ff Mon Sep 17 00:00:00 2001 From: Kang-Che Sung Date: Thu, 5 Sep 2019 23:40:38 +0800 Subject: bc: Add 'U' suffix in UINT_MAX preprocessor check Without the 'U' unsigned suffix, gcc will throw a "integer constant is so large that it is unsigned" warning. Signed-off-by: Kang-Che Sung Signed-off-by: Denys Vlasenko --- miscutils/bc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miscutils/bc.c b/miscutils/bc.c index e492f0f50..92721d18f 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c @@ -844,10 +844,10 @@ struct globals { # error Strange INT_MAX #endif -#if UINT_MAX == 4294967295 +#if UINT_MAX == 4294967295U # define BC_MAX_SCALE_STR "4294967295" # define BC_MAX_STRING_STR "4294967294" -#elif UINT_MAX == 18446744073709551615 +#elif UINT_MAX == 18446744073709551615U # define BC_MAX_SCALE_STR "18446744073709551615" # define BC_MAX_STRING_STR "18446744073709551614" #else -- cgit v1.2.3-55-g6feb From ca1ce4b9fa2b48f8898a51782543fe32546ba1ec Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 22 Sep 2019 18:26:05 +0200 Subject: ash: fix BASE###nn bashism to accept letter 'digits' for bases > 9 function old new delta evaluate_string 873 876 +3 Signed-off-by: Denys Vlasenko --- shell/math.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/shell/math.c b/shell/math.c index eaf4f2453..0c806ad39 100644 --- a/shell/math.c +++ b/shell/math.c @@ -538,9 +538,16 @@ static arith_t strto_arith_t(const char *nptr, char **endptr) n = 0; nptr = *endptr + 1; /* bash allows "N#" (empty "nnnn" part) */ - while (isdigit(*nptr)) { + for (;;) { + unsigned digit = (unsigned)*nptr - '0'; + if (digit >= 10 || digit >= base) { + digit = (unsigned)(*nptr | 0x20) - ('a' - 10); + if (digit >= base) + break; + } /* bash does not check for overflows */ - n = n * base + (*nptr++ - '0'); + n = n * base + digit; + nptr++; } *endptr = (char*)nptr; return n; -- cgit v1.2.3-55-g6feb From c58d785b9d0a337ff884002c4cef5283f901c9e4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 22 Sep 2019 23:40:10 +0200 Subject: ash: fix BASE###nn bashism for bases 36..64 function old new delta evaluate_string 876 932 +56 Signed-off-by: Denys Vlasenko --- shell/math.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/shell/math.c b/shell/math.c index 0c806ad39..af1ab55c0 100644 --- a/shell/math.c +++ b/shell/math.c @@ -540,11 +540,29 @@ static arith_t strto_arith_t(const char *nptr, char **endptr) /* bash allows "N#" (empty "nnnn" part) */ for (;;) { unsigned digit = (unsigned)*nptr - '0'; - if (digit >= 10 || digit >= base) { + if (digit >= 10) { + /* *nptr is not 0..9 */ + if (*nptr > 'z') + break; /* this rejects e.g. $((64#~)) */ + /* in bases up to 36, case does not matter for a-z */ digit = (unsigned)(*nptr | 0x20) - ('a' - 10); - if (digit >= base) - break; + if (base > 36 && *nptr <= '_') { + /* otherwise, A-Z,@,_ are 36..61,62,63 */ + if (*nptr == '@') + digit = 62; + else if (*nptr == '_') + digit = 63; + else if (digit < 36) /* A-Z */ + digit += 36 - 10; + else + break; /* error, such as [ or \ */ + } + //bb_error_msg("ch:'%c'%d digit:%u", *nptr, *nptr, digit); + //if (digit < 10) - example where we need this? + // break; } + if (digit >= base) + break; /* bash does not check for overflows */ n = n * base + digit; nptr++; -- cgit v1.2.3-55-g6feb From 11e024aa86f23a6dd86cdd58b8890756708cd708 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 24 Sep 2019 14:01:00 +0200 Subject: udhcpc6: add ELAPSED_TIME option to outgoing packets function old new delta init_d6_packet 53 121 +68 udhcpc_main 2577 2582 +5 udhcpc6_main 2593 2597 +4 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/0 up/down: 77/0) Total: 77 bytes Signed-off-by: Denys Vlasenko --- networking/udhcp/d6_dhcpc.c | 18 +++++++++++++++++- networking/udhcp/dhcpc.c | 4 ++-- networking/udhcp/dhcpc.h | 4 ++-- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c index a426b9933..85c410a7c 100644 --- a/networking/udhcp/d6_dhcpc.c +++ b/networking/udhcp/d6_dhcpc.c @@ -481,15 +481,31 @@ static ALWAYS_INLINE uint32_t random_xid(void) /* Initialize the packet with the proper defaults */ static uint8_t *init_d6_packet(struct d6_packet *packet, char type, uint32_t xid) { + uint8_t *ptr; struct d6_option *clientid; + unsigned secs; memset(packet, 0, sizeof(*packet)); packet->d6_xid32 = xid; packet->d6_msg_type = type; + /* ELAPSED_TIME option is required to be present by the RFC, + * and some servers do check for its presense. [which?] + */ + ptr = packet->d6_options; /* NB: it is 32-bit aligned */ + *((uint32_t*)ptr) = htonl((D6_OPT_ELAPSED_TIME << 16) + 2); + ptr += 4; + client_data.last_secs = monotonic_sec(); + if (client_data.first_secs == 0) + client_data.first_secs = client_data.last_secs; + secs = client_data.last_secs - client_data.first_secs; + *((uint16_t*)ptr) = (secs < 0xffff) ? htons(secs) : 0xffff; + ptr += 2; + + /* add CLIENTID option */ clientid = (void*)client_data.clientid; - return mempcpy(packet->d6_options, clientid, clientid->len + 2+2); + return mempcpy(ptr, clientid, clientid->len + 2+2); } static uint8_t *add_d6_client_options(uint8_t *ptr) diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index 656295ff7..5a1f8fd7a 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -606,7 +606,7 @@ static ALWAYS_INLINE uint32_t random_xid(void) /* Initialize the packet with the proper defaults */ static void init_packet(struct dhcp_packet *packet, char type) { - uint16_t secs; + unsigned secs; /* Fill in: op, htype, hlen, cookie fields; message type option: */ udhcp_init_header(packet, type); @@ -617,7 +617,7 @@ static void init_packet(struct dhcp_packet *packet, char type) if (client_data.first_secs == 0) client_data.first_secs = client_data.last_secs; secs = client_data.last_secs - client_data.first_secs; - packet->secs = htons(secs); + packet->secs = (secs < 0xffff) ? htons(secs) : 0xffff; memcpy(packet->chaddr, client_data.client_mac, 6); if (client_data.clientid) diff --git a/networking/udhcp/dhcpc.h b/networking/udhcp/dhcpc.h index 42fe71a36..b407a6cdb 100644 --- a/networking/udhcp/dhcpc.h +++ b/networking/udhcp/dhcpc.h @@ -22,8 +22,8 @@ struct client_data_t { uint8_t *hostname; /* Optional hostname to use */ uint8_t *fqdn; /* Optional fully qualified domain name to use */ - uint16_t first_secs; - uint16_t last_secs; + unsigned first_secs; + unsigned last_secs; int sockfd; smallint listen_mode; -- cgit v1.2.3-55-g6feb From 65741d004ee91c5a710559ae4f1664f25009255e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 25 Sep 2019 13:48:01 +0200 Subject: telnet: fix uninitialized variable bug function old new delta telnet_main 1236 1238 +2 Signed-off-by: Denys Vlasenko --- networking/telnet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/telnet.c b/networking/telnet.c index fa1628723..5c8805265 100644 --- a/networking/telnet.c +++ b/networking/telnet.c @@ -248,7 +248,7 @@ static void handle_net_input(int len) { byte c; int i; - int cstart = cstart; /* for compiler */ + int cstart = 0; i = 0; //bb_error_msg("[%u,'%.*s']", G.telstate, len, G.buf); -- cgit v1.2.3-55-g6feb From d8e4ce05039a89c2e0b41f008d74a83db45f2287 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 4 Oct 2019 16:45:04 +0200 Subject: fdisk: avoid overflow in "mega/gigabytes" calculation, code shrink function old new delta list_disk_geometry 175 145 -30 Signed-off-by: Denys Vlasenko --- util-linux/fdisk.c | 31 +++++++++++++------------------ util-linux/fdisk_osf.c | 4 ++-- util-linux/fdisk_sgi.c | 12 ++++++------ util-linux/fdisk_sun.c | 16 ++++++++-------- 4 files changed, 29 insertions(+), 34 deletions(-) diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c index f28d4fdd2..076c5ca57 100644 --- a/util-linux/fdisk.c +++ b/util-linux/fdisk.c @@ -299,9 +299,6 @@ static int get_boot(enum action what); static int get_boot(void); #endif -#define PLURAL 0 -#define SINGULAR 1 - static sector_t get_start_sect(const struct partition *p); static sector_t get_nr_sects(const struct partition *p); @@ -597,12 +594,10 @@ get_part_table(int i) return ptes[i].part_table; } -static const char * -str_units(int n) -{ /* n==1: use singular */ - if (n == 1) - return display_in_cyl_units ? "cylinder" : "sector"; - return display_in_cyl_units ? "cylinders" : "sectors"; +static ALWAYS_INLINE const char * +str_units(void) +{ + return display_in_cyl_units ? "cylinder" : "sector"; } static int @@ -1778,8 +1773,8 @@ change_units(void) { display_in_cyl_units = !display_in_cyl_units; update_units(); - printf("Changing display/entry units to %s\n", - str_units(PLURAL)); + printf("Changing display/entry units to %ss\n", + str_units()); } static void @@ -2030,8 +2025,7 @@ check_consistency(const struct partition *p, int partition) static void list_disk_geometry(void) { - ullong bytes = ((ullong)total_number_of_sectors << 9); - ullong xbytes = bytes / (1024*1024); + ullong xbytes = total_number_of_sectors / (1024*1024 / 512); char x = 'M'; if (xbytes >= 10000) { @@ -2041,11 +2035,12 @@ list_disk_geometry(void) } printf("Disk %s: %llu %cB, %llu bytes, %"SECT_FMT"u sectors\n" "%u cylinders, %u heads, %u sectors/track\n" - "Units: %s of %u * %u = %u bytes\n\n", + "Units: %ss of %u * %u = %u bytes\n" + "\n", disk_device, xbytes, x, - bytes, total_number_of_sectors, + ((ullong)total_number_of_sectors * 512), total_number_of_sectors, g_cylinders, g_heads, g_sectors, - str_units(PLURAL), + str_units(), units_per_sector, sector_size, units_per_sector * sector_size ); } @@ -2486,7 +2481,7 @@ add_partition(int n, int sys) for (i = 0; i < g_partitions; i++) first[i] = (cround(first[i]) - 1) * units_per_sector; - snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR)); + snprintf(mesg, sizeof(mesg), "First %s", str_units()); do { temp = start; for (i = 0; i < g_partitions; i++) { @@ -2548,7 +2543,7 @@ add_partition(int n, int sys) } else { snprintf(mesg, sizeof(mesg), "Last %s or +size{,K,M,G,T}", - str_units(SINGULAR) + str_units() ); stop = read_int(cround(start), cround(limit), cround(limit), cround(start), mesg); if (display_in_cyl_units) { diff --git a/util-linux/fdisk_osf.c b/util-linux/fdisk_osf.c index 1328c1fcd..92180b2bc 100644 --- a/util-linux/fdisk_osf.c +++ b/util-linux/fdisk_osf.c @@ -470,7 +470,7 @@ xbsd_new_part(void) end = xbsd_dlabel.d_secperunit - 1; #endif - snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR)); + snprintf(mesg, sizeof(mesg), "First %s", str_units()); begin = read_int(bsd_cround(begin), bsd_cround(begin), bsd_cround(end), 0, mesg); @@ -478,7 +478,7 @@ xbsd_new_part(void) begin = (begin - 1) * xbsd_dlabel.d_secpercyl; snprintf(mesg, sizeof(mesg), "Last %s or +size or +sizeM or +sizeK", - str_units(SINGULAR)); + str_units()); end = read_int(bsd_cround(begin), bsd_cround(end), bsd_cround(end), bsd_cround(begin), mesg); diff --git a/util-linux/fdisk_sgi.c b/util-linux/fdisk_sgi.c index 0e5491a19..c90c801e2 100644 --- a/util-linux/fdisk_sgi.c +++ b/util-linux/fdisk_sgi.c @@ -295,19 +295,19 @@ sgi_list_table(int xtra) "%u cylinders, %u physical cylinders\n" "%u extra sects/cyl, interleave %u:1\n" "%s\n" - "Units = %s of %u * 512 bytes\n\n", + "Units = %ss of %u * 512 bytes\n\n", disk_device, g_heads, g_sectors, g_cylinders, SGI_SSWAP16(sgiparam.pcylcount), SGI_SSWAP16(sgiparam.sparecyl), SGI_SSWAP16(sgiparam.ilfact), (char *)sgilabel, - str_units(PLURAL), units_per_sector); + str_units(), units_per_sector); } else { printf("\nDisk %s (SGI disk label): " "%u heads, %u sectors, %u cylinders\n" - "Units = %s of %u * 512 bytes\n\n", + "Units = %ss of %u * 512 bytes\n\n", disk_device, g_heads, g_sectors, g_cylinders, - str_units(PLURAL), units_per_sector ); + str_units(), units_per_sector ); } w = strlen(disk_device); @@ -720,7 +720,7 @@ sgi_add_partition(int n, int sys) printf("You got a partition overlap on the disk. Fix it first!\n"); return; } - snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR)); + snprintf(mesg, sizeof(mesg), "First %s", str_units()); while (1) { if (sys == SGI_VOLUME) { last = sgi_get_lastblock(); @@ -746,7 +746,7 @@ sgi_add_partition(int n, int sys) printf("You will get a partition overlap on the disk. " "Fix it first!\n"); } - snprintf(mesg, sizeof(mesg), " Last %s", str_units(SINGULAR)); + snprintf(mesg, sizeof(mesg), " Last %s", str_units()); last = read_int(scround(first), scround(last)-1, scround(last)-1, scround(first), mesg)+1; if (display_in_cyl_units) diff --git a/util-linux/fdisk_sun.c b/util-linux/fdisk_sun.c index 3697a69b9..29d7c283a 100644 --- a/util-linux/fdisk_sun.c +++ b/util-linux/fdisk_sun.c @@ -491,7 +491,7 @@ add_sun_partition(int n, int sys) return; } } - snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR)); + snprintf(mesg, sizeof(mesg), "First %s", str_units()); while (1) { if (whole_disk) first = read_int(0, 0, 0, 0, mesg); @@ -546,7 +546,7 @@ and is of type 'Whole disk'\n"); } snprintf(mesg, sizeof(mesg), "Last %s or +size or +sizeM or +sizeK", - str_units(SINGULAR)); + str_units()); if (whole_disk) last = read_int(scround(stop2), scround(stop2), scround(stop2), 0, mesg); @@ -567,8 +567,8 @@ and is of type 'Whole disk'\n"); "You haven't covered the whole disk with the 3rd partition,\n" "but your value %u %s covers some other partition.\n" "Your entry has been changed to %u %s\n", - scround(last), str_units(SINGULAR), - scround(stop), str_units(SINGULAR)); + scround(last), str_units(), + scround(stop), str_units()); last = stop; } } else if (!whole_disk && last > stop) @@ -636,20 +636,20 @@ sun_list_table(int xtra) "%u cylinders, %u alternate cylinders, %u physical cylinders\n" "%u extra sects/cyl, interleave %u:1\n" "%s\n" - "Units = %s of %u * 512 bytes\n\n", + "Units = %ss of %u * 512 bytes\n\n", disk_device, g_heads, g_sectors, SUN_SSWAP16(sunlabel->rspeed), g_cylinders, SUN_SSWAP16(sunlabel->nacyl), SUN_SSWAP16(sunlabel->pcylcount), SUN_SSWAP16(sunlabel->sparecyl), SUN_SSWAP16(sunlabel->ilfact), (char *)sunlabel, - str_units(PLURAL), units_per_sector); + str_units(), units_per_sector); else printf( "\nDisk %s (Sun disk label): %u heads, %u sectors, %u cylinders\n" - "Units = %s of %u * 512 bytes\n\n", + "Units = %ss of %u * 512 bytes\n\n", disk_device, g_heads, g_sectors, g_cylinders, - str_units(PLURAL), units_per_sector); + str_units(), units_per_sector); printf("%*s Flag Start End Blocks Id System\n", w + 1, "Device"); -- cgit v1.2.3-55-g6feb From 27f0e8a27584df50736398c26491c450b12fd00d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 4 Oct 2019 17:16:15 +0200 Subject: fdisk_aix: fix aliasing warning, comment out unused global variables Signed-off-by: Denys Vlasenko --- util-linux/fdisk_aix.c | 40 ++++++++++++++++++++-------------------- util-linux/fdisk_gpt.c | 6 +++--- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/util-linux/fdisk_aix.c b/util-linux/fdisk_aix.c index ee5df50e5..0a5e818fe 100644 --- a/util-linux/fdisk_aix.c +++ b/util-linux/fdisk_aix.c @@ -6,10 +6,10 @@ */ typedef struct { - unsigned int magic; /* expect AIX_LABEL_MAGIC */ - unsigned int fillbytes1[124]; - unsigned int physical_volume_id; - unsigned int fillbytes2[124]; + uint32_t magic; /* expect AIX_LABEL_MAGIC */ + uint32_t fillbytes1[124]; + uint32_t physical_volume_id; + uint32_t fillbytes2[124]; } aix_partition; #define AIX_LABEL_MAGIC 0xc9c2d4c1 @@ -17,20 +17,18 @@ typedef struct { #define AIX_INFO_MAGIC 0x00072959 #define AIX_INFO_MAGIC_SWAPPED 0x59290700 -#define aixlabel ((aix_partition *)MBRbuffer) - - /* - Changes: - * 1999-03-20 Arnaldo Carvalho de Melo - * Internationalization - * - * 2003-03-20 Phillip Kesling - * Some fixes -*/ + * Changes: + * 1999-03-20 Arnaldo Carvalho de Melo + * Internationalization + * + * 2003-03-20 Phillip Kesling + * Some fixes + */ -static smallint aix_other_endian; /* bool */ -static smallint aix_volumes = 1; /* max 15 */ +// Write-only vars, unfinished code? +//static smallint aix_other_endian; /* bool */ +//static smallint aix_volumes = 1; /* max 15 */ /* * only dealing with free blocks here @@ -54,18 +52,20 @@ aix_info(void) static int check_aix_label(void) { + aix_partition *aixlabel = (void*)MBRbuffer; + if (aixlabel->magic != AIX_LABEL_MAGIC && aixlabel->magic != AIX_LABEL_MAGIC_SWAPPED ) { - current_label_type = 0; - aix_other_endian = 0; + current_label_type = LABEL_DOS; +// aix_other_endian = 0; return 0; } - aix_other_endian = (aixlabel->magic == AIX_LABEL_MAGIC_SWAPPED); +// aix_other_endian = (aixlabel->magic == AIX_LABEL_MAGIC_SWAPPED); update_units(); current_label_type = LABEL_AIX; g_partitions = 1016; - aix_volumes = 15; +// aix_volumes = 15; aix_info(); /*aix_nolabel();*/ /* %% */ /*aix_label = 1;*/ /* %% */ diff --git a/util-linux/fdisk_gpt.c b/util-linux/fdisk_gpt.c index dbe889f7c..e884e3dc1 100644 --- a/util-linux/fdisk_gpt.c +++ b/util-linux/fdisk_gpt.c @@ -161,7 +161,7 @@ check_gpt_label(void) if (!valid_part_table_flag(MBRbuffer) || first->sys_ind != LEGACY_GPT_TYPE ) { - current_label_type = 0; + current_label_type = LABEL_DOS; return 0; } @@ -171,7 +171,7 @@ check_gpt_label(void) gpt_hdr = (void *)pe.sectorbuffer; if (gpt_hdr->magic != SWAP_LE64(GPT_MAGIC)) { - current_label_type = 0; + current_label_type = LABEL_DOS; return 0; } @@ -194,7 +194,7 @@ check_gpt_label(void) || SWAP_LE32(gpt_hdr->hdr_size) > sector_size ) { puts("\nwarning: unable to parse GPT disklabel\n"); - current_label_type = 0; + current_label_type = LABEL_DOS; return 0; } -- cgit v1.2.3-55-g6feb From 427c12cc5199813328bf7fdf0bc4fc3a7672bf0f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Oct 2019 14:25:45 +0200 Subject: tee: do not intercept SIGPIPE GNU tee does this only with -p, which we don't have yet. function old new delta tee_main 306 295 -11 Signed-off-by: Denys Vlasenko --- coreutils/tee.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/coreutils/tee.c b/coreutils/tee.c index fe5694331..e67296d43 100644 --- a/coreutils/tee.c +++ b/coreutils/tee.c @@ -39,6 +39,19 @@ //usage: "$ cat /tmp/foo\n" //usage: "Hello\n" +// Bare "tee" with no below options does not install SIGPIPE handler - just dies on it. +// TODO: +// --output-error[=MODE] +// 'warn' diagnose errors writing to any output +// 'warn-nopipe' diagnose errors writing to any output not a pipe +// 'exit' exit on error writing to any output +// 'exit-nopipe' exit on error writing to any output not a pipe +// ^^^ all of these should set SIGPIPE to SIG_IGN. +// Because "exit" mode should print error message and exit1(1) - not die on SIGPIPE. +// "exit-nopipe" does not exit on EPIPE and does not set exitcode to 1 too. +// -p diagnose errors writing to non pipes +// ^^^^ this should set SIGPIPE to SIG_IGN. EPIPE is ignored (same as "warn-nopipe") + #include "libbb.h" #include "common_bufsiz.h" @@ -66,12 +79,12 @@ int tee_main(int argc, char **argv) mode += (retval & 2); /* Since 'a' is the 2nd option... */ if (retval & 1) { - signal(SIGINT, SIG_IGN); /* TODO - switch to sigaction. (why?) */ + signal(SIGINT, SIG_IGN); } retval = EXIT_SUCCESS; - /* gnu tee ignores SIGPIPE in case one of the output files is a pipe - * that doesn't consume all its input. Good idea... */ - signal(SIGPIPE, SIG_IGN); + /* if (opt_p || opt_output_error) + signal(SIGPIPE, SIG_IGN); + */ /* Allocate an array of FILE *'s, with one extra for a sentinel. */ fp = files = xzalloc(sizeof(FILE *) * (argc + 2)); @@ -79,6 +92,7 @@ int tee_main(int argc, char **argv) files[0] = stdout; goto GOT_NEW_FILE; + do { *fp = stdout; if (NOT_LONE_DASH(*argv)) { @@ -102,6 +116,7 @@ int tee_main(int argc, char **argv) fp = files; do fwrite(buf, 1, c, *fp); + /* if (opt_p && fwrite() != c && !EPIPE) bb_error_msg("..."); */ while (*++fp); } if (c < 0) { /* Make sure read errors are signaled. */ @@ -113,6 +128,7 @@ int tee_main(int argc, char **argv) fp = files; do putc(c, *fp); + /* if (opt_p && putc() == EOF && !EPIPE) bb_error_msg("..."); */ while (*++fp); } #endif -- cgit v1.2.3-55-g6feb From 4527273f1c5bca044577f2f8ed2d7e4f203bf485 Mon Sep 17 00:00:00 2001 From: Tomas Paukrt Date: Tue, 8 Oct 2019 11:51:48 +0200 Subject: route: fix output of "route -n -A inet6" The output of the command "route -n -A inet6" may be corrupted due to partially initialized structure snaddr6 in the function INET6_displayroutes. Signed-off-by: Tomas Paukrt Signed-off-by: Denys Vlasenko --- networking/route.c | 1 + 1 file changed, 1 insertion(+) diff --git a/networking/route.c b/networking/route.c index a5d8d7cb9..e785b1da6 100644 --- a/networking/route.c +++ b/networking/route.c @@ -628,6 +628,7 @@ static void INET6_displayroutes(void) r = 0; while (1) { + memset(&snaddr6, 0, sizeof(snaddr6)); inet_pton(AF_INET6, addr6x + r, (struct sockaddr *) &snaddr6.sin6_addr); snaddr6.sin6_family = AF_INET6; -- cgit v1.2.3-55-g6feb From 71b268c7d962a819f88050c2567dced975aa249e Mon Sep 17 00:00:00 2001 From: Kaarle Ritvanen Date: Tue, 8 Oct 2019 14:07:50 +0200 Subject: ln: --no-target-directory implies --no-dereference as in GNU coreutils Signed-off-by: Kaarle Ritvanen Signed-off-by: Denys Vlasenko --- coreutils/ln.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/coreutils/ln.c b/coreutils/ln.c index ea2d10eab..5591e8335 100644 --- a/coreutils/ln.c +++ b/coreutils/ln.c @@ -41,7 +41,6 @@ /* This is a NOEXEC applet. Be very careful! */ - #define LN_SYMLINK (1 << 0) #define LN_FORCE (1 << 1) #define LN_NODEREFERENCE (1 << 2) @@ -63,7 +62,22 @@ int ln_main(int argc, char **argv) int (*link_func)(const char *, const char *); opts = getopt32(argv, "^" "sfnbS:vT" "\0" "-1", &suffix); - +/* + -s, --symbolic make symbolic links instead of hard links + -f, --force remove existing destination files + -n, --no-dereference treat LINK_NAME as a normal file if it is a symbolic link to a directory + -b like --backup but does not accept an argument + --backup[=CONTROL] make a backup of each existing destination file + -S, --suffix=SUFFIX override the usual backup suffix + -v, --verbose + -T, --no-target-directory + -d, -F, --directory allow the superuser to attempt to hard link directories + -i, --interactive prompt whether to remove destinations + -L, --logical dereference TARGETs that are symbolic links + -P, --physical make hard links directly to symbolic links + -r, --relative create symbolic links relative to link location + -t, --target-directory=DIRECTORY specify the DIRECTORY in which to create the links + */ last = argv[argc - 1]; argv += optind; argc -= optind; @@ -86,8 +100,11 @@ int ln_main(int argc, char **argv) src = last; if (is_directory(src, - (opts & LN_NODEREFERENCE) ^ LN_NODEREFERENCE - ) + /*followlinks:*/ !(opts & (LN_NODEREFERENCE|LN_LINKFILE)) + /* Why LN_LINKFILE does not follow links: + * -T/--no-target-directory implies -n/--no-dereference + */ + ) ) { if (opts & LN_LINKFILE) { bb_error_msg_and_die("'%s' is a directory", src); -- cgit v1.2.3-55-g6feb From 6c1af283f73fb8640cd7273c2bf13eb102f80954 Mon Sep 17 00:00:00 2001 From: Martin Lewis Date: Sun, 15 Sep 2019 18:04:49 +0200 Subject: brctl: add support for showmacs command function old new delta brctl_main 680 974 +294 packed_usage 33167 33187 +20 compare_fdbs - 19 +19 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 2/0 up/down: 333/0) Total: 333 bytes Signed-off-by: Martin Lewis Signed-off-by: Denys Vlasenko --- networking/brctl.c | 111 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 92 insertions(+), 19 deletions(-) diff --git a/networking/brctl.c b/networking/brctl.c index 586ca9b0c..ba5b6226f 100644 --- a/networking/brctl.c +++ b/networking/brctl.c @@ -61,10 +61,10 @@ //usage: "\n setbridgeprio BRIDGE PRIO Set bridge priority" //usage: "\n setportprio BRIDGE IFACE PRIO Set port priority" //usage: "\n setpathcost BRIDGE IFACE COST Set path cost" +//usage: "\n showmacs BRIDGE List MAC addresses" //usage: ) // Not yet implemented: // hairpin BRIDGE IFACE on|off Hairpin on/off -// showmacs BRIDGE List mac addrs // showstp BRIDGE Show stp info #include "libbb.h" @@ -196,6 +196,89 @@ static void write_uint(const char *name, const char *leaf, unsigned val) bb_simple_perror_msg_and_die(name); close(fd); } + +struct fdb_entry { + uint8_t mac_addr[6]; + uint8_t port_no; + uint8_t is_local; + uint32_t ageing_timer_value; + uint8_t port_hi; + uint8_t pad0; + uint16_t unused; +}; + +static int compare_fdbs(const void *_f0, const void *_f1) +{ + const struct fdb_entry *f0 = _f0; + const struct fdb_entry *f1 = _f1; + + return memcmp(f0->mac_addr, f1->mac_addr, 6); +} + +static size_t read_bridge_forward_db(const char *name, struct fdb_entry **_fdb) +{ + struct fdb_entry *fdb; + size_t nentries; + char *path; + int fd; + ssize_t cc; + + path = concat_path_file(name, "brforward"); + fd = open(path, O_RDONLY); + free(path); + if (fd < 0) + bb_error_msg_and_die("bridge %s does not exist", name); + + fdb = NULL; + nentries = 0; + for (;;) { + fdb = xrealloc_vector(fdb, 4, nentries); + cc = full_read(fd, &fdb[nentries], sizeof(*fdb)); + if (cc == 0) { + break; + } + if (cc != sizeof(*fdb)) { + bb_perror_msg_and_die("can't read bridge %s forward db", name); + } + ++nentries; + } + + close(fd); + + qsort(fdb, nentries, sizeof(*fdb), compare_fdbs); + + *_fdb = fdb; + return nentries; +} + +static void show_bridge_macs(const char *name) +{ + struct fdb_entry *fdb; + size_t nentries; + size_t i; + + nentries = read_bridge_forward_db(name, &fdb); + + printf("port no\tmac addr\t\tis local?\tageing timer\n"); + for (i = 0; i < nentries; ++i) { + const struct fdb_entry *f = &fdb[i]; + unsigned long tvmsec = 10UL * f->ageing_timer_value; + unsigned tv_sec = tvmsec / 1000; + unsigned tv_msec = tvmsec % 1000; + printf("%3u\t" + "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\t" + "%s\t\t" + "%4u.%.2u\n", + f->port_no, + f->mac_addr[0], f->mac_addr[1], f->mac_addr[2], + f->mac_addr[3], f->mac_addr[4], f->mac_addr[5], + (f->is_local ? "yes" : "no"), + tv_sec, tv_msec / 10 + ); + } + + free(fdb); +} #endif int brctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -208,6 +291,7 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) "setageing\0" "setfd\0" "sethello\0" "setmaxage\0" "setpathcost\0" "setportprio\0" "setbridgeprio\0" + "showmacs\0" ) IF_FEATURE_BRCTL_SHOW("show\0"); enum { ARG_addbr = 0, ARG_delbr, ARG_addif, ARG_delif @@ -215,7 +299,8 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) ARG_stp, ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage, ARG_setpathcost, ARG_setportprio, - ARG_setbridgeprio + ARG_setbridgeprio, + ARG_showmacs ) IF_FEATURE_BRCTL_SHOW(, ARG_show) }; @@ -299,6 +384,11 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) return EXIT_SUCCESS; } + if (key == ARG_showmacs) { + show_bridge_macs(br); + return EXIT_SUCCESS; + } + if (!*argv) /* all but 'addbr/delbr' need at least two arguments */ bb_show_usage(); @@ -365,23 +455,6 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) //goto done_next_argv; return EXIT_SUCCESS; } - -/* TODO: "showmacs BR" - * port no\tmac addr\t\tis local?\tageing timer - * 1\txx:xx:xx:xx:xx:xx\tno\t\t1.31 - * port no mac addr is local? ageing timer - * 1 xx:xx:xx:xx:xx:xx no 1.31 - * Read fixed-sized records from /sys/class/net/BR/brforward: - * struct __fdb_entry { - * uint8_t mac_addr[ETH_ALEN]; - * uint8_t port_no; //lsb - * uint8_t is_local; - * uint32_t ageing_timer_value; - * uint8_t port_hi; - * uint8_t pad0; - * uint16_t unused; - * }; - */ #endif /* always true: if (key == ARG_addif || key == ARG_delif) */ { /* addif or delif */ -- cgit v1.2.3-55-g6feb From 1f1988d5256c9705a4f296ed48cdb7e463525ba4 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 25 Sep 2019 14:03:13 +0200 Subject: udhcpc: fix segmentation fault on empty bin opt The following caused udhcpc to segfault: busybox udhcpc -i lo -s /dev/null -x 0x3d: function old new delta udhcp_str2optset 629 641 +12 Signed-off-by: Michal Kazior Signed-off-by: Denys Vlasenko --- networking/udhcp/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c index 4a452cdb9..9ec752dfc 100644 --- a/networking/udhcp/common.c +++ b/networking/udhcp/common.c @@ -539,7 +539,7 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, if (optflag->flags == OPTION_BIN) { val = strtok(NULL, ""); /* do not split "'q w e'" */ - trim(val); + if (val) trim(val); } else val = strtok(NULL, ", \t"); if (!val) -- cgit v1.2.3-55-g6feb From b7b7452f292f03eefafa6fd1da9bcfc933dee15a Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 18 Sep 2019 09:28:49 -0700 Subject: date: Use 64 prefix syscall if we have to Some 32-bit architectures no longer have the 32-bit time_t syscalls. Instead they have suffixed syscalls that returns a 64-bit time_t. If the architecture doesn't have the non-suffixed syscall and is using a 64-bit time_t let's use the suffixed syscall instead. This fixes build issues when building for RISC-V 32-bit with 5.1+ kernel headers. If an architecture only supports the suffixed syscalls, but is still using a 32-bit time_t fall back to the libc call. Signed-off-by: Alistair Francis Signed-off-by: Denys Vlasenko --- coreutils/date.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/coreutils/date.c b/coreutils/date.c index feb400430..731241536 100644 --- a/coreutils/date.c +++ b/coreutils/date.c @@ -36,7 +36,7 @@ //config:# defaults to "no": stat's nanosecond field is a bit non-portable //config:config FEATURE_DATE_NANO //config: bool "Support %[num]N nanosecond format specifier" -//config: default n # syscall(__NR_clock_gettime) +//config: default n # syscall(__NR_clock_gettime) or syscall(__NR_clock_gettime64) //config: depends on DATE //config: select PLATFORM_LINUX //config: help @@ -271,10 +271,17 @@ int date_main(int argc UNUSED_PARAM, char **argv) */ #endif } else { -#if ENABLE_FEATURE_DATE_NANO +#if ENABLE_FEATURE_DATE_NANO && defined(__NR_clock_gettime) /* libc has incredibly messy way of doing this, * typically requiring -lrt. We just skip all this mess */ syscall(__NR_clock_gettime, CLOCK_REALTIME, &ts); +#elif ENABLE_FEATURE_DATE_NANO && __TIMESIZE == 64 + /* Let's only support the 64 suffix syscalls for 64-bit time_t. + * This simplifies the code for us as we don't need to convert + * between 64-bit and 32-bit. We also don't have a way to + * report overflow errors here. + */ + syscall(__NR_clock_gettime64, CLOCK_REALTIME, &ts); #else time(&ts.tv_sec); #endif -- cgit v1.2.3-55-g6feb From 902d3992922fc8db8495d5fb30a4581711b60c62 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 18 Sep 2019 09:28:50 -0700 Subject: time: Use 64 prefix syscall if we have to Some 32-bit architectures no longer have the 32-bit time_t syscalls. Instead they have suffixed syscalls that returns a 64-bit time_t. If the architecture doesn't have the non-suffixed syscall and is using a 64-bit time_t let's use the suffixed syscall instead. This fixes build issues when building for RISC-V 32-bit with 5.1+ kernel headers. If an architecture only supports the suffixed syscalls, but is still using a 32-bit time_t report a compilation error. This avoids us have to deal with converting between 64-bit and 32-bit values. There are currently no architectures where this is the case. Signed-off-by: Alistair Francis Signed-off-by: Denys Vlasenko --- libbb/time.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libbb/time.c b/libbb/time.c index cab0ad602..b6fcae28b 100644 --- a/libbb/time.c +++ b/libbb/time.c @@ -257,7 +257,14 @@ char* FAST_FUNC strftime_YYYYMMDDHHMMSS(char *buf, unsigned len, time_t *tp) * typically requiring -lrt. We just skip all this mess */ static void get_mono(struct timespec *ts) { +#if defined(__NR_clock_gettime) if (syscall(__NR_clock_gettime, CLOCK_MONOTONIC, ts)) +#elif __TIMESIZE == 64 + if (syscall(__NR_clock_gettime64, CLOCK_MONOTONIC, ts)) +#else +# error "We currently don't support architectures without " \ + "the __NR_clock_gettime syscall and 32-bit time_t" +#endif bb_simple_error_msg_and_die("clock_gettime(MONOTONIC) failed"); } unsigned long long FAST_FUNC monotonic_ns(void) -- cgit v1.2.3-55-g6feb From ad27d44ebe950335616f37e36863469dc181b455 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 18 Sep 2019 09:28:51 -0700 Subject: runsv: Use 64 prefix syscall if we have to Some 32-bit architectures no longer have the 32-bit time_t syscalls. Instead they have suffixed syscalls that returns a 64-bit time_t. If the architecture doesn't have the non-suffixed syscall and is using a 64-bit time_t let's use the suffixed syscall instead. This fixes build issues when building for RISC-V 32-bit with 5.1+ kernel headers. If an architecture only supports the suffixed syscalls, but is still using a 32-bit time_t report a compilation error. This avoids us have to deal with converting between 64-bit and 32-bit values. There are currently no architectures where this is the case. Signed-off-by: Alistair Francis Signed-off-by: Denys Vlasenko --- runit/runsv.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/runit/runsv.c b/runit/runsv.c index ccc762d78..737909b0e 100644 --- a/runit/runsv.c +++ b/runit/runsv.c @@ -55,7 +55,14 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * typically requiring -lrt. We just skip all this mess */ static void gettimeofday_ns(struct timespec *ts) { +#if defined(__NR_clock_gettime) syscall(__NR_clock_gettime, CLOCK_REALTIME, ts); +#elif __TIMESIZE == 64 + syscall(__NR_clock_gettime64, CLOCK_REALTIME, ts); +#else +# error "We currently don't support architectures without " \ + "the __NR_clock_gettime syscall and 32-bit time_t" +#endif } #else static void gettimeofday_ns(struct timespec *ts) -- cgit v1.2.3-55-g6feb From dd4686128290b34d61becaaba88c54d5213f7aa5 Mon Sep 17 00:00:00 2001 From: Martin Lewis Date: Sun, 15 Sep 2019 18:13:28 +0200 Subject: libbb: Converted safe_read to safe_write format Changed safe_read to be symmetrical to safe_write, it shall never return EINTR because it calls read multiple times, the error is considered transient. function old new delta safe_read 44 57 +13 Signed-off-by: Martin Lewis Signed-off-by: Denys Vlasenko --- libbb/read.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libbb/read.c b/libbb/read.c index 5906bc225..a342506a8 100644 --- a/libbb/read.c +++ b/libbb/read.c @@ -12,9 +12,17 @@ ssize_t FAST_FUNC safe_read(int fd, void *buf, size_t count) { ssize_t n; - do { + for (;;) { n = read(fd, buf, count); - } while (n < 0 && errno == EINTR); + if (n >= 0 || errno != EINTR) + break; + /* Some callers set errno=0, are upset when they see EINTR. + * Returning EINTR is wrong since we retry read(), + * the "error" was transient. + */ + errno = 0; + /* repeat the read() */ + } return n; } -- cgit v1.2.3-55-g6feb From 7011eca83afc313098f9869eea36742d4506bc02 Mon Sep 17 00:00:00 2001 From: Martin Lewis Date: Sun, 15 Sep 2019 18:51:30 +0200 Subject: replace: count_strstr - Handle an edge case where sub is empty If sub is empty, avoids an infinite loop. function old new delta count_strstr 45 63 +18 Signed-off-by: Martin Lewis Signed-off-by: Denys Vlasenko --- libbb/replace.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libbb/replace.c b/libbb/replace.c index a661d96e6..6183d3e6f 100644 --- a/libbb/replace.c +++ b/libbb/replace.c @@ -15,6 +15,10 @@ unsigned FAST_FUNC count_strstr(const char *str, const char *sub) size_t sub_len = strlen(sub); unsigned count = 0; + /* If sub is empty, avoid an infinite loop */ + if (sub_len == 0) + return strlen(str) + 1; + while ((str = strstr(str, sub)) != NULL) { count++; str += sub_len; -- cgit v1.2.3-55-g6feb From 42f454b13b8d972e85acd7f046065ec69af4d206 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 11 Oct 2019 14:11:44 +0200 Subject: dpkg-deb: work around bogus error message when working with XZ compressed packages function old new delta unpack_xz_stream 2309 2317 +8 bb_full_fd_action 464 472 +8 Signed-off-by: Denys Vlasenko --- archival/libarchive/decompress_unxz.c | 20 +++++++++++++++++++- archival/libarchive/unxz/xz_stream.h | 2 +- libbb/copyfd.c | 13 ++++++++----- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/archival/libarchive/decompress_unxz.c b/archival/libarchive/decompress_unxz.c index f03341384..3dd9bbf49 100644 --- a/archival/libarchive/decompress_unxz.c +++ b/archival/libarchive/decompress_unxz.c @@ -96,6 +96,24 @@ unpack_xz_stream(transformer_state_t *xstate) */ do { if (membuf[iobuf.in_pos] != 0) { + /* There is more data, but is it XZ data? + * Example: dpkg-deb -f busybox_1.30.1-4_amd64.deb + * reads control.tar.xz "control" file + * inside the ar archive, but tar.xz + * extraction code reaches end of xz data, + * reached this code and reads the beginning + * of data.tar.xz's ar header, which isn't xz data, + * and prints "corrupted data". + * The correct solution is to not read + * past nested archive (to simulate EOF). + * This is a workaround: + */ + if (membuf[iobuf.in_pos] != 0xfd) { + /* It's definitely not a xz signature + * (which is 0xfd,"7zXZ",0x00). + */ + goto end; + } xz_dec_reset(state); goto do_run; } @@ -128,7 +146,7 @@ unpack_xz_stream(transformer_state_t *xstate) break; } } - + end: xz_dec_end(state); free(membuf); diff --git a/archival/libarchive/unxz/xz_stream.h b/archival/libarchive/unxz/xz_stream.h index 66cb5a705..45056e42c 100644 --- a/archival/libarchive/unxz/xz_stream.h +++ b/archival/libarchive/unxz/xz_stream.h @@ -25,7 +25,7 @@ #define STREAM_HEADER_SIZE 12 -#define HEADER_MAGIC "\3757zXZ" +#define HEADER_MAGIC "\375""7zXZ" #define HEADER_MAGIC_SIZE 6 #define FOOTER_MAGIC "YZ" diff --git a/libbb/copyfd.c b/libbb/copyfd.c index ae5c26999..d41fd10f0 100644 --- a/libbb/copyfd.c +++ b/libbb/copyfd.c @@ -18,7 +18,7 @@ * was seen to cause largish delays when user tries to ^C a file copy. * Let's use a saner size. * Note: needs to be >= max(CONFIG_FEATURE_COPYBUF_KB), - * or else "copy to eof" code will use neddlesly short reads. + * or else "copy to eof" code will use needlesly short reads. */ #define SENDFILE_BIGBUF (16*1024*1024) @@ -60,10 +60,13 @@ static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size) ssize_t rd; if (sendfile_sz) { - rd = sendfile(dst_fd, src_fd, NULL, - size > sendfile_sz ? sendfile_sz : size); - if (rd >= 0) - goto read_ok; + /* dst_fd == -1 is a fake, else... */ + if (dst_fd >= 0) { + rd = sendfile(dst_fd, src_fd, NULL, + size > sendfile_sz ? sendfile_sz : size); + if (rd >= 0) + goto read_ok; + } sendfile_sz = 0; /* do not try sendfile anymore */ } #if CONFIG_FEATURE_COPYBUF_KB > 4 -- cgit v1.2.3-55-g6feb From 6dcf563633d3dae95c4ba4df3a5acc8fdd3f3107 Mon Sep 17 00:00:00 2001 From: Martin Lewis Date: Thu, 10 Oct 2019 16:00:19 -0500 Subject: brctl: add support for showstp command function old new delta brctl_main 974 2339 +1365 show_bridge_timer - 93 +93 static.state_names - 48 +48 printf_xstrtou - 26 +26 packed_usage 33243 33253 +10 show_bridge 333 323 -10 ------------------------------------------------------------------------------ (add/remove: 3/0 grow/shrink: 2/1 up/down: 1542/-10) Total: 1532 bytes text data bss dec hex filename 999868 551 5612 1006031 f59cf busybox_old 1002309 551 5612 1008472 f6358 busybox_unstripped Signed-off-by: Martin Lewis Signed-off-by: Denys Vlasenko --- networking/brctl.c | 218 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 215 insertions(+), 3 deletions(-) diff --git a/networking/brctl.c b/networking/brctl.c index ba5b6226f..e15710b5e 100644 --- a/networking/brctl.c +++ b/networking/brctl.c @@ -54,6 +54,7 @@ //usage: "\n delif BRIDGE IFACE Delete IFACE from BRIDGE" //usage: IF_FEATURE_BRCTL_FANCY( //usage: "\n stp BRIDGE 1/yes/on|0/no/off STP on/off" +//usage: "\n showstp BRIDGE Show stp info" //usage: "\n setageing BRIDGE SECONDS Set ageing time" //usage: "\n setfd BRIDGE SECONDS Set bridge forward delay" //usage: "\n sethello BRIDGE SECONDS Set hello time" @@ -65,7 +66,7 @@ //usage: ) // Not yet implemented: // hairpin BRIDGE IFACE on|off Hairpin on/off -// showstp BRIDGE Show stp info + #include "libbb.h" #include "common_bufsiz.h" @@ -146,8 +147,7 @@ static int show_bridge(const char *name, int need_hdr) if (need_hdr) puts("bridge name\tbridge id\t\tSTP enabled\tinterfaces"); - printf("%s\t\t", name); - printf("%s\t", filedata); + printf("%s\t\t%s\t", name, filedata); strcpy(sfx, "stp_state"); read_file(pathbuf); @@ -279,6 +279,212 @@ static void show_bridge_macs(const char *name) free(fdb); } + +static void show_bridge_timer(const char *msg) +{ + unsigned long long tvmsec = 10 * xstrtoull(filedata, 0); + unsigned tv_sec = tvmsec / 1000; + unsigned tv_msec = tvmsec % 1000; + printf("%s%4u.%.2u", msg, tv_sec, tv_msec / 10); +} + +static const char *show_bridge_state(unsigned state) +{ + /* See linux/if_bridge.h, BR_STATE_ constants */ + static const char state_names[] = + "disabled\0" //BR_STATE_DISABLED 0 + "listening\0" //BR_STATE_LISTENING 1 + "learning\0" //BR_STATE_LEARNING 2 + "forwarding\0" //BR_STATE_FORWARDING 3 + "blocking" //BR_STATE_BLOCKING 4 + ; + if (state < 5) + return nth_string(state_names, state); + return utoa(state); +} + +static void printf_xstrtou(const char *fmt) +{ + printf(fmt, xstrtou(filedata, 0)); +} + +static void show_bridge_port(const char *name) +{ + char pathbuf[IFNAMSIZ + sizeof("/brport/forward_delay_timer") + 32]; + char *sfx; + +#if IFNAMSIZ == 16 + sfx = pathbuf + sprintf(pathbuf, "%.16s/brport/", name); +#else + sfx = pathbuf + sprintf(pathbuf, "%.*s/brport/", (int)IFNAMSIZ, name); +#endif + + strcpy(sfx, "port_no"); + read_file(pathbuf); + printf("%s (%u)\n", name, xstrtou(filedata, 0)); + + strcpy(sfx + 5, "id"); // "port_id" + read_file(pathbuf); + printf_xstrtou(" port id\t\t%.4x"); + + strcpy(sfx, "state"); + read_file(pathbuf); + printf("\t\t\tstate\t\t%15s\n", show_bridge_state(xstrtou(filedata, 0))); + + strcpy(sfx, "designated_root"); + read_file(pathbuf); + printf(" designated root\t%s", filedata); + + strcpy(sfx, "path_cost"); + read_file(pathbuf); + printf_xstrtou("\tpath cost\t\t%4u\n"); + + strcpy(sfx, "designated_bridge"); + read_file(pathbuf); + printf(" designated bridge\t%s", filedata); + + strcpy(sfx, "message_age_timer"); + read_file(pathbuf); + show_bridge_timer("\tmessage age timer\t"); + + strcpy(sfx, "designated_port"); + read_file(pathbuf); + printf_xstrtou("\n designated port\t%.4x"); + + strcpy(sfx, "forward_delay_timer"); + read_file(pathbuf); + show_bridge_timer("\t\t\tforward delay timer\t"); + + strcpy(sfx, "designated_cost"); + read_file(pathbuf); + printf_xstrtou("\n designated cost\t%4u"); + + strcpy(sfx, "hold_timer"); + read_file(pathbuf); + show_bridge_timer("\t\t\thold timer\t\t"); + + printf("\n flags\t\t\t"); + + strcpy(sfx, "config_pending"); + read_file(pathbuf); + if (!LONE_CHAR(filedata, '0')) + printf("CONFIG_PENDING "); + + strcpy(sfx, "change_ack"); + read_file(pathbuf); + if (!LONE_CHAR(filedata, '0')) + printf("TOPOLOGY_CHANGE_ACK "); + + strcpy(sfx, "hairpin_mode"); + read_file(pathbuf); + if (!LONE_CHAR(filedata, '0')) + printf_xstrtou("\n hairpin mode\t\t%4u"); + + printf("\n\n"); +} + +static void show_bridge_ports(const char *name) +{ + DIR *ifaces; + struct dirent *ent; + char pathbuf[IFNAMSIZ + sizeof("/brif") + 8]; + +#if IFNAMSIZ == 16 + sprintf(pathbuf, "%.16s/brif", name); +#else + sprintf(pathbuf, "%.*s/brif", (int)IFNAMSIZ, name); +#endif + ifaces = opendir(pathbuf); + if (ifaces) { + while ((ent = readdir(ifaces)) != NULL) { + if (DOT_OR_DOTDOT(ent->d_name)) + continue; /* . or .. */ + show_bridge_port(ent->d_name); + } + closedir(ifaces); + } +} + +static void show_bridge_stp(const char *name) +{ + char pathbuf[IFNAMSIZ + sizeof("/bridge/topology_change_timer") + 32]; + char *sfx; + +#if IFNAMSIZ == 16 + sfx = pathbuf + sprintf(pathbuf, "%.16s/bridge/", name); +#else + sfx = pathbuf + sprintf(pathbuf, "%.*s/bridge/", (int)IFNAMSIZ, name); +#endif + + strcpy(sfx, "bridge_id"); + if (read_file(pathbuf) < 0) + bb_error_msg_and_die("bridge %s does not exist", name); + + printf("%s\n" + " bridge id\t\t%s", name, filedata); + + strcpy(sfx, "root_id"); + read_file(pathbuf); + printf("\n designated root\t%s", filedata); + + strcpy(sfx + 5, "port"); // "root_port" + read_file(pathbuf); + printf_xstrtou("\n root port\t\t%4u\t\t\t"); + + strcpy(sfx + 6, "ath_cost"); // "root_path_cost" + read_file(pathbuf); + printf_xstrtou("path cost\t\t%4u\n"); + + strcpy(sfx, "max_age"); + read_file(pathbuf); + show_bridge_timer(" max age\t\t"); + show_bridge_timer("\t\t\tbridge max age\t\t"); + + strcpy(sfx, "hello_time"); + read_file(pathbuf); + show_bridge_timer("\n hello time\t\t"); + show_bridge_timer("\t\t\tbridge hello time\t"); + + strcpy(sfx, "forward_delay"); + read_file(pathbuf); + show_bridge_timer("\n forward delay\t\t"); + show_bridge_timer("\t\t\tbridge forward delay\t"); + + strcpy(sfx, "ageing_time"); + read_file(pathbuf); + show_bridge_timer("\n ageing time\t\t"); + + strcpy(sfx, "hello_timer"); + read_file(pathbuf); + show_bridge_timer("\n hello timer\t\t"); + + strcpy(sfx, "tcn_timer"); + read_file(pathbuf); + show_bridge_timer("\t\t\ttcn timer\t\t"); + + strcpy(sfx, "topology_change_timer"); + read_file(pathbuf); + show_bridge_timer("\n topology change timer\t"); + + strcpy(sfx, "gc_timer"); + read_file(pathbuf); + show_bridge_timer("\t\t\tgc timer\t\t"); + + printf("\n flags\t\t\t"); + + strcpy(sfx, "topology_change"); + read_file(pathbuf); + if (!LONE_CHAR(filedata, '0')) + printf("TOPOLOGY_CHANGE "); + + strcpy(sfx, "topology_change_detected"); + read_file(pathbuf); + if (!LONE_CHAR(filedata, '0')) + printf("TOPOLOGY_CHANGE_DETECTED "); + printf("\n\n\n"); + + show_bridge_ports(name); +} #endif int brctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -288,6 +494,7 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) "addbr\0" "delbr\0" "addif\0" "delif\0" IF_FEATURE_BRCTL_FANCY( "stp\0" + "showstp\0" "setageing\0" "setfd\0" "sethello\0" "setmaxage\0" "setpathcost\0" "setportprio\0" "setbridgeprio\0" @@ -297,6 +504,7 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) enum { ARG_addbr = 0, ARG_delbr, ARG_addif, ARG_delif IF_FEATURE_BRCTL_FANCY(, ARG_stp, + ARG_showstp, ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage, ARG_setpathcost, ARG_setportprio, ARG_setbridgeprio, @@ -388,6 +596,10 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) show_bridge_macs(br); return EXIT_SUCCESS; } + if (key == ARG_showstp) { + show_bridge_stp(br); + return EXIT_SUCCESS; + } if (!*argv) /* all but 'addbr/delbr' need at least two arguments */ bb_show_usage(); -- cgit v1.2.3-55-g6feb From 339875381800668df26922dd0fb8789e9862698d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 12 Oct 2019 19:24:38 +0200 Subject: brctl: code shrink packed_usage 33253 33255 +2 write_uint 96 90 -6 show_bridge_timer 93 69 -24 brctl_main 2338 2235 -103 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/3 up/down: 2/-133) Total: -131 bytes Signed-off-by: Denys Vlasenko --- networking/brctl.c | 60 +++++++++++++++++++++++++----------------------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/networking/brctl.c b/networking/brctl.c index e15710b5e..04ea08253 100644 --- a/networking/brctl.c +++ b/networking/brctl.c @@ -54,7 +54,7 @@ //usage: "\n delif BRIDGE IFACE Delete IFACE from BRIDGE" //usage: IF_FEATURE_BRCTL_FANCY( //usage: "\n stp BRIDGE 1/yes/on|0/no/off STP on/off" -//usage: "\n showstp BRIDGE Show stp info" +//usage: "\n showstp BRIDGE Show STP info" //usage: "\n setageing BRIDGE SECONDS Set ageing time" //usage: "\n setfd BRIDGE SECONDS Set bridge forward delay" //usage: "\n sethello BRIDGE SECONDS Set hello time" @@ -67,7 +67,6 @@ // Not yet implemented: // hairpin BRIDGE IFACE on|off Hairpin on/off - #include "libbb.h" #include "common_bufsiz.h" #include @@ -130,7 +129,7 @@ static int show_bridge(const char *name, int need_hdr) *bridge name bridge id STP enabled interfaces *br0 8000.000000000000 no eth0 */ - char pathbuf[IFNAMSIZ + sizeof("/bridge/bridge_id") + 32]; + char pathbuf[IFNAMSIZ + sizeof("/bridge/bridge_id") + 8]; int tabs; DIR *ifaces; struct dirent *ent; @@ -194,7 +193,11 @@ static void write_uint(const char *name, const char *leaf, unsigned val) n = sprintf(filedata, "%u\n", val); if (write(fd, filedata, n) < 0) bb_simple_perror_msg_and_die(name); - close(fd); + /* So far all callers exit very soon after calling us. + * Do not bother closing fd (unless debugging): + */ + if (ENABLE_FEATURE_CLEAN_UP) + close(fd); } struct fdb_entry { @@ -217,15 +220,18 @@ static int compare_fdbs(const void *_f0, const void *_f1) static size_t read_bridge_forward_db(const char *name, struct fdb_entry **_fdb) { + char pathbuf[IFNAMSIZ + sizeof("/brforward") + 8]; struct fdb_entry *fdb; size_t nentries; - char *path; int fd; ssize_t cc; - path = concat_path_file(name, "brforward"); - fd = open(path, O_RDONLY); - free(path); +#if IFNAMSIZ == 16 + sprintf(pathbuf, "%.16s/brforward", name); +#else + sprintf(pathbuf, "%.*s/brforward", (int)IFNAMSIZ, name); +#endif + fd = open(pathbuf, O_RDONLY); if (fd < 0) bb_error_msg_and_die("bridge %s does not exist", name); @@ -243,7 +249,8 @@ static size_t read_bridge_forward_db(const char *name, struct fdb_entry **_fdb) ++nentries; } - close(fd); + if (ENABLE_FEATURE_CLEAN_UP) + close(fd); qsort(fdb, nentries, sizeof(*fdb), compare_fdbs); @@ -262,9 +269,8 @@ static void show_bridge_macs(const char *name) printf("port no\tmac addr\t\tis local?\tageing timer\n"); for (i = 0; i < nentries; ++i) { const struct fdb_entry *f = &fdb[i]; - unsigned long tvmsec = 10UL * f->ageing_timer_value; - unsigned tv_sec = tvmsec / 1000; - unsigned tv_msec = tvmsec % 1000; + unsigned tv_sec = f->ageing_timer_value / 100; + unsigned tv_csec = f->ageing_timer_value % 100; printf("%3u\t" "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\t" "%s\t\t" @@ -273,25 +279,26 @@ static void show_bridge_macs(const char *name) f->mac_addr[0], f->mac_addr[1], f->mac_addr[2], f->mac_addr[3], f->mac_addr[4], f->mac_addr[5], (f->is_local ? "yes" : "no"), - tv_sec, tv_msec / 10 + tv_sec, tv_csec ); } - free(fdb); + if (ENABLE_FEATURE_CLEAN_UP) + free(fdb); } static void show_bridge_timer(const char *msg) { - unsigned long long tvmsec = 10 * xstrtoull(filedata, 0); - unsigned tv_sec = tvmsec / 1000; - unsigned tv_msec = tvmsec % 1000; - printf("%s%4u.%.2u", msg, tv_sec, tv_msec / 10); + unsigned long long centisec = xstrtoull(filedata, 0); + unsigned tv_sec = centisec / 100; + unsigned tv_csec = centisec % 100; + printf("%s%4u.%.2u", msg, tv_sec, tv_csec); } static const char *show_bridge_state(unsigned state) { /* See linux/if_bridge.h, BR_STATE_ constants */ - static const char state_names[] = + static const char state_names[] ALIGN1 = "disabled\0" //BR_STATE_DISABLED 0 "listening\0" //BR_STATE_LISTENING 1 "learning\0" //BR_STATE_LEARNING 2 @@ -310,7 +317,7 @@ static void printf_xstrtou(const char *fmt) static void show_bridge_port(const char *name) { - char pathbuf[IFNAMSIZ + sizeof("/brport/forward_delay_timer") + 32]; + char pathbuf[IFNAMSIZ + sizeof("/brport/forward_delay_timer") + 8]; char *sfx; #if IFNAMSIZ == 16 @@ -407,7 +414,7 @@ static void show_bridge_ports(const char *name) static void show_bridge_stp(const char *name) { - char pathbuf[IFNAMSIZ + sizeof("/bridge/topology_change_timer") + 32]; + char pathbuf[IFNAMSIZ + sizeof("/bridge/topology_change_timer") + 8]; char *sfx; #if IFNAMSIZ == 16 @@ -614,7 +621,6 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name); onoff = (unsigned)onoff / 4; write_uint(br, "bridge/stp_state", onoff); - //goto done_next_argv; return EXIT_SUCCESS; } @@ -634,13 +640,11 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) ), str_to_jiffies(*argv) ); - //goto done_next_argv; return EXIT_SUCCESS; } if (key == ARG_setbridgeprio) { write_uint(br, "bridge/priority", xatoi_positive(*argv)); - //goto done_next_argv; return EXIT_SUCCESS; } @@ -663,8 +667,6 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) ), xatoi_positive(argv[1]) ); - //argv++; - //goto done_next_argv; return EXIT_SUCCESS; } #endif @@ -682,16 +684,10 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) key == ARG_addif ? SIOCBRADDIF : SIOCBRDELIF, &ifr, "bridge %s", br ); - //close(fd); - //goto done_next_argv; if (ENABLE_FEATURE_CLEAN_UP) close(fd); return EXIT_SUCCESS; } - -// done_next_argv: -// argv++; -// done: } return EXIT_SUCCESS; -- cgit v1.2.3-55-g6feb From b4fa16d5ed51d13c7c8e9037e4613cc147ce27da Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 12 Oct 2019 19:42:37 +0200 Subject: brctl: fold show_bridge_ports_ into its caller function old new delta brctl_main 2235 2171 -64 Signed-off-by: Denys Vlasenko --- networking/brctl.c | 318 ++++++++++++++++++++++++++--------------------------- 1 file changed, 153 insertions(+), 165 deletions(-) diff --git a/networking/brctl.c b/networking/brctl.c index 04ea08253..09c55cd0e 100644 --- a/networking/brctl.c +++ b/networking/brctl.c @@ -390,28 +390,6 @@ static void show_bridge_port(const char *name) printf("\n\n"); } -static void show_bridge_ports(const char *name) -{ - DIR *ifaces; - struct dirent *ent; - char pathbuf[IFNAMSIZ + sizeof("/brif") + 8]; - -#if IFNAMSIZ == 16 - sprintf(pathbuf, "%.16s/brif", name); -#else - sprintf(pathbuf, "%.*s/brif", (int)IFNAMSIZ, name); -#endif - ifaces = opendir(pathbuf); - if (ifaces) { - while ((ent = readdir(ifaces)) != NULL) { - if (DOT_OR_DOTDOT(ent->d_name)) - continue; /* . or .. */ - show_bridge_port(ent->d_name); - } - closedir(ifaces); - } -} - static void show_bridge_stp(const char *name) { char pathbuf[IFNAMSIZ + sizeof("/bridge/topology_change_timer") + 8]; @@ -490,7 +468,24 @@ static void show_bridge_stp(const char *name) printf("TOPOLOGY_CHANGE_DETECTED "); printf("\n\n\n"); - show_bridge_ports(name); + /* Show bridge ports */ + { + DIR *ifaces; + + /* sfx points past "BR/bridge/", turn it to "BR/brif": */ + strcpy(sfx - 4, "f"); + ifaces = opendir(pathbuf); + if (ifaces) { + struct dirent *ent; + while ((ent = readdir(ifaces)) != NULL) { + if (DOT_OR_DOTDOT(ent->d_name)) + continue; /* . or .. */ + show_bridge_port(ent->d_name); + } + if (ENABLE_FEATURE_CLEAN_UP) + closedir(ifaces); + } + } } #endif @@ -519,6 +514,8 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) ) IF_FEATURE_BRCTL_SHOW(, ARG_show) }; + int key; + char *br; argv++; if (!*argv) { @@ -528,166 +525,157 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) xchdir("/sys/class/net"); -// while (*argv) - { - smallint key; - char *br; - - key = index_in_strings(keywords, *argv); - if (key == -1) /* no match found in keywords array, bail out. */ - bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name); - argv++; + key = index_in_strings(keywords, *argv); + if (key == -1) /* no match found in keywords array, bail out. */ + bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name); + argv++; #if ENABLE_FEATURE_BRCTL_SHOW - if (key == ARG_show) { /* show [BR]... */ - DIR *net; - struct dirent *ent; - int need_hdr = 1; - int exitcode = EXIT_SUCCESS; - - if (*argv) { - /* "show BR1 BR2 BR3" */ - do { - if (show_bridge(*argv, need_hdr) >= 0) { - need_hdr = 0; - } else { - bb_error_msg("bridge %s does not exist", *argv); + if (key == ARG_show) { /* show [BR]... */ + DIR *net; + struct dirent *ent; + int need_hdr = 1; + int exitcode = EXIT_SUCCESS; + + if (*argv) { + /* "show BR1 BR2 BR3" */ + do { + if (show_bridge(*argv, need_hdr) >= 0) { + need_hdr = 0; + } else { + bb_error_msg("bridge %s does not exist", *argv); //TODO: if device exists, but is not a BR, brctl from bridge-utils 1.6 //says this instead: "device eth0 is not a bridge" - exitcode = EXIT_FAILURE; - } - } while (*++argv != NULL); - return exitcode; - } - - /* "show" (if no ifaces, shows nothing, not even header) */ - net = xopendir("."); - while ((ent = readdir(net)) != NULL) { - if (DOT_OR_DOTDOT(ent->d_name)) - continue; /* . or .. */ - if (show_bridge(ent->d_name, need_hdr) >= 0) - need_hdr = 0; - } - if (ENABLE_FEATURE_CLEAN_UP) - closedir(net); + exitcode = EXIT_FAILURE; + } + } while (*++argv != NULL); return exitcode; } + + /* "show" (if no ifaces, shows nothing, not even header) */ + net = xopendir("."); + while ((ent = readdir(net)) != NULL) { + if (DOT_OR_DOTDOT(ent->d_name)) + continue; /* . or .. */ + if (show_bridge(ent->d_name, need_hdr) >= 0) + need_hdr = 0; + } + if (ENABLE_FEATURE_CLEAN_UP) + closedir(net); + return exitcode; + } #endif - if (!*argv) /* all but 'show' need at least one argument */ - bb_show_usage(); + if (!*argv) /* all but 'show' need at least one argument */ + bb_show_usage(); - br = *argv++; - - if (key == ARG_addbr || key == ARG_delbr) { - /* addbr or delbr */ - /* brctl from bridge-utils 1.6 still uses ioctl - * for SIOCBRADDBR / SIOCBRDELBR, not /sys accesses - */ - int fd = xsocket(AF_INET, SOCK_STREAM, 0); - ioctl_or_perror_and_die(fd, - key == ARG_addbr ? SIOCBRADDBR : SIOCBRDELBR, - br, "bridge %s", br - ); - //close(fd); - //goto done; - /* bridge-utils 1.6 simply ignores trailing args: - * "brctl addbr BR1 ARGS" ignores ARGS - */ - if (ENABLE_FEATURE_CLEAN_UP) - close(fd); - return EXIT_SUCCESS; - } + br = *argv++; - if (key == ARG_showmacs) { - show_bridge_macs(br); - return EXIT_SUCCESS; - } - if (key == ARG_showstp) { - show_bridge_stp(br); - return EXIT_SUCCESS; - } + if (key == ARG_addbr || key == ARG_delbr) { + /* brctl from bridge-utils 1.6 still uses ioctl + * for SIOCBRADDBR / SIOCBRDELBR, not /sys accesses + */ + int fd = xsocket(AF_INET, SOCK_STREAM, 0); + ioctl_or_perror_and_die(fd, + key == ARG_addbr ? SIOCBRADDBR : SIOCBRDELBR, + br, "bridge %s", br + ); + //close(fd); + //goto done; + /* bridge-utils 1.6 simply ignores trailing args: + * "brctl addbr BR1 ARGS" ignores ARGS + */ + if (ENABLE_FEATURE_CLEAN_UP) + close(fd); + return EXIT_SUCCESS; + } - if (!*argv) /* all but 'addbr/delbr' need at least two arguments */ - bb_show_usage(); + if (key == ARG_showmacs) { + show_bridge_macs(br); + return EXIT_SUCCESS; + } + if (key == ARG_showstp) { + show_bridge_stp(br); + return EXIT_SUCCESS; + } + + if (!*argv) /* all but 'addbr/delbr' need at least two arguments */ + bb_show_usage(); #if ENABLE_FEATURE_BRCTL_FANCY - if (key == ARG_stp) { /* stp */ - static const char no_yes[] ALIGN1 = - "0\0" "off\0" "n\0" "no\0" /* 0 .. 3 */ - "1\0" "on\0" "y\0" "yes\0"; /* 4 .. 7 */ - int onoff = index_in_strings(no_yes, *argv); - if (onoff < 0) - bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name); - onoff = (unsigned)onoff / 4; - write_uint(br, "bridge/stp_state", onoff); - return EXIT_SUCCESS; - } + if (key == ARG_stp) { + static const char no_yes[] ALIGN1 = + "0\0" "off\0" "n\0" "no\0" /* 0 .. 3 */ + "1\0" "on\0" "y\0" "yes\0"; /* 4 .. 7 */ + int onoff = index_in_strings(no_yes, *argv); + if (onoff < 0) + bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name); + onoff = (unsigned)onoff / 4; + write_uint(br, "bridge/stp_state", onoff); + return EXIT_SUCCESS; + } - if ((unsigned)(key - ARG_setageing) < 4) { /* time related ops */ - /* setageing BR N: "N*100\n" to /sys/class/net/BR/bridge/ageing_time - * setfd BR N: "N*100\n" to /sys/class/net/BR/bridge/forward_delay - * sethello BR N: "N*100\n" to /sys/class/net/BR/bridge/hello_time - * setmaxage BR N: "N*100\n" to /sys/class/net/BR/bridge/max_age - */ - write_uint(br, - nth_string( - "bridge/ageing_time" "\0" /* ARG_setageing */ - "bridge/forward_delay""\0" /* ARG_setfd */ - "bridge/hello_time" "\0" /* ARG_sethello */ - "bridge/max_age", /* ARG_setmaxage */ - key - ARG_setageing - ), - str_to_jiffies(*argv) - ); - return EXIT_SUCCESS; - } + if ((unsigned)(key - ARG_setageing) < 4) { /* time related ops */ + /* setageing BR N: "N*100\n" to /sys/class/net/BR/bridge/ageing_time + * setfd BR N: "N*100\n" to /sys/class/net/BR/bridge/forward_delay + * sethello BR N: "N*100\n" to /sys/class/net/BR/bridge/hello_time + * setmaxage BR N: "N*100\n" to /sys/class/net/BR/bridge/max_age + */ + write_uint(br, + nth_string( + "bridge/ageing_time" "\0" /* ARG_setageing */ + "bridge/forward_delay""\0" /* ARG_setfd */ + "bridge/hello_time" "\0" /* ARG_sethello */ + "bridge/max_age", /* ARG_setmaxage */ + key - ARG_setageing + ), + str_to_jiffies(*argv) + ); + return EXIT_SUCCESS; + } - if (key == ARG_setbridgeprio) { - write_uint(br, "bridge/priority", xatoi_positive(*argv)); - return EXIT_SUCCESS; - } + if (key == ARG_setbridgeprio) { + write_uint(br, "bridge/priority", xatoi_positive(*argv)); + return EXIT_SUCCESS; + } - if (key == ARG_setpathcost - || key == ARG_setportprio - ) { - if (!argv[1]) - bb_show_usage(); - /* BR is not used (and ignored!) for these commands: - * "setpathcost BR PORT N" writes "N\n" to - * /sys/class/net/PORT/brport/path_cost - * "setportprio BR PORT N" writes "N\n" to - * /sys/class/net/PORT/brport/priority - */ - write_uint(argv[0], - nth_string( - "brport/path_cost" "\0" /* ARG_setpathcost */ - "brport/priority", /* ARG_setportprio */ - key - ARG_setpathcost - ), - xatoi_positive(argv[1]) - ); - return EXIT_SUCCESS; - } + if (key == ARG_setpathcost + || key == ARG_setportprio + ) { + if (!argv[1]) + bb_show_usage(); + /* BR is not used (and ignored!) for these commands: + * "setpathcost BR PORT N" writes "N\n" to + * /sys/class/net/PORT/brport/path_cost + * "setportprio BR PORT N" writes "N\n" to + * /sys/class/net/PORT/brport/priority + */ + write_uint(argv[0], + nth_string( + "brport/path_cost" "\0" /* ARG_setpathcost */ + "brport/priority", /* ARG_setportprio */ + key - ARG_setpathcost + ), + xatoi_positive(argv[1]) + ); + return EXIT_SUCCESS; + } #endif - /* always true: if (key == ARG_addif || key == ARG_delif) */ { - /* addif or delif */ - struct ifreq ifr; - int fd = xsocket(AF_INET, SOCK_STREAM, 0); - - strncpy_IFNAMSIZ(ifr.ifr_name, br); - ifr.ifr_ifindex = if_nametoindex(*argv); - if (ifr.ifr_ifindex == 0) { - bb_perror_msg_and_die("iface %s", *argv); - } - ioctl_or_perror_and_die(fd, - key == ARG_addif ? SIOCBRADDIF : SIOCBRDELIF, - &ifr, "bridge %s", br - ); - if (ENABLE_FEATURE_CLEAN_UP) - close(fd); - return EXIT_SUCCESS; + /* always true: if (key == ARG_addif || key == ARG_delif) */ { + struct ifreq ifr; + int fd = xsocket(AF_INET, SOCK_STREAM, 0); + + strncpy_IFNAMSIZ(ifr.ifr_name, br); + ifr.ifr_ifindex = if_nametoindex(*argv); + if (ifr.ifr_ifindex == 0) { + bb_perror_msg_and_die("iface %s", *argv); } + ioctl_or_perror_and_die(fd, + key == ARG_addif ? SIOCBRADDIF : SIOCBRDELIF, + &ifr, "bridge %s", br + ); + if (ENABLE_FEATURE_CLEAN_UP) + close(fd); } return EXIT_SUCCESS; -- cgit v1.2.3-55-g6feb From eb1395147ae98e56b455d0f3f9406725fe189822 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 12 Oct 2019 19:51:46 +0200 Subject: brctl: tweak help text, fix comments function old new delta packed_usage 33255 33236 -19 Signed-off-by: Denys Vlasenko --- networking/brctl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/networking/brctl.c b/networking/brctl.c index 09c55cd0e..8ed9d2096 100644 --- a/networking/brctl.c +++ b/networking/brctl.c @@ -53,8 +53,9 @@ //usage: "\n addif BRIDGE IFACE Add IFACE to BRIDGE" //usage: "\n delif BRIDGE IFACE Delete IFACE from BRIDGE" //usage: IF_FEATURE_BRCTL_FANCY( -//usage: "\n stp BRIDGE 1/yes/on|0/no/off STP on/off" +//usage: "\n showmacs BRIDGE List MAC addresses" //usage: "\n showstp BRIDGE Show STP info" +//usage: "\n stp BRIDGE 1/yes/on|0/no/off Set STP on/off" //usage: "\n setageing BRIDGE SECONDS Set ageing time" //usage: "\n setfd BRIDGE SECONDS Set bridge forward delay" //usage: "\n sethello BRIDGE SECONDS Set hello time" @@ -62,10 +63,9 @@ //usage: "\n setbridgeprio BRIDGE PRIO Set bridge priority" //usage: "\n setportprio BRIDGE IFACE PRIO Set port priority" //usage: "\n setpathcost BRIDGE IFACE COST Set path cost" -//usage: "\n showmacs BRIDGE List MAC addresses" //usage: ) // Not yet implemented: -// hairpin BRIDGE IFACE on|off Hairpin on/off +// hairpin BRIDGE IFACE on|off Set hairpin on/off #include "libbb.h" #include "common_bufsiz.h" @@ -566,7 +566,7 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) } #endif - if (!*argv) /* all but 'show' need at least one argument */ + if (!*argv) /* All of the below need at least one argument */ bb_show_usage(); br = *argv++; @@ -599,7 +599,7 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) return EXIT_SUCCESS; } - if (!*argv) /* all but 'addbr/delbr' need at least two arguments */ + if (!*argv) /* All of the below need at least two arguments */ bb_show_usage(); #if ENABLE_FEATURE_BRCTL_FANCY -- cgit v1.2.3-55-g6feb From ed79af77a4791aa0bbcb0a8d1b4c03ccf313fa94 Mon Sep 17 00:00:00 2001 From: James Byrne Date: Wed, 17 Jul 2019 15:53:04 +0000 Subject: config: PID_FILE_PATH required for FEATURE_CROND_SPECIAL_TIMES When crond is built with FEATURE_CROND_SPECIAL_TIMES enabled, it creates a file called 'crond.reboot' at CONFIG_PID_FILE_PATH, but if FEATURE_PIDFILE is disabled, this will be an empty string and the file will be created in the root directory, which is undesirable. This commit makes PID_FILE_PATH depend on FEATURE_CROND_SPECIAL_TIMES as well as FEATURE_PIDFILE so that you get sensible behaviour in crond when FEATURE_PIDFILE is switched off. Signed-off-by: James Byrne Signed-off-by: Denys Vlasenko --- Config.in | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Config.in b/Config.in index 14f54aacc..b62b2abb8 100644 --- a/Config.in +++ b/Config.in @@ -156,12 +156,13 @@ config FEATURE_PIDFILE config PID_FILE_PATH string "Directory for pidfiles" default "/var/run" - depends on FEATURE_PIDFILE + depends on FEATURE_PIDFILE || FEATURE_CROND_SPECIAL_TIMES help This is the default path where pidfiles are created. Applets which allow you to set the pidfile path on the command line will override this value. The option has no effect on applets that require you to - specify a pidfile path. + specify a pidfile path. When crond has the 'Support special times' + option enabled, the 'crond.reboot' file is also stored here. config BUSYBOX bool "Include busybox applet" -- cgit v1.2.3-55-g6feb From 37a9008f8e82b9469062f5a792a26f145012c617 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 15 Oct 2019 12:31:54 +0200 Subject: brctl: code shrink function old new delta show_bridge 323 317 -6 brctl_main 2171 2164 -7 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-13) Total: -13 bytes text data bss dec hex filename 1002083 551 5612 1008246 f6276 busybox_old 1002065 551 5612 1008228 f6264 busybox_unstripped Signed-off-by: Denys Vlasenko --- networking/brctl.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/networking/brctl.c b/networking/brctl.c index 8ed9d2096..25640246d 100644 --- a/networking/brctl.c +++ b/networking/brctl.c @@ -157,7 +157,8 @@ static int show_bridge(const char *name, int need_hdr) strcpy(filedata, "yes"); fputs(filedata, stdout); - strcpy(sfx - (sizeof("bridge/")-1), "brif"); + /* sfx points past "BR/bridge/", turn it into "BR/brif": */ + sfx[-4] = 'f'; sfx[-3] = '\0'; tabs = 0; ifaces = opendir(pathbuf); if (ifaces) { @@ -472,8 +473,8 @@ static void show_bridge_stp(const char *name) { DIR *ifaces; - /* sfx points past "BR/bridge/", turn it to "BR/brif": */ - strcpy(sfx - 4, "f"); + /* sfx points past "BR/bridge/", turn it into "BR/brif": */ + sfx[-4] = 'f'; sfx[-3] = '\0'; ifaces = opendir(pathbuf); if (ifaces) { struct dirent *ent; -- cgit v1.2.3-55-g6feb From 95867147f5cdf6650dbfc207c8dada86246f23ae Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 18 Oct 2019 16:47:37 +0200 Subject: telnet: add disabled code to emit EC and IP > I'm trying to connect to a Korenix 3005 switch through telnet > for management purposes, and all is well except for the backspace character > - seems like my switch doesn't handle it too well and instead of erasing > the last character all it does is print some garbage to the screen. > I've had the same issue before while using putty, but saw a solution that > suggests to enable "Telnet special commands" in the options menu, and it > worked. Signed-off-by: Denys Vlasenko --- networking/telnet.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/networking/telnet.c b/networking/telnet.c index 5c8805265..9fc85050b 100644 --- a/networking/telnet.c +++ b/networking/telnet.c @@ -238,6 +238,18 @@ static void handle_net_output(int len) *dst = '\r'; /* Enter -> CR LF */ *++dst = '\n'; } +#if 0 +/* putty's "special commands" mode does this: */ +/* Korenix 3005 switch needs at least the backspace tweak */ + if (c == 0x08 || c == 0x7f) { /* ctrl+h || backspace */ + *dst = IAC; + *++dst = EC; + } + if (c == 0x03) { /* ctrl+c */ + *dst = IAC; + *++dst = IP; + } +#endif dst++; } if (dst - outbuf != 0) -- cgit v1.2.3-55-g6feb From c763392458304d68951d0b22e89e2422b9c2f8ef Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 19 Oct 2019 18:33:49 +0200 Subject: gzip: code shrink huft_build() has way too many params function old new delta inflate_block 1293 1281 -12 huft_build 1085 1058 -27 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-39) Total: -39 bytes Signed-off-by: Denys Vlasenko --- archival/libarchive/decompress_gunzip.c | 53 ++++++++++++++++----------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/archival/libarchive/decompress_gunzip.c b/archival/libarchive/decompress_gunzip.c index 1ddce610c..e01687000 100644 --- a/archival/libarchive/decompress_gunzip.c +++ b/archival/libarchive/decompress_gunzip.c @@ -277,22 +277,19 @@ static unsigned fill_bitbuffer(STATE_PARAM unsigned bitbuffer, unsigned *current /* 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 (an oversubscribed set of lengths) - * - in this case stores NULL in *t. + * tables to decode that set of codes. * * 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 + * result: starting table */ -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) +static huft_t* huft_build(const unsigned *b, const unsigned n, + const unsigned s, const uint16_t *d, + const uint8_t *e, unsigned *m) { unsigned a; /* counter for codes of length k */ unsigned c[BMAX + 1]; /* bit length count table */ @@ -314,12 +311,12 @@ static int huft_build(const unsigned *b, const unsigned n, unsigned *xp; /* pointer into x */ int y; /* number of dummy codes added */ unsigned z; /* number of entries in current table */ + huft_t *result; + huft_t **t; /* 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 = b; @@ -335,9 +332,8 @@ static int huft_build(const unsigned *b, const unsigned n, q[1].b = 1; q[2].e = 99; /* invalid code marker */ q[2].b = 1; - *t = q + 1; *m = 1; - return 0; + return q + 1; } /* Find minimum and maximum length, bound *m by those */ @@ -353,11 +349,11 @@ static int huft_build(const unsigned *b, const unsigned n, for (y = 1 << j; j < i; j++, y <<= 1) { y -= c[j]; if (y < 0) - return 2; /* bad input: more codes than bits */ + return NULL; /* bad input: more codes than bits */ } y -= c[i]; if (y < 0) - return 2; + return NULL; c[i] += y; /* Generate starting offsets into the value table for each length */ @@ -384,6 +380,8 @@ static int huft_build(const unsigned *b, const unsigned n, } while (++i < n); /* Generate the Huffman codes and for each, make the table entries */ + result = NULL; + t = &result; x[0] = i = 0; /* first Huffman code is zero */ p = v; /* grab values in bit order */ htl = -1; /* no tables yet--level -1 */ @@ -475,8 +473,10 @@ static int huft_build(const unsigned *b, const unsigned n, /* return actual size of base table */ *m = ws[1]; - /* Return 1 if we were given an incomplete table */ - return y != 0 && g != 1; + if (y != 0 && g != 1) /* we were given an incomplete table */ + return NULL; + + return result; } @@ -777,14 +777,14 @@ static int inflate_block(STATE_PARAM smallint *e) 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 */ + inflate_codes_tl = huft_build(ll, 288, 257, cplens, cplext, &bl); + /* huft_build() never returns error here - 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); + inflate_codes_td = huft_build(ll, 30, 0, cpdist, cpdext, &bd); /* set up data for inflate_codes() */ inflate_codes_setup(PASS_STATE bl, bd); @@ -850,9 +850,9 @@ static int inflate_block(STATE_PARAM smallint *e) /* 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 */ + inflate_codes_tl = huft_build(ll, 19, 19, NULL, NULL, &bl); + if (!inflate_codes_tl) { + abort_unzip(PASS_STATE_ONLY); /* incomplete code set */ } /* read in literal and distance code lengths */ @@ -915,14 +915,13 @@ static int inflate_block(STATE_PARAM smallint *e) /* 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) { + inflate_codes_tl = huft_build(ll, nl, 257, cplens, cplext, &bl); + if (!inflate_codes_tl) { abort_unzip(PASS_STATE_ONLY); } bd = dbits; - i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &inflate_codes_td, &bd); - if (i != 0) { + inflate_codes_td = huft_build(ll + nl, nd, 0, cpdist, cpdext, &bd); + if (!inflate_codes_td) { abort_unzip(PASS_STATE_ONLY); } -- cgit v1.2.3-55-g6feb From 6572ef6e1e4822f785b7139ef166586c444dc01e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 19 Oct 2019 18:52:41 +0200 Subject: gzip: code shrink huft_build() still has way too many params function old new delta lit - 94 +94 dist - 94 +94 huft_build 1058 1054 -4 inflate_block 1281 1254 -27 cpdext 30 - -30 cplext 31 - -31 cpdist 60 - -60 cplens 62 - -62 ------------------------------------------------------------------------------ (add/remove: 2/4 grow/shrink: 0/2 up/down: 188/-214) Total: -26 bytes Signed-off-by: Denys Vlasenko --- archival/libarchive/decompress_gunzip.c | 55 ++++++++++++++++----------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/archival/libarchive/decompress_gunzip.c b/archival/libarchive/decompress_gunzip.c index e01687000..530661e15 100644 --- a/archival/libarchive/decompress_gunzip.c +++ b/archival/libarchive/decompress_gunzip.c @@ -184,29 +184,26 @@ static const uint16_t mask_bits[] ALIGN2 = { 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 +/* Put lengths/offsets and extra bits in a struct of arrays + * to make calls to huft_build() have one fewer parameter. + */ +struct cp_ext { + uint16_t cp[31]; + uint8_t ext[31]; }; - +/* Copy lengths and extra bits for literal codes 257..285 */ /* 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 +static const struct cp_ext lit = { + /*257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 */ + /*0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 */ + { 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 }, + { 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 */ }; - -/* 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 +/* Copy offsets and extra bits for distance codes 0..29 */ +static const struct cp_ext dist = { + /*0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 */ + { 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 }, + { 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. */ @@ -288,8 +285,8 @@ static unsigned fill_bitbuffer(STATE_PARAM unsigned bitbuffer, unsigned *current * result: starting table */ static huft_t* huft_build(const unsigned *b, const unsigned n, - const unsigned s, const uint16_t *d, - const uint8_t *e, unsigned *m) + const unsigned s, const struct cp_ext *cp_ext, + unsigned *m) { unsigned a; /* counter for codes of length k */ unsigned c[BMAX + 1]; /* bit length count table */ @@ -447,8 +444,8 @@ static huft_t* huft_build(const unsigned *b, const unsigned n, 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]; + r.e = (unsigned char) cp_ext->ext[*p - s]; /* non-simple--look up in lists */ + r.v.n = cp_ext->cp[*p++ - s]; } /* fill code-like entries with r */ @@ -777,14 +774,14 @@ static int inflate_block(STATE_PARAM smallint *e) for (; i < 288; i++) /* make a complete, but wrong code set */ ll[i] = 8; bl = 7; - inflate_codes_tl = huft_build(ll, 288, 257, cplens, cplext, &bl); + inflate_codes_tl = huft_build(ll, 288, 257, &lit, &bl); /* huft_build() never returns error here - we use known data */ /* set up distance table */ for (i = 0; i < 30; i++) /* make an incomplete code set */ ll[i] = 5; bd = 5; - inflate_codes_td = huft_build(ll, 30, 0, cpdist, cpdext, &bd); + inflate_codes_td = huft_build(ll, 30, 0, &dist, &bd); /* set up data for inflate_codes() */ inflate_codes_setup(PASS_STATE bl, bd); @@ -850,7 +847,7 @@ static int inflate_block(STATE_PARAM smallint *e) /* build decoding table for trees - single level, 7 bit lookup */ bl = 7; - inflate_codes_tl = huft_build(ll, 19, 19, NULL, NULL, &bl); + inflate_codes_tl = huft_build(ll, 19, 19, NULL, &bl); if (!inflate_codes_tl) { abort_unzip(PASS_STATE_ONLY); /* incomplete code set */ } @@ -915,12 +912,12 @@ static int inflate_block(STATE_PARAM smallint *e) /* build the decoding tables for literal/length and distance codes */ bl = lbits; - inflate_codes_tl = huft_build(ll, nl, 257, cplens, cplext, &bl); + inflate_codes_tl = huft_build(ll, nl, 257, &lit, &bl); if (!inflate_codes_tl) { abort_unzip(PASS_STATE_ONLY); } bd = dbits; - inflate_codes_td = huft_build(ll + nl, nd, 0, cpdist, cpdext, &bd); + inflate_codes_td = huft_build(ll + nl, nd, 0, &dist, &bd); if (!inflate_codes_td) { abort_unzip(PASS_STATE_ONLY); } -- cgit v1.2.3-55-g6feb From fb1103595f0562f98505882150fed384dea72f39 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 20 Oct 2019 19:07:06 +0200 Subject: gunzip: code shrink by using int-, not short-sized struct member function old new delta inflate_block 1254 1253 -1 inflate_codes 629 621 -8 huft_build 1054 1008 -46 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/3 up/down: 0/-55) Total: -55 bytes Signed-off-by: Denys Vlasenko --- archival/libarchive/decompress_gunzip.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/archival/libarchive/decompress_gunzip.c b/archival/libarchive/decompress_gunzip.c index 530661e15..0f8173d0a 100644 --- a/archival/libarchive/decompress_gunzip.c +++ b/archival/libarchive/decompress_gunzip.c @@ -39,7 +39,8 @@ 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 */ + unsigned n; /* literal, length base, or distance base */ + /* ^^^^^ was "unsigned short", but that results in larger code */ struct huft_t *t; /* pointer to next level of table */ } v; } huft_t; -- cgit v1.2.3-55-g6feb From 3ef513e787781e26f5996fc19b3540287a57fb9f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 21 Oct 2019 16:47:09 +0200 Subject: shell/ulimit: code shrink text data bss dec hex filename 1001949 551 5612 1008112 f61f0 busybox_old 1001906 551 5612 1008069 f61c5 busybox_unstripped Signed-off-by: Denys Vlasenko --- shell/shell_common.c | 77 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 18 deletions(-) diff --git a/shell/shell_common.c b/shell/shell_common.c index a93533903..12c4a073c 100644 --- a/shell/shell_common.c +++ b/shell/shell_common.c @@ -322,52 +322,91 @@ shell_builtin_read(struct builtin_read_params *params) struct limits { uint8_t cmd; /* RLIMIT_xxx fit into it */ uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */ - const char *name; }; static const struct limits limits_tbl[] = { - { RLIMIT_CORE, 9, "core file size (blocks)" }, // -c - { RLIMIT_DATA, 10, "data seg size (kb)" }, // -d - { RLIMIT_NICE, 0, "scheduling priority" }, // -e - { RLIMIT_FSIZE, 9, "file size (blocks)" }, // -f + { RLIMIT_CORE, 9, }, // -c + { RLIMIT_DATA, 10, }, // -d + { RLIMIT_NICE, 0, }, // -e + { RLIMIT_FSIZE, 9, }, // -f #define LIMIT_F_IDX 3 #ifdef RLIMIT_SIGPENDING - { RLIMIT_SIGPENDING, 0, "pending signals" }, // -i + { RLIMIT_SIGPENDING, 0, }, // -i #endif #ifdef RLIMIT_MEMLOCK - { RLIMIT_MEMLOCK, 10, "max locked memory (kb)" }, // -l + { RLIMIT_MEMLOCK, 10, }, // -l #endif #ifdef RLIMIT_RSS - { RLIMIT_RSS, 10, "max memory size (kb)" }, // -m + { RLIMIT_RSS, 10, }, // -m #endif #ifdef RLIMIT_NOFILE - { RLIMIT_NOFILE, 0, "open files" }, // -n + { RLIMIT_NOFILE, 0, }, // -n #endif #ifdef RLIMIT_MSGQUEUE - { RLIMIT_MSGQUEUE, 0, "POSIX message queues (bytes)" }, // -q + { RLIMIT_MSGQUEUE, 0, }, // -q #endif #ifdef RLIMIT_RTPRIO - { RLIMIT_RTPRIO, 0, "real-time priority" }, // -r + { RLIMIT_RTPRIO, 0, }, // -r #endif #ifdef RLIMIT_STACK - { RLIMIT_STACK, 10, "stack size (kb)" }, // -s + { RLIMIT_STACK, 10, }, // -s #endif #ifdef RLIMIT_CPU - { RLIMIT_CPU, 0, "cpu time (seconds)" }, // -t + { RLIMIT_CPU, 0, }, // -t #endif #ifdef RLIMIT_NPROC - { RLIMIT_NPROC, 0, "max user processes" }, // -u + { RLIMIT_NPROC, 0, }, // -u #endif #ifdef RLIMIT_AS - { RLIMIT_AS, 10, "virtual memory (kb)" }, // -v + { RLIMIT_AS, 10, }, // -v #endif #ifdef RLIMIT_LOCKS - { RLIMIT_LOCKS, 0, "file locks" }, // -x + { RLIMIT_LOCKS, 0, }, // -x #endif }; // bash also shows: //pipe size (512 bytes, -p) 8 +static const char limits_help[] ALIGN1 = + "core file size (blocks)" // -c + "\0""data seg size (kb)" // -d + "\0""scheduling priority" // -e + "\0""file size (blocks)" // -f +#ifdef RLIMIT_SIGPENDING + "\0""pending signals" // -i +#endif +#ifdef RLIMIT_MEMLOCK + "\0""max locked memory (kb)" // -l +#endif +#ifdef RLIMIT_RSS + "\0""max memory size (kb)" // -m +#endif +#ifdef RLIMIT_NOFILE + "\0""open files" // -n +#endif +#ifdef RLIMIT_MSGQUEUE + "\0""POSIX message queues (bytes)" // -q +#endif +#ifdef RLIMIT_RTPRIO + "\0""real-time priority" // -r +#endif +#ifdef RLIMIT_STACK + "\0""stack size (kb)" // -s +#endif +#ifdef RLIMIT_CPU + "\0""cpu time (seconds)" // -t +#endif +#ifdef RLIMIT_NPROC + "\0""max user processes" // -u +#endif +#ifdef RLIMIT_AS + "\0""virtual memory (kb)" // -v +#endif +#ifdef RLIMIT_LOCKS + "\0""file locks" // -x +#endif +; + static const char limit_chars[] ALIGN1 = "c" "d" @@ -558,10 +597,12 @@ shell_builtin_ulimit(char **argv) if (!(opts & (OPT_hard | OPT_soft))) opts |= (OPT_hard | OPT_soft); if (opts & OPT_all) { + const char *help = limits_help; for (i = 0; i < ARRAY_SIZE(limits_tbl); i++) { getrlimit(limits_tbl[i].cmd, &limit); - printf("%-32s(-%c) ", limits_tbl[i].name, limit_chars[i]); + printf("%-32s(-%c) ", help, limit_chars[i]); printlim(opts, &limit, &limits_tbl[i]); + help += strlen(help) + 1; } return EXIT_SUCCESS; } @@ -592,7 +633,7 @@ shell_builtin_ulimit(char **argv) getrlimit(limits_tbl[i].cmd, &limit); if (!val_str) { if (opt_cnt > 1) - printf("%-32s(-%c) ", limits_tbl[i].name, limit_chars[i]); + printf("%-32s(-%c) ", nth_string(limits_help, i), limit_chars[i]); printlim(opts, &limit, &limits_tbl[i]); } else { rlim_t val = RLIM_INFINITY; -- cgit v1.2.3-55-g6feb From 7427406580e78666fad3634b4bfaf1922d4bb457 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 22 Oct 2019 14:25:43 +0200 Subject: shell: better comments in BASE#nn code function old new delta evaluate_string 932 930 -2 Signed-off-by: Denys Vlasenko --- shell/math.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/shell/math.c b/shell/math.c index af1ab55c0..aac5017d0 100644 --- a/shell/math.c +++ b/shell/math.c @@ -537,25 +537,23 @@ static arith_t strto_arith_t(const char *nptr, char **endptr) base = (unsigned)n; n = 0; nptr = *endptr + 1; - /* bash allows "N#" (empty "nnnn" part) */ for (;;) { unsigned digit = (unsigned)*nptr - '0'; - if (digit >= 10) { - /* *nptr is not 0..9 */ - if (*nptr > 'z') - break; /* this rejects e.g. $((64#~)) */ + if (digit >= 10 /* not 0..9 */ + && digit <= 'z' - '0' /* needed to reject e.g. $((64#~)) */ + ) { /* in bases up to 36, case does not matter for a-z */ digit = (unsigned)(*nptr | 0x20) - ('a' - 10); if (base > 36 && *nptr <= '_') { - /* otherwise, A-Z,@,_ are 36..61,62,63 */ - if (*nptr == '@') - digit = 62; - else if (*nptr == '_') + /* otherwise, A-Z,@,_ are 36-61,62,63 */ + if (*nptr == '_') digit = 63; + else if (*nptr == '@') + digit = 62; else if (digit < 36) /* A-Z */ digit += 36 - 10; else - break; /* error, such as [ or \ */ + break; /* error: one of [\]^ */ } //bb_error_msg("ch:'%c'%d digit:%u", *nptr, *nptr, digit); //if (digit < 10) - example where we need this? @@ -567,6 +565,12 @@ static arith_t strto_arith_t(const char *nptr, char **endptr) n = n * base + digit; nptr++; } + /* Note: we do not set errno on bad chars, we just set a pointer + * to the first invalid char. For example, this allows + * "N#" (empty "nnnn" part): 64#+1 is a valid expression, + * it means 64# + 1, whereas 64#~... is not, since ~ is not a valid + * operator. + */ *endptr = (char*)nptr; return n; } -- cgit v1.2.3-55-g6feb From be5a505d771a77c640acc35ceaa470c80e62f954 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 24 Oct 2019 16:26:55 +0200 Subject: Remove syscall wrappers around clock_gettime, closes 12091 12091 "Direct use of __NR_clock_gettime is not time64-safe". function old new delta runsv_main 1698 1712 +14 startservice 378 383 +5 get_mono 31 25 -6 date_main 932 926 -6 gettimeofday_ns 17 - -17 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 2/2 up/down: 19/-29) Total: -10 bytes Signed-off-by: Denys Vlasenko --- Makefile.flags | 6 ++++-- coreutils/date.c | 16 +++------------- libbb/time.c | 11 +---------- runit/runsv.c | 11 +---------- 4 files changed, 9 insertions(+), 35 deletions(-) diff --git a/Makefile.flags b/Makefile.flags index 6f6142cc5..bea464753 100644 --- a/Makefile.flags +++ b/Makefile.flags @@ -129,10 +129,12 @@ endif # fall back to using a temp file: CRYPT_AVAILABLE := $(shell echo 'int main(void){return 0;}' >crypttest.c; $(CC) $(CFLAGS) -lcrypt -o /dev/null crypttest.c >/dev/null 2>&1 && echo "y"; rm crypttest.c) ifeq ($(CRYPT_AVAILABLE),y) -LDLIBS += m crypt +LDLIBS += m rt crypt else -LDLIBS += m +LDLIBS += m rt endif +# libm may be needed for dc, awk, ntpd +# librt may be needed for clock_gettime() # libpam may use libpthread, libdl and/or libaudit. # On some platforms that requires an explicit -lpthread, -ldl, -laudit. diff --git a/coreutils/date.c b/coreutils/date.c index 731241536..f7e9a8d0e 100644 --- a/coreutils/date.c +++ b/coreutils/date.c @@ -33,10 +33,9 @@ //config: Enable option (-I) to output an ISO-8601 compliant //config: date/time string. //config: -//config:# defaults to "no": stat's nanosecond field is a bit non-portable //config:config FEATURE_DATE_NANO //config: bool "Support %[num]N nanosecond format specifier" -//config: default n # syscall(__NR_clock_gettime) or syscall(__NR_clock_gettime64) +//config: default n # stat's nanosecond field is a bit non-portable //config: depends on DATE //config: select PLATFORM_LINUX //config: help @@ -271,17 +270,8 @@ int date_main(int argc UNUSED_PARAM, char **argv) */ #endif } else { -#if ENABLE_FEATURE_DATE_NANO && defined(__NR_clock_gettime) - /* libc has incredibly messy way of doing this, - * typically requiring -lrt. We just skip all this mess */ - syscall(__NR_clock_gettime, CLOCK_REALTIME, &ts); -#elif ENABLE_FEATURE_DATE_NANO && __TIMESIZE == 64 - /* Let's only support the 64 suffix syscalls for 64-bit time_t. - * This simplifies the code for us as we don't need to convert - * between 64-bit and 32-bit. We also don't have a way to - * report overflow errors here. - */ - syscall(__NR_clock_gettime64, CLOCK_REALTIME, &ts); +#if ENABLE_FEATURE_DATE_NANO + clock_gettime(CLOCK_REALTIME, &ts); #else time(&ts.tv_sec); #endif diff --git a/libbb/time.c b/libbb/time.c index b6fcae28b..e66a9cba8 100644 --- a/libbb/time.c +++ b/libbb/time.c @@ -253,18 +253,9 @@ char* FAST_FUNC strftime_YYYYMMDDHHMMSS(char *buf, unsigned len, time_t *tp) #define CLOCK_MONOTONIC 1 #endif -/* libc has incredibly messy way of doing this, - * typically requiring -lrt. We just skip all this mess */ static void get_mono(struct timespec *ts) { -#if defined(__NR_clock_gettime) - if (syscall(__NR_clock_gettime, CLOCK_MONOTONIC, ts)) -#elif __TIMESIZE == 64 - if (syscall(__NR_clock_gettime64, CLOCK_MONOTONIC, ts)) -#else -# error "We currently don't support architectures without " \ - "the __NR_clock_gettime syscall and 32-bit time_t" -#endif + if (clock_gettime(CLOCK_MONOTONIC, ts)) bb_simple_error_msg_and_die("clock_gettime(MONOTONIC) failed"); } unsigned long long FAST_FUNC monotonic_ns(void) diff --git a/runit/runsv.c b/runit/runsv.c index 737909b0e..36d85101e 100644 --- a/runit/runsv.c +++ b/runit/runsv.c @@ -51,18 +51,9 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #if ENABLE_MONOTONIC_SYSCALL #include -/* libc has incredibly messy way of doing this, - * typically requiring -lrt. We just skip all this mess */ static void gettimeofday_ns(struct timespec *ts) { -#if defined(__NR_clock_gettime) - syscall(__NR_clock_gettime, CLOCK_REALTIME, ts); -#elif __TIMESIZE == 64 - syscall(__NR_clock_gettime64, CLOCK_REALTIME, ts); -#else -# error "We currently don't support architectures without " \ - "the __NR_clock_gettime syscall and 32-bit time_t" -#endif + clock_gettime(CLOCK_REALTIME, ts); } #else static void gettimeofday_ns(struct timespec *ts) -- cgit v1.2.3-55-g6feb From e1a7c97ac640701973eea000007fc8b9f9dd7126 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 25 Oct 2019 10:30:53 +0200 Subject: tar: fix fallout of: change -a from meaning "lzma" to mean "autodetect by extension" Signed-off-by: Denys Vlasenko --- archival/tar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archival/tar.c b/archival/tar.c index 4f64d2286..4ab38db29 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -1029,7 +1029,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) IF_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive IF_NOT_FEATURE_TAR_CREATE("t--x:x--t") // mutually exclusive #if ENABLE_FEATURE_TAR_LONG_OPTIONS - ":\xf9+" // --strip-components=NUM + ":\xf8+" // --strip-components=NUM #endif LONGOPTS , &base_dir // -C dir -- cgit v1.2.3-55-g6feb From af7169b4a70eb3f60555ced17a40780f70aaaa5c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 25 Oct 2019 12:12:22 +0200 Subject: clang/llvm 9 fix - do not eliminate a store to a fake "const" This is *much* better (9 kbytes better) than dropping "*const" optimization trick. Signed-off-by: Denys Vlasenko --- coreutils/test.c | 2 +- include/libbb.h | 22 +++++++++++++++++++++- libbb/appletlib.c | 2 +- libbb/lineedit.c | 2 +- shell/ash.c | 6 +++--- 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/coreutils/test.c b/coreutils/test.c index 868ffbecb..a08986130 100644 --- a/coreutils/test.c +++ b/coreutils/test.c @@ -411,7 +411,7 @@ extern struct test_statics *const test_ptr_to_statics; #define leaving (S.leaving ) #define INIT_S() do { \ - (*(struct test_statics**)&test_ptr_to_statics) = xzalloc(sizeof(S)); \ + (*(struct test_statics**)not_const_pp(&test_ptr_to_statics)) = xzalloc(sizeof(S)); \ barrier(); \ } while (0) #define DEINIT_S() do { \ diff --git a/include/libbb.h b/include/libbb.h index 111d1b790..05a560977 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -2153,12 +2153,32 @@ struct globals; * Magic prevents ptr_to_globals from going into rodata. * If you want to assign a value, use SET_PTR_TO_GLOBALS(x) */ extern struct globals *const ptr_to_globals; + +#if defined(__clang_major__) && __clang_major__ >= 9 +/* Clang/llvm drops assignment to "constant" storage. Silently. + * Needs serious convincing to not eliminate the store. + */ +static ALWAYS_INLINE void* not_const_pp(const void *p) +{ + void *pp; + __asm__ __volatile__( + "# forget that p points to const" + : /*outputs*/ "=r" (pp) + : /*inputs*/ "0" (p) + ); + return pp; +} +#else +static ALWAYS_INLINE void* not_const_pp(const void *p) { return (void*)p; } +#endif + /* At least gcc 3.4.6 on mipsel system needs optimization barrier */ #define barrier() __asm__ __volatile__("":::"memory") #define SET_PTR_TO_GLOBALS(x) do { \ - (*(struct globals**)&ptr_to_globals) = (void*)(x); \ + (*(struct globals**)not_const_pp(&ptr_to_globals)) = (void*)(x); \ barrier(); \ } while (0) + #define FREE_PTR_TO_GLOBALS() do { \ if (ENABLE_FEATURE_CLEAN_UP) { \ free(ptr_to_globals); \ diff --git a/libbb/appletlib.c b/libbb/appletlib.c index 9fa17cfa1..f842e73cc 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -304,7 +304,7 @@ void lbb_prepare(const char *applet IF_FEATURE_INDIVIDUAL(, char **argv)) { #ifdef __GLIBC__ - (*(int **)&bb_errno) = __errno_location(); + (*(int **)not_const_pp(&bb_errno)) = __errno_location(); barrier(); #endif applet_name = applet; diff --git a/libbb/lineedit.c b/libbb/lineedit.c index fbabc6c12..b1ec52b88 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -203,7 +203,7 @@ extern struct lineedit_statics *const lineedit_ptr_to_statics; #define delbuf (S.delbuf ) #define INIT_S() do { \ - (*(struct lineedit_statics**)&lineedit_ptr_to_statics) = xzalloc(sizeof(S)); \ + (*(struct lineedit_statics**)not_const_pp(&lineedit_ptr_to_statics)) = xzalloc(sizeof(S)); \ barrier(); \ cmdedit_termw = 80; \ IF_USERNAME_OR_HOMEDIR(home_pwd_buf = (char*)null_str;) \ diff --git a/shell/ash.c b/shell/ash.c index c5588ea66..4b5eafa7c 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -489,7 +489,7 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc; #define random_gen (G_misc.random_gen ) #define backgndpid (G_misc.backgndpid ) #define INIT_G_misc() do { \ - (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \ + (*(struct globals_misc**)not_const_pp(&ash_ptr_to_globals_misc)) = xzalloc(sizeof(G_misc)); \ barrier(); \ curdir = nullstr; \ physdir = nullstr; \ @@ -1542,7 +1542,7 @@ extern struct globals_memstack *BB_GLOBAL_CONST ash_ptr_to_globals_memstack; #define g_stacknleft (G_memstack.g_stacknleft) #define stackbase (G_memstack.stackbase ) #define INIT_G_memstack() do { \ - (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \ + (*(struct globals_memstack**)not_const_pp(&ash_ptr_to_globals_memstack)) = xzalloc(sizeof(G_memstack)); \ barrier(); \ g_stackp = &stackbase; \ g_stacknxt = stackbase.space; \ @@ -2165,7 +2165,7 @@ extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var; #endif #define INIT_G_var() do { \ unsigned i; \ - (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \ + (*(struct globals_var**)not_const_pp(&ash_ptr_to_globals_var)) = xzalloc(sizeof(G_var)); \ barrier(); \ for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \ varinit[i].flags = varinit_data[i].flags; \ -- cgit v1.2.3-55-g6feb From b4ef2e3467d8e980ccf13c9dd342459c013b455f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 25 Oct 2019 12:56:51 +0200 Subject: Makefile.flags: suppress some clang-9 warnings Signed-off-by: Denys Vlasenko --- Makefile.flags | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/Makefile.flags b/Makefile.flags index bea464753..e378fbad9 100644 --- a/Makefile.flags +++ b/Makefile.flags @@ -47,12 +47,28 @@ endif # gcc 3.x emits bogus "old style proto" warning on find.c:alloc_action() CFLAGS += $(call cc-ifversion, -ge, 0400, -Wold-style-definition) -CFLAGS += $(call cc-option,-fno-builtin-strlen -finline-limit=0 -fomit-frame-pointer -ffunction-sections -fdata-sections,) +ifneq ($(CC),clang) +# "clang-9: warning: optimization flag '-finline-limit=0' is not supported +CFLAGS += $(call cc-option,-finline-limit=0,) +endif + +CFLAGS += $(call cc-option,-fno-builtin-strlen -fomit-frame-pointer -ffunction-sections -fdata-sections,) # -fno-guess-branch-probability: prohibit pseudo-random guessing # of branch probabilities (hopefully makes bloatcheck more stable): CFLAGS += $(call cc-option,-fno-guess-branch-probability,) -CFLAGS += $(call cc-option,-funsigned-char -static-libgcc,) -CFLAGS += $(call cc-option,-falign-functions=1 -falign-jumps=1 -falign-labels=1 -falign-loops=1,) +CFLAGS += $(call cc-option,-funsigned-char,) + +ifneq ($(CC),clang) +# "clang-9: warning: argument unused during compilation: '-static-libgcc'" +CFLAGS += $(call cc-option,-static-libgcc,) +endif + +CFLAGS += $(call cc-option,-falign-functions=1,) +ifneq ($(CC),clang) +# "clang-9: warning: optimization flag '-falign-jumps=1' is not supported" (and same for other two) +CFLAGS += $(call cc-option,-falign-jumps=1 -falign-labels=1 -falign-loops=1,) +endif + # Defeat .eh_frame bloat (gcc 4.6.3 x86-32 defconfig: 20% smaller busybox binary): CFLAGS += $(call cc-option,-fno-unwind-tables,) CFLAGS += $(call cc-option,-fno-asynchronous-unwind-tables,) @@ -60,6 +76,9 @@ CFLAGS += $(call cc-option,-fno-asynchronous-unwind-tables,) # (try disabling this and comparing assembly, it's instructive) CFLAGS += $(call cc-option,-fno-builtin-printf,) +# clang-9 does not like "str" + N and "if (CONFIG_ITEM && cond)" constructs +CFLAGS += $(call cc-option,-Wno-string-plus-int -Wno-constant-logical-operand) + # FIXME: These warnings are at least partially to be concerned about and should # be fixed.. #CFLAGS += $(call cc-option,-Wconversion,) -- cgit v1.2.3-55-g6feb From 1f1492bb96e318a36dee940e6d4bec0ef915339f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 25 Oct 2019 13:00:01 +0200 Subject: netstat: suppress a warning (conversion from 'int' to 'smallint' changes value) Signed-off-by: Denys Vlasenko --- networking/netstat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/netstat.c b/networking/netstat.c index 29b891cdc..c7934423b 100644 --- a/networking/netstat.c +++ b/networking/netstat.c @@ -172,7 +172,7 @@ struct prg_node { #define PRG_HASH_SIZE 211 struct globals { - smallint flags; + smalluint flags; #if ENABLE_FEATURE_NETSTAT_PRG smallint prg_cache_loaded; struct prg_node *prg_hash[PRG_HASH_SIZE]; -- cgit v1.2.3-55-g6feb From e5897d041d704a40efc8480cb2a72ef6843d0642 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 25 Oct 2019 13:05:15 +0200 Subject: suppress a few "unused function" warnings Signed-off-by: Denys Vlasenko --- networking/ntpd.c | 2 ++ networking/tls_aesgcm.c | 2 ++ procps/nmeter.c | 5 ----- util-linux/fdisk.c | 2 ++ 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/networking/ntpd.c b/networking/ntpd.c index 48dc1c379..47410c21e 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -504,12 +504,14 @@ static ALWAYS_INLINE double MAXD(double a, double b) return a; return b; } +#if !USING_KERNEL_PLL_LOOP static ALWAYS_INLINE double MIND(double a, double b) { if (a < b) return a; return b; } +#endif static NOINLINE double my_SQRT(double X) { union { diff --git a/networking/tls_aesgcm.c b/networking/tls_aesgcm.c index a4663cd79..5ddcdd2ad 100644 --- a/networking/tls_aesgcm.c +++ b/networking/tls_aesgcm.c @@ -13,6 +13,7 @@ typedef uint32_t word32; /* from wolfssl-3.15.3/wolfcrypt/src/aes.c */ +#ifdef UNUSED static ALWAYS_INLINE void FlattenSzInBits(byte* buf, word32 sz) { /* Multiply the sz by 8 */ @@ -32,6 +33,7 @@ static ALWAYS_INLINE void FlattenSzInBits(byte* buf, word32 sz) // buf[7] = sz & 0xff; *(uint32_t*)(buf + 4) = SWAP_BE32(sz); } +#endif static void RIGHTSHIFTX(byte* x) { diff --git a/procps/nmeter.c b/procps/nmeter.c index f0eb36740..ae16d8548 100644 --- a/procps/nmeter.c +++ b/procps/nmeter.c @@ -122,11 +122,6 @@ static inline void reset_outbuf(void) cur_outbuf = outbuf; } -static inline int outbuf_count(void) -{ - return cur_outbuf - outbuf; -} - static void print_outbuf(void) { int sz = cur_outbuf - outbuf; diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c index 076c5ca57..e58cb0fd1 100644 --- a/util-linux/fdisk.c +++ b/util-linux/fdisk.c @@ -588,11 +588,13 @@ partname(const char *dev, int pno, int lth) return bufp; } +#if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_OSF_LABEL static ALWAYS_INLINE struct partition * get_part_table(int i) { return ptes[i].part_table; } +#endif static ALWAYS_INLINE const char * str_units(void) -- cgit v1.2.3-55-g6feb From e076162897638a9b4952a77bf9cd7d24b2a296be Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 25 Oct 2019 13:39:41 +0200 Subject: traceroute: fix gcc-ism Signed-off-by: Denys Vlasenko --- networking/traceroute.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/networking/traceroute.c b/networking/traceroute.c index 0435d6ba6..06d3f19da 100644 --- a/networking/traceroute.c +++ b/networking/traceroute.c @@ -546,11 +546,11 @@ pr_type(unsigned char t) }; # if ENABLE_TRACEROUTE6 static const char *const ttab6[] = { -[0] "Error", "Dest Unreachable", "Packet Too Big", "Time Exceeded", -[4] "Param Problem", -[8] "Echo Request", "Echo Reply", "Membership Query", "Membership Report", -[12] "Membership Reduction", "Router Solicit", "Router Advert", "Neighbor Solicit", -[16] "Neighbor Advert", "Redirect", +[0] = "Error", "Dest Unreachable", "Packet Too Big", "Time Exceeded", +[4] = "Param Problem", +[8] = "Echo Request", "Echo Reply", "Membership Query", "Membership Report", +[12] = "Membership Reduction", "Router Solicit", "Router Advert", "Neighbor Solicit", +[16] = "Neighbor Advert", "Redirect", }; if (dest_lsa->u.sa.sa_family == AF_INET6) { -- cgit v1.2.3-55-g6feb From b4ad1d86b62090fed831e074a3c154af43cd66ce Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 25 Oct 2019 13:41:31 +0200 Subject: tc: array address is never NULL Signed-off-by: Denys Vlasenko --- networking/tc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/networking/tc.c b/networking/tc.c index 2e1078d31..510684443 100644 --- a/networking/tc.c +++ b/networking/tc.c @@ -215,8 +215,6 @@ static int prio_print_opt(struct rtattr *opt) if (opt == NULL) return 0; parse_rtattr_nested_compat(tb, TCA_PRIO_MAX, opt, qopt, sizeof(*qopt)); - if (tb == NULL) - return 0; printf("bands %u priomap ", qopt->bands); for (i=0; i<=TC_PRIO_MAX; i++) printf(" %d", qopt->priomap[i]); -- cgit v1.2.3-55-g6feb From d6ff27de153c8f9361de13f75c7f7ed319044f7c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 25 Oct 2019 17:35:58 +0200 Subject: ntpd: abs(tmx.offset) was truncating a "long" typed value Signed-off-by: Denys Vlasenko --- networking/ntpd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/networking/ntpd.c b/networking/ntpd.c index 47410c21e..e11160a55 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -1876,9 +1876,11 @@ update_local_clock(peer_t *p) //15:31:53.473 update from: offset:+0.000007 delay:0.158142 jitter:0.010922 clock drift:+9.343ppm tc:6 //15:32:58.902 update from: offset:-0.000728 delay:0.158222 jitter:0.009454 clock drift:+9.298ppm tc:6 /* - * This expression would choose MIN_FREQHOLD + 8 in the above example. + * This expression would choose MIN_FREQHOLD + 8 in the above example + * (off_065 is +1 for each 0.065536 seconds of offset). */ - G.FREQHOLD_cnt = 1 + MIN_FREQHOLD + ((unsigned)(abs(tmx.offset)) >> 16); + unsigned off_065 = abs((int)(tmx.offset >> 16)); + G.FREQHOLD_cnt = 1 + MIN_FREQHOLD + off_065; } G.FREQHOLD_cnt--; tmx.status |= STA_FREQHOLD; -- cgit v1.2.3-55-g6feb From f39a71817ead331b664bc658ac26dec4ec3b75bc Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 25 Oct 2019 17:40:57 +0200 Subject: read_key(): placate "warning: shifting a negative signed value is undefined" Signed-off-by: Denys Vlasenko --- libbb/read_key.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libbb/read_key.c b/libbb/read_key.c index 951786869..03b7da656 100644 --- a/libbb/read_key.c +++ b/libbb/read_key.c @@ -259,7 +259,8 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) buffer[-1] = 0; /* Pack into "1 " 32-bit sequence */ - col |= (((-1 << 15) | row) << 16); + row |= ((unsigned)(-1) << 15); + col |= (row << 16); /* Return it in high-order word */ return ((int64_t) col << 32) | (uint32_t)KEYCODE_CURSOR_POS; } -- cgit v1.2.3-55-g6feb From 9a0c404d5f71f1592c6eaeb9119abc6e3756e525 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 25 Oct 2019 17:42:23 +0200 Subject: vi: placate "warning: shifting a negative signed value is undefined" 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 f8fab7028..51dfc1209 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -3490,7 +3490,7 @@ static void do_cmd(int c) } while (--cmdcnt > 0); break; case '{': // {- move backward paragraph - q = char_search(dot, "\n\n", (BACK << 1) | FULL); + q = char_search(dot, "\n\n", ((unsigned)BACK << 1) | FULL); if (q != NULL) { // found blank line dot = next_line(q); // move to next blank line } -- cgit v1.2.3-55-g6feb From 122a8cbd4a3053e32bb76e6aa081deb890b10b11 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 25 Oct 2019 17:47:22 +0200 Subject: hdparm: placate "warning: taking the absolute value of unsigned type" Signed-off-by: Denys Vlasenko --- miscutils/hdparm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miscutils/hdparm.c b/miscutils/hdparm.c index b453efba9..beabb1ad5 100644 --- a/miscutils/hdparm.c +++ b/miscutils/hdparm.c @@ -996,7 +996,7 @@ static void identify(uint16_t *val) /* check Endian of capacity bytes */ nn = val[LCYLS_CUR] * val[LHEADS_CUR] * val[LSECTS_CUR]; oo = (uint32_t)val[CAPACITY_LSB] << 16 | val[CAPACITY_MSB]; - if (abs(mm - nn) > abs(oo - nn)) + if (abs((int)(mm - nn)) > abs((int)(oo - nn))) mm = oo; } printf("\tCHS current addressable sectors:%11u\n", mm); -- cgit v1.2.3-55-g6feb From caf5ee0dd9250a4ca913691bcdc247f8fe814e22 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 26 Oct 2019 20:04:34 +0200 Subject: gunzip: fix incorrect decoding of "fixed" inflate blocks function old new delta huft_build 1008 1022 +14 inflate_block 1253 1256 +3 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 17/0) Total: 17 bytes Signed-off-by: Denys Vlasenko --- archival/libarchive/decompress_gunzip.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/archival/libarchive/decompress_gunzip.c b/archival/libarchive/decompress_gunzip.c index 0f8173d0a..03049cc9b 100644 --- a/archival/libarchive/decompress_gunzip.c +++ b/archival/libarchive/decompress_gunzip.c @@ -280,11 +280,17 @@ static unsigned fill_bitbuffer(STATE_PARAM unsigned bitbuffer, unsigned *current * 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 + * cp_ext->cp,ext: list of base values/extra bits for non-simple codes * m: maximum lookup bits, returns actual * result: starting table + * + * On error, returns a value with lowest-bit set on error. + * It can be just the value of 0x1, + * or a valid pointer to a Huffman table, ORed with 0x1 if incompete table + * is given: "fixed inflate" decoder feeds us such data. */ +#define BAD_HUFT(p) ((uintptr_t)(p) & 1) +#define ERR_RET ((huft_t*)(uintptr_t)1) static huft_t* huft_build(const unsigned *b, const unsigned n, const unsigned s, const struct cp_ext *cp_ext, unsigned *m) @@ -347,11 +353,11 @@ static huft_t* huft_build(const unsigned *b, const unsigned n, for (y = 1 << j; j < i; j++, y <<= 1) { y -= c[j]; if (y < 0) - return NULL; /* bad input: more codes than bits */ + return ERR_RET; /* bad input: more codes than bits */ } y -= c[i]; if (y < 0) - return NULL; + return ERR_RET; c[i] += y; /* Generate starting offsets into the value table for each length */ @@ -378,7 +384,7 @@ static huft_t* huft_build(const unsigned *b, const unsigned n, } while (++i < n); /* Generate the Huffman codes and for each, make the table entries */ - result = NULL; + result = ERR_RET; t = &result; x[0] = i = 0; /* first Huffman code is zero */ p = v; /* grab values in bit order */ @@ -472,7 +478,8 @@ static huft_t* huft_build(const unsigned *b, const unsigned n, *m = ws[1]; if (y != 0 && g != 1) /* we were given an incomplete table */ - return NULL; + /* return "result" ORed with 1 */ + return (void*)((uintptr_t)result | 1); return result; } @@ -776,13 +783,16 @@ static int inflate_block(STATE_PARAM smallint *e) ll[i] = 8; bl = 7; inflate_codes_tl = huft_build(ll, 288, 257, &lit, &bl); - /* huft_build() never returns error here - we use known data */ + /* ^^^ never returns error here - we use known data */ /* set up distance table */ for (i = 0; i < 30; i++) /* make an incomplete code set */ ll[i] = 5; bd = 5; inflate_codes_td = huft_build(ll, 30, 0, &dist, &bd); + /* ^^^ does return error here! (lsb bit is set) - we gave it incomplete code set */ + /* clearing error bit: */ + inflate_codes_td = (void*)((uintptr_t)inflate_codes_td & ~(uintptr_t)1); /* set up data for inflate_codes() */ inflate_codes_setup(PASS_STATE bl, bd); @@ -849,7 +859,7 @@ static int inflate_block(STATE_PARAM smallint *e) /* build decoding table for trees - single level, 7 bit lookup */ bl = 7; inflate_codes_tl = huft_build(ll, 19, 19, NULL, &bl); - if (!inflate_codes_tl) { + if (BAD_HUFT(inflate_codes_tl)) { abort_unzip(PASS_STATE_ONLY); /* incomplete code set */ } @@ -914,12 +924,12 @@ static int inflate_block(STATE_PARAM smallint *e) /* build the decoding tables for literal/length and distance codes */ bl = lbits; inflate_codes_tl = huft_build(ll, nl, 257, &lit, &bl); - if (!inflate_codes_tl) { + if (BAD_HUFT(inflate_codes_tl)) { abort_unzip(PASS_STATE_ONLY); } bd = dbits; inflate_codes_td = huft_build(ll + nl, nd, 0, &dist, &bd); - if (!inflate_codes_td) { + if (BAD_HUFT(inflate_codes_td)) { abort_unzip(PASS_STATE_ONLY); } -- cgit v1.2.3-55-g6feb From 8c3b520d4f937b1d1856898dec5f634b12d9cc36 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Thu, 27 Jun 2019 17:27:28 +0200 Subject: nslookup: handle replies without RRs Under some circumstances, a DNS reply might contain no resource records, e.g. when a valid domain is queried that does not have records of the requested type. Example with nslookup from BIND dnsutils: $ nslookup -q=SRV example.org Server: 10.11.12.13 Address: 10.11.12.13#53 Non-authoritative answer: *** Can't find example.org: No answer Currently the busybox nslookup applet simply prints nothing after the "Non-authoritative answer:" line in the same situation. This change modifies nslookup to either print "Parse error" or "No answer" diagnostics, depending on the parse_reply() return value. function old new delta send_queries 1676 1711 +35 Signed-off-by: Jo-Philipp Wich Signed-off-by: Denys Vlasenko --- networking/nslookup.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/networking/nslookup.c b/networking/nslookup.c index 8adde14b8..a7dd823f0 100644 --- a/networking/nslookup.c +++ b/networking/nslookup.c @@ -615,9 +615,15 @@ static int send_queries(struct ns *ns) G.query[qn].name, rcodes[rcode]); G.exitcode = EXIT_FAILURE; } else { - if (parse_reply(reply, recvlen) < 0) { + switch (parse_reply(reply, recvlen)) { + case -1: printf("*** Can't find %s: Parse error\n", G.query[qn].name); G.exitcode = EXIT_FAILURE; + break; + + case 0: + printf("*** Can't find %s: No answer\n", G.query[qn].name); + break; } } bb_putchar('\n'); -- cgit v1.2.3-55-g6feb From 6b4960155e94076bf25518e4e268a7a5f849308e Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Thu, 27 Jun 2019 17:27:29 +0200 Subject: nslookup: implement support for SRV records Add support for querying and parsing SRV DNS records. function old new delta send_queries 1711 1865 +154 qtypes 72 80 +8 Signed-off-by: Jo-Philipp Wich Signed-off-by: Denys Vlasenko --- networking/nslookup.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/networking/nslookup.c b/networking/nslookup.c index a7dd823f0..c43e60558 100644 --- a/networking/nslookup.c +++ b/networking/nslookup.c @@ -283,6 +283,7 @@ static const struct { { ns_t_cname, "CNAME" }, { ns_t_mx, "MX" }, { ns_t_txt, "TXT" }, + { ns_t_srv, "SRV" }, { ns_t_ptr, "PTR" }, { ns_t_any, "ANY" }, }; @@ -435,6 +436,25 @@ static int parse_reply(const unsigned char *msg, size_t len) } break; + case ns_t_srv: + if (rdlen < 6) { + //printf("SRV record too short\n"); + return -1; + } + + cp = ns_rr_rdata(rr); + n = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), + cp + 6, dname, sizeof(dname)); + + if (n < 0) { + //printf("Unable to uncompress domain: %s\n", strerror(errno)); + return -1; + } + + printf("%s\tservice = %u %u %u %s\n", ns_rr_name(rr), + ns_get16(cp), ns_get16(cp + 2), ns_get16(cp + 4), dname); + break; + case ns_t_soa: if (rdlen < 20) { dbg("SOA record too short:%d\n", rdlen); -- cgit v1.2.3-55-g6feb From ea096d6c1389c93bdb6c6c45a04aff9062c7d8cf Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 30 Oct 2019 12:13:46 +0100 Subject: ntpd: decrease MIN_FREQHOLD by 2, increase "penalty" for largish offset x2 > 2018-07-25: > ntpd: increase MIN_FREQHOLD by 3 > This means we'll start correcting frequency ~5 minutes after start, > not ~3.5 ones. > With previous settings I still often see largish ~0.7s initial offsets > only about 1/2 corrected before frequency correction kicks in, > resulting in ~200ppm "correction" which is then slowly undone. Review of real-world results of the above shows that with small initial offsets, freq correction can be allowed to kick in sooner, whereas with large (~0.8s) offsets, we still start freq correction a bit too soon. Let's rebalance this a bit. Signed-off-by: Denys Vlasenko --- networking/ntpd.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/networking/ntpd.c b/networking/ntpd.c index e11160a55..0f12409f9 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -164,7 +164,7 @@ */ #define INITIAL_SAMPLES 4 /* how many samples do we want for init */ -#define MIN_FREQHOLD 12 /* adjust offset, but not freq in this many first adjustments */ +#define MIN_FREQHOLD 10 /* adjust offset, but not freq in this many first adjustments */ #define BAD_DELAY_GROWTH 4 /* drop packet if its delay grew by more than this factor */ #define RETRY_INTERVAL 32 /* on send/recv error, retry in N secs (need to be power of 2) */ @@ -1876,11 +1876,11 @@ update_local_clock(peer_t *p) //15:31:53.473 update from: offset:+0.000007 delay:0.158142 jitter:0.010922 clock drift:+9.343ppm tc:6 //15:32:58.902 update from: offset:-0.000728 delay:0.158222 jitter:0.009454 clock drift:+9.298ppm tc:6 /* - * This expression would choose MIN_FREQHOLD + 8 in the above example - * (off_065 is +1 for each 0.065536 seconds of offset). + * This expression would choose MIN_FREQHOLD + 14 in the above example + * (off_032 is +1 for each 0.032768 seconds of offset). */ - unsigned off_065 = abs((int)(tmx.offset >> 16)); - G.FREQHOLD_cnt = 1 + MIN_FREQHOLD + off_065; + unsigned off_032 = abs((int)(tmx.offset >> 15)); + G.FREQHOLD_cnt = 1 + MIN_FREQHOLD + off_032; } G.FREQHOLD_cnt--; tmx.status |= STA_FREQHOLD; -- cgit v1.2.3-55-g6feb From 21806562ca6350c78a14a89c22f985900ce96ade Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 1 Nov 2019 14:16:07 +0100 Subject: hush: restore redirected stdin function old new delta restore_redirects 52 95 +43 save_fd_on_redirect 243 253 +10 hfopen 90 99 +9 fgetc_interactive 259 261 +2 builtin_type 117 115 -2 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 4/1 up/down: 64/-2) Total: 62 bytes Signed-off-by: Denys Vlasenko --- shell/ash_test/ash-redir/redir_stdin1.right | 3 +++ shell/ash_test/ash-redir/redir_stdin1.tests | 7 +++++++ shell/hush.c | 29 ++++++++++++++++++++------- shell/hush_test/hush-redir/redir_stdin1.right | 3 +++ shell/hush_test/hush-redir/redir_stdin1.tests | 7 +++++++ 5 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 shell/ash_test/ash-redir/redir_stdin1.right create mode 100755 shell/ash_test/ash-redir/redir_stdin1.tests create mode 100644 shell/hush_test/hush-redir/redir_stdin1.right create mode 100755 shell/hush_test/hush-redir/redir_stdin1.tests diff --git a/shell/ash_test/ash-redir/redir_stdin1.right b/shell/ash_test/ash-redir/redir_stdin1.right new file mode 100644 index 000000000..1c6217e92 --- /dev/null +++ b/shell/ash_test/ash-redir/redir_stdin1.right @@ -0,0 +1,3 @@ +#Testing that stdin redirect is restored +read2 +Ok:0 diff --git a/shell/ash_test/ash-redir/redir_stdin1.tests b/shell/ash_test/ash-redir/redir_stdin1.tests new file mode 100755 index 000000000..f72253f9d --- /dev/null +++ b/shell/ash_test/ash-redir/redir_stdin1.tests @@ -0,0 +1,7 @@ +#Testing that stdin redirect is restored +echo read2 | $THIS_SH -c 'read r is_stdin = (name == NULL); + if (name == NULL) + G.HFILE_stdin = fp; fp->fd = fd; fp->cur = fp->end = fp->buf; fp->next_hfile = G.HFILE_list; @@ -2666,7 +2667,7 @@ static int fgetc_interactive(struct in_str *i) { int ch; /* If it's interactive stdin, get new line. */ - if (G_interactive_fd && i->file->is_stdin) { + if (G_interactive_fd && i->file == G.HFILE_stdin) { /* Returns first char (or EOF), the rest is in i->p[] */ ch = get_user_input(i); G.promptmode = 1; /* PS2 */ @@ -7605,7 +7606,9 @@ static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp) avoid_fd = 9; #if ENABLE_HUSH_INTERACTIVE - if (fd == G_interactive_fd) { + if (fd != 0 /* don't trigger for G_interactive_fd == 0 (that's "not interactive" flag) */ + && fd == G_interactive_fd + ) { /* Testcase: "ls -l /proc/$$/fd 255>&-" should work */ G_interactive_fd = xdup_CLOEXEC_and_close(G_interactive_fd, avoid_fd); debug_printf_redir("redirect_fd %d: matches interactive_fd, moving it to %d\n", fd, G_interactive_fd); @@ -7619,7 +7622,7 @@ static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp) /* No need to move script fds. * For NOMMU case, it's actively wrong: we'd change ->fd * fields in memory for the parent, but parent's fds - * aren't be moved, it would use wrong fd! + * aren't moved, it would use wrong fd! * Reproducer: "cmd 3>FILE" in script. * If we would call move_HFILEs_on_redirect(), child would: * fcntl64(3, F_DUPFD_CLOEXEC, 10) = 10 @@ -7683,6 +7686,20 @@ static void restore_redirects(struct squirrel *sq) } free(sq); } + if (G.HFILE_stdin + && G.HFILE_stdin->fd != STDIN_FILENO + ) { + /* Testcase: interactive "read r fd to e.g. 10, + * and it is not restored above (we do not restore script fds + * after redirects, we just use new, "moved" fds). + * However for stdin, get_user_input() -> read_line_input(), + * and read builtin, depend on fd == STDIN_FILENO. + */ + debug_printf_redir("restoring %d to stdin\n", G.HFILE_stdin->fd); + xmove_fd(G.HFILE_stdin->fd, STDIN_FILENO); + G.HFILE_stdin->fd = STDIN_FILENO; + } /* If moved, G_interactive_fd stays on new fd, not restoring it */ } @@ -10214,8 +10231,6 @@ int hush_main(int argc, char **argv) G_saved_tty_pgrp = 0; } } -// TODO: track & disallow any attempts of user -// to (inadvertently) close/redirect G_interactive_fd } debug_printf("interactive_fd:%d\n", G_interactive_fd); if (G_interactive_fd) { diff --git a/shell/hush_test/hush-redir/redir_stdin1.right b/shell/hush_test/hush-redir/redir_stdin1.right new file mode 100644 index 000000000..1c6217e92 --- /dev/null +++ b/shell/hush_test/hush-redir/redir_stdin1.right @@ -0,0 +1,3 @@ +#Testing that stdin redirect is restored +read2 +Ok:0 diff --git a/shell/hush_test/hush-redir/redir_stdin1.tests b/shell/hush_test/hush-redir/redir_stdin1.tests new file mode 100755 index 000000000..f72253f9d --- /dev/null +++ b/shell/hush_test/hush-redir/redir_stdin1.tests @@ -0,0 +1,7 @@ +#Testing that stdin redirect is restored +echo read2 | $THIS_SH -c 'read r Date: Fri, 1 Nov 2019 15:44:49 +0100 Subject: taskset: add support for taking/printing CPU list (-c option) function old new delta taskset_main 511 855 +344 Based on patch by Fryderyk Wrobel Signed-off-by: Denys Vlasenko --- util-linux/taskset.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 118 insertions(+), 11 deletions(-) diff --git a/util-linux/taskset.c b/util-linux/taskset.c index ed8878ad4..cebc20fea 100644 --- a/util-linux/taskset.c +++ b/util-linux/taskset.c @@ -20,6 +20,14 @@ //config: Needed for machines with more than 32-64 CPUs: //config: affinity parameter 0xHHHHHHHHHHHHHHHHHHHH can be arbitrarily long //config: in this case. Otherwise, it is limited to sizeof(long). +//config: +//config:config FEATURE_TASKSET_CPULIST +//config: bool "CPU list support (-c option)" +//config: default y +//config: depends on FEATURE_TASKSET_FANCY +//config: help +//config: Add support for taking/printing affinity as CPU list when '-c' +//config: option is used. For example, it prints '0-3,7' instead of mask '8f'. //applet:IF_TASKSET(APPLET_NOEXEC(taskset, taskset, BB_DIR_USR_BIN, BB_SUID_DROP, taskset)) @@ -108,26 +116,109 @@ static unsigned long *get_aff(int pid, unsigned *sz) return mask; } +#if ENABLE_FEATURE_TASKSET_CPULIST +/* + * Parse the CPU list and set the mask accordingly. + * + * The list element can be either a CPU index or a range of CPU indices. + * Example: "1,3,5-7". + * + * note1: pattern specifiers after a range (e.g. 0-255:2/64) are not supported + * note2: leading/trailing white-spaces are not allowed + */ +static void parse_cpulist(ul *mask, unsigned max, char *s) +{ + char *aff = s; + for (;;) { + unsigned bit, end; + + bit = end = bb_strtou(s, &s, 10); + if (*s == '-') { + s++; + end = bb_strtou(s, &s, 10); + } + if ((*s != ',' && *s != '\0') + || bit > end + || end == UINT_MAX /* bb_strtou returns this on malformed / ERANGE numbers */ + ) { + bb_error_msg_and_die("bad affinity '%s'", aff); + } + while (bit <= end && bit < max) { + mask[bit / BITS_UL] |= (1UL << (bit & MASK_UL)); + bit++; + } + if (*s == '\0') + break; + s++; + } +} +static void print_cpulist(const ul *mask, unsigned mask_size_in_bytes) +{ + const ul *mask_end; + const char *delim; + unsigned pos; + ul bit; + + mask_end = mask + mask_size_in_bytes / sizeof(mask[0]); + delim = ""; + pos = 0; + bit = 1; + for (;;) { + if (*mask & bit) { + unsigned onebit = pos + 1; + printf("%s%u", delim, pos); + do { + pos++; + bit <<= 1; + if (bit == 0) { + mask++; + if (mask >= mask_end) + break; + bit = 1; + } + } while (*mask & bit); + if (onebit != pos) + printf("-%u", pos - 1); + delim = ","; + } + pos++; + bit <<= 1; + if (bit == 0) { + mask++; + if (mask >= mask_end) + break; + bit = 1; + } + } + bb_putchar('\n'); +} +#endif + int taskset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int taskset_main(int argc UNUSED_PARAM, char **argv) { ul *mask; unsigned mask_size_in_bytes; pid_t pid = 0; - unsigned opt_p; const char *current_new; char *aff; + unsigned opts; + enum { + OPT_p = 1 << 0, + OPT_c = (1 << 1) * ENABLE_FEATURE_TASKSET_CPULIST, + }; /* NB: we mimic util-linux's taskset: -p does not take * an argument, i.e., "-pN" is NOT valid, only "-p N"! * Indeed, util-linux-2.13-pre7 uses: * getopt_long(argc, argv, "+pchV", ...), not "...p:..." */ - opt_p = getopt32(argv, "^+" "p" "\0" "-1" /* at least 1 arg */); + opts = getopt32(argv, "^+" "p"IF_FEATURE_TASKSET_CPULIST("c") + "\0" "-1" /* at least 1 arg */); argv += optind; aff = *argv++; - if (opt_p) { + if (opts & OPT_p) { char *pid_str = aff; if (*argv) { /* "-p ...rest.is.ignored..." */ pid_str = *argv; /* NB: *argv != NULL in this case */ @@ -144,8 +235,14 @@ int taskset_main(int argc UNUSED_PARAM, char **argv) current_new = "current"; print_aff: mask = get_aff(pid, &mask_size_in_bytes); - if (opt_p) { - printf("pid %d's %s affinity mask: "TASKSET_PRINTF_MASK"\n", + if (opts & OPT_p) { +#if ENABLE_FEATURE_TASKSET_CPULIST + if (opts & OPT_c) { + printf("pid %d's %s affinity list: ", pid, current_new); + print_cpulist(mask, mask_size_in_bytes); + } else +#endif + printf("pid %d's %s affinity mask: "TASKSET_PRINTF_MASK"\n", pid, current_new, from_mask(mask, mask_size_in_bytes)); if (*argv == NULL) { /* Either it was just "-p ", @@ -158,17 +255,27 @@ int taskset_main(int argc UNUSED_PARAM, char **argv) } memset(mask, 0, mask_size_in_bytes); - /* Affinity was specified, translate it into mask */ - /* it is always in hex, skip "0x" if it exists */ - if (aff[0] == '0' && (aff[1]|0x20) == 'x') - aff += 2; - if (!ENABLE_FEATURE_TASKSET_FANCY) { + /* Affinity was specified, translate it into mask */ + /* it is always in hex, skip "0x" if it exists */ + if (aff[0] == '0' && (aff[1]|0x20) == 'x') + aff += 2; mask[0] = xstrtoul(aff, 16); - } else { + } +#if ENABLE_FEATURE_TASKSET_CPULIST + else if (opts & OPT_c) { + parse_cpulist(mask, mask_size_in_bytes * 8, aff); + } +#endif + else { unsigned i; char *last_char; + /* Affinity was specified, translate it into mask */ + /* it is always in hex, skip "0x" if it exists */ + if (aff[0] == '0' && (aff[1]|0x20) == 'x') + aff += 2; + i = 0; /* bit pos in mask[] */ /* aff is ASCII hex string, accept very long masks in this form. -- cgit v1.2.3-55-g6feb From e5586605ca3dfa1e4ad2bb5ddea818777846dca2 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 8 Nov 2019 16:32:37 +0100 Subject: taskset: update comment Signed-off-by: Denys Vlasenko --- util-linux/taskset.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/util-linux/taskset.c b/util-linux/taskset.c index cebc20fea..157bf5e4c 100644 --- a/util-linux/taskset.c +++ b/util-linux/taskset.c @@ -123,8 +123,14 @@ static unsigned long *get_aff(int pid, unsigned *sz) * The list element can be either a CPU index or a range of CPU indices. * Example: "1,3,5-7". * - * note1: pattern specifiers after a range (e.g. 0-255:2/64) are not supported - * note2: leading/trailing white-spaces are not allowed + * note1: stride (e.g. 0-255:2) is not supported + * note2: leading and trailing whitespace is not allowed + * util-linux 2.31 allows leading and sometimes trailing whitespace: + * ok: taskset -c ' 1, 2' + * ok: taskset -c ' 1 , 2' + * ok: taskset -c ' 1-7: 2 ,8' + * not ok: taskset -c ' 1 ' + * not ok: taskset -c ' 1-7: 2 ' */ static void parse_cpulist(ul *mask, unsigned max, char *s) { -- cgit v1.2.3-55-g6feb From 2f57b5139e701e04a7b543220f6bb117b5e71967 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 8 Nov 2019 16:37:28 +0100 Subject: unxz: show -t in --help function old new delta packed_usage 33236 33247 +11 Signed-off-by: Denys Vlasenko --- archival/bbunzip.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/archival/bbunzip.c b/archival/bbunzip.c index d31aaf7f3..87a802209 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c @@ -536,6 +536,7 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv) //usage: "\n -c Write to stdout" //usage: "\n -f Force" //usage: "\n -k Keep input files" +//usage: "\n -t Test file integrity" //usage: //usage:#define xz_trivial_usage //usage: "-d [-cfk] [FILE]..." @@ -545,6 +546,7 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv) //usage: "\n -c Write to stdout" //usage: "\n -f Force" //usage: "\n -k Keep input files" +//usage: "\n -t Test file integrity" //usage: //usage:#define xzcat_trivial_usage //usage: "[FILE]..." -- cgit v1.2.3-55-g6feb From a82fb1b9d8a046e01dbad33bb57d064815d60e5c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 9 Nov 2019 17:05:14 +0100 Subject: taskset: implement stride argument function old new delta taskset_main 925 986 +61 Signed-off-by: Denys Vlasenko --- util-linux/taskset.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/util-linux/taskset.c b/util-linux/taskset.c index 157bf5e4c..df1bc0a4f 100644 --- a/util-linux/taskset.c +++ b/util-linux/taskset.c @@ -121,10 +121,8 @@ static unsigned long *get_aff(int pid, unsigned *sz) * Parse the CPU list and set the mask accordingly. * * The list element can be either a CPU index or a range of CPU indices. - * Example: "1,3,5-7". - * - * note1: stride (e.g. 0-255:2) is not supported - * note2: leading and trailing whitespace is not allowed + * Example: "1,3,5-7". Stride can be specified: "0-7:2" is "0,2,4,6". + * Note: leading and trailing whitespace is not allowed. * util-linux 2.31 allows leading and sometimes trailing whitespace: * ok: taskset -c ' 1, 2' * ok: taskset -c ' 1 , 2' @@ -137,21 +135,28 @@ static void parse_cpulist(ul *mask, unsigned max, char *s) char *aff = s; for (;;) { unsigned bit, end; + unsigned stride = 1; bit = end = bb_strtou(s, &s, 10); if (*s == '-') { s++; end = bb_strtou(s, &s, 10); + if (*s == ':') { + s++; + stride = bb_strtou(s, &s, 10); + } } if ((*s != ',' && *s != '\0') || bit > end || end == UINT_MAX /* bb_strtou returns this on malformed / ERANGE numbers */ + || stride == 0 + || stride == UINT_MAX ) { bb_error_msg_and_die("bad affinity '%s'", aff); } while (bit <= end && bit < max) { mask[bit / BITS_UL] |= (1UL << (bit & MASK_UL)); - bit++; + bit += stride; } if (*s == '\0') break; -- cgit v1.2.3-55-g6feb From b230fdfa9da2f31e6cc90f90579c6d020c770f86 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 9 Nov 2019 17:32:43 +0100 Subject: taskset: tighten the check for stride values function old new delta taskset_main 986 987 +1 Signed-off-by: Denys Vlasenko --- util-linux/taskset.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util-linux/taskset.c b/util-linux/taskset.c index df1bc0a4f..b542f8c83 100644 --- a/util-linux/taskset.c +++ b/util-linux/taskset.c @@ -149,8 +149,8 @@ static void parse_cpulist(ul *mask, unsigned max, char *s) if ((*s != ',' && *s != '\0') || bit > end || end == UINT_MAX /* bb_strtou returns this on malformed / ERANGE numbers */ - || stride == 0 - || stride == UINT_MAX + || (stride - 1) > (UINT_MAX / 4) + /* disallow 0, malformed input, and too large stride prone to overflows */ ) { bb_error_msg_and_die("bad affinity '%s'", aff); } -- cgit v1.2.3-55-g6feb From af6bc54fdefabae9ca433e515f7f1aa050184c9a Mon Sep 17 00:00:00 2001 From: "Liu, Shuang (ADITG/ESM)" Date: Wed, 13 Nov 2019 14:36:20 +0000 Subject: chgrp: correct the usage for non-desktop chgrp calls When IF_DESKTOP is not defined, chown and chgrp only takes option -R -h, However the usage output of chgrp is wrong: $ ./busybox.nosuid chown Usage: chown [-Rh]... USER[:[GRP]] FILE... $ ./busybox.nosuid chgrp Usage: chgrp [-RhLHP]... GROUP FILE... $ ./busybox.nosuid chgrp -H group dummy chgrp: invalid option -- 'H' Usage: chgrp [-RhLHP]... GROUP FILE... The chgrp is now a wrapper of chown, so the recognized options shall be the same. This is introduced by 34425389e09353a8dacdd6b23a62553f699c544c I would expect the correct behavior shall be the same as chown. So suggest the below patch, the behavior shall be: $ ./busybox.nosuid chgrp Usage: chgrp [-Rh]... GROUP FILE... Signed-off-by: Shuang Liu Signed-off-by: Denys Vlasenko --- coreutils/chgrp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreutils/chgrp.c b/coreutils/chgrp.c index ae216aa3f..4da43c45e 100644 --- a/coreutils/chgrp.c +++ b/coreutils/chgrp.c @@ -21,15 +21,15 @@ /* http://www.opengroup.org/onlinepubs/007904975/utilities/chgrp.html */ //usage:#define chgrp_trivial_usage -//usage: "[-RhLHP"IF_DESKTOP("cvf")"]... GROUP FILE..." +//usage: "[-Rh"IF_DESKTOP("LHPcvf")"]... GROUP FILE..." //usage:#define chgrp_full_usage "\n\n" //usage: "Change the group membership of each FILE to GROUP\n" //usage: "\n -R Recurse" //usage: "\n -h Affect symlinks instead of symlink targets" +//usage: IF_DESKTOP( //usage: "\n -L Traverse all symlinks to directories" //usage: "\n -H Traverse symlinks on command line only" //usage: "\n -P Don't traverse symlinks (default)" -//usage: IF_DESKTOP( //usage: "\n -c List changed files" //usage: "\n -v Verbose" //usage: "\n -f Hide errors" -- cgit v1.2.3-55-g6feb From 419d0294e9e9c272c0d740e4951dd083d19d479f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 17 Nov 2019 17:48:53 +0100 Subject: Updated inittab example documentation Signed-off-by: Denys Vlasenko --- examples/inittab | 47 ++++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/examples/inittab b/examples/inittab index 01ceaef25..4761aa19c 100644 --- a/examples/inittab +++ b/examples/inittab @@ -19,30 +19,43 @@ # # : The runlevels field is completely ignored. # -# : Valid actions include: sysinit, respawn, askfirst, wait, once, -# restart, ctrlaltdel, and shutdown. +# : Valid actions include: sysinit, wait, once, respawn, askfirst, +# shutdown, restart and ctrlaltdel. # -# Note: askfirst acts just like respawn, but before running the specified -# process it displays the line "Please press Enter to activate this -# console." and then waits for the user to press enter before starting -# the specified process. +# sysinit actions are started first, and init waits for them to complete. +# wait actions are started next, and init waits for them to complete. +# once actions are started next (and not waited for). # -# Note: unrecognized actions (like initdefault) will cause init to emit -# an error message, and then go along with its business. +# askfirst and respawn are started next. +# For askfirst, before running the specified process, init displays +# the line "Please press Enter to activate this console" +# and then waits for the user to press enter before starting it. +# +# shutdown actions are run on halt/reboot/poweroff, or on SIGQUIT. +# Then the machine is halted/rebooted/powered off, or for SIGQUIT, +# restart action is exec'ed (init process is replaced by that process). +# If no restart action specified, SIGQUIT has no effect. +# +# ctrlaltdel actions are run when SIGINT is received +# (this might be initiated by Ctrl-Alt-Del key combination). +# After they complete, normal processing of askfirst / respawn resumes. +# +# Note: unrecognized actions (like initdefault) will cause init to emit +# an error message, and then go along with its business. # # : Specifies the process to be executed and it's command line. # # Note: BusyBox init works just fine without an inittab. If no inittab is # found, it has the following default behavior: -# ::sysinit:/etc/init.d/rcS -# ::askfirst:/bin/sh -# ::ctrlaltdel:/sbin/reboot -# ::shutdown:/sbin/swapoff -a -# ::shutdown:/bin/umount -a -r -# ::restart:/sbin/init -# tty2::askfirst:/bin/sh -# tty3::askfirst:/bin/sh -# tty4::askfirst:/bin/sh +# ::sysinit:/etc/init.d/rcS +# ::askfirst:/bin/sh +# ::ctrlaltdel:/sbin/reboot +# ::shutdown:/sbin/swapoff -a +# ::shutdown:/bin/umount -a -r +# ::restart:/sbin/init +# tty2::askfirst:/bin/sh +# tty3::askfirst:/bin/sh +# tty4::askfirst:/bin/sh # # Boot-time system configuration/initialization script. # This is run first except when booting in single-user mode. -- cgit v1.2.3-55-g6feb From d3539be8f27b8cbfdfee460fe08299158f08bcd9 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 19 Nov 2019 13:06:40 +0100 Subject: Remove stime() function calls stime() has been deprecated in glibc 2.31 and replaced with clock_settime(). Let's replace the stime() function calls with clock_settime() in preperation. function old new delta rdate_main 197 224 +27 clock_settime - 27 +27 date_main 926 941 +15 stime 37 - -37 ------------------------------------------------------------------------------ (add/remove: 2/2 grow/shrink: 2/0 up/down: 69/-37) Total: 32 bytes Signed-off-by: Alistair Francis Signed-off-by: Denys Vlasenko --- coreutils/date.c | 6 +++++- libbb/missing_syscalls.c | 8 -------- util-linux/rdate.c | 8 ++++++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/coreutils/date.c b/coreutils/date.c index f7e9a8d0e..b9b7fd2cb 100644 --- a/coreutils/date.c +++ b/coreutils/date.c @@ -276,6 +276,9 @@ int date_main(int argc UNUSED_PARAM, char **argv) time(&ts.tv_sec); #endif } +#if !ENABLE_FEATURE_DATE_NANO + ts.tv_nsec = 0; +#endif localtime_r(&ts.tv_sec, &tm_time); /* If date string is given, update tm_time, and maybe set date */ @@ -298,9 +301,10 @@ int date_main(int argc UNUSED_PARAM, char **argv) if (date_str[0] != '@') tm_time.tm_isdst = -1; ts.tv_sec = validate_tm_time(date_str, &tm_time); + ts.tv_nsec = 0; /* if setting time, set it */ - if ((opt & OPT_SET) && stime(&ts.tv_sec) < 0) { + if ((opt & OPT_SET) && clock_settime(CLOCK_REALTIME, &ts) < 0) { bb_simple_perror_msg("can't set date"); } } diff --git a/libbb/missing_syscalls.c b/libbb/missing_syscalls.c index 87cf59b3d..dc40d9155 100644 --- a/libbb/missing_syscalls.c +++ b/libbb/missing_syscalls.c @@ -15,14 +15,6 @@ pid_t getsid(pid_t pid) return syscall(__NR_getsid, pid); } -int stime(const time_t *t) -{ - struct timeval tv; - tv.tv_sec = *t; - tv.tv_usec = 0; - return settimeofday(&tv, NULL); -} - int sethostname(const char *name, size_t len) { return syscall(__NR_sethostname, name, len); diff --git a/util-linux/rdate.c b/util-linux/rdate.c index 41aade5ea..bb1dc519a 100644 --- a/util-linux/rdate.c +++ b/util-linux/rdate.c @@ -95,9 +95,13 @@ int rdate_main(int argc UNUSED_PARAM, char **argv) if (!(flags & 2)) { /* no -p (-s may be present) */ if (time(NULL) == remote_time) bb_simple_error_msg("current time matches remote time"); - else - if (stime(&remote_time) < 0) + else { + struct timespec ts; + ts.tv_sec = remote_time; + ts.tv_nsec = 0; + if (clock_settime(CLOCK_REALTIME, &ts) < 0) bb_simple_perror_msg_and_die("can't set time of day"); + } } if (flags != 1) /* not lone -s */ -- cgit v1.2.3-55-g6feb From 008413754ba588e6168c3d15280181fb2c331770 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 23 Nov 2019 17:25:21 +0100 Subject: bc: fix comparison bug, closes 12336 function old new delta bc_num_cmp 249 259 +10 Signed-off-by: Denys Vlasenko --- miscutils/bc.c | 5 ++++- testsuite/bc.tests | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/miscutils/bc.c b/miscutils/bc.c index 92721d18f..c7246ea1a 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c @@ -1465,7 +1465,10 @@ static ssize_t bc_num_cmp(BcNum *a, BcNum *b) b_int = BC_NUM_INT(b); a_int -= b_int; - if (a_int != 0) return (ssize_t) a_int; + if (a_int != 0) { + if (neg) return - (ssize_t) a_int; + return (ssize_t) a_int; + } a_max = (a->rdx > b->rdx); if (a_max) { diff --git a/testsuite/bc.tests b/testsuite/bc.tests index 3fde60a2c..179d5d2a2 100755 --- a/testsuite/bc.tests +++ b/testsuite/bc.tests @@ -187,6 +187,11 @@ testing "bc { print 1 }" \ "1" \ "" "{ print 1 }" +testing "bc comparison 1" \ + "bc" \ + "1\n" \ + "" "-10 < -9" + testing "bc nested loops and breaks" \ "bc" \ "\ -- cgit v1.2.3-55-g6feb From 1b76ffaae400f266fe5aea0d5900a7e2ab9d7aa8 Mon Sep 17 00:00:00 2001 From: Tomi Leppanen Date: Mon, 25 Nov 2019 17:59:52 +0200 Subject: grep: add -R This adds -R option to grep similar to GNU grep. It is the same as -r but also dereferences symbolic links to directories. function old new delta grep_main 834 850 +16 packed_usage 33362 33368 +6 grep_file 1440 1441 +1 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/0 up/down: 23/0) Total: 23 bytes Signed-off-by: Tomi Leppanen Signed-off-by: Denys Vlasenko --- findutils/grep.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/findutils/grep.c b/findutils/grep.c index 2cbe7ea91..5b8644c36 100644 --- a/findutils/grep.c +++ b/findutils/grep.c @@ -60,7 +60,7 @@ /* options */ //usage:#define grep_trivial_usage -//usage: "[-HhnlLoqvsriwFE" +//usage: "[-HhnlLoqvsrRiwFE" //usage: IF_EXTRA_COMPAT("z") //usage: "] [-m N] " //usage: IF_FEATURE_GREP_CONTEXT("[-A/B/C N] ") @@ -78,6 +78,7 @@ //usage: "\n -v Select non-matching lines" //usage: "\n -s Suppress open and read errors" //usage: "\n -r Recurse" +//usage: "\n -R Recurse and dereference symlinks" //usage: "\n -i Ignore case" //usage: "\n -w Match whole words only" //usage: "\n -x Match whole lines only" @@ -108,7 +109,7 @@ /* -e,-f are lists; -m,-A,-B,-C have numeric param */ #define OPTSTR_GREP \ - "lnqvscFiHhe:*f:*Lorm:+wx" \ + "lnqvscFiHhe:*f:*LorRm:+wx" \ IF_FEATURE_GREP_CONTEXT("A:+B:+C:+") \ "E" \ IF_EXTRA_COMPAT("z") \ @@ -131,6 +132,7 @@ enum { OPTBIT_L, /* list unmatched file names only */ OPTBIT_o, /* show only matching parts of lines */ OPTBIT_r, /* recurse dirs */ + OPTBIT_R, /* recurse dirs and symlinks to dirs */ OPTBIT_m, /* -m MAX_MATCHES */ OPTBIT_w, /* -w whole word match */ OPTBIT_x, /* -x whole line match */ @@ -154,6 +156,7 @@ enum { OPT_L = 1 << OPTBIT_L, OPT_o = 1 << OPTBIT_o, OPT_r = 1 << OPTBIT_r, + OPT_R = 1 << OPTBIT_R, OPT_m = 1 << OPTBIT_m, OPT_w = 1 << OPTBIT_w, OPT_x = 1 << OPTBIT_x, @@ -687,6 +690,7 @@ static int grep_dir(const char *dir) int matched = 0; recursive_action(dir, /* recurse=yes */ ACTION_RECURSE | + /* followLinks=always */ ((option_mask32 & OPT_R) ? ACTION_FOLLOWLINKS : 0) | /* followLinks=command line only */ ACTION_FOLLOWLINKS_L0 | /* depthFirst=yes */ ACTION_DEPTHFIRST, /* fileAction= */ file_action_grep, @@ -827,7 +831,7 @@ int grep_main(int argc UNUSED_PARAM, char **argv) if (!cur_file || LONE_DASH(cur_file)) { cur_file = "(standard input)"; } else { - if (option_mask32 & OPT_r) { + if (option_mask32 & (OPT_r|OPT_R)) { struct stat st; if (stat(cur_file, &st) == 0 && S_ISDIR(st.st_mode)) { if (!(option_mask32 & OPT_h)) -- cgit v1.2.3-55-g6feb From 259747caa7d86a5a46013b80a19b2ee2d4e0a73b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 28 Nov 2019 10:28:14 +0100 Subject: hush: fix preprocessor directives indentation Signed-off-by: Denys Vlasenko --- shell/hush.c | 64 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/shell/hush.c b/shell/hush.c index 25e5fb906..97202b953 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -3653,9 +3653,9 @@ static void debug_print_tree(struct pipe *pi, int lvl) fdprintf(2, "%*s cmd %d assignment_cnt:%d", lvl*2, "", prn, command->assignment_cnt); -#if ENABLE_HUSH_LINENO_VAR +# if ENABLE_HUSH_LINENO_VAR fdprintf(2, " LINENO:%u", command->lineno); -#endif +# endif if (command->group) { fdprintf(2, " group %s: (argv=%p)%s%s\n", CMDTYPE[command->cmd_type], @@ -4771,9 +4771,9 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign # endif end_ch &= (DOUBLE_CLOSE_CHAR_FLAG - 1); -#if ENABLE_HUSH_INTERACTIVE +# if ENABLE_HUSH_INTERACTIVE G.promptmode = 1; /* PS2 */ -#endif +# endif debug_printf_prompt("%s promptmode=%d\n", __func__, G.promptmode); while (1) { @@ -4829,13 +4829,13 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign syntax_error_unterm_ch(end_ch); return 0; } -#if 0 +# if 0 if (ch == '\n') { /* "backslash+newline", ignore both */ o_delchr(dest); /* undo insertion of '\' */ continue; } -#endif +# endif o_addchr(dest, ch); //bb_error_msg("%s:o_addchr('%c') after '\\'", __func__, ch); continue; @@ -4992,7 +4992,7 @@ static int parse_dollar(o_string *as_string, if (last_ch == 0) /* error? */ return 0; #else -#error Simple code to only allow ${var} is not implemented +# error Simple code to only allow ${var} is not implemented #endif if (as_string) { o_addstr(as_string, dest->data + pos); @@ -8701,9 +8701,9 @@ static int process_wait_result(struct pipe *fg_pipe, pid_t childpid, int status) pi->cmds[i].pid = 0; pi->alive_cmds--; if (!pi->alive_cmds) { -#if ENABLE_HUSH_BASH_COMPAT +# if ENABLE_HUSH_BASH_COMPAT G.dead_job_exitcode = job_exited_or_stopped(pi); -#endif +# endif if (G_interactive_fd) { printf(JOB_STATUS_FORMAT, pi->jobid, "Done", pi->cmdtext); @@ -10552,10 +10552,10 @@ static int FAST_FUNC builtin_type(char **argv) if (0) {} /* make conditional compile easier below */ /*else if (find_alias(*argv)) type = "an alias";*/ -#if ENABLE_HUSH_FUNCTIONS +# if ENABLE_HUSH_FUNCTIONS else if (find_function(*argv)) type = "a function"; -#endif +# endif else if (find_builtin(*argv)) type = "a shell builtin"; else if ((path = find_in_path(*argv)) != NULL) @@ -10610,11 +10610,11 @@ static int FAST_FUNC builtin_read(char **argv) * Option string must start with "sr" to match BUILTIN_READ_xxx */ params.read_flags = getopt32(argv, -#if BASH_READ_D +# if BASH_READ_D "!srn:p:t:u:d:", ¶ms.opt_n, ¶ms.opt_p, ¶ms.opt_t, ¶ms.opt_u, ¶ms.opt_d -#else +# else "!srn:p:t:u:", ¶ms.opt_n, ¶ms.opt_p, ¶ms.opt_t, ¶ms.opt_u -#endif +# endif ); if ((uint32_t)params.read_flags == (uint32_t)-1) return EXIT_FAILURE; @@ -10787,24 +10787,24 @@ static int FAST_FUNC builtin_export(char **argv) { unsigned opt_unexport; -#if ENABLE_HUSH_EXPORT_N +# if ENABLE_HUSH_EXPORT_N /* "!": do not abort on errors */ opt_unexport = getopt32(argv, "!n"); if (opt_unexport == (uint32_t)-1) return EXIT_FAILURE; argv += optind; -#else +# else opt_unexport = 0; argv++; -#endif +# endif if (argv[0] == NULL) { char **e = environ; if (e) { while (*e) { -#if 0 +# if 0 puts(*e++); -#else +# else /* ash emits: export VAR='VAL' * bash: declare -x VAR="VAL" * we follow ash example */ @@ -10817,7 +10817,7 @@ static int FAST_FUNC builtin_export(char **argv) printf("export %.*s", (int)(p - s) + 1, s); print_escaped(p + 1); putchar('\n'); -#endif +# endif } /*fflush_all(); - done after each builtin anyway */ } @@ -11472,9 +11472,9 @@ static int FAST_FUNC builtin_kill(char **argv) #if ENABLE_HUSH_WAIT /* http://www.opengroup.org/onlinepubs/9699919799/utilities/wait.html */ -#if !ENABLE_HUSH_JOB -# define wait_for_child_or_signal(pipe,pid) wait_for_child_or_signal(pid) -#endif +# if !ENABLE_HUSH_JOB +# define wait_for_child_or_signal(pipe,pid) wait_for_child_or_signal(pid) +# endif static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid) { int ret = 0; @@ -11506,7 +11506,7 @@ static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid /* Can't pass waitfor_pipe into checkjobs(): it won't be interruptible */ ret = checkjobs(NULL, waitfor_pid); /* waitpid(WNOHANG) inside */ debug_printf_exec("checkjobs:%d\n", ret); -#if ENABLE_HUSH_JOB +# if ENABLE_HUSH_JOB if (waitfor_pipe) { int rcode = job_exited_or_stopped(waitfor_pipe); debug_printf_exec("job_exited_or_stopped:%d\n", rcode); @@ -11516,7 +11516,7 @@ static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid break; } } -#endif +# endif /* if ECHILD, there are no children (ret is -1 or 0) */ /* if ret == 0, no children changed state */ /* if ret != 0, it's exitcode+1 of exited waitfor_pid child */ @@ -11524,12 +11524,12 @@ static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid ret--; if (ret < 0) /* if ECHILD, may need to fix "ret" */ ret = 0; -#if ENABLE_HUSH_BASH_COMPAT +# if ENABLE_HUSH_BASH_COMPAT if (waitfor_pid == -1 && errno == ECHILD) { /* exitcode of "wait -n" with no children is 127, not 0 */ ret = 127; } -#endif +# endif sigprocmask(SIG_SETMASK, &oldset, NULL); break; } @@ -11558,14 +11558,14 @@ static int FAST_FUNC builtin_wait(char **argv) int status; argv = skip_dash_dash(argv); -#if ENABLE_HUSH_BASH_COMPAT +# if ENABLE_HUSH_BASH_COMPAT if (argv[0] && strcmp(argv[0], "-n") == 0) { /* wait -n */ /* (bash accepts "wait -n PID" too and ignores PID) */ G.dead_job_exitcode = -1; return wait_for_child_or_signal(NULL, -1 /*no job, wait for one job*/); } -#endif +# endif if (argv[0] == NULL) { /* Don't care about wait results */ /* Note 1: must wait until there are no more children */ @@ -11589,7 +11589,7 @@ static int FAST_FUNC builtin_wait(char **argv) do { pid_t pid = bb_strtou(*argv, NULL, 10); if (errno || pid <= 0) { -#if ENABLE_HUSH_JOB +# if ENABLE_HUSH_JOB if (argv[0][0] == '%') { struct pipe *wait_pipe; ret = 127; /* bash compat for bad jobspecs */ @@ -11606,7 +11606,7 @@ static int FAST_FUNC builtin_wait(char **argv) /* else: parse_jobspec() already emitted error msg */ continue; } -#endif +# endif /* mimic bash message */ bb_error_msg("wait: '%s': not a pid or valid job spec", *argv); ret = EXIT_FAILURE; @@ -11628,7 +11628,7 @@ static int FAST_FUNC builtin_wait(char **argv) ret = G.last_bg_pid_exitcode; } else { /* Example: "wait 1". mimic bash message */ - bb_error_msg("wait: pid %d is not a child of this shell", (int)pid); + bb_error_msg("wait: pid %u is not a child of this shell", (unsigned)pid); } } else { /* ??? */ -- cgit v1.2.3-55-g6feb From 113c776f4d2ce4ead7c2d11a3ca62adeec9a2e34 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 2 Dec 2019 16:39:54 +0100 Subject: init: if tcgetattr() fails, don't even try to tcsetattr() function old new delta set_sane_term 111 114 +3 Signed-off-by: Denys Vlasenko --- init/init.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/init/init.c b/init/init.c index 0f3c5fa4d..db1d99add 100644 --- a/init/init.c +++ b/init/init.c @@ -145,13 +145,6 @@ # 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 -# define CBAUD 0 -# define CBAUDEX 0 -#endif - /* Was a CONFIG_xxx option. A lot of people were building * not fully functional init by switching it on! */ #define DEBUG_INIT 0 @@ -347,7 +340,8 @@ static void set_sane_term(void) { struct termios tty; - tcgetattr(STDIN_FILENO, &tty); + if (tcgetattr(STDIN_FILENO, &tty) != 0) + return; /* set control chars */ tty.c_cc[VINTR] = 3; /* C-c */ @@ -365,10 +359,15 @@ static void set_sane_term(void) #endif /* Make it be sane */ +/* On systems where the baud rate is stored in a separate field, we can safely disable these. */ +#ifndef CBAUD +# define CBAUD 0 +# define CBAUDEX 0 +#endif +/* Added CRTSCTS to fix Debian bug 528560 */ #ifndef CRTSCTS # define CRTSCTS 0 #endif - /* added CRTSCTS to fix Debian bug 528560 */ tty.c_cflag &= CBAUD | CBAUDEX | CSIZE | CSTOPB | PARENB | PARODD | CRTSCTS; tty.c_cflag |= CREAD | HUPCL | CLOCAL; -- cgit v1.2.3-55-g6feb From 356f23de20b48382f5a2c5db29dc4f6dc9d10289 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 3 Dec 2019 13:48:55 +0100 Subject: init: improve handling of signals racing with each other Before this change, a request to reboot could be "overwritten" by e.g. SIGHUP. function old new delta init_main 709 793 +84 packed_usage 33273 33337 +64 run_actions 109 117 +8 stop_handler 87 88 +1 check_delayed_sigs 340 335 -5 run 214 198 -16 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 4/2 up/down: 157/-21) Total: 136 bytes Signed-off-by: Denys Vlasenko --- init/init.c | 278 ++++++++++++++++++++++++++---------------------------------- 1 file changed, 119 insertions(+), 159 deletions(-) diff --git a/init/init.c b/init/init.c index db1d99add..28775a65c 100644 --- a/init/init.c +++ b/init/init.c @@ -210,6 +210,8 @@ struct globals { #if !ENABLE_FEATURE_INIT_SYSLOG const char *log_console; #endif + sigset_t delayed_sigset; + struct timespec zero_ts; } FIX_ALIASING; #define G (*(struct globals*)bb_common_bufsiz1) #define INIT_G() do { \ @@ -411,14 +413,8 @@ static int open_stdio_to_tty(const char* tty_name) static void reset_sighandlers_and_unblock_sigs(void) { bb_signals(0 - + (1 << SIGUSR1) - + (1 << SIGUSR2) - + (1 << SIGTERM) - + (1 << SIGQUIT) - + (1 << SIGINT) - + (1 << SIGHUP) - + (1 << SIGTSTP) - + (1 << SIGSTOP) + | (1 << SIGTSTP) + | (1 << SIGSTOP) , SIG_DFL); sigprocmask_allsigs(SIG_UNBLOCK); } @@ -484,16 +480,13 @@ static pid_t run(const struct init_action *a) { pid_t pid; - /* Careful: don't be affected by a signal in vforked child */ - sigprocmask_allsigs(SIG_BLOCK); if (BB_MMU && (a->action_type & ASKFIRST)) pid = fork(); else pid = vfork(); - if (pid < 0) - message(L_LOG | L_CONSOLE, "can't fork"); if (pid) { - sigprocmask_allsigs(SIG_UNBLOCK); + if (pid < 0) + message(L_LOG | L_CONSOLE, "can't fork"); return pid; /* Parent or error */ } @@ -587,9 +580,11 @@ static void waitfor(pid_t pid) while (1) { pid_t wpid = wait(NULL); mark_terminated(wpid); - /* Unsafe. SIGTSTP handler might have wait'ed it already */ - /*if (wpid == pid) break;*/ - /* More reliable: */ + if (wpid == pid) /* this was the process we waited for */ + break; + /* The above is not reliable enough: SIGTSTP handler might have + * wait'ed it already. Double check, exit if process is gone: + */ if (kill(pid, 0)) break; } @@ -798,23 +793,17 @@ static void run_shutdown_and_kill_processes(void) * Delayed handlers just set a flag variable. The variable is checked * in the main loop and acted upon. * - * halt/poweroff/reboot and restart have immediate handlers. - * They only traverse linked list of struct action's, never modify it, - * this should be safe to do even in signal handler. Also they - * never return. - * * SIGSTOP and SIGTSTP have immediate handlers. They just wait * for SIGCONT to happen. * + * halt/poweroff/reboot and restart have delayed handlers. + * * SIGHUP has a delayed handler, because modifying linked list * of struct action's from a signal handler while it is manipulated * by the program may be disastrous. * * Ctrl-Alt-Del has a delayed handler. Not a must, but allowing * it to happen even somewhere inside "sysinit" would be a bit awkward. - * - * There is a tiny probability that SIGHUP and Ctrl-Alt-Del will collide - * and only one will be remembered and acted upon. */ /* The SIGPWR/SIGUSR[12]/SIGTERM handler */ @@ -898,11 +887,9 @@ static void exec_restart_action(void) */ static void stop_handler(int sig UNUSED_PARAM) { - smallint saved_bb_got_signal; - int saved_errno; + int saved_errno = errno; - saved_bb_got_signal = bb_got_signal; - saved_errno = errno; + bb_got_signal = 0; signal(SIGCONT, record_signo); while (1) { @@ -916,12 +903,12 @@ static void stop_handler(int sig UNUSED_PARAM) */ wpid = wait_any_nohang(NULL); mark_terminated(wpid); - sleep(1); + if (wpid <= 0) /* no processes exited? sleep a bit */ + sleep(1); } signal(SIGCONT, SIG_DFL); errno = saved_errno; - bb_got_signal = saved_bb_got_signal; } #if ENABLE_FEATURE_USE_INITTAB @@ -986,43 +973,39 @@ static void reload_inittab(void) } #endif -static int check_delayed_sigs(void) +static void check_delayed_sigs(struct timespec *ts) { - int sigs_seen = 0; + int sig = sigtimedwait(&G.delayed_sigset, /* siginfo_t */ NULL, ts); + if (sig <= 0) + return; - while (1) { - smallint sig = bb_got_signal; + /* The signal "sig" was caught */ - if (!sig) - return sigs_seen; - bb_got_signal = 0; - sigs_seen = 1; #if ENABLE_FEATURE_USE_INITTAB - if (sig == SIGHUP) - reload_inittab(); + if (sig == SIGHUP) + reload_inittab(); #endif - if (sig == SIGINT) - run_actions(CTRLALTDEL); - if (sig == SIGQUIT) { - exec_restart_action(); - /* returns only if no restart action defined */ - } - if ((1 << sig) & (0 + if (sig == SIGINT) + run_actions(CTRLALTDEL); + if (sig == SIGQUIT) { + exec_restart_action(); + /* returns only if no restart action defined */ + } + if ((1 << sig) & (0 #ifdef SIGPWR - + (1 << SIGPWR) + | (1 << SIGPWR) #endif - + (1 << SIGUSR1) - + (1 << SIGUSR2) - + (1 << SIGTERM) - )) { - halt_reboot_pwoff(sig); - } + | (1 << SIGUSR1) + | (1 << SIGUSR2) + | (1 << SIGTERM) + )) { + halt_reboot_pwoff(sig); } + /* if (sig == SIGCHLD) do nothing */ } #if DEBUG_SEGV_HANDLER -static -void handle_sigsegv(int sig, siginfo_t *info, void *ucontext) +static void handle_sigsegv(int sig, siginfo_t *info, void *ucontext) { long ip; ucontext_t *uc; @@ -1049,50 +1032,62 @@ void handle_sigsegv(int sig, siginfo_t *info, void *ucontext) static void sleep_much(void) { - sleep(30 * 24*60*60); + sleep(30 * 24*60*60); } int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int init_main(int argc UNUSED_PARAM, char **argv) { + struct sigaction sa; + INIT_G(); + /* Some users send poweroff signals to init VERY early. + * To handle this, mask signals early. + */ + /* sigemptyset(&G.delayed_sigset); - done by INIT_G() */ + sigaddset(&G.delayed_sigset, SIGINT); /* Ctrl-Alt-Del */ + sigaddset(&G.delayed_sigset, SIGQUIT); /* re-exec another init */ +#ifdef SIGPWR + sigaddset(&G.delayed_sigset, SIGPWR); /* halt */ +#endif + sigaddset(&G.delayed_sigset, SIGUSR1); /* halt */ + sigaddset(&G.delayed_sigset, SIGTERM); /* reboot */ + sigaddset(&G.delayed_sigset, SIGUSR2); /* poweroff */ +#if ENABLE_FEATURE_USE_INITTAB + sigaddset(&G.delayed_sigset, SIGHUP); /* reread /etc/inittab */ +#endif + sigaddset(&G.delayed_sigset, SIGCHLD); /* make sigtimedwait() exit on SIGCHLD */ + sigprocmask(SIG_BLOCK, &G.delayed_sigset, NULL); + +#if DEBUG_SEGV_HANDLER + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = handle_sigsegv; + sa.sa_flags = SA_SIGINFO; + sigaction_set(SIGSEGV, &sa); + sigaction_set(SIGILL, &sa); + sigaction_set(SIGFPE, &sa); + sigaction_set(SIGBUS, &sa); +#endif + if (argv[1] && strcmp(argv[1], "-q") == 0) { 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); +#if !DEBUG_INIT + /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */ + if (getpid() != 1 + && (!ENABLE_LINUXRC || applet_name[0] != 'l') /* not linuxrc? */ + ) { + bb_simple_error_msg_and_die("must be run as PID 1"); } -#endif - - if (!DEBUG_INIT) { - /* Some users send poweroff signals to init VERY early. - * To handle this, mask signals early, - * and unmask them only after signal handlers are installed. - */ - sigprocmask_allsigs(SIG_BLOCK); - /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */ - if (getpid() != 1 - && (!ENABLE_LINUXRC || applet_name[0] != 'l') /* not linuxrc? */ - ) { - bb_simple_error_msg_and_die("must be run as PID 1"); - } -#ifdef RB_DISABLE_CAD - /* Turn off rebooting via CTL-ALT-DEL - we get a - * SIGINT on CAD so we can shut things down gracefully... */ - reboot(RB_DISABLE_CAD); /* misnomer */ +# ifdef RB_DISABLE_CAD + /* Turn off rebooting via CTL-ALT-DEL - we get a + * SIGINT on CAD so we can shut things down gracefully... */ + reboot(RB_DISABLE_CAD); /* misnomer */ +# endif #endif - } /* If, say, xmalloc would ever die, we don't want to oops kernel * by exiting. @@ -1156,106 +1151,65 @@ int init_main(int argc UNUSED_PARAM, char **argv) } #endif - if (ENABLE_FEATURE_INIT_MODIFY_CMDLINE) { - /* Make the command line just say "init" - that's all, nothing else */ - strncpy(argv[0], "init", strlen(argv[0])); - /* Wipe argv[1]-argv[N] so they don't clutter the ps listing */ - while (*++argv) - nuke_str(*argv); - } - - /* Set up signal handlers */ - if (!DEBUG_INIT) { - struct sigaction sa; - - /* Stop handler must allow only SIGCONT inside itself */ - memset(&sa, 0, sizeof(sa)); - sigfillset(&sa.sa_mask); - sigdelset(&sa.sa_mask, SIGCONT); - sa.sa_handler = stop_handler; - /* NB: sa_flags doesn't have SA_RESTART. - * It must be able to interrupt wait(). - */ - sigaction_set(SIGTSTP, &sa); /* pause */ - /* Does not work as intended, at least in 2.6.20. - * SIGSTOP is simply ignored by init: - */ - sigaction_set(SIGSTOP, &sa); /* pause */ - - /* These signals must interrupt wait(), - * setting handler without SA_RESTART flag. - */ - bb_signals_recursive_norestart(0 - + (1 << SIGINT) /* Ctrl-Alt-Del */ - + (1 << SIGQUIT) /* re-exec another init */ -#ifdef SIGPWR - + (1 << SIGPWR) /* halt */ -#endif - + (1 << SIGUSR1) /* halt */ - + (1 << SIGTERM) /* reboot */ - + (1 << SIGUSR2) /* poweroff */ -#if ENABLE_FEATURE_USE_INITTAB - + (1 << SIGHUP) /* reread /etc/inittab */ +#if ENABLE_FEATURE_INIT_MODIFY_CMDLINE + /* Make the command line just say "init" - that's all, nothing else */ + strncpy(argv[0], "init", strlen(argv[0])); + /* Wipe argv[1]-argv[N] so they don't clutter the ps listing */ + while (*++argv) + nuke_str(*argv); #endif - , record_signo); - sigprocmask_allsigs(SIG_UNBLOCK); - } + /* Set up STOP signal handlers */ + /* Stop handler must allow only SIGCONT inside itself */ + memset(&sa, 0, sizeof(sa)); + sigfillset(&sa.sa_mask); + sigdelset(&sa.sa_mask, SIGCONT); + sa.sa_handler = stop_handler; + sa.sa_flags = SA_RESTART; + sigaction_set(SIGTSTP, &sa); /* pause */ + /* Does not work as intended, at least in 2.6.20. + * SIGSTOP is simply ignored by init + * (NB: behavior might differ under strace): + */ + sigaction_set(SIGSTOP, &sa); /* pause */ /* Now run everything that needs to be run */ /* First run the sysinit command */ run_actions(SYSINIT); - check_delayed_sigs(); + check_delayed_sigs(&G.zero_ts); /* Next run anything that wants to block */ run_actions(WAIT); - check_delayed_sigs(); + check_delayed_sigs(&G.zero_ts); /* Next run anything to be run only once */ run_actions(ONCE); - /* Now run the looping stuff for the rest of forever. - */ + /* Now run the looping stuff for the rest of forever */ while (1) { - int maybe_WNOHANG; - - maybe_WNOHANG = check_delayed_sigs(); - /* (Re)run the respawn/askfirst stuff */ run_actions(RESPAWN | ASKFIRST); - maybe_WNOHANG |= check_delayed_sigs(); - /* Don't consume all CPU time - sleep a bit */ - sleep(1); - maybe_WNOHANG |= check_delayed_sigs(); - - /* Wait for any child process(es) to exit. - * - * If check_delayed_sigs above reported that a signal - * was caught, wait will be nonblocking. This ensures - * that if SIGHUP has reloaded inittab, respawn and askfirst - * actions will not be delayed until next child death. - */ - if (maybe_WNOHANG) - maybe_WNOHANG = WNOHANG; + /* Wait for any signal (typically it's SIGCHLD) */ + check_delayed_sigs(NULL); /* NULL timespec makes it wait */ + + /* Wait for any child process(es) to exit */ while (1) { pid_t wpid; struct init_action *a; - /* If signals happen _in_ the wait, they interrupt it, - * bb_signals_recursive_norestart set them up that way - */ - wpid = waitpid(-1, NULL, maybe_WNOHANG); + wpid = waitpid(-1, NULL, WNOHANG); if (wpid <= 0) break; a = mark_terminated(wpid); if (a) { - message(L_LOG, "process '%s' (pid %d) exited. " + message(L_LOG, "process '%s' (pid %u) exited. " "Scheduling for restart.", - a->command, wpid); + a->command, (unsigned)wpid); } - /* See if anyone else is waiting to be reaped */ - maybe_WNOHANG = WNOHANG; } + + /* Don't consume all CPU time - sleep a bit */ + sleep(1); } /* while (1) */ } @@ -1268,11 +1222,17 @@ int init_main(int argc UNUSED_PARAM, char **argv) //usage: "Init is the first process started during boot. It never exits." //usage: IF_FEATURE_USE_INITTAB( //usage: "\n""It (re)spawns children according to /etc/inittab." +//usage: "\n""Signals:" +//usage: "\n""HUP: reload /etc/inittab" //usage: ) //usage: IF_NOT_FEATURE_USE_INITTAB( //usage: "\n""This version of init doesn't use /etc/inittab," //usage: "\n""has fixed set of processed to run." +//usage: "\n""Signals:" //usage: ) +//usage: "\n""TSTP: stop respawning until CONT" +//usage: "\n""QUIT: re-exec another init" +//usage: "\n""USR1/TERM/USR2/INT: run halt/reboot/poweroff/Ctrl-Alt-Del script" //usage: //usage:#define init_notes_usage //usage: "This version of init is designed to be run only by the kernel.\n" -- cgit v1.2.3-55-g6feb From 9ec836c033fc6e55e80f3309b3e05acdf09bb297 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 3 Dec 2019 14:52:17 +0100 Subject: whois: limit total length of response to 32+2 kb function old new delta query 517 554 +37 Signed-off-by: Denys Vlasenko --- networking/whois.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/networking/whois.c b/networking/whois.c index 55e1de964..caa71ac51 100644 --- a/networking/whois.c +++ b/networking/whois.c @@ -53,7 +53,9 @@ static char *query(const char *host, int port, const char *domain) fp = xfdopen_for_read(fd); success = 0; - while (fgets(linebuf, sizeof(linebuf)-1, fp)) { + while (bufpos < 32*1024 /* paranoia */ + && fgets(linebuf, sizeof(linebuf)-1, fp) + ) { unsigned len; len = strcspn(linebuf, "\r\n"); -- cgit v1.2.3-55-g6feb