aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2018-03-15 08:49:48 +0000
committerRon Yorston <rmy@pobox.com>2018-03-15 08:49:48 +0000
commit6fe4ad9a6c96624c2b75c0d51b035bc1a71d9eba (patch)
treebb7620a3217f5adf6fb5f3358b2b89a97331b5e8
parentf3d24e08a385a68c4bacb284bd8a8e3da7f0f4b3 (diff)
parentbbe47d9b9aee3824845f1ce08c9caeb262c15059 (diff)
downloadbusybox-w32-6fe4ad9a6c96624c2b75c0d51b035bc1a71d9eba.tar.gz
busybox-w32-6fe4ad9a6c96624c2b75c0d51b035bc1a71d9eba.tar.bz2
busybox-w32-6fe4ad9a6c96624c2b75c0d51b035bc1a71d9eba.zip
Merge branch 'busybox' into merge
-rw-r--r--coreutils/md5_sha1_sum.c2
-rwxr-xr-xexamples/var_service/dhcpd_if/run4
-rw-r--r--examples/var_service/dhcpd_if/udhcpd.conf (renamed from examples/var_service/dhcpd_if/udhcpc.conf)0
-rw-r--r--include/libbb.h2
-rw-r--r--libbb/missing_syscalls.c5
-rw-r--r--libbb/vfork_daemon_rexec.c15
-rw-r--r--networking/httpd.c6
-rw-r--r--networking/ifconfig.c8
-rw-r--r--networking/interface.c235
-rw-r--r--networking/ip.c2
-rw-r--r--networking/libiproute/ipaddress.c5
-rw-r--r--networking/ntpd.c100
-rw-r--r--networking/tcpudp.c11
-rw-r--r--networking/udhcp/common.h2
-rw-r--r--networking/udhcp/d6_dhcpc.c9
-rw-r--r--networking/udhcp/dhcpc.c9
-rw-r--r--networking/udhcp/dhcpd.c49
-rw-r--r--networking/udhcp/signalpipe.c11
-rw-r--r--networking/wget.c8
-rw-r--r--procps/top.c44
-rw-r--r--runit/svlogd.c4
-rw-r--r--shell/ash_test/ash-quoting/bkslash_in_varexp.right5
-rwxr-xr-xshell/ash_test/ash-quoting/bkslash_in_varexp.tests16
-rw-r--r--shell/ash_test/ash-quoting/bkslash_in_varexp1.right5
-rwxr-xr-xshell/ash_test/ash-quoting/bkslash_in_varexp1.tests6
-rw-r--r--shell/ash_test/ash-quoting/squote_in_varexp.right5
-rwxr-xr-xshell/ash_test/ash-quoting/squote_in_varexp.tests6
-rw-r--r--shell/ash_test/ash-quoting/squote_in_varexp1.right3
-rwxr-xr-xshell/ash_test/ash-quoting/squote_in_varexp1.tests4
-rw-r--r--shell/ash_test/ash-quoting/squote_in_varexp2.right3
-rwxr-xr-xshell/ash_test/ash-quoting/squote_in_varexp2.tests4
-rw-r--r--shell/hush.c32
-rw-r--r--shell/hush_test/hush-quoting/bkslash_in_varexp.right5
-rwxr-xr-xshell/hush_test/hush-quoting/bkslash_in_varexp.tests16
-rw-r--r--shell/hush_test/hush-quoting/bkslash_in_varexp1.right5
-rwxr-xr-xshell/hush_test/hush-quoting/bkslash_in_varexp1.tests6
-rw-r--r--shell/hush_test/hush-quoting/squote_in_varexp.right5
-rwxr-xr-xshell/hush_test/hush-quoting/squote_in_varexp.tests6
-rw-r--r--shell/hush_test/hush-quoting/squote_in_varexp1.right3
-rwxr-xr-xshell/hush_test/hush-quoting/squote_in_varexp1.tests4
-rw-r--r--shell/hush_test/hush-quoting/squote_in_varexp2.right3
-rwxr-xr-xshell/hush_test/hush-quoting/squote_in_varexp2.tests4
-rw-r--r--shell/match.c2
-rw-r--r--sysklogd/syslogd_and_logger.c1
-rw-r--r--util-linux/ipcs.c76
-rw-r--r--util-linux/readprofile.c67
46 files changed, 500 insertions, 323 deletions
diff --git a/coreutils/md5_sha1_sum.c b/coreutils/md5_sha1_sum.c
index ccdfd6855..871145143 100644
--- a/coreutils/md5_sha1_sum.c
+++ b/coreutils/md5_sha1_sum.c
@@ -9,7 +9,7 @@
9//config: bool "md5sum (6.8 kb)" 9//config: bool "md5sum (6.8 kb)"
10//config: default y 10//config: default y
11//config: help 11//config: help
12//config: md5sum is used to print or check MD5 checksums. 12//config: Compute and check MD5 message digest
13//config: 13//config:
14//config:config SHA1SUM 14//config:config SHA1SUM
15//config: bool "sha1sum (6 kb)" 15//config: bool "sha1sum (6 kb)"
diff --git a/examples/var_service/dhcpd_if/run b/examples/var_service/dhcpd_if/run
index de85dece0..a603bdc71 100755
--- a/examples/var_service/dhcpd_if/run
+++ b/examples/var_service/dhcpd_if/run
@@ -11,13 +11,13 @@ echo "* Upping iface $if"
11ip link set dev $if up 11ip link set dev $if up
12 12
13>>udhcpd.leases 13>>udhcpd.leases
14sed 's/^interface.*$/interface '"$if/" -i udhcpc.conf 14sed 's/^interface.*$/interface '"$if/" -i udhcpd.conf
15 15
16echo "* Starting udhcpd" 16echo "* Starting udhcpd"
17exec \ 17exec \
18env - PATH="$PATH" \ 18env - PATH="$PATH" \
19softlimit \ 19softlimit \
20setuidgid root \ 20setuidgid root \
21udhcpd -f -vv udhcpc.conf 21udhcpd -f -vv udhcpd.conf
22 22
23exit $? 23exit $?
diff --git a/examples/var_service/dhcpd_if/udhcpc.conf b/examples/var_service/dhcpd_if/udhcpd.conf
index a81925970..a81925970 100644
--- a/examples/var_service/dhcpd_if/udhcpc.conf
+++ b/examples/var_service/dhcpd_if/udhcpd.conf
diff --git a/include/libbb.h b/include/libbb.h
index e816a2726..2c0e02971 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -1415,7 +1415,7 @@ struct hwtype {
1415 int FAST_FUNC (*activate)(int fd); 1415 int FAST_FUNC (*activate)(int fd);
1416 int suppress_null_addr; 1416 int suppress_null_addr;
1417}; 1417};
1418extern smallint interface_opt_a; 1418#define IFNAME_SHOW_DOWNED_TOO ((char*)(intptr_t)1)
1419int display_interfaces(char *ifname) FAST_FUNC; 1419int display_interfaces(char *ifname) FAST_FUNC;
1420int in_ether(const char *bufp, struct sockaddr *sap) FAST_FUNC; 1420int in_ether(const char *bufp, struct sockaddr *sap) FAST_FUNC;
1421#if ENABLE_FEATURE_HWIB 1421#if ENABLE_FEATURE_HWIB
diff --git a/libbb/missing_syscalls.c b/libbb/missing_syscalls.c
index 093412811..87cf59b3d 100644
--- a/libbb/missing_syscalls.c
+++ b/libbb/missing_syscalls.c
@@ -3,14 +3,13 @@
3 * 3 *
4 * Licensed under GPLv2, see file LICENSE in this source tree. 4 * Licensed under GPLv2, see file LICENSE in this source tree.
5 */ 5 */
6
7//kbuild:lib-y += missing_syscalls.o 6//kbuild:lib-y += missing_syscalls.o
8 7
9/*#include <linux/timex.h> - for struct timex, but may collide with <time.h> */
10#include <sys/syscall.h>
11#include "libbb.h" 8#include "libbb.h"
12 9
13#if defined(ANDROID) || defined(__ANDROID__) 10#if defined(ANDROID) || defined(__ANDROID__)
11/*# include <linux/timex.h> - for struct timex, but may collide with <time.h> */
12# include <sys/syscall.h>
14pid_t getsid(pid_t pid) 13pid_t getsid(pid_t pid)
15{ 14{
16 return syscall(__NR_getsid, pid); 15 return syscall(__NR_getsid, pid);
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c
index 1c24f0d10..569a6fc34 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -14,14 +14,6 @@
14 * 14 *
15 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 15 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
16 */ 16 */
17#include <sys/prctl.h>
18#ifndef PR_SET_NAME
19#define PR_SET_NAME 15
20#endif
21#ifndef PR_GET_NAME
22#define PR_GET_NAME 16
23#endif
24
25#include "busybox.h" /* uses applet tables */ 17#include "busybox.h" /* uses applet tables */
26#include "NUM_APPLETS.h" 18#include "NUM_APPLETS.h"
27 19
@@ -29,6 +21,13 @@
29#define NOEXEC_SUPPORT ((NUM_APPLETS > 1) && (ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE)) 21#define NOEXEC_SUPPORT ((NUM_APPLETS > 1) && (ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE))
30 22
31#if defined(__linux__) && (NUM_APPLETS > 1) 23#if defined(__linux__) && (NUM_APPLETS > 1)
24# include <sys/prctl.h>
25# ifndef PR_SET_NAME
26# define PR_SET_NAME 15
27# endif
28# ifndef PR_GET_NAME
29# define PR_GET_NAME 16
30# endif
32void FAST_FUNC set_task_comm(const char *comm) 31void FAST_FUNC set_task_comm(const char *comm)
33{ 32{
34 /* okay if too long (truncates) */ 33 /* okay if too long (truncates) */
diff --git a/networking/httpd.c b/networking/httpd.c
index 74196a4f1..9439e206c 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -1046,6 +1046,7 @@ static void send_headers(int responseNum)
1046 /* Fixed size 29-byte string. Example: Sun, 06 Nov 1994 08:49:37 GMT */ 1046 /* Fixed size 29-byte string. Example: Sun, 06 Nov 1994 08:49:37 GMT */
1047 char date_str[40]; /* using a bit larger buffer to paranoia reasons */ 1047 char date_str[40]; /* using a bit larger buffer to paranoia reasons */
1048 1048
1049 struct tm tm;
1049 const char *responseString = ""; 1050 const char *responseString = "";
1050 const char *infoString = NULL; 1051 const char *infoString = NULL;
1051#if ENABLE_FEATURE_HTTPD_ERROR_PAGES 1052#if ENABLE_FEATURE_HTTPD_ERROR_PAGES
@@ -1074,7 +1075,8 @@ static void send_headers(int responseNum)
1074 * always fit into those kbytes. 1075 * always fit into those kbytes.
1075 */ 1076 */
1076 1077
1077 strftime(date_str, sizeof(date_str), RFC1123FMT, gmtime(&timer)); 1078 strftime(date_str, sizeof(date_str), RFC1123FMT, gmtime_r(&timer, &tm));
1079 /* ^^^ using gmtime_r() instead of gmtime() to not use static data */
1078 len = sprintf(iobuf, 1080 len = sprintf(iobuf,
1079 "HTTP/1.0 %d %s\r\n" 1081 "HTTP/1.0 %d %s\r\n"
1080 "Content-type: %s\r\n" 1082 "Content-type: %s\r\n"
@@ -1128,7 +1130,7 @@ static void send_headers(int responseNum)
1128#endif 1130#endif
1129 1131
1130 if (file_size != -1) { /* file */ 1132 if (file_size != -1) { /* file */
1131 strftime(date_str, sizeof(date_str), RFC1123FMT, gmtime(&last_mod)); 1133 strftime(date_str, sizeof(date_str), RFC1123FMT, gmtime_r(&last_mod, &tm));
1132#if ENABLE_FEATURE_HTTPD_RANGES 1134#if ENABLE_FEATURE_HTTPD_RANGES
1133 if (responseNum == HTTP_PARTIAL_CONTENT) { 1135 if (responseNum == HTTP_PARTIAL_CONTENT) {
1134 len += sprintf(iobuf + len, 1136 len += sprintf(iobuf + len,
diff --git a/networking/ifconfig.c b/networking/ifconfig.c
index 61d91788a..5c47abc16 100644
--- a/networking/ifconfig.c
+++ b/networking/ifconfig.c
@@ -338,6 +338,7 @@ int ifconfig_main(int argc UNUSED_PARAM, char **argv)
338 char *p; 338 char *p;
339 /*char host[128];*/ 339 /*char host[128];*/
340 const char *host = NULL; /* make gcc happy */ 340 const char *host = NULL; /* make gcc happy */
341 IF_FEATURE_IFCONFIG_STATUS(char *show_all_param;)
341 342
342 did_flags = 0; 343 did_flags = 0;
343#if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS 344#if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS
@@ -349,15 +350,16 @@ int ifconfig_main(int argc UNUSED_PARAM, char **argv)
349 ++argv; 350 ++argv;
350 351
351#if ENABLE_FEATURE_IFCONFIG_STATUS 352#if ENABLE_FEATURE_IFCONFIG_STATUS
352 if (argv[0] && (argv[0][0] == '-' && argv[0][1] == 'a' && !argv[0][2])) { 353 show_all_param = NULL;
353 interface_opt_a = 1; 354 if (argv[0] && argv[0][0] == '-' && argv[0][1] == 'a' && !argv[0][2]) {
354 ++argv; 355 ++argv;
356 show_all_param = IFNAME_SHOW_DOWNED_TOO;
355 } 357 }
356#endif 358#endif
357 359
358 if (!argv[0] || !argv[1]) { /* one or no args */ 360 if (!argv[0] || !argv[1]) { /* one or no args */
359#if ENABLE_FEATURE_IFCONFIG_STATUS 361#if ENABLE_FEATURE_IFCONFIG_STATUS
360 return display_interfaces(argv[0] /* can be NULL */); 362 return display_interfaces(argv[0] ? argv[0] : show_all_param);
361#else 363#else
362 bb_error_msg_and_die("no support for status display"); 364 bb_error_msg_and_die("no support for status display");
363#endif 365#endif
diff --git a/networking/interface.c b/networking/interface.c
index 89427f2f4..e5e55d8d4 100644
--- a/networking/interface.c
+++ b/networking/interface.c
@@ -318,31 +318,37 @@ struct interface {
318 char name[IFNAMSIZ]; /* interface name */ 318 char name[IFNAMSIZ]; /* interface name */
319 short type; /* if type */ 319 short type; /* if type */
320 short flags; /* various flags */ 320 short flags; /* various flags */
321 int tx_queue_len; /* transmit queue length */
322
323 /* these should be contiguous, zeroed in one go in if_fetch(): */
324#define FIRST_TO_ZERO metric
321 int metric; /* routing metric */ 325 int metric; /* routing metric */
322 int mtu; /* MTU value */ 326 int mtu; /* MTU value */
323 int tx_queue_len; /* transmit queue length */
324 struct ifmap map; /* hardware setup */ 327 struct ifmap map; /* hardware setup */
325 struct sockaddr addr; /* IP address */ 328 struct sockaddr addr; /* IP address */
326 struct sockaddr dstaddr; /* P-P IP address */ 329 struct sockaddr dstaddr; /* P-P IP address */
327 struct sockaddr broadaddr; /* IP broadcast address */ 330 struct sockaddr broadaddr; /* IP broadcast address */
328 struct sockaddr netmask; /* IP network mask */ 331 struct sockaddr netmask; /* IP network mask */
329 int has_ip;
330 char hwaddr[32]; /* HW address */ 332 char hwaddr[32]; /* HW address */
331 int statistics_valid; 333#define LAST_TO_ZERO hwaddr
334
335 smallint has_ip;
336 smallint statistics_valid;
332 struct user_net_device_stats stats; /* statistics */ 337 struct user_net_device_stats stats; /* statistics */
338#if 0 /* UNUSED */
333 int keepalive; /* keepalive value for SLIP */ 339 int keepalive; /* keepalive value for SLIP */
334 int outfill; /* outfill value for SLIP */ 340 int outfill; /* outfill value for SLIP */
341#endif
335}; 342};
336 343
337 344struct iface_list {
338smallint interface_opt_a; /* show all interfaces */ 345 struct interface *int_list, *int_last;
339 346};
340static struct interface *int_list, *int_last;
341 347
342 348
343#if 0 349#if 0
344/* like strcmp(), but knows about numbers */ 350/* like strcmp(), but knows about numbers */
345except that the freshly added calls to xatoul() brf on ethernet aliases with 351except that the freshly added calls to xatoul() barf on ethernet aliases with
346uClibc with e.g.: ife->name='lo' name='eth0:1' 352uClibc with e.g.: ife->name='lo' name='eth0:1'
347static int nstrcmp(const char *a, const char *b) 353static int nstrcmp(const char *a, const char *b)
348{ 354{
@@ -368,11 +374,11 @@ static int nstrcmp(const char *a, const char *b)
368} 374}
369#endif 375#endif
370 376
371static struct interface *add_interface(char *name) 377static struct interface *add_interface(struct iface_list *ilist, char *name)
372{ 378{
373 struct interface *ife, **nextp, *new; 379 struct interface *ife, **nextp, *new;
374 380
375 for (ife = int_last; ife; ife = ife->prev) { 381 for (ife = ilist->int_last; ife; ife = ife->prev) {
376 int n = /*n*/strcmp(ife->name, name); 382 int n = /*n*/strcmp(ife->name, name);
377 383
378 if (n == 0) 384 if (n == 0)
@@ -383,43 +389,43 @@ static struct interface *add_interface(char *name)
383 389
384 new = xzalloc(sizeof(*new)); 390 new = xzalloc(sizeof(*new));
385 strncpy_IFNAMSIZ(new->name, name); 391 strncpy_IFNAMSIZ(new->name, name);
386 nextp = ife ? &ife->next : &int_list; 392
393 nextp = ife ? &ife->next : &ilist->int_list;
387 new->prev = ife; 394 new->prev = ife;
388 new->next = *nextp; 395 new->next = *nextp;
389 if (new->next) 396 if (new->next)
390 new->next->prev = new; 397 new->next->prev = new;
391 else 398 else
392 int_last = new; 399 ilist->int_last = new;
393 *nextp = new; 400 *nextp = new;
394 return new; 401 return new;
395} 402}
396 403
397static char *get_name(char *name, char *p) 404static char *get_name(char name[IFNAMSIZ], char *p)
398{ 405{
399 /* Extract <name> from nul-terminated p where p matches 406 /* Extract NAME from nul-terminated p of the form "<whitespace>NAME:"
400 * <name>: after leading whitespace. 407 * If match is not made, set NAME to "" and return unchanged p.
401 * If match is not made, set name empty and return unchanged p
402 */ 408 */
403 char *nameend; 409 char *nameend;
404 char *namestart = skip_whitespace(p); 410 char *namestart;
405 411
406 nameend = namestart; 412 nameend = namestart = skip_whitespace(p);
407 while (*nameend && *nameend != ':' && !isspace(*nameend)) 413
408 nameend++; 414 for (;;) {
409 if (*nameend == ':') { 415 if ((nameend - namestart) >= IFNAMSIZ)
410 if ((nameend - namestart) < IFNAMSIZ) { 416 break; /* interface name too large - return "" */
417 if (*nameend == ':') {
411 memcpy(name, namestart, nameend - namestart); 418 memcpy(name, namestart, nameend - namestart);
412 name[nameend - namestart] = '\0'; 419 name[nameend - namestart] = '\0';
413 p = nameend; 420 return nameend + 1;
414 } else {
415 /* Interface name too large */
416 name[0] = '\0';
417 } 421 }
418 } else { 422 nameend++;
419 /* trailing ':' not found - return empty */ 423 /* isspace, NUL, any control char? */
420 name[0] = '\0'; 424 if ((unsigned char)*nameend <= (unsigned char)' ')
425 break; /* trailing ':' not found - return "" */
421 } 426 }
422 return p + 1; 427 name[0] = '\0';
428 return p;
423} 429}
424 430
425/* If scanf supports size qualifiers for %n conversions, then we can 431/* If scanf supports size qualifiers for %n conversions, then we can
@@ -435,7 +441,10 @@ static char *get_name(char *name, char *p)
435/* "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu" */ 441/* "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu" */
436/* }; */ 442/* }; */
437 443
438 /* Lie about the size of the int pointed to for %n. */ 444/* We use %n for unavailable data in older versions of /proc/net/dev formats.
445 * This results in bogus stores to ife->FOO members corresponding to
446 * %n specifiers (even the size of integers may not match).
447 */
439#if INT_MAX == LONG_MAX 448#if INT_MAX == LONG_MAX
440static const char *const ss_fmt[] = { 449static const char *const ss_fmt[] = {
441 "%n%llu%u%u%u%u%n%n%n%llu%u%u%u%u%u", 450 "%n%llu%u%u%u%u%n%n%n%llu%u%u%u%u%u",
@@ -448,7 +457,6 @@ static const char *const ss_fmt[] = {
448 "%llu%llu%lu%lu%lu%lu%n%n%llu%llu%lu%lu%lu%lu%lu", 457 "%llu%llu%lu%lu%lu%lu%n%n%llu%llu%lu%lu%lu%lu%lu",
449 "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu" 458 "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu"
450}; 459};
451
452#endif 460#endif
453 461
454static void get_dev_fields(char *bp, struct interface *ife, int procnetdev_vsn) 462static void get_dev_fields(char *bp, struct interface *ife, int procnetdev_vsn)
@@ -456,22 +464,22 @@ static void get_dev_fields(char *bp, struct interface *ife, int procnetdev_vsn)
456 memset(&ife->stats, 0, sizeof(struct user_net_device_stats)); 464 memset(&ife->stats, 0, sizeof(struct user_net_device_stats));
457 465
458 sscanf(bp, ss_fmt[procnetdev_vsn], 466 sscanf(bp, ss_fmt[procnetdev_vsn],
459 &ife->stats.rx_bytes, /* missing for 0 */ 467 &ife->stats.rx_bytes, /* missing for v0 */
460 &ife->stats.rx_packets, 468 &ife->stats.rx_packets,
461 &ife->stats.rx_errors, 469 &ife->stats.rx_errors,
462 &ife->stats.rx_dropped, 470 &ife->stats.rx_dropped,
463 &ife->stats.rx_fifo_errors, 471 &ife->stats.rx_fifo_errors,
464 &ife->stats.rx_frame_errors, 472 &ife->stats.rx_frame_errors,
465 &ife->stats.rx_compressed, /* missing for <= 1 */ 473 &ife->stats.rx_compressed, /* missing for v0, v1 */
466 &ife->stats.rx_multicast, /* missing for <= 1 */ 474 &ife->stats.rx_multicast, /* missing for v0, v1 */
467 &ife->stats.tx_bytes, /* missing for 0 */ 475 &ife->stats.tx_bytes, /* missing for v0 */
468 &ife->stats.tx_packets, 476 &ife->stats.tx_packets,
469 &ife->stats.tx_errors, 477 &ife->stats.tx_errors,
470 &ife->stats.tx_dropped, 478 &ife->stats.tx_dropped,
471 &ife->stats.tx_fifo_errors, 479 &ife->stats.tx_fifo_errors,
472 &ife->stats.collisions, 480 &ife->stats.collisions,
473 &ife->stats.tx_carrier_errors, 481 &ife->stats.tx_carrier_errors,
474 &ife->stats.tx_compressed /* missing for <= 1 */ 482 &ife->stats.tx_compressed /* missing for v0, v1 */
475 ); 483 );
476 484
477 if (procnetdev_vsn <= 1) { 485 if (procnetdev_vsn <= 1) {
@@ -494,31 +502,25 @@ static int procnetdev_version(char *buf)
494 return 0; 502 return 0;
495} 503}
496 504
497static int if_readconf(void) 505static void if_readconf(struct iface_list *ilist)
498{ 506{
499 int numreqs = 30; 507 int numreqs = 30;
500 struct ifconf ifc; 508 struct ifconf ifc;
501 struct ifreq *ifr; 509 struct ifreq *ifr;
502 int n, err = -1; 510 int n;
503 int skfd; 511 int skfd;
504 512
505 ifc.ifc_buf = NULL; 513 ifc.ifc_buf = NULL;
506 514
507 /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets 515 /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
508 (as of 2.1.128) */ 516 (as of 2.1.128) */
509 skfd = socket(AF_INET, SOCK_DGRAM, 0); 517 skfd = xsocket(AF_INET, SOCK_DGRAM, 0);
510 if (skfd < 0) {
511 bb_perror_msg("error: no inet socket available");
512 return -1;
513 }
514 518
515 for (;;) { 519 for (;;) {
516 ifc.ifc_len = sizeof(struct ifreq) * numreqs; 520 ifc.ifc_len = sizeof(struct ifreq) * numreqs;
517 ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len); 521 ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);
518 522
519 if (ioctl_or_warn(skfd, SIOCGIFCONF, &ifc) < 0) { 523 xioctl(skfd, SIOCGIFCONF, &ifc);
520 goto out;
521 }
522 if (ifc.ifc_len == (int)(sizeof(struct ifreq) * numreqs)) { 524 if (ifc.ifc_len == (int)(sizeof(struct ifreq) * numreqs)) {
523 /* assume it overflowed and try again */ 525 /* assume it overflowed and try again */
524 numreqs += 10; 526 numreqs += 10;
@@ -529,67 +531,54 @@ static int if_readconf(void)
529 531
530 ifr = ifc.ifc_req; 532 ifr = ifc.ifc_req;
531 for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) { 533 for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
532 add_interface(ifr->ifr_name); 534 add_interface(ilist, ifr->ifr_name);
533 ifr++; 535 ifr++;
534 } 536 }
535 err = 0;
536 537
537 out:
538 close(skfd); 538 close(skfd);
539 free(ifc.ifc_buf); 539 free(ifc.ifc_buf);
540 return err;
541} 540}
542 541
543static int if_readlist_proc(char *target) 542static int if_readlist_proc(struct iface_list *ilist, char *ifname)
544{ 543{
545 static smallint proc_read;
546
547 FILE *fh; 544 FILE *fh;
548 char buf[512]; 545 char buf[512];
549 struct interface *ife; 546 struct interface *ife;
550 int err, procnetdev_vsn; 547 int procnetdev_vsn;
551 548 int ret;
552 if (proc_read)
553 return 0;
554 if (!target)
555 proc_read = 1;
556 549
557 fh = fopen_or_warn(_PATH_PROCNET_DEV, "r"); 550 fh = fopen_or_warn(_PATH_PROCNET_DEV, "r");
558 if (!fh) { 551 if (!fh) {
559 return if_readconf(); 552 return 0; /* "not found" */
560 } 553 }
561 fgets(buf, sizeof buf, fh); /* eat line */ 554 fgets(buf, sizeof buf, fh); /* eat line */
562 fgets(buf, sizeof buf, fh); 555 fgets(buf, sizeof buf, fh);
563 556
564 procnetdev_vsn = procnetdev_version(buf); 557 procnetdev_vsn = procnetdev_version(buf);
565 558
566 err = 0; 559 ret = 0;
567 while (fgets(buf, sizeof buf, fh)) { 560 while (fgets(buf, sizeof buf, fh)) {
568 char *s, name[128]; 561 char *s, name[IFNAMSIZ];
569 562
570 s = get_name(name, buf); 563 s = get_name(name, buf);
571 ife = add_interface(name); 564 ife = add_interface(ilist, name);
572 get_dev_fields(s, ife, procnetdev_vsn); 565 get_dev_fields(s, ife, procnetdev_vsn);
573 ife->statistics_valid = 1; 566 ife->statistics_valid = 1;
574 if (target && strcmp(target, name) == 0) 567 if (ifname && strcmp(ifname, name) == 0) {
568 ret = 1; /* found */
575 break; 569 break;
576 } 570 }
577 if (ferror(fh)) {
578 bb_perror_msg(_PATH_PROCNET_DEV);
579 err = -1;
580 proc_read = 0;
581 } 571 }
582 fclose(fh); 572 fclose(fh);
583 return err; 573 return ret;
584} 574}
585 575
586static int if_readlist(void) 576static void if_readlist(struct iface_list *ilist, char *ifname)
587{ 577{
588 int err = if_readlist_proc(NULL); 578 int found = if_readlist_proc(ilist, ifname);
589 /* Needed in order to get ethN:M aliases */ 579 /* Needed in order to get ethN:M aliases */
590 if (!err) 580 if (!found)
591 err = if_readconf(); 581 if_readconf(ilist);
592 return err;
593} 582}
594 583
595/* Fetch the interface configuration from the kernel. */ 584/* Fetch the interface configuration from the kernel. */
@@ -608,24 +597,29 @@ static int if_fetch(struct interface *ife)
608 } 597 }
609 ife->flags = ifr.ifr_flags; 598 ife->flags = ifr.ifr_flags;
610 599
600 /* set up default values if ioctl's would fail */
601 ife->tx_queue_len = -1; /* unknown value */
602 memset(&ife->FIRST_TO_ZERO, 0,
603 offsetof(struct interface, LAST_TO_ZERO)
604 - offsetof(struct interface, FIRST_TO_ZERO)
605 + sizeof(ife->LAST_TO_ZERO)
606 );
607
611 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 608 strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
612 memset(ife->hwaddr, 0, 32);
613 if (ioctl(skfd, SIOCGIFHWADDR, &ifr) >= 0) 609 if (ioctl(skfd, SIOCGIFHWADDR, &ifr) >= 0)
614 memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8); 610 memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
615 611
612//er.... why this _isnt_ inside if()?
616 ife->type = ifr.ifr_hwaddr.sa_family; 613 ife->type = ifr.ifr_hwaddr.sa_family;
617 614
618 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 615 strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
619 ife->metric = 0;
620 if (ioctl(skfd, SIOCGIFMETRIC, &ifr) >= 0) 616 if (ioctl(skfd, SIOCGIFMETRIC, &ifr) >= 0)
621 ife->metric = ifr.ifr_metric; 617 ife->metric = ifr.ifr_metric;
622 618
623 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 619 strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
624 ife->mtu = 0;
625 if (ioctl(skfd, SIOCGIFMTU, &ifr) >= 0) 620 if (ioctl(skfd, SIOCGIFMTU, &ifr) >= 0)
626 ife->mtu = ifr.ifr_mtu; 621 ife->mtu = ifr.ifr_mtu;
627 622
628 memset(&ife->map, 0, sizeof(struct ifmap));
629#ifdef SIOCGIFMAP 623#ifdef SIOCGIFMAP
630 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 624 strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
631 if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0) 625 if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0)
@@ -634,31 +628,24 @@ static int if_fetch(struct interface *ife)
634 628
635#ifdef HAVE_TXQUEUELEN 629#ifdef HAVE_TXQUEUELEN
636 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 630 strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
637 ife->tx_queue_len = -1; /* unknown value */
638 if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) >= 0) 631 if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) >= 0)
639 ife->tx_queue_len = ifr.ifr_qlen; 632 ife->tx_queue_len = ifr.ifr_qlen;
640#else
641 ife->tx_queue_len = -1; /* unknown value */
642#endif 633#endif
643 634
644 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 635 strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
645 ifr.ifr_addr.sa_family = AF_INET; 636 ifr.ifr_addr.sa_family = AF_INET;
646 memset(&ife->addr, 0, sizeof(struct sockaddr));
647 if (ioctl(skfd, SIOCGIFADDR, &ifr) == 0) { 637 if (ioctl(skfd, SIOCGIFADDR, &ifr) == 0) {
648 ife->has_ip = 1; 638 ife->has_ip = 1;
649 ife->addr = ifr.ifr_addr; 639 ife->addr = ifr.ifr_addr;
650 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 640 strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
651 memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
652 if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) >= 0) 641 if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) >= 0)
653 ife->dstaddr = ifr.ifr_dstaddr; 642 ife->dstaddr = ifr.ifr_dstaddr;
654 643
655 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 644 strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
656 memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
657 if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) >= 0) 645 if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) >= 0)
658 ife->broadaddr = ifr.ifr_broadaddr; 646 ife->broadaddr = ifr.ifr_broadaddr;
659 647
660 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 648 strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
661 memset(&ife->netmask, 0, sizeof(struct sockaddr));
662 if (ioctl(skfd, SIOCGIFNETMASK, &ifr) >= 0) 649 if (ioctl(skfd, SIOCGIFNETMASK, &ifr) >= 0)
663 ife->netmask = ifr.ifr_netmask; 650 ife->netmask = ifr.ifr_netmask;
664 } 651 }
@@ -1020,10 +1007,12 @@ static void ife_print(struct interface *ptr)
1020 1007
1021 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */ 1008 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
1022 printf(" MTU:%d Metric:%d", ptr->mtu, ptr->metric ? ptr->metric : 1); 1009 printf(" MTU:%d Metric:%d", ptr->mtu, ptr->metric ? ptr->metric : 1);
1010#if 0
1023#ifdef SIOCSKEEPALIVE 1011#ifdef SIOCSKEEPALIVE
1024 if (ptr->outfill || ptr->keepalive) 1012 if (ptr->outfill || ptr->keepalive)
1025 printf(" Outfill:%d Keepalive:%d", ptr->outfill, ptr->keepalive); 1013 printf(" Outfill:%d Keepalive:%d", ptr->outfill, ptr->keepalive);
1026#endif 1014#endif
1015#endif
1027 bb_putchar('\n'); 1016 bb_putchar('\n');
1028 1017
1029 /* If needed, display the interface statistics. */ 1018 /* If needed, display the interface statistics. */
@@ -1077,67 +1066,44 @@ static void ife_print(struct interface *ptr)
1077 bb_putchar('\n'); 1066 bb_putchar('\n');
1078} 1067}
1079 1068
1080static int do_if_print(struct interface *ife) /*, int *opt_a)*/ 1069static int do_if_print(struct interface *ife, int show_downed_too)
1081{ 1070{
1082 int res; 1071 int res;
1083 1072
1084 res = do_if_fetch(ife); 1073 res = do_if_fetch(ife);
1085 if (res >= 0) { 1074 if (res >= 0) {
1086 if ((ife->flags & IFF_UP) || interface_opt_a) 1075 if ((ife->flags & IFF_UP) || show_downed_too)
1087 ife_print(ife); 1076 ife_print(ife);
1088 } 1077 }
1089 return res; 1078 return res;
1090} 1079}
1091 1080
1092static struct interface *lookup_interface(char *name) 1081int FAST_FUNC display_interfaces(char *ifname)
1093{
1094 struct interface *ife = NULL;
1095
1096 if (if_readlist_proc(name) < 0)
1097 return NULL;
1098 ife = add_interface(name);
1099 return ife;
1100}
1101
1102#ifdef UNUSED
1103static int for_all_interfaces(int (*doit) (struct interface *, void *),
1104 void *cookie)
1105{ 1082{
1106 struct interface *ife; 1083 struct interface *ife;
1084 int res;
1085 struct iface_list ilist;
1107 1086
1108 if (!int_list && (if_readlist() < 0)) 1087 ilist.int_list = NULL;
1109 return -1; 1088 ilist.int_last = NULL;
1110 for (ife = int_list; ife; ife = ife->next) { 1089 if_readlist(&ilist, ifname != IFNAME_SHOW_DOWNED_TOO ? ifname : NULL);
1111 int err = doit(ife, cookie);
1112 if (err)
1113 return err;
1114 }
1115 return 0;
1116}
1117#endif
1118 1090
1119/* for ipv4 add/del modes */ 1091 if (!ifname || ifname == IFNAME_SHOW_DOWNED_TOO) {
1120static int if_print(char *ifname) 1092 for (ife = ilist.int_list; ife; ife = ife->next) {
1121{
1122 struct interface *ife;
1123 int res;
1124 1093
1125 if (!ifname) { 1094 BUILD_BUG_ON((int)(intptr_t)IFNAME_SHOW_DOWNED_TOO != 1);
1126 /*res = for_all_interfaces(do_if_print, &interface_opt_a);*/ 1095
1127 if (!int_list && (if_readlist() < 0)) 1096 res = do_if_print(ife, (int)(intptr_t)ifname);
1128 return -1; 1097 if (res < 0)
1129 for (ife = int_list; ife; ife = ife->next) { 1098 goto ret;
1130 int err = do_if_print(ife); /*, &interface_opt_a);*/
1131 if (err)
1132 return err;
1133 } 1099 }
1134 return 0; 1100 return 0;
1135 } 1101 }
1136 ife = lookup_interface(ifname); 1102
1137 res = do_if_fetch(ife); 1103 ife = add_interface(&ilist, ifname);
1138 if (res >= 0) 1104 res = do_if_print(ife, /*show_downed_too:*/ 1);
1139 ife_print(ife); 1105 ret:
1140 return res; 1106 return (res < 0); /* status < 0 == 1 -- error */
1141} 1107}
1142 1108
1143#if ENABLE_FEATURE_HWIB 1109#if ENABLE_FEATURE_HWIB
@@ -1153,12 +1119,3 @@ int FAST_FUNC in_ib(const char *bufp, struct sockaddr *sap)
1153 return 0; 1119 return 0;
1154} 1120}
1155#endif 1121#endif
1156
1157int FAST_FUNC display_interfaces(char *ifname)
1158{
1159 int status;
1160
1161 status = if_print(ifname);
1162
1163 return (status < 0); /* status < 0 == 1 -- error */
1164}
diff --git a/networking/ip.c b/networking/ip.c
index accf90759..9ecb99abb 100644
--- a/networking/ip.c
+++ b/networking/ip.c
@@ -157,7 +157,7 @@
157//usage:#define iplink_trivial_usage 157//usage:#define iplink_trivial_usage
158//usage: /*Usage:iplink*/"set IFACE [up|down] [arp on|off] [multicast on|off]\n" 158//usage: /*Usage:iplink*/"set IFACE [up|down] [arp on|off] [multicast on|off]\n"
159//usage: " [promisc on|off] [mtu NUM] [name NAME] [qlen NUM] [address MAC]\n" 159//usage: " [promisc on|off] [mtu NUM] [name NAME] [qlen NUM] [address MAC]\n"
160//usage: " [master IFACE | nomaster]\n" 160//usage: " [master IFACE | nomaster]"
161// * short help shows only "set" command, long help continues (with just one "\n") 161// * short help shows only "set" command, long help continues (with just one "\n")
162// * and shows all other commands: 162// * and shows all other commands:
163//usage:#define iplink_full_usage "\n" 163//usage:#define iplink_full_usage "\n"
diff --git a/networking/libiproute/ipaddress.c b/networking/libiproute/ipaddress.c
index d7f888176..9ec665b69 100644
--- a/networking/libiproute/ipaddress.c
+++ b/networking/libiproute/ipaddress.c
@@ -570,7 +570,10 @@ int FAST_FUNC ipaddr_list_or_flush(char **argv, int flush)
570 } 570 }
571 571
572 for (l = linfo; l; l = l->next) { 572 for (l = linfo; l; l = l->next) {
573 if (no_link || print_linkinfo(&l->h) == 0) { 573 if (no_link
574 || (oneline || print_linkinfo(&l->h) == 0)
575 /* ^^^^^^^^^ "ip -oneline a" does not print link info */
576 ) {
574 struct ifinfomsg *ifi = NLMSG_DATA(&l->h); 577 struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
575 if (G_filter.family != AF_PACKET) 578 if (G_filter.family != AF_PACKET)
576 print_selected_addrinfo(ifi->ifi_index, ainfo); 579 print_selected_addrinfo(ifi->ifi_index, ainfo);
diff --git a/networking/ntpd.c b/networking/ntpd.c
index 17e5c7da6..8205ab271 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -165,8 +165,12 @@
165 * Using exact power of 2 (1/8) results in smaller code 165 * Using exact power of 2 (1/8) results in smaller code
166 */ 166 */
167#define SLEW_THRESHOLD 0.125 167#define SLEW_THRESHOLD 0.125
168//^^^^^^^^^^^^^^^^^^^^^^^^^^ TODO: man adjtimex about tmx.offset:
169// "Since Linux 2.6.26, the supplied value is clamped to the range (-0.5s, +0.5s)"
170// - can use this larger value instead?
171
168/* Stepout threshold (sec). std ntpd uses 900 (11 mins (!)) */ 172/* Stepout threshold (sec). std ntpd uses 900 (11 mins (!)) */
169#define WATCH_THRESHOLD 128 173//UNUSED: #define WATCH_THRESHOLD 128
170/* NB: set WATCH_THRESHOLD to ~60 when debugging to save time) */ 174/* NB: set WATCH_THRESHOLD to ~60 when debugging to save time) */
171//UNUSED: #define PANIC_THRESHOLD 1000 /* panic threshold (sec) */ 175//UNUSED: #define PANIC_THRESHOLD 1000 /* panic threshold (sec) */
172 176
@@ -419,6 +423,7 @@ struct globals {
419 uint8_t discipline_state; // doc calls it c.state 423 uint8_t discipline_state; // doc calls it c.state
420 uint8_t poll_exp; // s.poll 424 uint8_t poll_exp; // s.poll
421 int polladj_count; // c.count 425 int polladj_count; // c.count
426 int FREQHOLD_cnt;
422 long kernel_freq_drift; 427 long kernel_freq_drift;
423 peer_t *last_update_peer; 428 peer_t *last_update_peer;
424 double last_update_offset; // c.last 429 double last_update_offset; // c.last
@@ -1034,6 +1039,7 @@ step_time(double offset)
1034 tval = tvn.tv_sec; 1039 tval = tvn.tv_sec;
1035 strftime_YYYYMMDDHHMMSS(buf, sizeof(buf), &tval); 1040 strftime_YYYYMMDDHHMMSS(buf, sizeof(buf), &tval);
1036 bb_error_msg("setting time to %s.%06u (offset %+fs)", buf, (unsigned)tvn.tv_usec, offset); 1041 bb_error_msg("setting time to %s.%06u (offset %+fs)", buf, (unsigned)tvn.tv_usec, offset);
1042 //maybe? G.FREQHOLD_cnt = 0;
1037 1043
1038 /* Correct various fields which contain time-relative values: */ 1044 /* Correct various fields which contain time-relative values: */
1039 1045
@@ -1709,39 +1715,96 @@ update_local_clock(peer_t *p)
1709 tmx.freq = G.discipline_freq_drift * 65536e6; 1715 tmx.freq = G.discipline_freq_drift * 65536e6;
1710#endif 1716#endif
1711 tmx.modes = ADJ_OFFSET | ADJ_STATUS | ADJ_TIMECONST;// | ADJ_MAXERROR | ADJ_ESTERROR; 1717 tmx.modes = ADJ_OFFSET | ADJ_STATUS | ADJ_TIMECONST;// | ADJ_MAXERROR | ADJ_ESTERROR;
1712 tmx.constant = (int)G.poll_exp - 4; 1718
1713 /* EXPERIMENTAL.
1714 * The below if statement should be unnecessary, but...
1715 * It looks like Linux kernel's PLL is far too gentle in changing
1716 * tmx.freq in response to clock offset. Offset keeps growing
1717 * and eventually we fall back to smaller poll intervals.
1718 * We can make correction more aggressive (about x2) by supplying
1719 * PLL time constant which is one less than the real one.
1720 * To be on a safe side, let's do it only if offset is significantly
1721 * larger than jitter.
1722 */
1723 if (G.offset_to_jitter_ratio >= TIMECONST_HACK_GATE)
1724 tmx.constant--;
1725 tmx.offset = (long)(offset * 1000000); /* usec */ 1719 tmx.offset = (long)(offset * 1000000); /* usec */
1726 if (SLEW_THRESHOLD < STEP_THRESHOLD) { 1720 if (SLEW_THRESHOLD < STEP_THRESHOLD) {
1727 if (tmx.offset > (long)(SLEW_THRESHOLD * 1000000)) { 1721 if (tmx.offset > (long)(SLEW_THRESHOLD * 1000000)) {
1728 tmx.offset = (long)(SLEW_THRESHOLD * 1000000); 1722 tmx.offset = (long)(SLEW_THRESHOLD * 1000000);
1729 tmx.constant--;
1730 } 1723 }
1731 if (tmx.offset < -(long)(SLEW_THRESHOLD * 1000000)) { 1724 if (tmx.offset < -(long)(SLEW_THRESHOLD * 1000000)) {
1732 tmx.offset = -(long)(SLEW_THRESHOLD * 1000000); 1725 tmx.offset = -(long)(SLEW_THRESHOLD * 1000000);
1733 tmx.constant--;
1734 } 1726 }
1735 } 1727 }
1736 if (tmx.constant < 0)
1737 tmx.constant = 0;
1738 1728
1739 tmx.status = STA_PLL; 1729 tmx.status = STA_PLL;
1730 if (G.FREQHOLD_cnt != 0) {
1731 /* man adjtimex on STA_FREQHOLD:
1732 * "Normally adjustments made via ADJ_OFFSET result in dampened
1733 * frequency adjustments also being made.
1734 * This flag prevents the small frequency adjustment from being
1735 * made when correcting for an ADJ_OFFSET value."
1736 *
1737 * Use this flag for a few first adjustments at the beginning
1738 * of ntpd execution, otherwise even relatively small initial
1739 * offset tend to cause largish changes to in-kernel tmx.freq.
1740 * If ntpd was restarted due to e.g. switch to another network,
1741 * this destroys already well-established tmx.freq value.
1742 */
1743 if (G.FREQHOLD_cnt < 0) {
1744 /* Initialize it */
1745// Example: a laptop whose clock runs slower when hibernated,
1746// after wake up it still has good tmx.freq, but accumulated ~0.5 sec offset:
1747// Run with code where initial G.FREQHOLD_cnt was always 8:
1748//15:17:52.947 no valid datapoints, no peer selected
1749//15:17:56.515 update from:<IP> offset:+0.485133 delay:0.157762 jitter:0.209310 clock drift:-1.393ppm tc:4
1750//15:17:57.719 update from:<IP> offset:+0.483825 delay:0.158070 jitter:0.181159 clock drift:-1.393ppm tc:4
1751//15:17:59.925 update from:<IP> offset:+0.479504 delay:0.158147 jitter:0.156657 clock drift:-1.393ppm tc:4
1752//15:18:33.322 update from:<IP> offset:+0.428119 delay:0.158317 jitter:0.138071 clock drift:-1.393ppm tc:4
1753//15:19:06.718 update from:<IP> offset:+0.376932 delay:0.158276 jitter:0.122075 clock drift:-1.393ppm tc:4
1754//15:19:39.114 update from:<IP> offset:+0.327022 delay:0.158384 jitter:0.108538 clock drift:-1.393ppm tc:4
1755//15:20:12.715 update from:<IP> offset:+0.275596 delay:0.158297 jitter:0.097292 clock drift:-1.393ppm tc:4
1756//15:20:45.111 update from:<IP> offset:+0.225715 delay:0.158271 jitter:0.087841 clock drift:-1.393ppm tc:4
1757// If allwed to continue, it would start increasing tmx.freq now.
1758// Instead, it was ^Ced, and started anew:
1759//15:21:15.043 no valid datapoints, no peer selected
1760//15:21:17.408 update from:<IP> offset:+0.175910 delay:0.158314 jitter:0.076683 clock drift:-1.393ppm tc:4
1761//15:21:19.774 update from:<IP> offset:+0.171784 delay:0.158401 jitter:0.066436 clock drift:-1.393ppm tc:4
1762//15:21:22.140 update from:<IP> offset:+0.171660 delay:0.158592 jitter:0.057536 clock drift:-1.393ppm tc:4
1763//15:21:22.140 update from:<IP> offset:+0.167126 delay:0.158507 jitter:0.049792 clock drift:-1.393ppm tc:4
1764//15:21:55.696 update from:<IP> offset:+0.115223 delay:0.158277 jitter:0.050240 clock drift:-1.393ppm tc:4
1765//15:22:29.093 update from:<IP> offset:+0.068051 delay:0.158243 jitter:0.049405 clock drift:-1.393ppm tc:5
1766//15:23:02.490 update from:<IP> offset:+0.051632 delay:0.158215 jitter:0.043545 clock drift:-1.393ppm tc:5
1767//15:23:34.726 update from:<IP> offset:+0.039984 delay:0.158157 jitter:0.038106 clock drift:-1.393ppm tc:5
1768// STA_FREQHOLD no longer set, started increasing tmx.freq now:
1769//15:24:06.961 update from:<IP> offset:+0.030968 delay:0.158190 jitter:0.033306 clock drift:+2.387ppm tc:5
1770//15:24:40.357 update from:<IP> offset:+0.023648 delay:0.158211 jitter:0.029072 clock drift:+5.454ppm tc:5
1771//15:25:13.774 update from:<IP> offset:+0.018068 delay:0.157660 jitter:0.025288 clock drift:+7.728ppm tc:5
1772//15:26:19.173 update from:<IP> offset:+0.010057 delay:0.157969 jitter:0.022255 clock drift:+8.361ppm tc:6
1773//15:27:26.602 update from:<IP> offset:+0.006737 delay:0.158103 jitter:0.019316 clock drift:+8.792ppm tc:6
1774//15:28:33.030 update from:<IP> offset:+0.004513 delay:0.158294 jitter:0.016765 clock drift:+9.080ppm tc:6
1775//15:29:40.617 update from:<IP> offset:+0.002787 delay:0.157745 jitter:0.014543 clock drift:+9.258ppm tc:6
1776//15:30:47.045 update from:<IP> offset:+0.001324 delay:0.157709 jitter:0.012594 clock drift:+9.342ppm tc:6
1777//15:31:53.473 update from:<IP> offset:+0.000007 delay:0.158142 jitter:0.010922 clock drift:+9.343ppm tc:6
1778//15:32:58.902 update from:<IP> offset:-0.000728 delay:0.158222 jitter:0.009454 clock drift:+9.298ppm tc:6
1779 /*
1780 * This expression would choose 15 in the above example.
1781 */
1782 G.FREQHOLD_cnt = 8 + ((unsigned)(abs(tmx.offset)) >> 16);
1783 }
1784 G.FREQHOLD_cnt--;
1785 tmx.status |= STA_FREQHOLD;
1786 }
1740 if (G.ntp_status & LI_PLUSSEC) 1787 if (G.ntp_status & LI_PLUSSEC)
1741 tmx.status |= STA_INS; 1788 tmx.status |= STA_INS;
1742 if (G.ntp_status & LI_MINUSSEC) 1789 if (G.ntp_status & LI_MINUSSEC)
1743 tmx.status |= STA_DEL; 1790 tmx.status |= STA_DEL;
1744 1791
1792 tmx.constant = (int)G.poll_exp - 4;
1793 /* EXPERIMENTAL.
1794 * The below if statement should be unnecessary, but...
1795 * It looks like Linux kernel's PLL is far too gentle in changing
1796 * tmx.freq in response to clock offset. Offset keeps growing
1797 * and eventually we fall back to smaller poll intervals.
1798 * We can make correction more aggressive (about x2) by supplying
1799 * PLL time constant which is one less than the real one.
1800 * To be on a safe side, let's do it only if offset is significantly
1801 * larger than jitter.
1802 */
1803 if (G.offset_to_jitter_ratio >= TIMECONST_HACK_GATE)
1804 tmx.constant--;
1805 if (tmx.constant < 0)
1806 tmx.constant = 0;
1807
1745 //tmx.esterror = (uint32_t)(clock_jitter * 1e6); 1808 //tmx.esterror = (uint32_t)(clock_jitter * 1e6);
1746 //tmx.maxerror = (uint32_t)((sys_rootdelay / 2 + sys_rootdisp) * 1e6); 1809 //tmx.maxerror = (uint32_t)((sys_rootdelay / 2 + sys_rootdisp) * 1e6);
1747 rc = adjtimex(&tmx); 1810 rc = adjtimex(&tmx);
@@ -2227,6 +2290,7 @@ static NOINLINE void ntp_init(char **argv)
2227 if (BURSTPOLL != 0) 2290 if (BURSTPOLL != 0)
2228 G.poll_exp = BURSTPOLL; /* speeds up initial sync */ 2291 G.poll_exp = BURSTPOLL; /* speeds up initial sync */
2229 G.last_script_run = G.reftime = G.last_update_recv_time = gettime1900d(); /* sets G.cur_time too */ 2292 G.last_script_run = G.reftime = G.last_update_recv_time = gettime1900d(); /* sets G.cur_time too */
2293 G.FREQHOLD_cnt = -1;
2230 2294
2231 /* Parse options */ 2295 /* Parse options */
2232 peers = NULL; 2296 peers = NULL;
diff --git a/networking/tcpudp.c b/networking/tcpudp.c
index a90e3f80a..c914221ae 100644
--- a/networking/tcpudp.c
+++ b/networking/tcpudp.c
@@ -270,17 +270,22 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv)
270 270
271 tcp = (applet_name[0] == 't'); 271 tcp = (applet_name[0] == 't');
272 272
273 /* "+": stop on first non-option */
273#ifdef SSLSVD 274#ifdef SSLSVD
274 opts = getopt32(argv, "^+" 275 opts = getopt32(argv, "^+"
275 "c:+C:i:x:u:l:Eb:+hpt:vU:/:Z:K:" /* -c NUM, -b NUM */ 276 "c:+C:i:x:u:l:Eb:+hpt:vU:/:Z:K:" /* -c NUM, -b NUM */
277 "\0"
276 /* 3+ args, -i at most once, -p implies -h, -v is a counter */ 278 /* 3+ args, -i at most once, -p implies -h, -v is a counter */
277 "\0" "-3:i--i:ph:vv", 279 "-3:i--i:ph:vv",
278 &cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname, 280 &cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname,
279 &backlog, &str_t, &ssluser, &root, &cert, &key, &verbose 281 &backlog, &str_t, &ssluser, &root, &cert, &key, &verbose
280 ); 282 );
281#else 283#else
282 /* "+": stop on first non-option */ 284 opts = getopt32(argv, "^+"
283 opts = getopt32(argv, "+c:+C:i:x:u:l:Eb:hpt:v", 285 "c:+C:i:x:u:l:Eb:+hpt:v" /* -c NUM, -b NUM */
286 "\0"
287 /* 3+ args, -i at most once, -p implies -h, -v is a counter */
288 "-3:i--i:ph:vv",
284 &cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname, 289 &cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname,
285 &backlog, &str_t, &verbose 290 &backlog, &str_t, &verbose
286 ); 291 );
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
index 04939e707..13059f106 100644
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
@@ -314,7 +314,7 @@ int udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
314 314
315void udhcp_sp_setup(void) FAST_FUNC; 315void udhcp_sp_setup(void) FAST_FUNC;
316void udhcp_sp_fd_set(struct pollfd *pfds, int extra_fd) FAST_FUNC; 316void udhcp_sp_fd_set(struct pollfd *pfds, int extra_fd) FAST_FUNC;
317int udhcp_sp_read(struct pollfd *pfds) FAST_FUNC; 317int udhcp_sp_read(void) FAST_FUNC;
318 318
319int udhcp_read_interface(const char *interface, int *ifindex, uint32_t *nip, uint8_t *mac) FAST_FUNC; 319int udhcp_read_interface(const char *interface, int *ifindex, uint32_t *nip, uint8_t *mac) FAST_FUNC;
320 320
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
index 35c99e89c..289df66ee 100644
--- a/networking/udhcp/d6_dhcpc.c
+++ b/networking/udhcp/d6_dhcpc.c
@@ -1375,13 +1375,12 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1375 /* yah, I know, *you* say it would never happen */ 1375 /* yah, I know, *you* say it would never happen */
1376 timeout = INT_MAX; 1376 timeout = INT_MAX;
1377 continue; /* back to main loop */ 1377 continue; /* back to main loop */
1378 } /* if select timed out */ 1378 } /* if poll timed out */
1379 1379
1380 /* select() didn't timeout, something happened */ 1380 /* poll() didn't timeout, something happened */
1381 1381
1382 /* Is it a signal? */ 1382 /* Is it a signal? */
1383 /* note: udhcp_sp_read checks poll result before reading */ 1383 switch (udhcp_sp_read()) {
1384 switch (udhcp_sp_read(pfds)) {
1385 case SIGUSR1: 1384 case SIGUSR1:
1386 client_config.first_secs = 0; /* make secs field count from 0 */ 1385 client_config.first_secs = 0; /* make secs field count from 0 */
1387 already_waited_sec = 0; 1386 already_waited_sec = 0;
@@ -1416,7 +1415,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1416 } 1415 }
1417 1416
1418 /* Is it a packet? */ 1417 /* Is it a packet? */
1419 if (listen_mode == LISTEN_NONE || !pfds[1].revents) 1418 if (!pfds[1].revents)
1420 continue; /* no */ 1419 continue; /* no */
1421 1420
1422 { 1421 {
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index 35694fbe3..90b07bf4b 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -1574,13 +1574,12 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1574 /* yah, I know, *you* say it would never happen */ 1574 /* yah, I know, *you* say it would never happen */
1575 timeout = INT_MAX; 1575 timeout = INT_MAX;
1576 continue; /* back to main loop */ 1576 continue; /* back to main loop */
1577 } /* if select timed out */ 1577 } /* if poll timed out */
1578 1578
1579 /* select() didn't timeout, something happened */ 1579 /* poll() didn't timeout, something happened */
1580 1580
1581 /* Is it a signal? */ 1581 /* Is it a signal? */
1582 /* note: udhcp_sp_read checks poll result before reading */ 1582 switch (udhcp_sp_read()) {
1583 switch (udhcp_sp_read(pfds)) {
1584 case SIGUSR1: 1583 case SIGUSR1:
1585 client_config.first_secs = 0; /* make secs field count from 0 */ 1584 client_config.first_secs = 0; /* make secs field count from 0 */
1586 already_waited_sec = 0; 1585 already_waited_sec = 0;
@@ -1615,7 +1614,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1615 } 1614 }
1616 1615
1617 /* Is it a packet? */ 1616 /* Is it a packet? */
1618 if (listen_mode == LISTEN_NONE || !pfds[1].revents) 1617 if (!pfds[1].revents)
1619 continue; /* no */ 1618 continue; /* no */
1620 1619
1621 { 1620 {
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c
index 093239536..19f94a2d7 100644
--- a/networking/udhcp/dhcpd.c
+++ b/networking/udhcp/dhcpd.c
@@ -853,6 +853,9 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
853 /* Would rather not do read_config before daemonization - 853 /* Would rather not do read_config before daemonization -
854 * otherwise NOMMU machines will parse config twice */ 854 * otherwise NOMMU machines will parse config twice */
855 read_config(argv[0] ? argv[0] : DHCPD_CONF_FILE); 855 read_config(argv[0] ? argv[0] : DHCPD_CONF_FILE);
856 /* prevent poll timeout overflow */
857 if (server_config.auto_time > INT_MAX / 1000)
858 server_config.auto_time = INT_MAX / 1000;
856 859
857 /* Make sure fd 0,1,2 are open */ 860 /* Make sure fd 0,1,2 are open */
858 bb_sanitize_stdio(); 861 bb_sanitize_stdio();
@@ -914,21 +917,31 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
914 } 917 }
915 918
916 udhcp_sp_fd_set(pfds, server_socket); 919 udhcp_sp_fd_set(pfds, server_socket);
917 tv = timeout_end - monotonic_sec(); 920
918 retval = 0; 921 new_tv:
919 if (!server_config.auto_time || tv > 0) { 922 tv = -1;
920 retval = poll(pfds, 2, server_config.auto_time ? tv * 1000 : -1); 923 if (server_config.auto_time) {
921 } 924 tv = timeout_end - monotonic_sec();
922 if (retval == 0) { 925 if (tv <= 0) {
923 write_leases(); 926 write_leases:
924 goto continue_with_autotime; 927 write_leases();
928 goto continue_with_autotime;
929 }
930 tv *= 1000;
925 } 931 }
926 if (retval < 0 && errno != EINTR) { 932
927 log1("error on select"); 933 /* Block here waiting for either signal or packet */
928 continue; 934 retval = poll(pfds, 2, tv);
935 if (retval <= 0) {
936 if (retval == 0)
937 goto write_leases;
938 if (errno == EINTR)
939 goto new_tv;
940 /* < 0 and not EINTR: should not happen */
941 bb_perror_msg_and_die("poll");
929 } 942 }
930 943
931 switch (udhcp_sp_read(pfds)) { 944 if (pfds[0].revents) switch (udhcp_sp_read()) {
932 case SIGUSR1: 945 case SIGUSR1:
933 bb_error_msg("received %s", "SIGUSR1"); 946 bb_error_msg("received %s", "SIGUSR1");
934 write_leases(); 947 write_leases();
@@ -938,12 +951,16 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
938 bb_error_msg("received %s", "SIGTERM"); 951 bb_error_msg("received %s", "SIGTERM");
939 write_leases(); 952 write_leases();
940 goto ret0; 953 goto ret0;
941 case 0: /* no signal: read a packet */
942 break;
943 default: /* signal or error (probably EINTR): back to select */
944 continue;
945 } 954 }
946 955
956 /* Is it a packet? */
957 if (!pfds[1].revents)
958 continue; /* no */
959
960 /* Note: we do not block here, we block on poll() instead.
961 * Blocking here would prevent SIGTERM from working:
962 * socket read inside this call is restarted on caught signals.
963 */
947 bytes = udhcp_recv_kernel_packet(&packet, server_socket); 964 bytes = udhcp_recv_kernel_packet(&packet, server_socket);
948 if (bytes < 0) { 965 if (bytes < 0) {
949 /* bytes can also be -2 ("bad packet data") */ 966 /* bytes can also be -2 ("bad packet data") */
diff --git a/networking/udhcp/signalpipe.c b/networking/udhcp/signalpipe.c
index b101b4ce4..2ff78f0f2 100644
--- a/networking/udhcp/signalpipe.c
+++ b/networking/udhcp/signalpipe.c
@@ -40,6 +40,7 @@ void FAST_FUNC udhcp_sp_setup(void)
40 xpiped_pair(signal_pipe); 40 xpiped_pair(signal_pipe);
41 close_on_exec_on(signal_pipe.rd); 41 close_on_exec_on(signal_pipe.rd);
42 close_on_exec_on(signal_pipe.wr); 42 close_on_exec_on(signal_pipe.wr);
43 ndelay_on(signal_pipe.rd);
43 ndelay_on(signal_pipe.wr); 44 ndelay_on(signal_pipe.wr);
44 bb_signals(0 45 bb_signals(0
45 + (1 << SIGUSR1) 46 + (1 << SIGUSR1)
@@ -61,20 +62,20 @@ void FAST_FUNC udhcp_sp_fd_set(struct pollfd pfds[2], int extra_fd)
61 pfds[1].fd = extra_fd; 62 pfds[1].fd = extra_fd;
62 pfds[1].events = POLLIN; 63 pfds[1].events = POLLIN;
63 } 64 }
65 /* this simplifies "is extra_fd ready?" tests elsewhere: */
66 pfds[1].revents = 0;
64} 67}
65 68
66/* Read a signal from the signal pipe. Returns 0 if there is 69/* Read a signal from the signal pipe. Returns 0 if there is
67 * no signal, -1 on error (and sets errno appropriately), and 70 * no signal, -1 on error (and sets errno appropriately), and
68 * your signal on success */ 71 * your signal on success */
69int FAST_FUNC udhcp_sp_read(struct pollfd pfds[2]) 72int FAST_FUNC udhcp_sp_read(void)
70{ 73{
71 unsigned char sig; 74 unsigned char sig;
72 75
73 if (!pfds[0].revents) 76 /* Can't block here, fd is in nonblocking mode */
74 return 0;
75
76 if (safe_read(signal_pipe.rd, &sig, 1) != 1) 77 if (safe_read(signal_pipe.rd, &sig, 1) != 1)
77 return -1; 78 return 0;
78 79
79 return sig; 80 return sig;
80} 81}
diff --git a/networking/wget.c b/networking/wget.c
index b9225fac0..150bc8e12 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -1017,7 +1017,6 @@ static void download_one_url(const char *url)
1017 len_and_sockaddr *lsa; 1017 len_and_sockaddr *lsa;
1018 FILE *sfp; /* socket to web/ftp server */ 1018 FILE *sfp; /* socket to web/ftp server */
1019 FILE *dfp; /* socket to ftp server (data) */ 1019 FILE *dfp; /* socket to ftp server (data) */
1020 char *proxy = NULL;
1021 char *fname_out_alloc; 1020 char *fname_out_alloc;
1022 char *redirected_path = NULL; 1021 char *redirected_path = NULL;
1023 struct host_info server; 1022 struct host_info server;
@@ -1033,13 +1032,14 @@ static void download_one_url(const char *url)
1033 /* Use the proxy if necessary */ 1032 /* Use the proxy if necessary */
1034 use_proxy = (strcmp(G.proxy_flag, "off") != 0); 1033 use_proxy = (strcmp(G.proxy_flag, "off") != 0);
1035 if (use_proxy) { 1034 if (use_proxy) {
1036 proxy = getenv(target.protocol[0] == 'f' ? "ftp_proxy" : "http_proxy"); 1035 char *proxy = getenv(target.protocol[0] == 'f' ? "ftp_proxy" : "http_proxy");
1037//FIXME: what if protocol is https? Ok to use http_proxy? 1036//FIXME: what if protocol is https? Ok to use http_proxy?
1038 use_proxy = (proxy && proxy[0]); 1037 use_proxy = (proxy && proxy[0]);
1039 if (use_proxy) 1038 if (use_proxy)
1040 parse_url(proxy, &server); 1039 parse_url(proxy, &server);
1041 } 1040 }
1042 if (!use_proxy) { 1041 if (!use_proxy) {
1042 server.protocol = target.protocol;
1043 server.port = target.port; 1043 server.port = target.port;
1044 if (ENABLE_FEATURE_IPV6) { 1044 if (ENABLE_FEATURE_IPV6) {
1045 //free(server.allocated); - can't be non-NULL 1045 //free(server.allocated); - can't be non-NULL
@@ -1104,7 +1104,7 @@ static void download_one_url(const char *url)
1104 /* Open socket to http(s) server */ 1104 /* Open socket to http(s) server */
1105#if ENABLE_FEATURE_WGET_OPENSSL 1105#if ENABLE_FEATURE_WGET_OPENSSL
1106 /* openssl (and maybe internal TLS) support is configured */ 1106 /* openssl (and maybe internal TLS) support is configured */
1107 if (target.protocol == P_HTTPS) { 1107 if (server.protocol == P_HTTPS) {
1108 /* openssl-based helper 1108 /* openssl-based helper
1109 * Inconvenient API since we can't give it an open fd 1109 * Inconvenient API since we can't give it an open fd
1110 */ 1110 */
@@ -1128,7 +1128,7 @@ static void download_one_url(const char *url)
1128#elif ENABLE_FEATURE_WGET_HTTPS 1128#elif ENABLE_FEATURE_WGET_HTTPS
1129 /* Only internal TLS support is configured */ 1129 /* Only internal TLS support is configured */
1130 sfp = open_socket(lsa); 1130 sfp = open_socket(lsa);
1131 if (target.protocol == P_HTTPS) 1131 if (server.protocol == P_HTTPS)
1132 spawn_ssl_client(server.host, fileno(sfp), /*flags*/ 0); 1132 spawn_ssl_client(server.host, fileno(sfp), /*flags*/ 0);
1133#else 1133#else
1134 /* ssl (https) support is not configured */ 1134 /* ssl (https) support is not configured */
diff --git a/procps/top.c b/procps/top.c
index b777c494e..075c96c27 100644
--- a/procps/top.c
+++ b/procps/top.c
@@ -180,7 +180,7 @@ struct globals {
180#else 180#else
181 cmp_funcp sort_function[SORT_DEPTH]; 181 cmp_funcp sort_function[SORT_DEPTH];
182 struct save_hist *prev_hist; 182 struct save_hist *prev_hist;
183 int prev_hist_count; 183 unsigned prev_hist_count;
184 jiffy_counts_t cur_jif, prev_jif; 184 jiffy_counts_t cur_jif, prev_jif;
185 /* int hist_iterations; */ 185 /* int hist_iterations; */
186 unsigned total_pcpu; 186 unsigned total_pcpu;
@@ -189,7 +189,7 @@ struct globals {
189#if ENABLE_FEATURE_TOP_SMP_CPU 189#if ENABLE_FEATURE_TOP_SMP_CPU
190 /* Per CPU samples: current and last */ 190 /* Per CPU samples: current and last */
191 jiffy_counts_t *cpu_jif, *cpu_prev_jif; 191 jiffy_counts_t *cpu_jif, *cpu_prev_jif;
192 int num_cpus; 192 unsigned num_cpus;
193#endif 193#endif
194#if ENABLE_FEATURE_TOP_INTERACTIVE 194#if ENABLE_FEATURE_TOP_INTERACTIVE
195 char kbd_input[KEYCODE_BUFFER_SIZE]; 195 char kbd_input[KEYCODE_BUFFER_SIZE];
@@ -355,7 +355,8 @@ static void do_stats(void)
355{ 355{
356 top_status_t *cur; 356 top_status_t *cur;
357 pid_t pid; 357 pid_t pid;
358 int i, last_i, n; 358 int n;
359 unsigned i, last_i;
359 struct save_hist *new_hist; 360 struct save_hist *new_hist;
360 361
361 get_jiffy_counts(); 362 get_jiffy_counts();
@@ -607,7 +608,6 @@ static NOINLINE void display_process_list(int lines_rem, int scr_width)
607 }; 608 };
608 609
609 top_status_t *s; 610 top_status_t *s;
610 char vsz_str_buf[8];
611 unsigned long total_memory = display_header(scr_width, &lines_rem); /* or use total_vsz? */ 611 unsigned long total_memory = display_header(scr_width, &lines_rem); /* or use total_vsz? */
612 /* xxx_shift and xxx_scale variables allow us to replace 612 /* xxx_shift and xxx_scale variables allow us to replace
613 * expensive divides with multiply and shift */ 613 * expensive divides with multiply and shift */
@@ -688,19 +688,18 @@ static NOINLINE void display_process_list(int lines_rem, int scr_width)
688 lines_rem = ntop - G_scroll_ofs; 688 lines_rem = ntop - G_scroll_ofs;
689 s = top + G_scroll_ofs; 689 s = top + G_scroll_ofs;
690 while (--lines_rem >= 0) { 690 while (--lines_rem >= 0) {
691 char vsz_str_buf[8];
691 unsigned col; 692 unsigned col;
693
692 CALC_STAT(pmem, (s->vsz*pmem_scale + pmem_half) >> pmem_shift); 694 CALC_STAT(pmem, (s->vsz*pmem_scale + pmem_half) >> pmem_shift);
693#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE 695#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
694 CALC_STAT(pcpu, (s->pcpu*pcpu_scale + pcpu_half) >> pcpu_shift); 696 CALC_STAT(pcpu, (s->pcpu*pcpu_scale + pcpu_half) >> pcpu_shift);
695#endif 697#endif
696 698
697 if (s->vsz >= 100000) 699 smart_ulltoa5(s->vsz, vsz_str_buf, " mgtpezy");
698 sprintf(vsz_str_buf, "%6ldm", s->vsz/1024);
699 else
700 sprintf(vsz_str_buf, "%7lu", s->vsz);
701 /* PID PPID USER STAT VSZ %VSZ [%CPU] COMMAND */ 700 /* PID PPID USER STAT VSZ %VSZ [%CPU] COMMAND */
702 col = snprintf(line_buf, scr_width, 701 col = snprintf(line_buf, scr_width,
703 "\n" "%5u%6u %-8.8s %s%s" FMT 702 "\n" "%5u%6u %-8.8s %s %.5s" FMT
704 IF_FEATURE_TOP_SMP_PROCESS(" %3d") 703 IF_FEATURE_TOP_SMP_PROCESS(" %3d")
705 IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE(FMT) 704 IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE(FMT)
706 " ", 705 " ",
@@ -710,7 +709,7 @@ static NOINLINE void display_process_list(int lines_rem, int scr_width)
710 IF_FEATURE_TOP_SMP_PROCESS(, s->last_seen_on_cpu) 709 IF_FEATURE_TOP_SMP_PROCESS(, s->last_seen_on_cpu)
711 IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE(, SHOW_STAT(pcpu)) 710 IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE(, SHOW_STAT(pcpu))
712 ); 711 );
713 if ((int)(col + 1) < scr_width) 712 if ((int)(scr_width - col) > 1)
714 read_cmdline(line_buf + col, scr_width - col, s->pid, s->comm); 713 read_cmdline(line_buf + col, scr_width - col, s->pid, s->comm);
715 fputs(line_buf, stdout); 714 fputs(line_buf, stdout);
716 /* printf(" %d/%d %lld/%lld", s->pcpu, total_pcpu, 715 /* printf(" %d/%d %lld/%lld", s->pcpu, total_pcpu,
@@ -897,7 +896,8 @@ enum {
897 | PSSCAN_PID 896 | PSSCAN_PID
898 | PSSCAN_SMAPS 897 | PSSCAN_SMAPS
899 | PSSCAN_COMM, 898 | PSSCAN_COMM,
900 EXIT_MASK = (unsigned)-1, 899 EXIT_MASK = 0,
900 NO_RESCAN_MASK = (unsigned)-1,
901}; 901};
902 902
903#if ENABLE_FEATURE_TOP_INTERACTIVE 903#if ENABLE_FEATURE_TOP_INTERACTIVE
@@ -935,7 +935,7 @@ static unsigned handle_input(unsigned scan_mask, unsigned interval)
935 } 935 }
936 if (c == KEYCODE_HOME) { 936 if (c == KEYCODE_HOME) {
937 G_scroll_ofs = 0; 937 G_scroll_ofs = 0;
938 break; 938 goto normalize_ofs;
939 } 939 }
940 if (c == KEYCODE_END) { 940 if (c == KEYCODE_END) {
941 G_scroll_ofs = ntop - G.lines / 2; 941 G_scroll_ofs = ntop - G.lines / 2;
@@ -952,7 +952,7 @@ static unsigned handle_input(unsigned scan_mask, unsigned interval)
952 G_scroll_ofs = ntop - 1; 952 G_scroll_ofs = ntop - 1;
953 if (G_scroll_ofs < 0) 953 if (G_scroll_ofs < 0)
954 G_scroll_ofs = 0; 954 G_scroll_ofs = 0;
955 break; 955 return NO_RESCAN_MASK;
956 } 956 }
957 957
958 c |= 0x20; /* lowercase */ 958 c |= 0x20; /* lowercase */
@@ -1157,6 +1157,7 @@ int top_main(int argc UNUSED_PARAM, char **argv)
1157#endif 1157#endif
1158 1158
1159 while (scan_mask != EXIT_MASK) { 1159 while (scan_mask != EXIT_MASK) {
1160 unsigned new_mask;
1160 procps_status_t *p = NULL; 1161 procps_status_t *p = NULL;
1161 1162
1162 if (OPT_BATCH_MODE) { 1163 if (OPT_BATCH_MODE) {
@@ -1234,21 +1235,32 @@ int top_main(int argc UNUSED_PARAM, char **argv)
1234#else 1235#else
1235 qsort(top, ntop, sizeof(top_status_t), (void*)(sort_function[0])); 1236 qsort(top, ntop, sizeof(top_status_t), (void*)(sort_function[0]));
1236#endif 1237#endif
1237 display_process_list(G.lines, col);
1238 } 1238 }
1239#if ENABLE_FEATURE_TOPMEM 1239#if ENABLE_FEATURE_TOPMEM
1240 else { /* TOPMEM */ 1240 else { /* TOPMEM */
1241 qsort(topmem, ntop, sizeof(topmem_status_t), (void*)topmem_sort); 1241 qsort(topmem, ntop, sizeof(topmem_status_t), (void*)topmem_sort);
1242 }
1243#endif
1244 IF_FEATURE_TOP_INTERACTIVE(display:)
1245 IF_FEATURE_TOPMEM(if (scan_mask != TOPMEM_MASK)) {
1246 display_process_list(G.lines, col);
1247 }
1248#if ENABLE_FEATURE_TOPMEM
1249 else { /* TOPMEM */
1242 display_topmem_process_list(G.lines, col); 1250 display_topmem_process_list(G.lines, col);
1243 } 1251 }
1244#endif 1252#endif
1245 clearmems();
1246 if (iterations >= 0 && !--iterations) 1253 if (iterations >= 0 && !--iterations)
1247 break; 1254 break;
1248#if !ENABLE_FEATURE_TOP_INTERACTIVE 1255#if !ENABLE_FEATURE_TOP_INTERACTIVE
1256 clearmems();
1249 sleep(interval); 1257 sleep(interval);
1250#else 1258#else
1251 scan_mask = handle_input(scan_mask, interval); 1259 new_mask = handle_input(scan_mask, interval);
1260 if (new_mask == NO_RESCAN_MASK)
1261 goto display;
1262 scan_mask = new_mask;
1263 clearmems();
1252#endif 1264#endif
1253 } /* end of "while (not Q)" */ 1265 } /* end of "while (not Q)" */
1254 1266
diff --git a/runit/svlogd.c b/runit/svlogd.c
index 412290ca9..13de2570f 100644
--- a/runit/svlogd.c
+++ b/runit/svlogd.c
@@ -347,11 +347,13 @@ static unsigned pmatch(const char *p, const char *s, unsigned len)
347/* NUL terminated */ 347/* NUL terminated */
348static void fmt_time_human_30nul(char *s, char dt_delim) 348static void fmt_time_human_30nul(char *s, char dt_delim)
349{ 349{
350 struct tm tm;
350 struct tm *ptm; 351 struct tm *ptm;
351 struct timeval tv; 352 struct timeval tv;
352 353
353 gettimeofday(&tv, NULL); 354 gettimeofday(&tv, NULL);
354 ptm = gmtime(&tv.tv_sec); 355 ptm = gmtime_r(&tv.tv_sec, &tm);
356 /* ^^^ using gmtime_r() instead of gmtime() to not use static data */
355 sprintf(s, "%04u-%02u-%02u%c%02u:%02u:%02u.%06u000", 357 sprintf(s, "%04u-%02u-%02u%c%02u:%02u:%02u.%06u000",
356 (unsigned)(1900 + ptm->tm_year), 358 (unsigned)(1900 + ptm->tm_year),
357 (unsigned)(ptm->tm_mon + 1), 359 (unsigned)(ptm->tm_mon + 1),
diff --git a/shell/ash_test/ash-quoting/bkslash_in_varexp.right b/shell/ash_test/ash-quoting/bkslash_in_varexp.right
new file mode 100644
index 000000000..d03047024
--- /dev/null
+++ b/shell/ash_test/ash-quoting/bkslash_in_varexp.right
@@ -0,0 +1,5 @@
1Nothing:
2Nothing:
3Nothing:
4Nothing:
5Ok:0
diff --git a/shell/ash_test/ash-quoting/bkslash_in_varexp.tests b/shell/ash_test/ash-quoting/bkslash_in_varexp.tests
new file mode 100755
index 000000000..6c7b4b0cc
--- /dev/null
+++ b/shell/ash_test/ash-quoting/bkslash_in_varexp.tests
@@ -0,0 +1,16 @@
1x='a]'
2#
3# \] is not a valid escape for ] in set glob expression.
4# Glob sets have no escaping at all:
5# ] can be in a set if it is the first char: []abc],
6# dash can be in a set if it is first or last: [abc-],
7# [ and \ need no protections at all: [a[b\c] is a valid set of 5 chars.
8#
9# bash-4.3.43 misinterprets [a\]] as "set of 'a' or ']'".
10# Correct interpretation is "set of 'a' or '\', followed by ']'".
11#
12echo Nothing:${x#[a\]]}
13echo Nothing:"${x#[a\]]}"
14echo Nothing:${x%[a\]]}
15echo Nothing:"${x%[a\]]}"
16echo Ok:$?
diff --git a/shell/ash_test/ash-quoting/bkslash_in_varexp1.right b/shell/ash_test/ash-quoting/bkslash_in_varexp1.right
new file mode 100644
index 000000000..d03047024
--- /dev/null
+++ b/shell/ash_test/ash-quoting/bkslash_in_varexp1.right
@@ -0,0 +1,5 @@
1Nothing:
2Nothing:
3Nothing:
4Nothing:
5Ok:0
diff --git a/shell/ash_test/ash-quoting/bkslash_in_varexp1.tests b/shell/ash_test/ash-quoting/bkslash_in_varexp1.tests
new file mode 100755
index 000000000..3c817eae1
--- /dev/null
+++ b/shell/ash_test/ash-quoting/bkslash_in_varexp1.tests
@@ -0,0 +1,6 @@
1x=a
2echo Nothing:${x#[]a]}
3echo Nothing:"${x#[]a]}"
4echo Nothing:${x%[]a]}
5echo Nothing:"${x%[]a]}"
6echo Ok:$?
diff --git a/shell/ash_test/ash-quoting/squote_in_varexp.right b/shell/ash_test/ash-quoting/squote_in_varexp.right
new file mode 100644
index 000000000..a75c0bfd6
--- /dev/null
+++ b/shell/ash_test/ash-quoting/squote_in_varexp.right
@@ -0,0 +1,5 @@
1z
2z
3y
4y
5Ok:0
diff --git a/shell/ash_test/ash-quoting/squote_in_varexp.tests b/shell/ash_test/ash-quoting/squote_in_varexp.tests
new file mode 100755
index 000000000..a2d05a246
--- /dev/null
+++ b/shell/ash_test/ash-quoting/squote_in_varexp.tests
@@ -0,0 +1,6 @@
1x=yz
2echo ${x#'y'}
3echo "${x#'y'}"
4echo ${x%'z'}
5echo "${x%'z'}"
6echo Ok:$?
diff --git a/shell/ash_test/ash-quoting/squote_in_varexp1.right b/shell/ash_test/ash-quoting/squote_in_varexp1.right
new file mode 100644
index 000000000..9d0add3c5
--- /dev/null
+++ b/shell/ash_test/ash-quoting/squote_in_varexp1.right
@@ -0,0 +1,3 @@
1Nothing:
2Nothing:
3Ok:0
diff --git a/shell/ash_test/ash-quoting/squote_in_varexp1.tests b/shell/ash_test/ash-quoting/squote_in_varexp1.tests
new file mode 100755
index 000000000..efb380db3
--- /dev/null
+++ b/shell/ash_test/ash-quoting/squote_in_varexp1.tests
@@ -0,0 +1,4 @@
1x='\\\\'
2printf Nothing:'%s\n' ${x#\\\\\\\\}
3printf Nothing:'%s\n' "${x#\\\\\\\\}"
4echo Ok:$?
diff --git a/shell/ash_test/ash-quoting/squote_in_varexp2.right b/shell/ash_test/ash-quoting/squote_in_varexp2.right
new file mode 100644
index 000000000..9d0add3c5
--- /dev/null
+++ b/shell/ash_test/ash-quoting/squote_in_varexp2.right
@@ -0,0 +1,3 @@
1Nothing:
2Nothing:
3Ok:0
diff --git a/shell/ash_test/ash-quoting/squote_in_varexp2.tests b/shell/ash_test/ash-quoting/squote_in_varexp2.tests
new file mode 100755
index 000000000..806ad12b9
--- /dev/null
+++ b/shell/ash_test/ash-quoting/squote_in_varexp2.tests
@@ -0,0 +1,4 @@
1x='\\\\'
2printf Nothing:'%s\n' ${x#'\\\\'}
3printf Nothing:'%s\n' "${x#'\\\\'}"
4echo Ok:$?
diff --git a/shell/hush.c b/shell/hush.c
index e005b0a20..6e64efb70 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -4488,7 +4488,7 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign
4488 } 4488 }
4489 if (ch == end_ch 4489 if (ch == end_ch
4490# if BASH_SUBSTR || BASH_PATTERN_SUBST 4490# if BASH_SUBSTR || BASH_PATTERN_SUBST
4491 || ch == end_char2 4491 || ch == end_char2
4492# endif 4492# endif
4493 ) { 4493 ) {
4494 if (!dbl) 4494 if (!dbl)
@@ -4500,6 +4500,7 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign
4500 } 4500 }
4501 } 4501 }
4502 o_addchr(dest, ch); 4502 o_addchr(dest, ch);
4503 //bb_error_msg("%s:o_addchr('%c')", __func__, ch);
4503 if (ch == '(' || ch == '{') { 4504 if (ch == '(' || ch == '{') {
4504 ch = (ch == '(' ? ')' : '}'); 4505 ch = (ch == '(' ? ')' : '}');
4505 if (!add_till_closing_bracket(dest, input, ch)) 4506 if (!add_till_closing_bracket(dest, input, ch))
@@ -4529,7 +4530,7 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign
4529 /* \x. Copy verbatim. Important for \(, \) */ 4530 /* \x. Copy verbatim. Important for \(, \) */
4530 ch = i_getch(input); 4531 ch = i_getch(input);
4531 if (ch == EOF) { 4532 if (ch == EOF) {
4532 syntax_error_unterm_ch(')'); 4533 syntax_error_unterm_ch(end_ch);
4533 return 0; 4534 return 0;
4534 } 4535 }
4535#if 0 4536#if 0
@@ -4540,6 +4541,7 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign
4540 } 4541 }
4541#endif 4542#endif
4542 o_addchr(dest, ch); 4543 o_addchr(dest, ch);
4544 //bb_error_msg("%s:o_addchr('%c') after '\\'", __func__, ch);
4543 continue; 4545 continue;
4544 } 4546 }
4545 } 4547 }
@@ -5842,17 +5844,24 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
5842 unsigned scan_flags = pick_scan(exp_op, *exp_word); 5844 unsigned scan_flags = pick_scan(exp_op, *exp_word);
5843 if (exp_op == *exp_word) /* ## or %% */ 5845 if (exp_op == *exp_word) /* ## or %% */
5844 exp_word++; 5846 exp_word++;
5845 exp_exp_word = encode_then_expand_string(exp_word, /*process_bkslash:*/ 1, /*unbackslash:*/ 1); 5847 debug_printf_expand("expand: exp_word:'%s'\n", exp_word);
5848 /*
5849 * process_bkslash:1 unbackslash:1 breaks this:
5850 * a='a\\'; echo ${a%\\\\} # correct output is: a
5851 * process_bkslash:1 unbackslash:0 breaks this:
5852 * a='a}'; echo ${a%\}} # correct output is: a
5853 */
5854 exp_exp_word = encode_then_expand_string(exp_word, /*process_bkslash:*/ 0, /*unbackslash:*/ 0);
5846 if (exp_exp_word) 5855 if (exp_exp_word)
5847 exp_word = exp_exp_word; 5856 exp_word = exp_exp_word;
5857 debug_printf_expand("expand: exp_exp_word:'%s'\n", exp_word);
5848 /* HACK ALERT. We depend here on the fact that 5858 /* HACK ALERT. We depend here on the fact that
5849 * G.global_argv and results of utoa and get_local_var_value 5859 * G.global_argv and results of utoa and get_local_var_value
5850 * are actually in writable memory: 5860 * are actually in writable memory:
5851 * scan_and_match momentarily stores NULs there. */ 5861 * scan_and_match momentarily stores NULs there. */
5852 t = (char*)val; 5862 t = (char*)val;
5853 loc = scan_and_match(t, exp_word, scan_flags); 5863 loc = scan_and_match(t, exp_word, scan_flags);
5854 //bb_error_msg("op:%c str:'%s' pat:'%s' res:'%s'", 5864 debug_printf_expand("op:%c str:'%s' pat:'%s' res:'%s'\n", exp_op, t, exp_word, loc);
5855 // exp_op, t, exp_word, loc);
5856 free(exp_exp_word); 5865 free(exp_exp_word);
5857 if (loc) { /* match was found */ 5866 if (loc) { /* match was found */
5858 if (scan_flags & SCAN_MATCH_LEFT_HALF) /* #[#] */ 5867 if (scan_flags & SCAN_MATCH_LEFT_HALF) /* #[#] */
@@ -7172,21 +7181,22 @@ static const struct built_in_command *find_builtin(const char *name)
7172#if ENABLE_HUSH_FUNCTIONS 7181#if ENABLE_HUSH_FUNCTIONS
7173static struct function **find_function_slot(const char *name) 7182static struct function **find_function_slot(const char *name)
7174{ 7183{
7184 struct function *funcp;
7175 struct function **funcpp = &G.top_func; 7185 struct function **funcpp = &G.top_func;
7176 while (*funcpp) { 7186
7177 if (strcmp(name, (*funcpp)->name) == 0) { 7187 while ((funcp = *funcpp) != NULL) {
7188 if (strcmp(name, funcp->name) == 0) {
7189 debug_printf_exec("found function '%s'\n", name);
7178 break; 7190 break;
7179 } 7191 }
7180 funcpp = &(*funcpp)->next; 7192 funcpp = &funcp->next;
7181 } 7193 }
7182 return funcpp; 7194 return funcpp;
7183} 7195}
7184 7196
7185static const struct function *find_function(const char *name) 7197static ALWAYS_INLINE const struct function *find_function(const char *name)
7186{ 7198{
7187 const struct function *funcp = *find_function_slot(name); 7199 const struct function *funcp = *find_function_slot(name);
7188 if (funcp)
7189 debug_printf_exec("found function '%s'\n", name);
7190 return funcp; 7200 return funcp;
7191} 7201}
7192 7202
diff --git a/shell/hush_test/hush-quoting/bkslash_in_varexp.right b/shell/hush_test/hush-quoting/bkslash_in_varexp.right
new file mode 100644
index 000000000..d03047024
--- /dev/null
+++ b/shell/hush_test/hush-quoting/bkslash_in_varexp.right
@@ -0,0 +1,5 @@
1Nothing:
2Nothing:
3Nothing:
4Nothing:
5Ok:0
diff --git a/shell/hush_test/hush-quoting/bkslash_in_varexp.tests b/shell/hush_test/hush-quoting/bkslash_in_varexp.tests
new file mode 100755
index 000000000..6c7b4b0cc
--- /dev/null
+++ b/shell/hush_test/hush-quoting/bkslash_in_varexp.tests
@@ -0,0 +1,16 @@
1x='a]'
2#
3# \] is not a valid escape for ] in set glob expression.
4# Glob sets have no escaping at all:
5# ] can be in a set if it is the first char: []abc],
6# dash can be in a set if it is first or last: [abc-],
7# [ and \ need no protections at all: [a[b\c] is a valid set of 5 chars.
8#
9# bash-4.3.43 misinterprets [a\]] as "set of 'a' or ']'".
10# Correct interpretation is "set of 'a' or '\', followed by ']'".
11#
12echo Nothing:${x#[a\]]}
13echo Nothing:"${x#[a\]]}"
14echo Nothing:${x%[a\]]}
15echo Nothing:"${x%[a\]]}"
16echo Ok:$?
diff --git a/shell/hush_test/hush-quoting/bkslash_in_varexp1.right b/shell/hush_test/hush-quoting/bkslash_in_varexp1.right
new file mode 100644
index 000000000..d03047024
--- /dev/null
+++ b/shell/hush_test/hush-quoting/bkslash_in_varexp1.right
@@ -0,0 +1,5 @@
1Nothing:
2Nothing:
3Nothing:
4Nothing:
5Ok:0
diff --git a/shell/hush_test/hush-quoting/bkslash_in_varexp1.tests b/shell/hush_test/hush-quoting/bkslash_in_varexp1.tests
new file mode 100755
index 000000000..3c817eae1
--- /dev/null
+++ b/shell/hush_test/hush-quoting/bkslash_in_varexp1.tests
@@ -0,0 +1,6 @@
1x=a
2echo Nothing:${x#[]a]}
3echo Nothing:"${x#[]a]}"
4echo Nothing:${x%[]a]}
5echo Nothing:"${x%[]a]}"
6echo Ok:$?
diff --git a/shell/hush_test/hush-quoting/squote_in_varexp.right b/shell/hush_test/hush-quoting/squote_in_varexp.right
new file mode 100644
index 000000000..a75c0bfd6
--- /dev/null
+++ b/shell/hush_test/hush-quoting/squote_in_varexp.right
@@ -0,0 +1,5 @@
1z
2z
3y
4y
5Ok:0
diff --git a/shell/hush_test/hush-quoting/squote_in_varexp.tests b/shell/hush_test/hush-quoting/squote_in_varexp.tests
new file mode 100755
index 000000000..a2d05a246
--- /dev/null
+++ b/shell/hush_test/hush-quoting/squote_in_varexp.tests
@@ -0,0 +1,6 @@
1x=yz
2echo ${x#'y'}
3echo "${x#'y'}"
4echo ${x%'z'}
5echo "${x%'z'}"
6echo Ok:$?
diff --git a/shell/hush_test/hush-quoting/squote_in_varexp1.right b/shell/hush_test/hush-quoting/squote_in_varexp1.right
new file mode 100644
index 000000000..9d0add3c5
--- /dev/null
+++ b/shell/hush_test/hush-quoting/squote_in_varexp1.right
@@ -0,0 +1,3 @@
1Nothing:
2Nothing:
3Ok:0
diff --git a/shell/hush_test/hush-quoting/squote_in_varexp1.tests b/shell/hush_test/hush-quoting/squote_in_varexp1.tests
new file mode 100755
index 000000000..efb380db3
--- /dev/null
+++ b/shell/hush_test/hush-quoting/squote_in_varexp1.tests
@@ -0,0 +1,4 @@
1x='\\\\'
2printf Nothing:'%s\n' ${x#\\\\\\\\}
3printf Nothing:'%s\n' "${x#\\\\\\\\}"
4echo Ok:$?
diff --git a/shell/hush_test/hush-quoting/squote_in_varexp2.right b/shell/hush_test/hush-quoting/squote_in_varexp2.right
new file mode 100644
index 000000000..9d0add3c5
--- /dev/null
+++ b/shell/hush_test/hush-quoting/squote_in_varexp2.right
@@ -0,0 +1,3 @@
1Nothing:
2Nothing:
3Ok:0
diff --git a/shell/hush_test/hush-quoting/squote_in_varexp2.tests b/shell/hush_test/hush-quoting/squote_in_varexp2.tests
new file mode 100755
index 000000000..806ad12b9
--- /dev/null
+++ b/shell/hush_test/hush-quoting/squote_in_varexp2.tests
@@ -0,0 +1,4 @@
1x='\\\\'
2printf Nothing:'%s\n' ${x#'\\\\'}
3printf Nothing:'%s\n' "${x#'\\\\'}"
4echo Ok:$?
diff --git a/shell/match.c b/shell/match.c
index fee3cf2a8..ee8abb2db 100644
--- a/shell/match.c
+++ b/shell/match.c
@@ -71,9 +71,11 @@ char* FAST_FUNC scan_and_match(char *string, const char *pattern, unsigned flags
71 if (flags & SCAN_MATCH_LEFT_HALF) { 71 if (flags & SCAN_MATCH_LEFT_HALF) {
72 *loc = '\0'; 72 *loc = '\0';
73 r = fnmatch(pattern, string, 0); 73 r = fnmatch(pattern, string, 0);
74 //bb_error_msg("fnmatch('%s','%s',0):%d", pattern, string, r);
74 *loc = c; 75 *loc = c;
75 } else { 76 } else {
76 r = fnmatch(pattern, loc, 0); 77 r = fnmatch(pattern, loc, 0);
78 //bb_error_msg("fnmatch('%s','%s',0):%d", pattern, loc, r);
77 } 79 }
78 if (r == 0) /* match found */ 80 if (r == 0) /* match found */
79 return loc; 81 return loc;
diff --git a/sysklogd/syslogd_and_logger.c b/sysklogd/syslogd_and_logger.c
index 9bba195d4..94d8273b6 100644
--- a/sysklogd/syslogd_and_logger.c
+++ b/sysklogd/syslogd_and_logger.c
@@ -53,6 +53,7 @@ typedef struct _code {
53static const CODE *const bb_prioritynames = prioritynames; 53static const CODE *const bb_prioritynames = prioritynames;
54static const CODE *const bb_facilitynames = facilitynames; 54static const CODE *const bb_facilitynames = facilitynames;
55 55
56
56#if ENABLE_SYSLOGD 57#if ENABLE_SYSLOGD
57#include "syslogd.c" 58#include "syslogd.c"
58#endif 59#endif
diff --git a/util-linux/ipcs.c b/util-linux/ipcs.c
index 7092ecd92..4863a5c29 100644
--- a/util-linux/ipcs.c
+++ b/util-linux/ipcs.c
@@ -101,8 +101,6 @@ union semun {
101#define TIME 4 101#define TIME 4
102#define PID 5 102#define PID 5
103 103
104static char format;
105
106static void print_perms(int id, struct ipc_perm *ipcp) 104static void print_perms(int id, struct ipc_perm *ipcp)
107{ 105{
108 struct passwd *pw; 106 struct passwd *pw;
@@ -125,8 +123,7 @@ static void print_perms(int id, struct ipc_perm *ipcp)
125 else printf(" %-10d\n", ipcp->gid); 123 else printf(" %-10d\n", ipcp->gid);
126} 124}
127 125
128 126static NOINLINE void do_shm(int format)
129static NOINLINE void do_shm(void)
130{ 127{
131 int maxid, shmid, id; 128 int maxid, shmid, id;
132 struct shmid_ds shmseg; 129 struct shmid_ds shmseg;
@@ -252,8 +249,7 @@ static NOINLINE void do_shm(void)
252 } 249 }
253} 250}
254 251
255 252static NOINLINE void do_sem(int format)
256static NOINLINE void do_sem(void)
257{ 253{
258 int maxid, semid, id; 254 int maxid, semid, id;
259 struct semid_ds semary; 255 struct semid_ds semary;
@@ -358,8 +354,7 @@ static NOINLINE void do_sem(void)
358 } 354 }
359} 355}
360 356
361 357static NOINLINE void do_msg(int format)
362static NOINLINE void do_msg(void)
363{ 358{
364 int maxid, msqid, id; 359 int maxid, msqid, id;
365 struct msqid_ds msgque; 360 struct msqid_ds msgque;
@@ -466,7 +461,6 @@ static NOINLINE void do_msg(void)
466 } 461 }
467} 462}
468 463
469
470static void print_shm(int shmid) 464static void print_shm(int shmid)
471{ 465{
472 struct shmid_ds shmds; 466 struct shmid_ds shmds;
@@ -493,7 +487,6 @@ static void print_shm(int shmid)
493 printf("change_time=%-26.24s\n\n", ctime(&shmds.shm_ctime)); 487 printf("change_time=%-26.24s\n\n", ctime(&shmds.shm_ctime));
494} 488}
495 489
496
497static void print_msg(int msqid) 490static void print_msg(int msqid)
498{ 491{
499 struct msqid_ds buf; 492 struct msqid_ds buf;
@@ -570,9 +563,9 @@ static void print_sem(int semid)
570} 563}
571 564
572//usage:#define ipcs_trivial_usage 565//usage:#define ipcs_trivial_usage
573//usage: "[[-smq] -i shmid] | [[-asmq] [-tcplu]]" 566//usage: "[[-smq] -i SHMID] | [[-asmq] [-tcplu]]"
574//usage:#define ipcs_full_usage "\n\n" 567//usage:#define ipcs_full_usage "\n\n"
575//usage: " -i Show specific resource" 568//usage: " -i ID Show specific resource"
576//usage: "\nResource specification:" 569//usage: "\nResource specification:"
577//usage: "\n -m Shared memory segments" 570//usage: "\n -m Shared memory segments"
578//usage: "\n -q Message queues" 571//usage: "\n -q Message queues"
@@ -588,60 +581,57 @@ static void print_sem(int semid)
588int ipcs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 581int ipcs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
589int ipcs_main(int argc UNUSED_PARAM, char **argv) 582int ipcs_main(int argc UNUSED_PARAM, char **argv)
590{ 583{
591 int id = 0; 584 int format = 0;
592 unsigned flags = 0;
593 unsigned opt; 585 unsigned opt;
594 char *opt_i; 586 char *opt_i;
595#define flag_print (1<<0)
596#define flag_msg (1<<1)
597#define flag_sem (1<<2)
598#define flag_shm (1<<3)
599 587
600 opt = getopt32(argv, "i:aqsmtcplu", &opt_i); 588 opt = getopt32(argv, "i:aqsmtcplu", &opt_i);
601 if (opt & 0x1) { // -i 589#define flag_msg (1<<2)
590#define flag_sem (1<<3)
591#define flag_shm (1<<4)
592 if (opt & (1<<5)) format = TIME; // -t
593 if (opt & (1<<6)) format = CREATOR; // -c
594 if (opt & (1<<7)) format = PID; // -p
595 if (opt & (1<<8)) format = LIMITS; // -l
596 if (opt & (1<<9)) format = STATUS; // -u
597
598 if (opt & (1<<0)) { // -i
599 int id;
600
602 id = xatoi(opt_i); 601 id = xatoi(opt_i);
603 flags |= flag_print; 602 if (opt & flag_shm) {
604 }
605 if (opt & 0x2) flags |= flag_msg | flag_sem | flag_shm; // -a
606 if (opt & 0x4) flags |= flag_msg; // -q
607 if (opt & 0x8) flags |= flag_sem; // -s
608 if (opt & 0x10) flags |= flag_shm; // -m
609 if (opt & 0x20) format = TIME; // -t
610 if (opt & 0x40) format = CREATOR; // -c
611 if (opt & 0x80) format = PID; // -p
612 if (opt & 0x100) format = LIMITS; // -l
613 if (opt & 0x200) format = STATUS; // -u
614
615 if (flags & flag_print) {
616 if (flags & flag_shm) {
617 print_shm(id); 603 print_shm(id);
618 fflush_stdout_and_exit(EXIT_SUCCESS); 604 fflush_stdout_and_exit(EXIT_SUCCESS);
619 } 605 }
620 if (flags & flag_sem) { 606 if (opt & flag_sem) {
621 print_sem(id); 607 print_sem(id);
622 fflush_stdout_and_exit(EXIT_SUCCESS); 608 fflush_stdout_and_exit(EXIT_SUCCESS);
623 } 609 }
624 if (flags & flag_msg) { 610 if (opt & flag_msg) {
625 print_msg(id); 611 print_msg(id);
626 fflush_stdout_and_exit(EXIT_SUCCESS); 612 fflush_stdout_and_exit(EXIT_SUCCESS);
627 } 613 }
628 bb_show_usage(); 614 bb_show_usage();
629 } 615 }
630 616
631 if (!(flags & (flag_shm | flag_msg | flag_sem))) 617 if ((opt & (1<<1)) // -a
632 flags |= flag_msg | flag_shm | flag_sem; 618 || !(opt & (flag_msg | flag_sem | flag_shm)) // none of -q,-s,-m == all
619 ) {
620 opt |= flag_msg | flag_sem | flag_shm;
621 }
622
633 bb_putchar('\n'); 623 bb_putchar('\n');
634 624
635 if (flags & flag_msg) { 625 if (opt & flag_msg) {
636 do_msg(); 626 do_msg(format);
637 bb_putchar('\n'); 627 bb_putchar('\n');
638 } 628 }
639 if (flags & flag_shm) { 629 if (opt & flag_shm) {
640 do_shm(); 630 do_shm(format);
641 bb_putchar('\n'); 631 bb_putchar('\n');
642 } 632 }
643 if (flags & flag_sem) { 633 if (opt & flag_sem) {
644 do_sem(); 634 do_sem(format);
645 bb_putchar('\n'); 635 bb_putchar('\n');
646 } 636 }
647 fflush_stdout_and_exit(EXIT_SUCCESS); 637 fflush_stdout_and_exit(EXIT_SUCCESS);
diff --git a/util-linux/readprofile.c b/util-linux/readprofile.c
index 8fc33be3c..219c0c18c 100644
--- a/util-linux/readprofile.c
+++ b/util-linux/readprofile.c
@@ -61,27 +61,22 @@
61 61
62#define S_LEN 128 62#define S_LEN 128
63 63
64/* These are the defaults */
65static const char defaultmap[] ALIGN1 = "/boot/System.map";
66static const char defaultpro[] ALIGN1 = "/proc/profile";
67
68int readprofile_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 64int readprofile_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
69int readprofile_main(int argc UNUSED_PARAM, char **argv) 65int readprofile_main(int argc UNUSED_PARAM, char **argv)
70{ 66{
71 FILE *map; 67 FILE *map;
72 const char *mapFile, *proFile; 68 const char *mapFile, *proFile;
73 unsigned long indx = 1; 69 unsigned long indx;
74 size_t len; 70 size_t len;
75 uint64_t add0 = 0; 71 uint64_t add0;
76 unsigned int step; 72 unsigned int step;
77 unsigned int *buf, total, fn_len; 73 unsigned int *buf, total, fn_len;
78 unsigned long long fn_add, next_add; /* current and next address */ 74 unsigned long long fn_add, next_add; /* current and next address */
79 char fn_name[S_LEN], next_name[S_LEN]; /* current and next name */ 75 char fn_name[S_LEN], next_name[S_LEN]; /* current and next name */
80 char mapline[S_LEN]; 76 char mapline[S_LEN];
81 char mode[8]; 77 char mode[8];
82 int maplineno = 1; 78 int maplineno;
83 int header_printed; 79 int multiplier;
84 int multiplier = 0;
85 unsigned opt; 80 unsigned opt;
86 enum { 81 enum {
87 OPT_M = (1 << 0), 82 OPT_M = (1 << 0),
@@ -106,8 +101,9 @@ int readprofile_main(int argc UNUSED_PARAM, char **argv)
106 101
107#define next (current^1) 102#define next (current^1)
108 103
109 proFile = defaultpro; 104 proFile = "/proc/profile";
110 mapFile = defaultmap; 105 mapFile = "/boot/System.map";
106 multiplier = 0;
111 107
112 opt = getopt32(argv, "M:+m:p:nabsirv", &multiplier, &mapFile, &proFile); 108 opt = getopt32(argv, "M:+m:p:nabsirv", &multiplier, &mapFile, &proFile);
113 109
@@ -122,7 +118,7 @@ int readprofile_main(int argc UNUSED_PARAM, char **argv)
122 if (!optMult) 118 if (!optMult)
123 to_write = 1; /* sth different from sizeof(int) */ 119 to_write = 1; /* sth different from sizeof(int) */
124 120
125 fd = xopen(defaultpro, O_WRONLY); 121 fd = xopen("/proc/profile", O_WRONLY);
126 xwrite(fd, &multiplier, to_write); 122 xwrite(fd, &multiplier, to_write);
127 close(fd); 123 close(fd);
128 return EXIT_SUCCESS; 124 return EXIT_SUCCESS;
@@ -133,12 +129,13 @@ int readprofile_main(int argc UNUSED_PARAM, char **argv)
133 */ 129 */
134 len = MAXINT(ssize_t); 130 len = MAXINT(ssize_t);
135 buf = xmalloc_xopen_read_close(proFile, &len); 131 buf = xmalloc_xopen_read_close(proFile, &len);
132 len /= sizeof(*buf);
133
136 if (!optNative) { 134 if (!optNative) {
137 int entries = len / sizeof(*buf); 135 int big = 0, small = 0;
138 int big = 0, small = 0, i;
139 unsigned *p; 136 unsigned *p;
140 137
141 for (p = buf+1; p < buf+entries; p++) { 138 for (p = buf+1; p < buf+len; p++) {
142 if (*p & ~0U << (sizeof(*buf)*4)) 139 if (*p & ~0U << (sizeof(*buf)*4))
143 big++; 140 big++;
144 if (*p & ((1 << (sizeof(*buf)*4))-1)) 141 if (*p & ((1 << (sizeof(*buf)*4))-1))
@@ -147,15 +144,15 @@ int readprofile_main(int argc UNUSED_PARAM, char **argv)
147 if (big > small) { 144 if (big > small) {
148 bb_error_msg("assuming reversed byte order, " 145 bb_error_msg("assuming reversed byte order, "
149 "use -n to force native byte order"); 146 "use -n to force native byte order");
150 for (p = buf; p < buf+entries; p++) 147 BUILD_BUG_ON(sizeof(*p) > 8);
151 for (i = 0; i < sizeof(*buf)/2; i++) { 148 for (p = buf; p < buf+len; p++) {
152 unsigned char *b = (unsigned char *) p; 149 if (sizeof(*p) == 2)
153 unsigned char tmp; 150 *p = bswap_16(*p);
154 151 if (sizeof(*p) == 4)
155 tmp = b[i]; 152 *p = bswap_32(*p);
156 b[i] = b[sizeof(*buf)-i-1]; 153 if (sizeof(*p) == 8)
157 b[sizeof(*buf)-i-1] = tmp; 154 *p = bb_bswap_64(*p);
158 } 155 }
159 } 156 }
160 } 157 }
161 158
@@ -165,10 +162,9 @@ int readprofile_main(int argc UNUSED_PARAM, char **argv)
165 return EXIT_SUCCESS; 162 return EXIT_SUCCESS;
166 } 163 }
167 164
168 total = 0;
169
170 map = xfopen_for_read(mapFile); 165 map = xfopen_for_read(mapFile);
171 166 add0 = 0;
167 maplineno = 1;
172 while (fgets(mapline, S_LEN, map)) { 168 while (fgets(mapline, S_LEN, map)) {
173 if (sscanf(mapline, "%llx %s %s", &fn_add, mode, fn_name) != 3) 169 if (sscanf(mapline, "%llx %s %s", &fn_add, mode, fn_name) != 3)
174 bb_error_msg_and_die("%s(%i): wrong map line", 170 bb_error_msg_and_die("%s(%i): wrong map line",
@@ -187,8 +183,11 @@ int readprofile_main(int argc UNUSED_PARAM, char **argv)
187 /* 183 /*
188 * Main loop. 184 * Main loop.
189 */ 185 */
186 total = 0;
187 indx = 1;
190 while (fgets(mapline, S_LEN, map)) { 188 while (fgets(mapline, S_LEN, map)) {
191 unsigned int this = 0; 189 bool header_printed;
190 unsigned int this;
192 191
193 if (sscanf(mapline, "%llx %s %s", &next_add, mode, next_name) != 3) 192 if (sscanf(mapline, "%llx %s %s", &next_add, mode, next_name) != 3)
194 bb_error_msg_and_die("%s(%i): wrong map line", 193 bb_error_msg_and_die("%s(%i): wrong map line",
@@ -198,17 +197,17 @@ int readprofile_main(int argc UNUSED_PARAM, char **argv)
198 197
199 /* ignore any LEADING (before a '[tT]' symbol is found) 198 /* ignore any LEADING (before a '[tT]' symbol is found)
200 Absolute symbols */ 199 Absolute symbols */
201 if ((*mode == 'A' || *mode == '?') && total == 0) continue; 200 if ((mode[0] == 'A' || mode[0] == '?') && total == 0)
202 if (*mode != 'T' && *mode != 't' 201 continue;
203 && *mode != 'W' && *mode != 'w' 202 if ((mode[0]|0x20) != 't' && (mode[0]|0x20) != 'w') {
204 ) {
205 break; /* only text is profiled */ 203 break; /* only text is profiled */
206 } 204 }
207 205
208 if (indx >= len / sizeof(*buf)) 206 if (indx >= len)
209 bb_error_msg_and_die("profile address out of range. " 207 bb_error_msg_and_die("profile address out of range. "
210 "Wrong map file?"); 208 "Wrong map file?");
211 209
210 this = 0;
212 while (indx < (next_add-add0)/step) { 211 while (indx < (next_add-add0)/step) {
213 if (optBins && (buf[indx] || optAll)) { 212 if (optBins && (buf[indx] || optAll)) {
214 if (!header_printed) { 213 if (!header_printed) {
@@ -256,7 +255,7 @@ int readprofile_main(int argc UNUSED_PARAM, char **argv)
256 } 255 }
257 256
258 /* clock ticks, out of kernel text - probably modules */ 257 /* clock ticks, out of kernel text - probably modules */
259 printf("%6u %s\n", buf[len/sizeof(*buf)-1], "*unknown*"); 258 printf("%6u *unknown*\n", buf[len-1]);
260 259
261 /* trailer */ 260 /* trailer */
262 if (optVerbose) 261 if (optVerbose)